From 00f8b34fffa5cc81dbca6d7a62d8accf8e9598bc Mon Sep 17 00:00:00 2001 From: Mika Bostrom Date: Wed, 23 Sep 2009 23:36:17 +0300 Subject: [PATCH 01/15] Simplify database creation Database.py : fillDefaultData() Sql-coder had fixed the default data insert, and in the process changed the default type ID. Since his works in general case, I can remove my modifications. --- pyfpdb/Database.py | 2 -- 1 file changed, 2 deletions(-) diff --git a/pyfpdb/Database.py b/pyfpdb/Database.py index 341a1434..9a22c472 100755 --- a/pyfpdb/Database.py +++ b/pyfpdb/Database.py @@ -1011,8 +1011,6 @@ class Database: c.execute("INSERT INTO Sites (name,currency) VALUES ('PartyPoker', 'USD')") if self.backend == self.SQLITE: c.execute("INSERT INTO TourneyTypes (id, siteId, buyin, fee) VALUES (NULL, 1, 0, 0);") - elif self.backend == self.PGSQL: - c.execute("insert into TourneyTypes values (0,1,0,0,0,False,False,null,False,False,False);") else: c.execute("""insert into TourneyTypes(id, siteId, buyin, fee, maxSeats, knockout ,rebuyOrAddon, speed, headsUp, shootout, matrix) From df71dcf2c7c7a06104c0ed62af5b78d9a6fa3460 Mon Sep 17 00:00:00 2001 From: Mika Bostrom Date: Wed, 23 Sep 2009 23:44:57 +0300 Subject: [PATCH 02/15] Fix knockout variable type fpdb_parse_logic.py : recogniseTourneyTypeId() The column in table is of type 'boolean' but the default value was integer '0'; this triggered an error --- pyfpdb/fpdb_parse_logic.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pyfpdb/fpdb_parse_logic.py b/pyfpdb/fpdb_parse_logic.py index 4ce1f678..1972fc30 100644 --- a/pyfpdb/fpdb_parse_logic.py +++ b/pyfpdb/fpdb_parse_logic.py @@ -81,7 +81,7 @@ def mainParser(settings, siteID, category, hand, config, db = None, writeq = Non fee = fpdb_simple.parseFee(hand[0]) entries = -1 #todo: parse this prizepool = -1 #todo: parse this - knockout = 0 + knockout = False tourneyStartTime= handStartTime #todo: read tourney start time rebuyOrAddon = fpdb_simple.isRebuyOrAddon(hand[0]) From 6f536d29e7282e9c9be35fde45b8a33f885bca9e Mon Sep 17 00:00:00 2001 From: Mika Bostrom Date: Thu, 24 Sep 2009 07:08:32 +0300 Subject: [PATCH 03/15] Fix import on PostgreSQL Database.py : fillDefaultData() Remove manual 'id' from INSERT command. In database schema, TourneyTypes.id is a primary key and thus autoincrement. In postgres, autoincrements are implemented as sequences - inserting a value "manually" bypasses the sequence generation, which resulted in a remarkably weird error. Namely, upon the first hand to import, the insert fails due to primary key violation. The default value from an unused sequence is 1, but a row with such an id already exists. The solution is to create the single row of default data values with unspecified TourneyTypes.id, hence allowing postgres to generate the correct id from the sequence. This way the import works again. --- pyfpdb/Database.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pyfpdb/Database.py b/pyfpdb/Database.py index 9a22c472..22630fb6 100755 --- a/pyfpdb/Database.py +++ b/pyfpdb/Database.py @@ -1012,9 +1012,9 @@ class Database: if self.backend == self.SQLITE: c.execute("INSERT INTO TourneyTypes (id, siteId, buyin, fee) VALUES (NULL, 1, 0, 0);") else: - c.execute("""insert into TourneyTypes(id, siteId, buyin, fee, maxSeats, knockout + c.execute("""insert into TourneyTypes(siteId, buyin, fee, maxSeats, knockout ,rebuyOrAddon, speed, headsUp, shootout, matrix) - values (1, 1, 0, 0, 0, False, False, null, False, False, False);""") + values (1, 0, 0, 0, False, False, null, False, False, False);""") #end def fillDefaultData From 7eb368f2212b22b357a76fe48f1e9b3af15707ae Mon Sep 17 00:00:00 2001 From: Mika Bostrom Date: Sat, 3 Oct 2009 08:17:41 +0300 Subject: [PATCH 04/15] Debian package: architecture any -> all The installed files are scripts and even the bytecode versions are generated on install. There is no need to build arch-dependent packages. --- packaging/debian/control | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packaging/debian/control b/packaging/debian/control index 93660791..784c4b40 100644 --- a/packaging/debian/control +++ b/packaging/debian/control @@ -6,7 +6,7 @@ Build-Depends: debhelper, python-support Standards-Version: 3.8.0 Package: python-fpdb -Architecture: any +Architecture: all Section: games Priority: extra Depends: ${python:Depends}, python-gtk2, python-matplotlib, From 18cc51ba7aa1751a93d0bbcb2ec47267ea276def Mon Sep 17 00:00:00 2001 From: Mika Bostrom Date: Sat, 3 Oct 2009 21:05:41 +0300 Subject: [PATCH 05/15] 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 2c83ccd0..ce8c7c9f 100644 --- a/pyfpdb/Hud.py +++ b/pyfpdb/Hud.py @@ -82,6 +82,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']) @@ -116,7 +117,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 c77e1434365d9c742f16a4556a181f89ea72be1c Mon Sep 17 00:00:00 2001 From: Mika Bostrom Date: Sat, 3 Oct 2009 21:10:09 +0300 Subject: [PATCH 06/15] 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, 4 Oct 2009 12:26:37 +0100 Subject: [PATCH 07/15] make separate hud menus for player and opponents stats --- pyfpdb/Hud.py | 165 +++++++++++++++++++++++++++++++++++++------------- 1 file changed, 123 insertions(+), 42 deletions(-) diff --git a/pyfpdb/Hud.py b/pyfpdb/Hud.py index 2c83ccd0..ad42bb59 100644 --- a/pyfpdb/Hud.py +++ b/pyfpdb/Hud.py @@ -146,14 +146,65 @@ class Hud: menu.append(repositem) repositem.connect("activate", self.reposition_windows) - aggitem = gtk.MenuItem('Show Stats') + aggitem = gtk.MenuItem('Show Player Stats') menu.append(aggitem) self.aggMenu = gtk.Menu() aggitem.set_submenu(self.aggMenu) # set agg_bb_mult to 1 to stop aggregation item = gtk.CheckMenuItem('For This Blind Level Only') self.aggMenu.append(item) - item.connect("activate", self.set_aggregation, 1) + item.connect("activate", self.set_aggregation, ('P',1)) + setattr(self, 'h_aggBBmultItem1', item) + # + item = gtk.MenuItem('For Multiple Blind Levels:') + self.aggMenu.append(item) + # + item = gtk.CheckMenuItem(' 0.5 to 2.0 x Current Blinds') + self.aggMenu.append(item) + item.connect("activate", self.set_aggregation, ('P',2)) + setattr(self, 'h_aggBBmultItem2', item) + # + item = gtk.CheckMenuItem(' 0.33 to 3.0 x Current Blinds') + self.aggMenu.append(item) + item.connect("activate", self.set_aggregation, ('P',3)) + setattr(self, 'h_aggBBmultItem3', item) + # + item = gtk.CheckMenuItem(' 0.1 to 10 x Current Blinds') + self.aggMenu.append(item) + item.connect("activate", self.set_aggregation, ('P',10)) + setattr(self, 'h_aggBBmultItem10', item) + # + item = gtk.CheckMenuItem(' All Levels') + self.aggMenu.append(item) + item.connect("activate", self.set_aggregation, ('P',10000)) + setattr(self, 'h_aggBBmultItem10000', item) + # + item = gtk.MenuItem('Since:') + self.aggMenu.append(item) + # + item = gtk.CheckMenuItem(' All Time') + self.aggMenu.append(item) + item.connect("activate", self.set_hud_style, ('P','A')) + setattr(self, 'h_hudStyleOptionA', item) + # + item = gtk.CheckMenuItem(' Session') + self.aggMenu.append(item) + item.connect("activate", self.set_hud_style, ('P','S')) + setattr(self, 'h_hudStyleOptionS', item) + # + item = gtk.CheckMenuItem(' %s Days' % (self.hud_params['h_hud_days'])) + self.aggMenu.append(item) + item.connect("activate", self.set_hud_style, ('P','T')) + setattr(self, 'h_hudStyleOptionT', item) + + aggitem = gtk.MenuItem('Show Opponent Stats') + menu.append(aggitem) + self.aggMenu = gtk.Menu() + aggitem.set_submenu(self.aggMenu) + # set agg_bb_mult to 1 to stop aggregation + item = gtk.CheckMenuItem('For This Blind Level Only') + self.aggMenu.append(item) + item.connect("activate", self.set_aggregation, ('O',1)) setattr(self, 'aggBBmultItem1', item) # item = gtk.MenuItem('For Multiple Blind Levels:') @@ -161,44 +212,54 @@ class Hud: # item = gtk.CheckMenuItem(' 0.5 to 2.0 x Current Blinds') self.aggMenu.append(item) - item.connect("activate", self.set_aggregation, 2) + item.connect("activate", self.set_aggregation, ('O',2)) setattr(self, 'aggBBmultItem2', item) # item = gtk.CheckMenuItem(' 0.33 to 3.0 x Current Blinds') self.aggMenu.append(item) - item.connect("activate", self.set_aggregation, 3) + item.connect("activate", self.set_aggregation, ('O',3)) setattr(self, 'aggBBmultItem3', item) # item = gtk.CheckMenuItem(' 0.1 to 10 x Current Blinds') self.aggMenu.append(item) - item.connect("activate", self.set_aggregation, 10) + item.connect("activate", self.set_aggregation, ('O',10)) setattr(self, 'aggBBmultItem10', item) # item = gtk.CheckMenuItem(' All Levels') self.aggMenu.append(item) - item.connect("activate", self.set_aggregation, 10000) + item.connect("activate", self.set_aggregation, ('O',10000)) setattr(self, 'aggBBmultItem10000', item) # - item = gtk.MenuItem('For Hero:') + item = gtk.MenuItem('Since:') self.aggMenu.append(item) - setattr(self, 'showStatsMenuItem7', item) # item = gtk.CheckMenuItem(' All Time') self.aggMenu.append(item) - item.connect("activate", self.set_hud_style, 'HA') - setattr(self, 'HAStyleOption', item) + item.connect("activate", self.set_hud_style, ('O','A')) + setattr(self, 'hudStyleOptionA', item) # item = gtk.CheckMenuItem(' Session') self.aggMenu.append(item) - item.connect("activate", self.set_hud_style, 'HS') - setattr(self, 'HSStyleOption', item) + item.connect("activate", self.set_hud_style, ('O','S')) + setattr(self, 'hudStyleOptionS', item) # item = gtk.CheckMenuItem(' %s Days' % (self.hud_params['h_hud_days'])) self.aggMenu.append(item) - item.connect("activate", self.set_hud_style, 'HT') - setattr(self, 'HTStyleOption', item) + item.connect("activate", self.set_hud_style, ('O','T')) + setattr(self, 'hudStyleOptionT', item) # set active on current options: + if self.hud_params['h_agg_bb_mult'] == 1: + getattr(self, 'h_aggBBmultItem1').set_active(True) + elif self.hud_params['h_agg_bb_mult'] == 2: + getattr(self, 'h_aggBBmultItem2').set_active(True) + elif self.hud_params['h_agg_bb_mult'] == 3: + getattr(self, 'h_aggBBmultItem3').set_active(True) + elif self.hud_params['h_agg_bb_mult'] == 10: + getattr(self, 'h_aggBBmultItem10').set_active(True) + elif self.hud_params['h_agg_bb_mult'] > 9000: + getattr(self, 'h_aggBBmultItemAll').set_active(True) + # if self.hud_params['agg_bb_mult'] == 1: getattr(self, 'aggBBmultItem1').set_active(True) elif self.hud_params['agg_bb_mult'] == 2: @@ -209,12 +270,20 @@ class Hud: getattr(self, 'aggBBmultItem10').set_active(True) elif self.hud_params['agg_bb_mult'] > 9000: getattr(self, 'aggBBmultItemAll').set_active(True) + # if self.hud_params['h_hud_style'] == 'A': - getattr(self, 'HAStyleOption').set_active(True) + getattr(self, 'h_hudStyleOptionA').set_active(True) elif self.hud_params['h_hud_style'] == 'S': - getattr(self, 'HSStyleOption').set_active(True) + getattr(self, 'h_hudStyleOptionS').set_active(True) elif self.hud_params['h_hud_style'] == 'T': - getattr(self, 'HTStyleOption').set_active(True) + getattr(self, 'h_hudStyleOptionT').set_active(True) + # + if self.hud_params['hud_style'] == 'A': + getattr(self, 'hudStyleOptionA').set_active(True) + elif self.hud_params['hud_style'] == 'S': + getattr(self, 'hudStyleOptionS').set_active(True) + elif self.hud_params['hud_style'] == 'T': + getattr(self, 'hudStyleOptionT').set_active(True) eventbox.connect_object("button-press-event", self.on_button_press, menu) @@ -254,41 +323,53 @@ class Hud: pass def set_aggregation(self, widget, val): - # try setting these to true all the time, and set the multiplier to 1 to turn agg off: - self.hud_params['aggregate_ring'] = True - self.hud_params['aggregate_tour'] = True - self.hud_params['h_aggregate_ring'] = True - self.hud_params['h_aggregate_tour'] = True + (player_opp, num) = val + if player_opp == 'P': + # set these true all the time, set the multiplier to 1 to turn agg off: + self.hud_params['h_aggregate_ring'] = True + self.hud_params['h_aggregate_tour'] = True - if self.hud_params['agg_bb_mult'] != val \ - and getattr(self, 'aggBBmultItem'+str(val)).get_active(): - print 'set_aggregation', val - self.hud_params['agg_bb_mult'] = val - self.hud_params['h_agg_bb_mult'] = val - for mult in ('1', '2', '3', '10', '10000'): - if mult != str(val): - getattr(self, 'aggBBmultItem'+mult).set_active(False) + if self.hud_params['h_agg_bb_mult'] != num \ + and getattr(self, 'h_aggBBmultItem'+str(num)).get_active(): + print 'set_player_aggregation', num + self.hud_params['h_agg_bb_mult'] = num + for mult in ('1', '2', '3', '10', '10000'): + if mult != str(num): + getattr(self, 'h_aggBBmultItem'+mult).set_active(False) + else: + self.hud_params['aggregate_ring'] = True + self.hud_params['aggregate_tour'] = True + + if self.hud_params['agg_bb_mult'] != num \ + and getattr(self, 'aggBBmultItem'+str(num)).get_active(): + print 'set_opponent_aggregation', num + self.hud_params['agg_bb_mult'] = num + for mult in ('1', '2', '3', '10', '10000'): + if mult != str(num): + getattr(self, 'aggBBmultItem'+mult).set_active(False) def set_hud_style(self, widget, val): - # try setting these to true all the time, and set the multiplier to 1 to turn agg off: - if val[0] == 'H': + (player_opp, style) = val + if player_opp == 'P': param = 'h_hud_style' + prefix = 'h_' else: param = 'hud_style' + prefix = '' - if val[1] == 'A' and getattr(self, 'HAStyleOption').get_active(): + if style == 'A' and getattr(self, prefix+'hudStyleOptionA').get_active(): self.hud_params[param] = 'A' - getattr(self, 'HSStyleOption').set_active(False) - getattr(self, 'HTStyleOption').set_active(False) - elif val[1] == 'S' and getattr(self, 'HSStyleOption').get_active(): + getattr(self, prefix+'hudStyleOptionS').set_active(False) + getattr(self, prefix+'hudStyleOptionT').set_active(False) + elif style == 'S' and getattr(self, prefix+'hudStyleOptionS').get_active(): self.hud_params[param] = 'S' - getattr(self, 'HAStyleOption').set_active(False) - getattr(self, 'HTStyleOption').set_active(False) - elif val[1] == 'T' and self.HTStyleOption.get_active(): + getattr(self, prefix+'hudStyleOptionA').set_active(False) + getattr(self, prefix+'hudStyleOptionT').set_active(False) + elif style == 'T' and getattr(self, prefix+'hudStyleOptionT').get_active(): self.hud_params[param] = 'T' - getattr(self, 'HAStyleOption').set_active(False) - getattr(self, 'HSStyleOption').set_active(False) - print "setting self.hud_params[%s] = %s" % (param, val[1]) + getattr(self, prefix+'hudStyleOptionA').set_active(False) + getattr(self, prefix+'hudStyleOptionS').set_active(False) + print "setting self.hud_params[%s] = %s" % (param, style) def update_table_position(self): if os.name == 'nt': From 7900ebcebe429fe43a69c929ed6ea32222c797f8 Mon Sep 17 00:00:00 2001 From: sqlcoder Date: Sun, 4 Oct 2009 17:46:04 +0100 Subject: [PATCH 08/15] Tell user what is happening on startup --- pyfpdb/Configuration.py | 24 +++++++++++++++++++----- pyfpdb/fpdb.py | 9 ++++++++- 2 files changed, 27 insertions(+), 6 deletions(-) diff --git a/pyfpdb/Configuration.py b/pyfpdb/Configuration.py index b8022a45..a643696a 100755 --- a/pyfpdb/Configuration.py +++ b/pyfpdb/Configuration.py @@ -311,13 +311,21 @@ class Config: pass if file == None: # that didn't work either, just die - print "No HUD_config_xml found. Exiting" - sys.stderr.write("No HUD_config_xml found. Exiting") + print "No HUD_config_xml found after looking in current directory and "+self.default_config_path+"\nExiting" + sys.stderr.write("No HUD_config_xml found after looking in current directory and "+self.default_config_path+"\nExiting") + print "press enter to continue" + sys.stdin.readline() sys.exit() # Parse even if there was no real config file found and we are using the example # If using the example, we'll edit it later +# sc 2009/10/04 Example already copied to main filename, is this ok? log.info("Reading configuration file %s" % file) + if os.sep in file: + print "\nReading configuration file %s\n" % file + else: + print "\nReading configuration file %s" % file + print "in %s\n" % os.getcwd() try: doc = xml.dom.minidom.parse(file) except: @@ -405,6 +413,8 @@ class Config: db_pass = df_parms['db-password']) self.save(file=os.path.join(self.default_config_path, "HUD_config.xml")) + print "" + def set_hhArchiveBase(self, path): self.imp.node.setAttribute("hhArchiveBase", path) @@ -454,11 +464,15 @@ class Config: def find_example_config(self): if os.path.exists('HUD_config.xml.example'): # there is a HUD_config in the cwd - file = 'HUD_config.xml.example' # so we use it + file = 'HUD_config.xml' # so we use it + try: + shutil.copyfile(file+'.example', file) + except: + file = '' print "No HUD_config.xml found, using HUD_config.xml.example.\n", \ - "A HUD_config.xml will be written. You will probably have to edit it." + "A HUD_config.xml has been created. You will probably have to edit it." sys.stderr.write("No HUD_config.xml found, using HUD_config.xml.example.\n" + \ - "A HUD_config.xml will be written. You will probably have to edit it.") + "A HUD_config.xml has been created. You will probably have to edit it.") else: file = None return file diff --git a/pyfpdb/fpdb.py b/pyfpdb/fpdb.py index 4703d96d..4065c243 100755 --- a/pyfpdb/fpdb.py +++ b/pyfpdb/fpdb.py @@ -453,7 +453,14 @@ class fpdb: self.db.disconnect() self.sql = SQL.Sql(type = self.settings['db-type'], db_server = self.settings['db-server']) - self.db = Database.Database(self.config, sql = self.sql) + try: + self.db = Database.Database(self.config, sql = self.sql) + except FpdbError: + print "Failed to connect to %s database with username %s." % (self.settings['db-server'], self.settings['db-user']) + sys.stderr.write("Failed to connect to %s database with username %s." % (self.settings['db-server'], self.settings['db-user'])) + except: + print "Failed to connect to %s database with username %s." % (self.settings['db-server'], self.settings['db-user']) + sys.stderr.write("Failed to connect to %s database with username %s." % (self.settings['db-server'], self.settings['db-user'])) if self.db.fdb.wrongDbVersion: diaDbVersionWarning = gtk.Dialog(title="Strong Warning - Invalid database version", parent=None, flags=0, buttons=(gtk.STOCK_OK,gtk.RESPONSE_OK)) From 8851b141a2caea1780514ac90e3329b1490a07c1 Mon Sep 17 00:00:00 2001 From: sqlcoder Date: Mon, 5 Oct 2009 22:12:35 +0100 Subject: [PATCH 09/15] add dropdown to player name in filter --- pyfpdb/Database.py | 10 ++++++++++ pyfpdb/Filters.py | 12 +++++++++++- pyfpdb/SQL.py | 7 +++++++ 3 files changed, 28 insertions(+), 1 deletion(-) diff --git a/pyfpdb/Database.py b/pyfpdb/Database.py index c923517e..c5421684 100755 --- a/pyfpdb/Database.py +++ b/pyfpdb/Database.py @@ -537,6 +537,16 @@ class Database: else: return None + def get_player_names(self, config, site_id=None, like_player_name="%"): + """Fetch player names from players. Use site_id and like_player_name if provided""" + + if site_id == None: + site_id = -1 + c = self.get_cursor() + c.execute(self.sql.query['get_player_names'], (like_player_name, site_id, site_id)) + rows = c.fetchall() + return rows + #returns the SQL ids of the names given in an array # TODO: if someone gets industrious, they should make the parts that use the output of this function deal with a dict # { playername: id } instead of depending on it's relation to the positions list diff --git a/pyfpdb/Filters.py b/pyfpdb/Filters.py index 9ded56b4..d4563059 100644 --- a/pyfpdb/Filters.py +++ b/pyfpdb/Filters.py @@ -23,6 +23,7 @@ import os import sys from optparse import OptionParser from time import * +import gobject #import pokereval import Configuration @@ -228,7 +229,16 @@ class Filters(threading.Thread): pname.set_width_chars(20) hbox.pack_start(pname, False, True, 0) pname.connect("changed", self.__set_hero_name, site) - #TODO: Look at GtkCompletion - to fill out usernames + + # Added EntryCompletion but maybe comboBoxEntry is more flexible? (e.g. multiple choices) + completion = gtk.EntryCompletion() + pname.set_completion(completion) + liststore = gtk.ListStore(gobject.TYPE_STRING) + completion.set_model(liststore) + completion.set_text_column(0) + names = self.db.get_player_names(self.conf) # (config=self.conf, site_id=None, like_player_name="%") + for n in names: + liststore.append(n) self.__set_hero_name(pname, site) diff --git a/pyfpdb/SQL.py b/pyfpdb/SQL.py index 0c551634..1145afec 100644 --- a/pyfpdb/SQL.py +++ b/pyfpdb/SQL.py @@ -1235,6 +1235,13 @@ class Sql: and Players.siteId = Sites.id """ + self.query['get_player_names'] = """ + select p.name + from Players p + where lower(p.name) like lower(%s) + and (p.siteId = %s or %s = -1) + """ + self.query['getSiteId'] = """SELECT id from Sites where name = %s""" self.query['get_stats_from_hand'] = """ From 94af5b1ea82d707f689a70cfc5cf1b1c48d930c4 Mon Sep 17 00:00:00 2001 From: Worros Date: Tue, 6 Oct 2009 12:08:20 +0800 Subject: [PATCH 10/15] Fix order bug for seats in NEWIMPORT --- pyfpdb/Database.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/pyfpdb/Database.py b/pyfpdb/Database.py index f5e947e1..3c8c21c4 100755 --- a/pyfpdb/Database.py +++ b/pyfpdb/Database.py @@ -1419,9 +1419,8 @@ class Database: p['siteHandNo'], p['handStart'], datetime.today(), #importtime -# len(p['names']), #seats - p['maxSeats'], p['seats'], + p['maxSeats'], p['boardcard1'], p['boardcard2'], p['boardcard3'], From fdef5b12d9a2ea64b3e44617f2fb2f1112f6f3cb Mon Sep 17 00:00:00 2001 From: Worros Date: Tue, 6 Oct 2009 18:30:52 +0800 Subject: [PATCH 11/15] Add playersVpi to NEWIMPORT code Untested at the moment, moved the code from Hand.py into DerivedStats. --- pyfpdb/Database.py | 4 +-- pyfpdb/DerivedStats.py | 61 ++++++++++++++++++++++++++++++++++-------- pyfpdb/Hand.py | 58 +++++++++------------------------------ 3 files changed, 65 insertions(+), 58 deletions(-) diff --git a/pyfpdb/Database.py b/pyfpdb/Database.py index 3c8c21c4..22aeb677 100755 --- a/pyfpdb/Database.py +++ b/pyfpdb/Database.py @@ -1382,6 +1382,7 @@ class Database: importtime, seats, maxseats, + playersVpi, boardcard1, boardcard2, boardcard3, @@ -1395,9 +1396,8 @@ class Database: ) VALUES (%s, %s, %s, %s, %s, %s, %s, %s, %s, %s, - %s, %s, %s, %s, %s, %s, %s)""" + %s, %s, %s, %s, %s, %s, %s, %s)""" #--- texture, -#-- playersVpi, #-- playersAtStreet1, #-- playersAtStreet2, #-- playersAtStreet3, diff --git a/pyfpdb/DerivedStats.py b/pyfpdb/DerivedStats.py index 3de15ee5..9f900ce0 100644 --- a/pyfpdb/DerivedStats.py +++ b/pyfpdb/DerivedStats.py @@ -106,6 +106,9 @@ class DerivedStats(): print "hands =", self.hands print "handsplayers =", self.handsplayers + def getHands(self): + return self.hands + def assembleHands(self, hand): self.hands['tableName'] = hand.tablename self.hands['siteHandNo'] = hand.handid @@ -114,17 +117,53 @@ class DerivedStats(): self.hands['importTime'] = None self.hands['seats'] = self.countPlayers(hand) self.hands['maxSeats'] = hand.maxseats - self.hands['boardcard1'] = None - self.hands['boardcard2'] = None - self.hands['boardcard3'] = None - self.hands['boardcard4'] = None - self.hands['boardcard5'] = None - boardCard = 1 - for street in hand.communityStreets: - for card in hand.board[street]: - self.hands['boardcard%s' % str(boardCard)] = Card.encodeCard(card) - boardCard += 1 + # This (i think...) is correct for both stud and flop games, as hand.board['street'] disappears, and + # those values remain default in stud. + boardcards = hand.board['FLOP'] + hand.board['TURN'] + hand.board['RIVER'] + [u'0x', u'0x', u'0x', u'0x', u'0x'] + cards = [Card.encodeCard(c) for c in boardcards[0:5]] + self.hands['boardcard1'] = cards[0] + self.hands['boardcard2'] = cards[1] + self.hands['boardcard3'] = cards[2] + self.hands['boardcard4'] = cards[3] + self.hands['boardcard5'] = cards[4] + + #print "DEBUG: self.getStreetTotals = (%s, %s, %s, %s, %s)" % hand.getStreetTotals() + #FIXME: Pot size still in decimal, needs to be converted to cents + (self.hands['street1Pot'], + self.hands['street2Pot'], + self.hands['street3Pot'], + self.hands['street4Pot'], + self.hands['showdownPot']) = hand.getStreetTotals() + + + self.vpip(hand) # Gives playersVpi (num of players vpip) + # texture smallint, + # playersAtStreet1 SMALLINT NOT NULL, /* num of players seeing flop/street4 */ + # Needs to be recorded + # playersAtStreet2 SMALLINT NOT NULL, + # Needs to be recorded + # playersAtStreet3 SMALLINT NOT NULL, + # Needs to be recorded + # playersAtStreet4 SMALLINT NOT NULL, + # Needs to be recorded + # playersAtShowdown SMALLINT NOT NULL, + # Needs to be recorded + # street0Raises TINYINT NOT NULL, /* num small bets paid to see flop/street4, including blind */ + # Needs to be recorded + # street1Raises TINYINT NOT NULL, /* num small bets paid to see turn/street5 */ + # Needs to be recorded + # street2Raises TINYINT NOT NULL, /* num big bets paid to see river/street6 */ + # Needs to be recorded + # street3Raises TINYINT NOT NULL, /* num big bets paid to see sd/street7 */ + # Needs to be recorded + # street4Raises TINYINT NOT NULL, /* num big bets paid to see showdown */ + # Needs to be recorded + + # comment TEXT, + # commentTs DATETIME + + def assembleHandsPlayers(self, hand): self.vpip(self.hand) @@ -157,4 +196,4 @@ class DerivedStats(): self.handsplayers[player[1]]['street%sAggr' % i] = False def countPlayers(self, hand): - pass \ No newline at end of file + pass diff --git a/pyfpdb/Hand.py b/pyfpdb/Hand.py index 05ec3541..2527f636 100644 --- a/pyfpdb/Hand.py +++ b/pyfpdb/Hand.py @@ -194,64 +194,32 @@ dealt whether they were seen in a 'dealt to' line """ Function to insert Hand into database Should not commit, and do minimal selects. Callers may want to cache commits db: a connected fpdb_db object""" - # TODO: + + ##### + # Players, Gametypes, TourneyTypes are all shared functions that are needed for additional tables + # These functions are intended for prep insert eventually + ##### # Players - base playerid and siteid tuple sqlids = db.getSqlPlayerIDs([p[1] for p in self.players], self.siteId) #Gametypes gtid = db.getGameTypeId(self.siteId, self.gametype) + self.stats.assembleHands(self) + + ##### + # End prep functions + ##### + # HudCache data to come from DerivedStats class # HandsActions - all actions for all players for all streets - self.actions + # Hands - Summary information of hand indexed by handId - gameinfo - #This should be moved to prepInsert - hh = {} - hh['siteHandNo'] = self.handid - hh['handStart'] = self.starttime + hh = self.stats.getHands() hh['gameTypeId'] = gtid # seats TINYINT NOT NULL, - hh['tableName'] = self.tablename - hh['maxSeats'] = self.maxseats hh['seats'] = len(sqlids) - # Flop turn and river may all be empty - add (likely) too many elements and trim with range - boardcards = self.board['FLOP'] + self.board['TURN'] + self.board['RIVER'] + [u'0x', u'0x', u'0x', u'0x', u'0x'] - cards = [Card.encodeCard(c) for c in boardcards[0:5]] - hh['boardcard1'] = cards[0] - hh['boardcard2'] = cards[1] - hh['boardcard3'] = cards[2] - hh['boardcard4'] = cards[3] - hh['boardcard5'] = cards[4] - # texture smallint, - # playersVpi SMALLINT NOT NULL, /* num of players vpi */ - # Needs to be recorded - # playersAtStreet1 SMALLINT NOT NULL, /* num of players seeing flop/street4 */ - # Needs to be recorded - # playersAtStreet2 SMALLINT NOT NULL, - # Needs to be recorded - # playersAtStreet3 SMALLINT NOT NULL, - # Needs to be recorded - # playersAtStreet4 SMALLINT NOT NULL, - # Needs to be recorded - # playersAtShowdown SMALLINT NOT NULL, - # Needs to be recorded - # street0Raises TINYINT NOT NULL, /* num small bets paid to see flop/street4, including blind */ - # Needs to be recorded - # street1Raises TINYINT NOT NULL, /* num small bets paid to see turn/street5 */ - # Needs to be recorded - # street2Raises TINYINT NOT NULL, /* num big bets paid to see river/street6 */ - # Needs to be recorded - # street3Raises TINYINT NOT NULL, /* num big bets paid to see sd/street7 */ - # Needs to be recorded - # street4Raises TINYINT NOT NULL, /* num big bets paid to see showdown */ - # Needs to be recorded - - #print "DEBUG: self.getStreetTotals = (%s, %s, %s, %s, %s)" % self.getStreetTotals() - #FIXME: Pot size still in decimal, needs to be converted to cents - (hh['street1Pot'], hh['street2Pot'], hh['street3Pot'], hh['street4Pot'], hh['showdownPot']) = self.getStreetTotals() - - # comment TEXT, - # commentTs DATETIME #print hh handid = db.storeHand(hh) # HandsPlayers - ? ... Do we fix winnings? From 024618235f68ab29ca9d2e4379332bcd76260b6a Mon Sep 17 00:00:00 2001 From: Worros Date: Wed, 7 Oct 2009 14:15:12 +0800 Subject: [PATCH 12/15] Clean up variables in DerivedStats Doesn't look like they are going to be used like that --- pyfpdb/DerivedStats.py | 70 ------------------------------------------ 1 file changed, 70 deletions(-) diff --git a/pyfpdb/DerivedStats.py b/pyfpdb/DerivedStats.py index 9f900ce0..ffc673b1 100644 --- a/pyfpdb/DerivedStats.py +++ b/pyfpdb/DerivedStats.py @@ -22,76 +22,6 @@ class DerivedStats(): def __init__(self, hand): self.hand = hand - self.activeSeats = 0 - self.position = 0 - self.tourneyTypeId = 0 - - self.HDs = 0 - self.street0VPI = 0 - self.street0Aggr = 0 - self.street0_3BChance = 0 - self.street0_3BDone = 0 - self.street0_4BChance = 0 - self.street0_4BDone = 0 - - self.street1Seen = 0 - self.street2Seen = 0 - self.street3Seen = 0 - self.street4Seen = 0 - self.sawShowdown = 0 - - self.street1Aggr = 0 - self.street2Aggr = 0 - self.street3Aggr = 0 - self.street4Aggr = 0 - - self.otherRaisedStreet1 = 0 - self.otherRaisedStreet2 = 0 - self.otherRaisedStreet3 = 0 - self.otherRaisedStreet4 = 0 - self.foldToOtherRaisedStreet1 = 0 - self.foldToOtherRaisedStreet2 = 0 - self.foldToOtherRaisedStreet3 = 0 - self.foldToOtherRaisedStreet4 = 0 - self.wonWhenSeenStreet1 = 0 - self.wonAtSD = 0 - - self.stealAttemptChance = 0 - self.stealAttempted = 0 - self.foldBbToStealChance = 0 - self.foldedBbToSteal = 0 - self.foldSbToStealChance = 0 - self.foldedSbToSteal = 0 - - self.street1CBChance = 0 - self.street1CBDone = 0 - self.street2CBChance = 0 - self.street2CBDone = 0 - self.street3CBChance = 0 - self.street3CBDone = 0 - self.street4CBChance = 0 - self.street4CBDone = 0 - - self.foldToStreet1CBChance = 0 - self.foldToStreet1CBDone = 0 - self.foldToStreet2CBChance = 0 - self.foldToStreet2CBDone = 0 - self.foldToStreet3CBChance = 0 - self.foldToStreet3CBDone = 0 - self.foldToStreet4CBChance = 0 - self.foldToStreet4CBDone = 0 - - self.totalProfit = 0 - - self.street1CheckCallRaiseChance = 0 - self.street1CheckCallRaiseDone = 0 - self.street2CheckCallRaiseChance = 0 - self.street2CheckCallRaiseDone = 0 - self.street3CheckCallRaiseChance = 0 - self.street3CheckCallRaiseDone = 0 - self.street4CheckCallRaiseChance = 0 - self.street4CheckCallRaiseDone = 0 - self.hands = {} self.handsplayers = {} From 31f48c493279c0d8863a904c1f0e775882efcbf0 Mon Sep 17 00:00:00 2001 From: Worros Date: Thu, 8 Oct 2009 18:01:49 +0800 Subject: [PATCH 13/15] [NEWIMPORT] Calculate playersAtStreetX Untested code. Still missing playersAtShowdown, haven't looked to see if hand.actionStreets contains showdown. --- pyfpdb/DerivedStats.py | 54 ++++++++++++++++++++++++++++++++++-------- 1 file changed, 44 insertions(+), 10 deletions(-) diff --git a/pyfpdb/DerivedStats.py b/pyfpdb/DerivedStats.py index ffc673b1..a4fb630b 100644 --- a/pyfpdb/DerivedStats.py +++ b/pyfpdb/DerivedStats.py @@ -68,17 +68,10 @@ class DerivedStats(): self.vpip(hand) # Gives playersVpi (num of players vpip) + self.playersAtStreetX(hand) # Gives playersAtStreet1..4 and Showdown + # texture smallint, - # playersAtStreet1 SMALLINT NOT NULL, /* num of players seeing flop/street4 */ - # Needs to be recorded - # playersAtStreet2 SMALLINT NOT NULL, - # Needs to be recorded - # playersAtStreet3 SMALLINT NOT NULL, - # Needs to be recorded - # playersAtStreet4 SMALLINT NOT NULL, - # Needs to be recorded - # playersAtShowdown SMALLINT NOT NULL, - # Needs to be recorded + # street0Raises TINYINT NOT NULL, /* num small bets paid to see flop/street4, including blind */ # Needs to be recorded # street1Raises TINYINT NOT NULL, /* num small bets paid to see turn/street5 */ @@ -113,6 +106,47 @@ class DerivedStats(): self.handsplayers[player[1]]['vpip'] = False self.hands['playersVpi'] = len(vpipers) + def playersAtStreetX(self, hand): + """playersAtStreet1 SMALLINT NOT NULL, /* num of players seeing flop/street4/draw1 */""" + # self.actions[street] is a list of all actions in a tuple, contining the player name first + # [ (player, action, ....), (player2, action, ...) ] + # The number of unique players in the list per street gives the value for playersAtStreetXXX + + self.hands['playersAtStreet1'] = 0 + self.hands['playersAtStreet2'] = 0 + self.hands['playersAtStreet3'] = 0 + self.hands['playersAtStreet4'] = 0 + self.hands['playersAtShowdown'] = 0 + + for street in hand.actionStreets: + actors = {} + for act in a[street]: + actors[act[0]] = 1 + #print "len(actors.keys(%s)): %s" % ( street, len(actors.keys())) + if hand.gametype['base'] in ("hold"): + if street in "FLOP": self.hands['playersAtStreet1'] = len(actors.keys()) + elif street in "TURN": self.hands['playersAtStreet2'] = len(actors.keys()) + elif street in "RIVER": self.hands['playersAtStreet3'] = len(actors.keys()) + elif hand.gametype['base'] in ("stud"): + if street in "FOURTH": self.hands['playersAtStreet1'] = len(actors.keys()) + elif street in "FIFTH": self.hands['playersAtStreet2'] = len(actors.keys()) + elif street in "SIXTH": self.hands['playersAtStreet3'] = len(actors.keys()) + elif street in "SEVENTH": self.hands['playersAtStreet4'] = len(actors.keys()) + elif hand.gametype['base'] in ("draw"): + if street in "DRAWONE": self.hands['playersAtStreet1'] = len(actors.keys()) + elif street in "DRAWTWO": self.hands['playersAtStreet2'] = len(actors.keys()) + elif street in "DRAWTHREE": self.hands['playersAtStreet3'] = len(actors.keys()) + + #Need playersAtShowdown + + + def streetXRaises(self, hand): + # self.actions[street] is a list of all actions in a tuple, contining the action as the second element + # [ (player, action, ....), (player2, action, ...) ] + # No idea what this value is actually supposed to be + # In theory its "num small bets paid to see flop/street4, including blind" which makes sense for limit. Not so useful for nl + + def aggr(self, hand, i): aggrers = set() for act in hand.actions[hand.actionStreets[i]]: From cf6c3c8ad00075d166abb815d256130eaae63114 Mon Sep 17 00:00:00 2001 From: Worros Date: Thu, 8 Oct 2009 18:07:54 +0800 Subject: [PATCH 14/15] [NEWIMPOR] Fix playersVpi from last patch Oops - forgot to add the argument --- pyfpdb/Database.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pyfpdb/Database.py b/pyfpdb/Database.py index 22aeb677..c798e72d 100755 --- a/pyfpdb/Database.py +++ b/pyfpdb/Database.py @@ -1382,7 +1382,7 @@ class Database: importtime, seats, maxseats, - playersVpi, + playersVpi, boardcard1, boardcard2, boardcard3, @@ -1421,12 +1421,12 @@ class Database: datetime.today(), #importtime p['seats'], p['maxSeats'], + p['playersVpi'], p['boardcard1'], p['boardcard2'], p['boardcard3'], p['boardcard4'], p['boardcard5'], -# hudCache['playersVpi'], # hudCache['playersAtStreet1'], # hudCache['playersAtStreet2'], # hudCache['playersAtStreet3'], From 6d0ec5d8316682aea4069f7b925b0d1f791a57be Mon Sep 17 00:00:00 2001 From: Worros Date: Thu, 8 Oct 2009 18:13:13 +0800 Subject: [PATCH 15/15] [NEWIMPORT] Add playersAtStreetX to insert --- pyfpdb/Database.py | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/pyfpdb/Database.py b/pyfpdb/Database.py index c798e72d..38c475d9 100755 --- a/pyfpdb/Database.py +++ b/pyfpdb/Database.py @@ -1388,6 +1388,11 @@ class Database: boardcard3, boardcard4, boardcard5, + playersAtStreet1, + playersAtStreet2, + playersAtStreet3, + playersAtStreet4, + playersAtShowdown, street1Pot, street2Pot, street3Pot, @@ -1396,19 +1401,14 @@ class Database: ) VALUES (%s, %s, %s, %s, %s, %s, %s, %s, %s, %s, - %s, %s, %s, %s, %s, %s, %s, %s)""" + %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, + %s, %s, %s)""" #--- texture, -#-- playersAtStreet1, -#-- playersAtStreet2, -#-- playersAtStreet3, -#-- playersAtStreet4, -#-- playersAtShowdown, #-- street0Raises, #-- street1Raises, #-- street2Raises, #-- street3Raises, #-- street4Raises, -#-- seats, q = q.replace('%s', self.sql.query['placeholder']) print "DEBUG: p: %s" %p @@ -1427,11 +1427,11 @@ class Database: p['boardcard3'], p['boardcard4'], p['boardcard5'], -# hudCache['playersAtStreet1'], -# hudCache['playersAtStreet2'], -# hudCache['playersAtStreet3'], -# hudCache['playersAtStreet4'], -# hudCache['playersAtShowdown'], + p['playersAtStreet1'], + p['playersAtStreet2'], + p['playersAtStreet3'], + p['playersAtStreet4'], + p['playersAtShowdown'], # hudCache['street0Raises'], # hudCache['street1Raises'], # hudCache['street2Raises'],