From 14122770ef1c8338124d3c8e578d4b5d5d307870 Mon Sep 17 00:00:00 2001 From: Mika Bostrom Date: Sat, 3 Oct 2009 21:05:41 +0300 Subject: [PATCH 01/14] Make hud's menu-area text configurable By default the hud positions a little box on top-left corner of each table. Make the text in this box user-modifiable without touching the source. Most likely useful for active users and those who play with smaller tables. On shrunk table the default box may cover some of the players' cards. --- pyfpdb/Configuration.py | 26 ++++++++++++++++++++++++++ pyfpdb/Hud.py | 3 ++- 2 files changed, 28 insertions(+), 1 deletion(-) diff --git a/pyfpdb/Configuration.py b/pyfpdb/Configuration.py index b8022a45..dbe973c1 100755 --- a/pyfpdb/Configuration.py +++ b/pyfpdb/Configuration.py @@ -278,6 +278,15 @@ class Import: return " interval = %s\n callFpdbHud = %s\n hhArchiveBase = %s\n saveActions = %s\n fastStoreHudCache = %s\n" \ % (self.interval, self.callFpdbHud, self.hhArchiveBase, self.saveActions, self.fastStoreHudCache) +class HudUI: + def __init__(self, node): + self.node = node + self.label = node.getAttribute('label') + + def __str__(self): + return " label = %s\n" % self.label + + class Tv: def __init__(self, node): self.combinedStealFold = node.getAttribute("combinedStealFold") @@ -389,6 +398,10 @@ class Config: imp = Import(node = imp_node) self.imp = imp + for hui_node in doc.getElementsByTagName('hud_ui'): + hui = HudUI(node = hui_node) + self.ui = hui + for tv_node in doc.getElementsByTagName("tv"): tv = Tv(node = tv_node) self.tv = tv @@ -598,6 +611,19 @@ class Config: try: tv['combinedPostflop'] = self.tv.combinedPostflop except: tv['combinedPostflop'] = True return tv + + # Allow to change the menu appearance + def get_hud_ui_parameters(self): + hui = {} + default_text = 'FPDB Menu - Right click\nLeft-Drag to Move' + try: + hui['label'] = self.ui.label + if self.ui.label == '': # Empty menu label is a big no-no + hui['label'] = default_text + except: + hui['label'] = default_text + return hui + def get_import_parameters(self): imp = {} diff --git a/pyfpdb/Hud.py b/pyfpdb/Hud.py index 77143d79..6d88e6d4 100644 --- a/pyfpdb/Hud.py +++ b/pyfpdb/Hud.py @@ -80,6 +80,7 @@ class Hud: (font, font_size) = config.get_default_font(self.table.site) self.colors = config.get_default_colors(self.table.site) + self.hud_ui = config.get_hud_ui_parameters() self.backgroundcolor = gtk.gdk.color_parse(self.colors['hudbgcolor']) self.foregroundcolor = gtk.gdk.color_parse(self.colors['hudfgcolor']) @@ -114,7 +115,7 @@ class Hud: win.set_opacity(self.colors["hudopacity"]) eventbox = gtk.EventBox() - label = gtk.Label("FPDB Menu - Right click\nLeft-Drag to Move") + label = gtk.Label(self.hud_ui['label']) win.add(eventbox) eventbox.add(label) From f6eb365b3c3d80bda88253932de2e024021356f7 Mon Sep 17 00:00:00 2001 From: Mika Bostrom Date: Sat, 3 Oct 2009 21:10:09 +0300 Subject: [PATCH 02/14] Add the default box text to example config Now that the text on HUD's box is configurable, move the default text from code to default/sample config. --- pyfpdb/HUD_config.xml.example | 3 +++ 1 file changed, 3 insertions(+) diff --git a/pyfpdb/HUD_config.xml.example b/pyfpdb/HUD_config.xml.example index adc8141c..de2f1bba 100644 --- a/pyfpdb/HUD_config.xml.example +++ b/pyfpdb/HUD_config.xml.example @@ -4,6 +4,9 @@ + + Date: Sun, 25 Oct 2009 14:22:49 +0300 Subject: [PATCH 03/14] Tiny fix --- pyfpdb/GuiGraphViewer.py | 1 + 1 file changed, 1 insertion(+) diff --git a/pyfpdb/GuiGraphViewer.py b/pyfpdb/GuiGraphViewer.py index f91c9870..d148d841 100644 --- a/pyfpdb/GuiGraphViewer.py +++ b/pyfpdb/GuiGraphViewer.py @@ -20,6 +20,7 @@ import pygtk pygtk.require('2.0') import gtk import os +import sys import traceback from time import * #import pokereval From c7410d6fc8b3c12d8cf3073949e75841bab9b0f3 Mon Sep 17 00:00:00 2001 From: grindi Date: Wed, 28 Oct 2009 18:57:54 +0300 Subject: [PATCH 04/14] Fix config's default values for hud colors 00000 -> #000000 FFFFF -> #FFFFFF --- pyfpdb/Configuration.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pyfpdb/Configuration.py b/pyfpdb/Configuration.py index 5dba6aac..9fcfd623 100755 --- a/pyfpdb/Configuration.py +++ b/pyfpdb/Configuration.py @@ -132,8 +132,8 @@ class Site: if self.use_frames == "": self.use_frames = False if self.font == "": self.font = "Sans" - if self.hudbgcolor == "": self.hudbgcolor = "000000" - if self.hudfgcolor == "": self.hudfgcolor = "FFFFFF" + if self.hudbgcolor == "": self.hudbgcolor = "#000000" + if self.hudfgcolor == "": self.hudfgcolor = "#FFFFFF" def __str__(self): temp = "Site = " + self.site_name + "\n" From dcbc7d72038726513c5e42b948a6162f90ea03fb Mon Sep 17 00:00:00 2001 From: unknown Date: Wed, 28 Oct 2009 17:40:25 -0400 Subject: [PATCH 05/14] fix format of line --- pyfpdb/fpdb_db.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pyfpdb/fpdb_db.py b/pyfpdb/fpdb_db.py index da0bbbe7..3dc77a51 100644 --- a/pyfpdb/fpdb_db.py +++ b/pyfpdb/fpdb_db.py @@ -78,7 +78,7 @@ class fpdb_db: if use_pool: MySQLdb = pool.manage(MySQLdb, pool_size=5) # try: - self.db = MySQLdb.connect(host = host, user = user, passwd = password, db = database, use_unicode=True) + self.db = MySQLdb.connect(host=host, user=user, passwd=password, db=database, use_unicode=True) #TODO: Add port option # except: # raise FpdbMySQLFailedError("MySQL connection failed") From 02e8154710d109be3126c6958570350113f174bf Mon Sep 17 00:00:00 2001 From: unknown Date: Wed, 28 Oct 2009 19:53:31 -0400 Subject: [PATCH 06/14] remove error trap on read_stdin() - please fix bugs instead of relying on error trap some reformatting in Tables.py, as well as some new debug prints to deal with some potential issues. Add code to deal with potential problems in Win x64, that are biting me at random. Not finished, but the problems stopped happening so can't continue. --- pyfpdb/HUD_main.py | 162 ++++++++++++++++++++++----------------------- pyfpdb/Tables.py | 52 ++++++++++----- 2 files changed, 114 insertions(+), 100 deletions(-) diff --git a/pyfpdb/HUD_main.py b/pyfpdb/HUD_main.py index a0f152b7..8ccc194e 100755 --- a/pyfpdb/HUD_main.py +++ b/pyfpdb/HUD_main.py @@ -189,99 +189,95 @@ class HUD_main(object): # be passed to HUDs for use in the gui thread. HUD objects should not # need their own access to the database, but should open their own # if it is required. - try: - self.db_connection = Database.Database(self.config) - tourny_finder = re.compile('(\d+) (\d+)') - -# get hero's screen names and player ids - self.hero, self.hero_ids = {}, {} - for site in self.config.get_supported_sites(): - result = self.db_connection.get_site_id(site) - if result: - site_id = result[0][0] - self.hero[site_id] = self.config.supported_sites[site].screen_name - self.hero_ids[site_id] = self.db_connection.get_player_id(self.config, site, self.hero[site_id]) + self.db_connection = Database.Database(self.config) + tourny_finder = re.compile('(\d+) (\d+)') - while 1: # wait for a new hand number on stdin - new_hand_id = sys.stdin.readline() - new_hand_id = string.rstrip(new_hand_id) - if new_hand_id == "": # blank line means quit - self.destroy() - break # this thread is not always killed immediately with gtk.main_quit() +# get hero's screen names and player ids + self.hero, self.hero_ids = {}, {} + for site in self.config.get_supported_sites(): + result = self.db_connection.get_site_id(site) + if result: + site_id = result[0][0] + self.hero[site_id] = self.config.supported_sites[site].screen_name + self.hero_ids[site_id] = self.db_connection.get_player_id(self.config, site, self.hero[site_id]) + + while 1: # wait for a new hand number on stdin + new_hand_id = sys.stdin.readline() + new_hand_id = string.rstrip(new_hand_id) + if new_hand_id == "": # blank line means quit + self.destroy() + break # this thread is not always killed immediately with gtk.main_quit() # get basic info about the new hand from the db # if there is a db error, complain, skip hand, and proceed - try: - (table_name, max, poker_game, type, site_id) = self.db_connection.get_table_name(new_hand_id) + try: + (table_name, max, poker_game, type, site_id) = self.db_connection.get_table_name(new_hand_id) - cards = self.db_connection.get_cards(new_hand_id) - comm_cards = self.db_connection.get_common_cards(new_hand_id) - if comm_cards != {}: # stud! - cards['common'] = comm_cards['common'] - except Exception, err: - err = traceback.extract_tb(sys.exc_info()[2])[-1] - print "db error: skipping "+str(new_hand_id)+" "+err[2]+"("+str(err[1])+"): "+str(sys.exc_info()[1]) - if new_hand_id: # new_hand_id is none if we had an error prior to the store - sys.stderr.write("Database error %s in hand %d. Skipping.\n" % (err, int(new_hand_id))) + cards = self.db_connection.get_cards(new_hand_id) + comm_cards = self.db_connection.get_common_cards(new_hand_id) + if comm_cards != {}: # stud! + cards['common'] = comm_cards['common'] + except Exception, err: + err = traceback.extract_tb(sys.exc_info()[2])[-1] + print "db error: skipping "+str(new_hand_id)+" "+err[2]+"("+str(err[1])+"): "+str(sys.exc_info()[1]) + if new_hand_id: # new_hand_id is none if we had an error prior to the store + sys.stderr.write("Database error %s in hand %d. Skipping.\n" % (err, int(new_hand_id))) + continue + + if type == "tour": # hand is from a tournament + mat_obj = tourny_finder.search(table_name) + if mat_obj: + (tour_number, tab_number) = mat_obj.group(1, 2) + temp_key = tour_number + else: # tourney, but can't get number and table + print "could not find tournament: skipping " + #sys.stderr.write("Could not find tournament %d in hand %d. Skipping.\n" % (int(tour_number), int(new_hand_id))) continue - - if type == "tour": # hand is from a tournament - mat_obj = tourny_finder.search(table_name) - if mat_obj: - (tour_number, tab_number) = mat_obj.group(1, 2) - temp_key = tour_number - else: # tourney, but can't get number and table - print "could not find tournament: skipping " - #sys.stderr.write("Could not find tournament %d in hand %d. Skipping.\n" % (int(tour_number), int(new_hand_id))) - continue - - else: - temp_key = table_name + + else: + temp_key = table_name # Update an existing HUD - if temp_key in self.hud_dict: - try: - # get stats using hud's specific params - self.db_connection.init_hud_stat_vars( self.hud_dict[temp_key].hud_params['hud_days'] - , self.hud_dict[temp_key].hud_params['h_hud_days']) - stat_dict = self.db_connection.get_stats_from_hand(new_hand_id, type, self.hud_dict[temp_key].hud_params, self.hero_ids[site_id]) - except: - err = traceback.extract_tb(sys.exc_info()[2])[-1] - print "db get_stats error: skipping "+str(new_hand_id)+" "+err[2]+"("+str(err[1])+"): "+str(sys.exc_info()[1]) - if new_hand_id: # new_hand_id is none if we had an error prior to the store - sys.stderr.write("Database get_stats error %s in hand %d. Skipping.\n" % (err, int(new_hand_id))) - continue - self.hud_dict[temp_key].stat_dict = stat_dict - self.hud_dict[temp_key].cards = cards - [aw.update_data(new_hand_id, self.db_connection) for aw in self.hud_dict[temp_key].aux_windows] - self.update_HUD(new_hand_id, temp_key, self.config) - + if temp_key in self.hud_dict: + try: + # get stats using hud's specific params + self.db_connection.init_hud_stat_vars( self.hud_dict[temp_key].hud_params['hud_days'] + , self.hud_dict[temp_key].hud_params['h_hud_days']) + stat_dict = self.db_connection.get_stats_from_hand(new_hand_id, type, self.hud_dict[temp_key].hud_params, self.hero_ids[site_id]) + except: + err = traceback.extract_tb(sys.exc_info()[2])[-1] + print "db get_stats error: skipping "+str(new_hand_id)+" "+err[2]+"("+str(err[1])+"): "+str(sys.exc_info()[1]) + if new_hand_id: # new_hand_id is none if we had an error prior to the store + sys.stderr.write("Database get_stats error %s in hand %d. Skipping.\n" % (err, int(new_hand_id))) + continue + self.hud_dict[temp_key].stat_dict = stat_dict + self.hud_dict[temp_key].cards = cards + [aw.update_data(new_hand_id, self.db_connection) for aw in self.hud_dict[temp_key].aux_windows] + self.update_HUD(new_hand_id, temp_key, self.config) + # Or create a new HUD + else: + try: + # get stats using default params + self.db_connection.init_hud_stat_vars( self.hud_params['hud_days'], self.hud_params['h_hud_days'] ) + stat_dict = self.db_connection.get_stats_from_hand(new_hand_id, type, self.hud_params, self.hero_ids[site_id]) + except: + err = traceback.extract_tb(sys.exc_info()[2])[-1] + print "db get_stats error: skipping "+str(new_hand_id)+" "+err[2]+"("+str(err[1])+"): "+str(sys.exc_info()[1]) + if new_hand_id: # new_hand_id is none if we had an error prior to the store + sys.stderr.write("Database get_stats error %s in hand %d. Skipping.\n" % (err, int(new_hand_id))) + continue + if type == "tour": + tablewindow = Tables.discover_tournament_table(self.config, tour_number, tab_number) else: - try: - # get stats using default params - self.db_connection.init_hud_stat_vars( self.hud_params['hud_days'], self.hud_params['h_hud_days'] ) - stat_dict = self.db_connection.get_stats_from_hand(new_hand_id, type, self.hud_params, self.hero_ids[site_id]) - except: - err = traceback.extract_tb(sys.exc_info()[2])[-1] - print "db get_stats error: skipping "+str(new_hand_id)+" "+err[2]+"("+str(err[1])+"): "+str(sys.exc_info()[1]) - if new_hand_id: # new_hand_id is none if we had an error prior to the store - sys.stderr.write("Database get_stats error %s in hand %d. Skipping.\n" % (err, int(new_hand_id))) - continue - if type == "tour": - tablewindow = Tables.discover_tournament_table(self.config, tour_number, tab_number) - else: - tablewindow = Tables.discover_table_by_name(self.config, table_name) - if tablewindow == None: + tablewindow = Tables.discover_table_by_name(self.config, table_name) + if tablewindow == None: # If no client window is found on the screen, complain and continue - if type == "tour": - table_name = "%s %s" % (tour_number, tab_number) - sys.stderr.write("table name "+table_name+" not found, skipping.\n") - else: - self.create_HUD(new_hand_id, tablewindow, temp_key, max, poker_game, type, stat_dict, cards) - self.db_connection.connection.rollback() - except: - err = traceback.extract_tb(sys.exc_info()[2])[-1] - print "***Error: "+err[2]+"("+str(err[1])+"): "+str(sys.exc_info()[1]) + if type == "tour": + table_name = "%s %s" % (tour_number, tab_number) + sys.stderr.write("table name "+table_name+" not found, skipping.\n") + else: + self.create_HUD(new_hand_id, tablewindow, temp_key, max, poker_game, type, stat_dict, cards) + self.db_connection.connection.rollback() if __name__== "__main__": diff --git a/pyfpdb/Tables.py b/pyfpdb/Tables.py index e725d5b8..46addabc 100755 --- a/pyfpdb/Tables.py +++ b/pyfpdb/Tables.py @@ -238,7 +238,8 @@ def discover_nt_by_name(c, tablename): try: # maybe it's better to make global titles[hwnd] decoding? # this can blow up in XP on some windows, eg firefox displaying http://docs.python.org/tutorial/classes.html - if not tablename.lower() in titles[hwnd].decode(LOCALE_ENCODING).lower(): continue + if not tablename.lower() in titles[hwnd].decode(LOCALE_ENCODING).lower(): + continue except: continue if 'History for table:' in titles[hwnd]: continue # Everleaf Network HH viewer window @@ -246,8 +247,8 @@ def discover_nt_by_name(c, tablename): if 'Chat:' in titles[hwnd]: continue # Some sites (FTP? PS? Others?) have seperable or seperately constructed chat windows if ' - Table ' in titles[hwnd]: continue # Absolute table Chat window.. sigh. TODO: Can we tell what site we're trying to discover for somehow in here, so i can limit this check just to AP searches? temp = decode_windows(c, titles[hwnd], hwnd) - #print "attach to window", temp - return decode_windows(c, titles[hwnd], hwnd) + print "attach to window", temp + return temp return None def discover_nt_tournament(c, tour_number, tab_number): @@ -257,9 +258,12 @@ def discover_nt_tournament(c, tour_number, tab_number): titles ={} win32gui.EnumWindows(win_enum_handler, titles) for hwnd in titles: - if 'Chat:' in titles[hwnd]: continue # Some sites (FTP? PS? Others?) have seperable or seperately constructed chat windows - if 'History for table:' in titles[hwnd]: continue # Everleaf Network HH viewer window - if 'HUD:' in titles[hwnd]: continue # FPDB HUD window + # Some sites (FTP? PS? Others?) have seperable or seperately constructed chat windows + if 'Chat:' in titles[hwnd]: continue + # Everleaf Network HH viewer window + if 'History for table:' in titles[hwnd]: continue + # FPDB HUD window + if 'HUD:' in titles[hwnd]: continue if re.search(search_string, titles[hwnd]): return decode_windows(c, titles[hwnd], hwnd) @@ -268,22 +272,34 @@ def discover_nt_tournament(c, tour_number, tab_number): def get_nt_exe(hwnd): """Finds the name of the executable that the given window handle belongs to.""" - # Request privileges to enable "debug process", so we can later use PROCESS_VM_READ, retardedly required to GetModuleFileNameEx() + # Request privileges to enable "debug process", so we can later use + # PROCESS_VM_READ, retardedly required to GetModuleFileNameEx() priv_flags = win32security.TOKEN_ADJUST_PRIVILEGES | win32security.TOKEN_QUERY - hToken = win32security.OpenProcessToken (win32api.GetCurrentProcess(), priv_flags) + hToken = win32security.OpenProcessToken (win32api.GetCurrentProcess(), + priv_flags) # enable "debug process" - privilege_id = win32security.LookupPrivilegeValue (None, win32security.SE_DEBUG_NAME) - old_privs = win32security.AdjustTokenPrivileges (hToken, 0, [(privilege_id, win32security.SE_PRIVILEGE_ENABLED)]) + privilege_id = win32security.LookupPrivilegeValue(None, + win32security.SE_DEBUG_NAME) + old_privs = win32security.AdjustTokenPrivileges(hToken, 0, + [(privilege_id, + win32security.SE_PRIVILEGE_ENABLED)]) # Open the process, and query it's filename processid = win32process.GetWindowThreadProcessId(hwnd) - pshandle = win32api.OpenProcess(win32con.PROCESS_QUERY_INFORMATION | win32con.PROCESS_VM_READ, False, processid[1]) - exename = win32process.GetModuleFileNameEx(pshandle, 0) - - # clean up - win32api.CloseHandle(pshandle) - win32api.CloseHandle(hToken) - + pshandle = win32api.OpenProcess(win32con.PROCESS_QUERY_INFORMATION | + win32con.PROCESS_VM_READ, False, + processid[1]) + try: + exename = win32process.GetModuleFileNameEx(pshandle, 0) + except pywintypes.error: + # insert code to call GetProcessImageName if we can find it.. + # returning None from here will hopefully break all following code + exename = None + finally: + # clean up + win32api.CloseHandle(pshandle) + win32api.CloseHandle(hToken) + return exename def decode_windows(c, title, hwnd): @@ -305,6 +321,8 @@ def decode_windows(c, title, hwnd): info['width'] = int( width ) - 2*b_width info['height'] = int( height ) - b_width - tb_height info['exe'] = get_nt_exe(hwnd) + print "get_nt_exe returned ", info['exe'] + # TODO: 'width' here is all sorts of screwed up. title_bits = re.split(' - ', info['title']) info['name'] = title_bits[0] From ca5fea5cc594b76c163c7bf5d1bc8d3b800853d6 Mon Sep 17 00:00:00 2001 From: Mika Bostrom Date: Fri, 30 Oct 2009 01:51:57 +0200 Subject: [PATCH 07/14] Fix HUD start from debianized install --- packaging/debian/python-fpdb.postinst | 1 + 1 file changed, 1 insertion(+) diff --git a/packaging/debian/python-fpdb.postinst b/packaging/debian/python-fpdb.postinst index 1f618958..9680be90 100644 --- a/packaging/debian/python-fpdb.postinst +++ b/packaging/debian/python-fpdb.postinst @@ -3,3 +3,4 @@ # When installed into .../fpdb/ the script gets mode 644 # Note: "dh_fixperms -Xfpdb.py" did not work, hence this hack chmod 755 /usr/bin/fpdb +chmod 755 /usr/share/pyshared/fpdb/HUD_main.py From 636727ebb6a68da9416ffbdf8fc946e9e720ce3b Mon Sep 17 00:00:00 2001 From: Worros Date: Fri, 30 Oct 2009 14:35:45 +0800 Subject: [PATCH 08/14] Start of Partouche support, shift NEWIMPORT functions --- pyfpdb/Database.py | 116 +++++++++++++++++----------------- pyfpdb/HUD_config.xml.example | 1 + 2 files changed, 60 insertions(+), 57 deletions(-) diff --git a/pyfpdb/Database.py b/pyfpdb/Database.py index 1533c05c..ba71310b 100755 --- a/pyfpdb/Database.py +++ b/pyfpdb/Database.py @@ -1145,6 +1145,7 @@ class Database: c.execute("INSERT INTO Sites (name,currency) VALUES ('Betfair', 'USD')") c.execute("INSERT INTO Sites (name,currency) VALUES ('Absolute', 'USD')") c.execute("INSERT INTO Sites (name,currency) VALUES ('PartyPoker', 'USD')") + c.execute("INSERT INTO Sites (name,currency) VALUES ('Partouche', 'EUR')") if self.backend == self.SQLITE: c.execute("INSERT INTO TourneyTypes (id, siteId, buyin, fee) VALUES (NULL, 1, 0, 0);") elif self.backend == self.PGSQL: @@ -1264,63 +1265,6 @@ class Database: print "Error during fdb.lock_for_insert:", str(sys.exc_value) #end def lock_for_insert - def getGameTypeId(self, siteid, game): - c = self.get_cursor() - #FIXME: Fixed for NL at the moment - c.execute(self.sql.query['getGametypeNL'], (siteid, game['type'], game['category'], game['limitType'], - int(Decimal(game['sb'])*100), int(Decimal(game['bb'])*100))) - tmp = c.fetchone() - if (tmp == None): - hilo = "h" - if game['category'] in ['studhilo', 'omahahilo']: - hilo = "s" - elif game['category'] in ['razz','27_3draw','badugi']: - hilo = "l" - tmp = self.insertGameTypes( (siteid, game['type'], game['base'], game['category'], game['limitType'], hilo, - int(Decimal(game['sb'])*100), int(Decimal(game['bb'])*100), 0, 0) ) - return tmp[0] - - def getSqlPlayerIDs(self, pnames, siteid): - result = {} - if(self.pcache == None): - self.pcache = LambdaDict(lambda key:self.insertPlayer(key, siteid)) - - for player in pnames: - result[player] = self.pcache[player] - # NOTE: Using the LambdaDict does the same thing as: - #if player in self.pcache: - # #print "DEBUG: cachehit" - # pass - #else: - # self.pcache[player] = self.insertPlayer(player, siteid) - #result[player] = self.pcache[player] - - return result - - def insertPlayer(self, name, site_id): - result = None - c = self.get_cursor() - q = "SELECT name, id FROM Players WHERE siteid=%s and name=%s" - q = q.replace('%s', self.sql.query['placeholder']) - - #print "DEBUG: name: %s site: %s" %(name, site_id) - - c.execute (q, (site_id, name)) - - tmp = c.fetchone() - if (tmp == None): #new player - c.execute ("INSERT INTO Players (name, siteId) VALUES (%s, %s)".replace('%s',self.sql.query['placeholder']) - ,(name, site_id)) - #Get last id might be faster here. - #c.execute ("SELECT id FROM Players WHERE name=%s", (name,)) - tmp = [self.get_last_insert_id(c)] - return tmp[0] - - def insertGameTypes(self, row): - c = self.get_cursor() - c.execute( self.sql.query['insertGameTypes'], row ) - return [self.get_last_insert_id(c)] - def store_the_hand(self, h): """Take a HandToWrite object and store it in the db""" @@ -1668,6 +1612,64 @@ class Database: # street4CheckCallRaiseChance, # street4CheckCallRaiseDone) + def getGameTypeId(self, siteid, game): + c = self.get_cursor() + #FIXME: Fixed for NL at the moment + c.execute(self.sql.query['getGametypeNL'], (siteid, game['type'], game['category'], game['limitType'], + int(Decimal(game['sb'])*100), int(Decimal(game['bb'])*100))) + tmp = c.fetchone() + if (tmp == None): + hilo = "h" + if game['category'] in ['studhilo', 'omahahilo']: + hilo = "s" + elif game['category'] in ['razz','27_3draw','badugi']: + hilo = "l" + tmp = self.insertGameTypes( (siteid, game['type'], game['base'], game['category'], game['limitType'], hilo, + int(Decimal(game['sb'])*100), int(Decimal(game['bb'])*100), 0, 0) ) + return tmp[0] + + def getSqlPlayerIDs(self, pnames, siteid): + result = {} + if(self.pcache == None): + self.pcache = LambdaDict(lambda key:self.insertPlayer(key, siteid)) + + for player in pnames: + result[player] = self.pcache[player] + # NOTE: Using the LambdaDict does the same thing as: + #if player in self.pcache: + # #print "DEBUG: cachehit" + # pass + #else: + # self.pcache[player] = self.insertPlayer(player, siteid) + #result[player] = self.pcache[player] + + return result + + def insertPlayer(self, name, site_id): + result = None + c = self.get_cursor() + q = "SELECT name, id FROM Players WHERE siteid=%s and name=%s" + q = q.replace('%s', self.sql.query['placeholder']) + + #print "DEBUG: name: %s site: %s" %(name, site_id) + + c.execute (q, (site_id, name)) + + tmp = c.fetchone() + if (tmp == None): #new player + c.execute ("INSERT INTO Players (name, siteId) VALUES (%s, %s)".replace('%s',self.sql.query['placeholder']) + ,(name, site_id)) + #Get last id might be faster here. + #c.execute ("SELECT id FROM Players WHERE name=%s", (name,)) + tmp = [self.get_last_insert_id(c)] + return tmp[0] + + def insertGameTypes(self, row): + c = self.get_cursor() + c.execute( self.sql.query['insertGameTypes'], row ) + return [self.get_last_insert_id(c)] + + ################################# # Finish of NEWIMPORT CODE diff --git a/pyfpdb/HUD_config.xml.example b/pyfpdb/HUD_config.xml.example index 34a8f16d..48ef3ea0 100644 --- a/pyfpdb/HUD_config.xml.example +++ b/pyfpdb/HUD_config.xml.example @@ -567,6 +567,7 @@ Left-Drag to Move" + From ce0e2c139bb7547339f12a403e1100dab3774c24 Mon Sep 17 00:00:00 2001 From: Worros Date: Sat, 31 Oct 2009 08:55:54 +0800 Subject: [PATCH 09/14] Revert "Print out actual exception when import fails" This reverts commit 626ff49eb41e5bb28d8db33277f3fe726d90aef5. Turns out this commit is python 2.6 syntax --- pyfpdb/GuiGraphViewer.py | 3 +-- pyfpdb/GuiSessionViewer.py | 7 ++++--- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/pyfpdb/GuiGraphViewer.py b/pyfpdb/GuiGraphViewer.py index 739a8f18..4011ba00 100644 --- a/pyfpdb/GuiGraphViewer.py +++ b/pyfpdb/GuiGraphViewer.py @@ -32,12 +32,11 @@ try: from matplotlib.backends.backend_gtkagg import NavigationToolbar2GTKAgg as NavigationToolbar from numpy import arange, cumsum from pylab import * -except ImportError as inst: +except ImportError: print """Failed to load libs for graphing, graphing will not function. Please in stall numpy and matplotlib if you want to use graphs.""" print """This is of no consequence for other parts of the program, e.g. import and HUD are NOT affected by this problem.""" - print "ImportError: %s" % inst.args import fpdb_import import Database diff --git a/pyfpdb/GuiSessionViewer.py b/pyfpdb/GuiSessionViewer.py index 5711cb89..7695cf73 100755 --- a/pyfpdb/GuiSessionViewer.py +++ b/pyfpdb/GuiSessionViewer.py @@ -37,10 +37,11 @@ try: # from matplotlib.dates import DateFormatter, WeekdayLocator, HourLocator, \ # DayLocator, MONDAY, timezone -except ImportError as inst: +except: + err = traceback.extract_tb(sys.exc_info()[2])[-1] + print "***Error: "+err[2]+"("+str(err[1])+"): "+str(sys.exc_info()[1]) print """Failed to load numpy in Session Viewer""" - print """This is of no consequence as the page is broken and only of interest to developers.""" - print "ImportError: %s" % inst.args + print """This is of no consequence as the module currently doesn't do anything.""" import Card import fpdb_import From 19b46e84441b574ab235380636be7c4bae5f5378 Mon Sep 17 00:00:00 2001 From: grindi Date: Sat, 31 Oct 2009 17:46:11 +0300 Subject: [PATCH 10/14] Revert "Revert "Print out actual exception when import fails"" This reverts commit ce0e2c139bb7547339f12a403e1100dab3774c24. --- pyfpdb/GuiGraphViewer.py | 3 ++- pyfpdb/GuiSessionViewer.py | 7 +++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/pyfpdb/GuiGraphViewer.py b/pyfpdb/GuiGraphViewer.py index 9387bdb7..9ce5c17a 100644 --- a/pyfpdb/GuiGraphViewer.py +++ b/pyfpdb/GuiGraphViewer.py @@ -33,11 +33,12 @@ try: from matplotlib.backends.backend_gtkagg import NavigationToolbar2GTKAgg as NavigationToolbar from numpy import arange, cumsum from pylab import * -except ImportError: +except ImportError as inst: print """Failed to load libs for graphing, graphing will not function. Please in stall numpy and matplotlib if you want to use graphs.""" print """This is of no consequence for other parts of the program, e.g. import and HUD are NOT affected by this problem.""" + print "ImportError: %s" % inst.args import fpdb_import import Database diff --git a/pyfpdb/GuiSessionViewer.py b/pyfpdb/GuiSessionViewer.py index 7695cf73..5711cb89 100755 --- a/pyfpdb/GuiSessionViewer.py +++ b/pyfpdb/GuiSessionViewer.py @@ -37,11 +37,10 @@ try: # from matplotlib.dates import DateFormatter, WeekdayLocator, HourLocator, \ # DayLocator, MONDAY, timezone -except: - err = traceback.extract_tb(sys.exc_info()[2])[-1] - print "***Error: "+err[2]+"("+str(err[1])+"): "+str(sys.exc_info()[1]) +except ImportError as inst: print """Failed to load numpy in Session Viewer""" - print """This is of no consequence as the module currently doesn't do anything.""" + print """This is of no consequence as the page is broken and only of interest to developers.""" + print "ImportError: %s" % inst.args import Card import fpdb_import From 5e6899a29e867e1e7c66a961433a4915d3a7e8c2 Mon Sep 17 00:00:00 2001 From: grindi Date: Sat, 31 Oct 2009 17:48:48 +0300 Subject: [PATCH 11/14] Print out actual exception when import fails. Python 2.5 compatible --- pyfpdb/GuiGraphViewer.py | 2 +- pyfpdb/GuiSessionViewer.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/pyfpdb/GuiGraphViewer.py b/pyfpdb/GuiGraphViewer.py index 9ce5c17a..670554e7 100644 --- a/pyfpdb/GuiGraphViewer.py +++ b/pyfpdb/GuiGraphViewer.py @@ -33,7 +33,7 @@ try: from matplotlib.backends.backend_gtkagg import NavigationToolbar2GTKAgg as NavigationToolbar from numpy import arange, cumsum from pylab import * -except ImportError as inst: +except ImportError, inst: print """Failed to load libs for graphing, graphing will not function. Please in stall numpy and matplotlib if you want to use graphs.""" print """This is of no consequence for other parts of the program, e.g. import diff --git a/pyfpdb/GuiSessionViewer.py b/pyfpdb/GuiSessionViewer.py index 5711cb89..0d391102 100755 --- a/pyfpdb/GuiSessionViewer.py +++ b/pyfpdb/GuiSessionViewer.py @@ -37,7 +37,7 @@ try: # from matplotlib.dates import DateFormatter, WeekdayLocator, HourLocator, \ # DayLocator, MONDAY, timezone -except ImportError as inst: +except ImportError, inst: print """Failed to load numpy in Session Viewer""" print """This is of no consequence as the page is broken and only of interest to developers.""" print "ImportError: %s" % inst.args From 97d2052cbe0046e7d4f1f83fa1198a8ba7f568e9 Mon Sep 17 00:00:00 2001 From: grindi Date: Sat, 31 Oct 2009 17:53:31 +0300 Subject: [PATCH 12/14] Party hhc tiny fixes --- pyfpdb/PartyPokerToFpdb.py | 23 +++++++++-------------- 1 file changed, 9 insertions(+), 14 deletions(-) diff --git a/pyfpdb/PartyPokerToFpdb.py b/pyfpdb/PartyPokerToFpdb.py index a3ea0ad0..4ed0c965 100755 --- a/pyfpdb/PartyPokerToFpdb.py +++ b/pyfpdb/PartyPokerToFpdb.py @@ -28,11 +28,12 @@ from HandHistoryConverter import * class PartyPokerParseError(FpdbParseError): "Usage: raise PartyPokerParseError([, hh=][, hid=])" + def __init__(self, msg='', hh=None, hid=None): if hh is not None: msg += "\n\nHand history attached below:\n" + self.wrapHh(hh) - return super(PartyPokerParseError, self).__init__(hid=hid) - #return super(PartyPokerParseError, self).__init__(msg, hid=hid) + return super(PartyPokerParseError, self).__init__(msg, hid=hid) + def wrapHh(self, hh): return ("%(DELIMETER)s\n%(HH)s\n%(DELIMETER)s") % \ {'DELIMETER': '#'*50, 'HH': hh} @@ -93,7 +94,7 @@ class PartyPoker(HandHistoryConverter): """, re.MULTILINE|re.VERBOSE) - re_TotalPlayers = re.compile("^Total\s+number\s+of\s+players\s*:\s*(?P\d+)", re.MULTILINE) +# re_TotalPlayers = re.compile("^Total\s+number\s+of\s+players\s*:\s*(?P\d+)", re.MULTILINE) re_SplitHands = re.compile('\x00+') re_TailSplitHands = re.compile('(\x00+)') lineSplitter = '\n' @@ -229,7 +230,6 @@ class PartyPoker(HandHistoryConverter): "Unknown game type '%s'" % mg['GAME'], hh = handText) - if 'TOURNO' in mg: info['type'] = 'tour' else: @@ -237,15 +237,12 @@ class PartyPoker(HandHistoryConverter): if info['type'] == 'ring': info['sb'], info['bb'] = ringBlinds(mg['RINGLIMIT']) - # FIXME: there are only $ and play money availible for cash - # to be honest, party doesn't save play money hh info['currency'] = currencies[mg['CURRENCY']] else: info['sb'] = clearMoneyString(mg['SB']) info['bb'] = clearMoneyString(mg['BB']) info['currency'] = 'T$' - # NB: SB, BB must be interpreted as blinds or bets depending on limit type. return info @@ -269,8 +266,8 @@ class PartyPoker(HandHistoryConverter): hh=hand.handText, hid = info['HID']) - m = self.re_TotalPlayers.search(hand.handText) - if m: info.update(m.groupdict()) +# m = self.re_TotalPlayers.search(hand.handText) +# if m: info.update(m.groupdict()) # FIXME: it's dirty hack @@ -318,7 +315,7 @@ class PartyPoker(HandHistoryConverter): hand.tourNo = info[key] if key == 'BUYIN': # FIXME: it's dirty hack T_T - # code below assumes that rake is equal to zero + # code below assumes that tournament rake is equal to zero cur = info[key][0] if info[key][0] not in '0123456789' else '' hand.buyin = info[key] + '+%s0' % cur if key == 'LEVEL': @@ -474,11 +471,9 @@ class PartyPoker(HandHistoryConverter): if m.group('CARDS') is not None: cards = renderCards(m.group('CARDS')) - (shown, mucked) = (False, False) - if m.group('SHOWED') == "show": shown = True - else: mucked = True + mucked = m.group('SHOWED') != "show" - hand.addShownCards(cards=cards, player=m.group('PNAME'), shown=shown, mucked=mucked) + hand.addShownCards(cards=cards, player=m.group('PNAME'), shown=True, mucked=mucked) def ringBlinds(ringLimit): "Returns blinds for current limit in cash games" From f4aa5f1fe191c2e3615dc441e5ef13d558338f4d Mon Sep 17 00:00:00 2001 From: Worros Date: Mon, 2 Nov 2009 13:38:36 +0800 Subject: [PATCH 13/14] First fix for sqlite in PlayerStats Fix courtesy of Eleatic Stranger on 2+2 - Page still does not work, need to find an sqlite equivalent to to_char() and variance() --- pyfpdb/SQL.py | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/pyfpdb/SQL.py b/pyfpdb/SQL.py index 3c25963f..2743a407 100644 --- a/pyfpdb/SQL.py +++ b/pyfpdb/SQL.py @@ -1895,9 +1895,9 @@ class Sql: self.query['playerDetailedStats'] = """ select AS hgametypeid ,gt.base - ,gt.category + ,gt.category AS category ,upper(gt.limitType) AS limittype - ,s.name + ,s.name AS name ,min(gt.bigBlind) AS minbigblind ,max(gt.bigBlind) AS maxbigblind /*, AS gtid*/ @@ -1939,7 +1939,8 @@ class Sql: ,100.0*avg((hp.totalProfit+hp.rake)/(gt.bigBlind+0.0)) AS bb100xr ,avg((hp.totalProfit+hp.rake)/100.0) AS profhndxr ,avg(h.seats+0.0) AS avgseats - ,variance(hp.totalProfit/100.0) AS variance + /*,variance(hp.totalProfit/100.0) AS variance*/ + ,0.0 AS variance from HandsPlayers hp inner join Hands h on (h.id = hp.handId) inner join Gametypes gt on (gt.Id = h.gameTypeId) From 28ca49d592c8e706ad6ee58dd26655bcc33fc5fb Mon Sep 17 00:00:00 2001 From: Worros Date: Mon, 2 Nov 2009 17:23:50 +0800 Subject: [PATCH 14/14] Fix GuiSessionStats.py for sqlite Fix based on solution from Eleatic Stranger on 2+2 --- pyfpdb/GuiSessionViewer.py | 2 ++ pyfpdb/SQL.py | 12 +++++++++++- 2 files changed, 13 insertions(+), 1 deletion(-) diff --git a/pyfpdb/GuiSessionViewer.py b/pyfpdb/GuiSessionViewer.py index 0d391102..79fe3191 100755 --- a/pyfpdb/GuiSessionViewer.py +++ b/pyfpdb/GuiSessionViewer.py @@ -248,6 +248,8 @@ class GuiSessionViewer (threading.Thread): nametest = nametest.replace("L", "") nametest = nametest.replace(",)",")") q = q.replace("", nametest) + q = q.replace("", "%s") + self.db.cursor.execute(q) THRESHOLD = 1800 hands = self.db.cursor.fetchall() diff --git a/pyfpdb/SQL.py b/pyfpdb/SQL.py index 2743a407..05edb56a 100644 --- a/pyfpdb/SQL.py +++ b/pyfpdb/SQL.py @@ -2502,7 +2502,17 @@ class Sql: AND h.handStart ORDER by time""" elif db_server == 'sqlite': - self.query['sessionStats'] = """ """ + self.query['sessionStats'] = """ + SELECT STRFTIME('', h.handStart) as time, hp.handId, hp.startCash, hp.winnings, hp.totalProfit + FROM HandsPlayers hp + INNER JOIN Hands h on (h.id = hp.handId) + INNER JOIN Gametypes gt on (gt.Id = h.gameTypeId) + INNER JOIN Sites s on (s.Id = gt.siteId) + INNER JOIN Players p on (p.Id = hp.playerId) + WHERE hp.playerId in + AND h.handStart + ORDER by time""" + #################################### # Queries to rebuild/modify hudcache