From 284b0c1f38e0353d146c4b976188d7cd6091300c Mon Sep 17 00:00:00 2001 From: Eric Blade Date: Mon, 30 Nov 2009 08:14:03 -0500 Subject: [PATCH 01/65] fix return tuple in import_file_dict, fix text from autoimport to actually show up in autoimport window --- pyfpdb/fpdb.py | 15 +++++++-------- pyfpdb/fpdb_import.py | 11 ++++++++--- 2 files changed, 15 insertions(+), 11 deletions(-) diff --git a/pyfpdb/fpdb.py b/pyfpdb/fpdb.py index d5f4faec..b960da05 100755 --- a/pyfpdb/fpdb.py +++ b/pyfpdb/fpdb.py @@ -115,7 +115,7 @@ class fpdb: self.pages.append(new_page) self.tabs.append(event_box) self.tab_names.append(new_tab_name) - + #self.nb.append_page(new_page, gtk.Label(new_tab_name)) self.nb.append_page(page, event_box) self.nb_tabs.append(new_tab_name) @@ -135,12 +135,12 @@ class fpdb: self.nb.set_current_page(tab_no) def create_custom_tab(self, text, nb): - #create a custom tab for notebook containing a + #create a custom tab for notebook containing a #label and a button with STOCK_ICON eventBox = gtk.EventBox() tabBox = gtk.HBox(False, 2) tabLabel = gtk.Label(text) - tabBox.pack_start(tabLabel, False) + tabBox.pack_start(tabLabel, False) eventBox.add(tabBox) if nb.get_n_pages() > 0: @@ -157,7 +157,7 @@ class fpdb: return eventBox def add_icon_to_button(self, button): - iconBox = gtk.HBox(False, 0) + iconBox = gtk.HBox(False, 0) image = gtk.Image() image.set_from_stock(gtk.STOCK_CLOSE, gtk.ICON_SIZE_SMALL_TOOLBAR) gtk.Button.set_relief(button, gtk.RELIEF_NONE) @@ -168,8 +168,8 @@ class fpdb: iconBox.pack_start(image, True, False, 0) button.add(iconBox) iconBox.show() - return - + return + # Remove a page from the notebook def remove_tab(self, button, data): (nb, text) = data @@ -183,7 +183,7 @@ class fpdb: #print " removing page", page del self.nb_tabs[page] nb.remove_page(page) - # Need to refresh the widget -- + # Need to refresh the widget -- # This forces the widget to redraw itself. #nb.queue_draw_area(0,0,-1,-1) needed or not?? @@ -752,7 +752,6 @@ This program is licensed under the AGPL3, see docs"""+os.sep+"agpl-3.0.txt") sys.stderr.write("fpdb starting ...") def window_state_event_cb(self, window, event): - print "window_state_event", event if event.changed_mask & gtk.gdk.WINDOW_STATE_ICONIFIED: # -20 = GWL_EXSTYLE can't find it in the pywin32 libs #bits = win32api.GetWindowLong(self.window.window.handle, -20) diff --git a/pyfpdb/fpdb_import.py b/pyfpdb/fpdb_import.py index 19bf18d1..b6cfb821 100644 --- a/pyfpdb/fpdb_import.py +++ b/pyfpdb/fpdb_import.py @@ -359,10 +359,15 @@ class Importer: # print "file",counter," updated", os.path.basename(file), stat_info.st_size, self.updatedsize[file], stat_info.st_mtime, self.updatedtime[file] try: if not os.path.isdir(file): - self.caller.addText("\n"+file) + self.caller.addText("\n"+os.path.basename(file)) except KeyError: # TODO: What error happens here? pass - self.import_file_dict(self.database, file, self.filelist[file][0], self.filelist[file][1], None) + (stored, duplicates, partial, errors, ttime) = self.import_file_dict(self.database, file, self.filelist[file][0], self.filelist[file][1], None) + try: + if not os.path.isdir(file): + self.caller.addText(" %d stored, %d duplicates, %d partial, %d errors (time = %d)" % (stored, duplicates, partial, errors, ttime)) + except KeyError: # TODO: Again, what error happens here? fix when we find out .. + pass self.updatedsize[file] = stat_info.st_size self.updatedtime[file] = time() else: @@ -393,7 +398,7 @@ class Importer: if os.path.isdir(file): self.addToDirList[file] = [site] + [filter] - return + return (0,0,0,0,0) conv = None (stored, duplicates, partial, errors, ttime) = (0, 0, 0, 0, 0) From 8c8fdba7c845886609f56eb77b9e7fd4c131df91 Mon Sep 17 00:00:00 2001 From: Eric Blade Date: Mon, 30 Nov 2009 09:08:30 -0500 Subject: [PATCH 02/65] ttime = float with us to ms resolution --- pyfpdb/fpdb_import.py | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/pyfpdb/fpdb_import.py b/pyfpdb/fpdb_import.py index b6cfb821..541b018f 100644 --- a/pyfpdb/fpdb_import.py +++ b/pyfpdb/fpdb_import.py @@ -21,7 +21,7 @@ import os # todo: remove this once import_dir is in fpdb_import import sys -from time import time, strftime, sleep +from time import time, strftime, sleep, clock import traceback import math import datetime @@ -101,6 +101,8 @@ class Importer: self.NEWIMPORT = Configuration.NEWIMPORT + clock() # init clock in windows + #Set functions def setCallHud(self, value): self.callHud = value @@ -365,7 +367,7 @@ class Importer: (stored, duplicates, partial, errors, ttime) = self.import_file_dict(self.database, file, self.filelist[file][0], self.filelist[file][1], None) try: if not os.path.isdir(file): - self.caller.addText(" %d stored, %d duplicates, %d partial, %d errors (time = %d)" % (stored, duplicates, partial, errors, ttime)) + self.caller.addText(" %d stored, %d duplicates, %d partial, %d errors (time = %f)" % (stored, duplicates, partial, errors, ttime)) except KeyError: # TODO: Again, what error happens here? fix when we find out .. pass self.updatedsize[file] = stat_info.st_size @@ -477,10 +479,13 @@ class Importer: self.pos_in_file[file] = inputFile.tell() inputFile.close() + x = clock() (stored, duplicates, partial, errors, ttime, handsId) = self.import_fpdb_lines(db, self.lines, starttime, file, site, q) db.commit() - ttime = time() - starttime + y = clock() + ttime = y - x + #ttime = time() - starttime if q is None: log.info("Total stored: %(stored)d\tduplicates:%(duplicates)d\terrors:%(errors)d\ttime:%(ttime)s" % locals()) From 9953e76c9e1e8566e79e9c02acaa35aa6ccdf57e Mon Sep 17 00:00:00 2001 From: Eric Blade Date: Mon, 30 Nov 2009 09:51:47 -0500 Subject: [PATCH 03/65] trap IOError on hud pipe write when hud closed without autoimport stopping, turn off hud --- pyfpdb/fpdb_import.py | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/pyfpdb/fpdb_import.py b/pyfpdb/fpdb_import.py index 541b018f..d735de04 100644 --- a/pyfpdb/fpdb_import.py +++ b/pyfpdb/fpdb_import.py @@ -564,7 +564,11 @@ class Importer: #print "call to HUD here. handsId:",handsId #pipe the Hands.id out to the HUD # print "fpdb_import: sending hand to hud", handsId, "pipe =", self.caller.pipe_to_hud - self.caller.pipe_to_hud.stdin.write("%s" % (handsId) + os.linesep) + try: + self.caller.pipe_to_hud.stdin.write("%s" % (handsId) + os.linesep) + except IOError: # hud closed + self.callHud = False + pass # continue import without hud except Exceptions.DuplicateError: duplicates += 1 db.rollback() From f7ed06d071a86bd2e8a9e205ea5cb949bc5843d5 Mon Sep 17 00:00:00 2001 From: sqlcoder Date: Mon, 30 Nov 2009 21:43:29 +0000 Subject: [PATCH 04/65] improve rebuild hudcache and indexes dialogs --- pyfpdb/Database.py | 17 ++++++++----- pyfpdb/fpdb.py | 63 +++++++++++++++++++++++++++++++++++++--------- 2 files changed, 62 insertions(+), 18 deletions(-) diff --git a/pyfpdb/Database.py b/pyfpdb/Database.py index cd6ad298..1c44bb61 100755 --- a/pyfpdb/Database.py +++ b/pyfpdb/Database.py @@ -58,7 +58,8 @@ class Database: PGSQL = 3 SQLITE = 4 - hero_hudstart_def = '1999-12-31' # default for length of Hero's stats in HUD + hero_hudstart_def = '1999-12-31' # default for length of Hero's stats in HUD + villain_hudstart_def = '1999-12-31' # default for length of Villain's stats in HUD # Data Structures for index and foreign key creation # drop_code is an int with possible values: 0 - don't drop for bulk import @@ -1324,7 +1325,7 @@ class Database: self.dropAllForeignKeys() self.createAllForeignKeys() - def rebuild_hudcache(self, start=None): + def rebuild_hudcache(self, h_start=None, v_start=None): """clears hudcache and rebuilds from the individual handsplayers records""" try: @@ -1344,13 +1345,17 @@ class Database: if p_id: self.hero_ids[site_id] = int(p_id) - if start is None: - start = self.hero_hudstart_def + if h_start is None: + h_start = self.hero_hudstart_def + if v_start is None: + v_start = self.villain_hudstart_def if self.hero_ids == {}: where = "" else: - where = "where hp.playerId not in " + str(tuple(self.hero_ids.values())) \ - + " or h.handStart > '" + start + "'" + where = "where ( hp.playerId not in " + str(tuple(self.hero_ids.values())) \ + + " and h.handStart > '" + v_start + "')" \ + + " or ( hp.playerId in " + str(tuple(self.hero_ids.values())) \ + + " and h.handStart > '" + h_start + "')" rebuild_sql = self.sql.query['rebuildHudCache'].replace('', where) self.get_cursor().execute(self.sql.query['clearHudCache']) diff --git a/pyfpdb/fpdb.py b/pyfpdb/fpdb.py index d5f4faec..faaf4fdc 100755 --- a/pyfpdb/fpdb.py +++ b/pyfpdb/fpdb.py @@ -334,27 +334,48 @@ class fpdb: diastring = "Please confirm that you want to re-create the HUD cache." self.dia_confirm.format_secondary_text(diastring) - hb = gtk.HBox(True, 1) + hb1 = gtk.HBox(True, 1) + self.h_start_date = gtk.Entry(max=12) + self.h_start_date.set_text( self.db.get_hero_hudcache_start() ) + lbl = gtk.Label(" Hero's cache starts: ") + btn = gtk.Button() + btn.set_image(gtk.image_new_from_stock(gtk.STOCK_INDEX, gtk.ICON_SIZE_BUTTON)) + btn.connect('clicked', self.__calendar_dialog, self.h_start_date) + + hb1.pack_start(lbl, expand=True, padding=3) + hb1.pack_start(self.h_start_date, expand=True, padding=2) + hb1.pack_start(btn, expand=False, padding=3) + self.dia_confirm.vbox.add(hb1) + hb1.show_all() + + hb2 = gtk.HBox(True, 1) self.start_date = gtk.Entry(max=12) self.start_date.set_text( self.db.get_hero_hudcache_start() ) - lbl = gtk.Label(" Hero's cache starts: ") + lbl = gtk.Label(" Villains' cache starts: ") btn = gtk.Button() btn.set_image(gtk.image_new_from_stock(gtk.STOCK_INDEX, gtk.ICON_SIZE_BUTTON)) btn.connect('clicked', self.__calendar_dialog, self.start_date) - hb.pack_start(lbl, expand=True, padding=3) - hb.pack_start(self.start_date, expand=True, padding=2) - hb.pack_start(btn, expand=False, padding=3) - self.dia_confirm.vbox.add(hb) - hb.show_all() + hb2.pack_start(lbl, expand=True, padding=3) + hb2.pack_start(self.start_date, expand=True, padding=2) + hb2.pack_start(btn, expand=False, padding=3) + self.dia_confirm.vbox.add(hb2) + hb2.show_all() response = self.dia_confirm.run() - self.dia_confirm.destroy() if response == gtk.RESPONSE_YES: - self.db.rebuild_hudcache( self.start_date.get_text() ) + lbl = gtk.Label(" Rebuilding HUD Cache ... ") + self.dia_confirm.vbox.add(lbl) + lbl.show() + while gtk.events_pending(): + gtk.main_iteration_do(False) + + self.db.rebuild_hudcache( self.h_start_date.get_text(), self.start_date.get_text() ) elif response == gtk.RESPONSE_NO: print 'User cancelled rebuilding hud cache' + self.dia_confirm.destroy() + self.release_global_lock() def dia_rebuild_indexes(self, widget, data=None): @@ -368,14 +389,28 @@ class fpdb: self.dia_confirm.format_secondary_text(diastring) response = self.dia_confirm.run() - self.dia_confirm.destroy() if response == gtk.RESPONSE_YES: + lbl = gtk.Label(" Rebuilding Indexes ... ") + self.dia_confirm.vbox.add(lbl) + lbl.show() + while gtk.events_pending(): + gtk.main_iteration_do(False) self.db.rebuild_indexes() + + lbl.set_text(" Cleaning Database ... ") + while gtk.events_pending(): + gtk.main_iteration_do(False) self.db.vacuumDB() + + lbl.set_text(" Analyzing Database ... ") + while gtk.events_pending(): + gtk.main_iteration_do(False) self.db.analyzeDB() elif response == gtk.RESPONSE_NO: print 'User cancelled rebuilding db indexes' + self.dia_confirm.destroy() + self.release_global_lock() def __calendar_dialog(self, widget, entry): @@ -397,10 +432,13 @@ class fpdb: d.show_all() def __get_dates(self): - t1 = self.start_date.get_text() + t1 = self.h_start_date.get_text() if t1 == '': t1 = '1970-01-01' - return (t1) + t2 = self.start_date.get_text() + if t2 == '': + t2 = '1970-01-01' + return (t1, t2) def __get_date(self, widget, calendar, entry, win): # year and day are correct, month is 0..11 @@ -835,6 +873,7 @@ This program is licensed under the AGPL3, see docs"""+os.sep+"agpl-3.0.txt") gtk.main() return 0 + if __name__ == "__main__": me = fpdb() me.main() From bec343abfdcd15ea541193b0f0e502c630da6f1a Mon Sep 17 00:00:00 2001 From: Eric Blade Date: Tue, 1 Dec 2009 06:58:33 -0500 Subject: [PATCH 05/65] argh at whitespace churn, do i have my editor settings screwey? trap error 2003 on mysql connect (same as 2002, but for tcp) --- pyfpdb/Database.py | 270 ++++++++++++++++++++++----------------------- pyfpdb/fpdb.py | 2 +- pyfpdb/fpdb_db.py | 2 +- 3 files changed, 137 insertions(+), 137 deletions(-) diff --git a/pyfpdb/Database.py b/pyfpdb/Database.py index cd6ad298..d71f8ab1 100755 --- a/pyfpdb/Database.py +++ b/pyfpdb/Database.py @@ -4,17 +4,17 @@ Create and manage the database objects. """ # Copyright 2008, Ray E. Barker -# +# # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2 of the License, or # (at your option) any later version. -# +# # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. -# +# # You should have received a copy of the GNU General Public License # along with this program; if not, write to the Free Software # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA @@ -63,7 +63,7 @@ class Database: # Data Structures for index and foreign key creation # drop_code is an int with possible values: 0 - don't drop for bulk import # 1 - drop during bulk import - # db differences: + # db differences: # - note that mysql automatically creates indexes on constrained columns when # foreign keys are created, while postgres does not. Hence the much longer list # of indexes is required for postgres. @@ -102,7 +102,7 @@ class Database: # {'tab':'Players', 'col':'name', 'drop':0} unique indexes not dropped # {'tab':'Hands', 'col':'siteHandNo', 'drop':0} unique indexes not dropped {'tab':'Hands', 'col':'gametypeId', 'drop':0} - , {'tab':'HandsPlayers', 'col':'handId', 'drop':0} + , {'tab':'HandsPlayers', 'col':'handId', 'drop':0} , {'tab':'HandsPlayers', 'col':'playerId', 'drop':0} , {'tab':'HandsPlayers', 'col':'tourneyTypeId', 'drop':0} , {'tab':'HandsPlayers', 'col':'tourneysPlayersId', 'drop':0} @@ -147,7 +147,7 @@ class Database: # (fkcol is used for foreigh key name) # mysql to list indexes: - # SELECT table_name, index_name, non_unique, column_name + # SELECT table_name, index_name, non_unique, column_name # FROM INFORMATION_SCHEMA.STATISTICS # WHERE table_name = 'tbl_name' # AND table_schema = 'db_name' @@ -183,16 +183,16 @@ class Database: # create index indexname on tablename (col); - def __init__(self, c, sql = None): + def __init__(self, c, sql = None): log.info("Creating Database instance, sql = %s" % sql) self.config = c self.fdb = fpdb_db.fpdb_db() # sets self.fdb.db self.fdb.cursor and self.fdb.sql self.do_connect(c) - + if self.backend == self.PGSQL: from psycopg2.extensions import ISOLATION_LEVEL_AUTOCOMMIT, ISOLATION_LEVEL_READ_COMMITTED, ISOLATION_LEVEL_SERIALIZABLE #ISOLATION_LEVEL_AUTOCOMMIT = 0 - #ISOLATION_LEVEL_READ_COMMITTED = 1 + #ISOLATION_LEVEL_READ_COMMITTED = 1 #ISOLATION_LEVEL_SERIALIZABLE = 2 @@ -262,11 +262,11 @@ class Database: def disconnect(self, due_to_error=False): """Disconnects the DB (rolls back if param is true, otherwise commits""" self.fdb.disconnect(due_to_error) - + def reconnect(self, due_to_error=False): """Reconnects the DB""" self.fdb.reconnect(due_to_error=False) - + def get_backend_name(self): """Returns the name of the currently used backend""" if self.backend==2: @@ -283,7 +283,7 @@ class Database: c.execute(self.sql.query['get_table_name'], (hand_id, )) row = c.fetchone() return row - + def get_table_info(self, hand_id): c = self.connection.cursor() c.execute(self.sql.query['get_table_name'], (hand_id, )) @@ -304,18 +304,18 @@ class Database: c.execute(self.sql.query['get_last_hand']) row = c.fetchone() return row[0] - + def get_xml(self, hand_id): c = self.connection.cursor() c.execute(self.sql.query['get_xml'], (hand_id)) row = c.fetchone() return row[0] - + def get_recent_hands(self, last_hand): c = self.connection.cursor() c.execute(self.sql.query['get_recent_hands'], {'last_hand': last_hand}) return c.fetchall() - + def get_hand_info(self, new_hand_id): c = self.connection.cursor() c.execute(self.sql.query['get_hand_info'], new_hand_id) @@ -549,7 +549,7 @@ class Database: query = query.replace("", 'signed ') else: query = query.replace("", '') - + subs = (self.hand_1day_ago, hand, hero_id, seats_min, seats_max , hero_id, h_seats_min, h_seats_max) c = self.get_cursor() @@ -577,7 +577,7 @@ class Database: elif name.lower() not in ('hand_id', 'player_id', 'seat', 'screen_name', 'seats'): stat_dict[playerid][name.lower()] += val n += 1 - if n >= 10000: break # todo: don't think this is needed so set nice and high + if n >= 10000: break # todo: don't think this is needed so set nice and high # prevents infinite loop so leave for now - comment out or remove? row = c.fetchone() else: @@ -587,7 +587,7 @@ class Database: #print "session stat_dict =", stat_dict #return stat_dict - + def get_player_id(self, config, site, player_name): c = self.connection.cursor() c.execute(self.sql.query['get_player_id'], (player_name, site)) @@ -596,7 +596,7 @@ class Database: return row[0] 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""" @@ -606,7 +606,7 @@ class Database: 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 @@ -666,7 +666,7 @@ class Database: # tmp = cursor.fetchall() # for n in tmp: # result.append(n[0]) - # + # # return result @@ -760,7 +760,7 @@ class Database: if 'dropHudCache' not in settings or settings['dropHudCache'] != 'drop': self.storeHudCache(self.backend, base, category, gametype_id, hand_start_time, player_ids, hudImportData) t5 = time() - #print "fills=(%4.3f) saves=(%4.3f,%4.3f,%4.3f)" % (t2-t0, t3-t2, t4-t3, t5-t4) + print "fills=(%4.3f) saves=(%4.3f,%4.3f,%4.3f)" % (t2-t0, t3-t2, t4-t3, t5-t4) return hands_id #end def ring_holdem_omaha @@ -827,7 +827,7 @@ class Database: #end def tourney_stud def prepareBulkImport(self): - """Drop some indexes/foreign keys to prepare for bulk import. + """Drop some indexes/foreign keys to prepare for bulk import. Currently keeping the standalone indexes as needed to import quickly""" stime = time() c = self.get_cursor() @@ -845,7 +845,7 @@ class Database: "FROM information_schema.KEY_COLUMN_USAGE " + #"WHERE REFERENCED_TABLE_SCHEMA = 'fpdb' "WHERE 1=1 " + - "AND table_name = %s AND column_name = %s " + + "AND table_name = %s AND column_name = %s " + "AND referenced_table_name = %s " + "AND referenced_column_name = %s ", (fk['fktab'], fk['fkcol'], fk['rtab'], fk['rcol']) ) @@ -862,7 +862,7 @@ class Database: print "dropping pg fk", fk['fktab'], fk['fkcol'] try: # try to lock table to see if index drop will work: - # hmmm, tested by commenting out rollback in grapher. lock seems to work but + # hmmm, tested by commenting out rollback in grapher. lock seems to work but # then drop still hangs :-( does work in some tests though?? # will leave code here for now pending further tests/enhancement ... c.execute( "lock table %s in exclusive mode nowait" % (fk['fktab'],) ) @@ -881,13 +881,13 @@ class Database: else: print "Only MySQL and Postgres supported so far" return -1 - + for idx in self.indexes[self.backend]: if idx['drop'] == 1: if self.backend == self.MYSQL_INNODB: print "dropping mysql index ", idx['tab'], idx['col'] try: - # apparently nowait is not implemented in mysql so this just hangs if there are locks + # apparently nowait is not implemented in mysql so this just hangs if there are locks # preventing the index drop :-( c.execute( "alter table %s drop index %s;", (idx['tab'],idx['col']) ) except: @@ -903,13 +903,13 @@ class Database: #print "after lock, status:", c.statusmessage try: # table locked ok so index drop should work: - #print "drop index %s_%s_idx" % (idx['tab'],idx['col']) + #print "drop index %s_%s_idx" % (idx['tab'],idx['col']) c.execute( "drop index if exists %s_%s_idx" % (idx['tab'],idx['col']) ) #print "dropped pg index ", idx['tab'], idx['col'] except: if "does not exist" not in str(sys.exc_value): print "warning: drop index %s_%s_idx failed: %s, continuing ..." \ - % (idx['tab'],idx['col'], str(sys.exc_value).rstrip('\n')) + % (idx['tab'],idx['col'], str(sys.exc_value).rstrip('\n')) except: print "warning: index %s_%s_idx not dropped %s, continuing ..." \ % (idx['tab'],idx['col'], str(sys.exc_value).rstrip('\n')) @@ -927,7 +927,7 @@ class Database: def afterBulkImport(self): """Re-create any dropped indexes/foreign keys after bulk import""" stime = time() - + c = self.get_cursor() if self.backend == self.MYSQL_INNODB: c.execute("SET foreign_key_checks=1") @@ -943,7 +943,7 @@ class Database: "FROM information_schema.KEY_COLUMN_USAGE " + #"WHERE REFERENCED_TABLE_SCHEMA = 'fpdb' "WHERE 1=1 " + - "AND table_name = %s AND column_name = %s " + + "AND table_name = %s AND column_name = %s " + "AND referenced_table_name = %s " + "AND referenced_column_name = %s ", (fk['fktab'], fk['fkcol'], fk['rtab'], fk['rcol']) ) @@ -954,8 +954,8 @@ class Database: else: print "creating fk ", fk['fktab'], fk['fkcol'], "->", fk['rtab'], fk['rcol'] try: - c.execute("alter table " + fk['fktab'] + " add foreign key (" - + fk['fkcol'] + ") references " + fk['rtab'] + "(" + c.execute("alter table " + fk['fktab'] + " add foreign key (" + + fk['fkcol'] + ") references " + fk['rtab'] + "(" + fk['rcol'] + ")") except: print " create fk failed: " + str(sys.exc_info()) @@ -971,7 +971,7 @@ class Database: else: print "Only MySQL and Postgres supported so far" return -1 - + for idx in self.indexes[self.backend]: if idx['drop'] == 1: if self.backend == self.MYSQL_INNODB: @@ -1021,10 +1021,10 @@ class Database: c.execute("ALTER TABLE " + inner[j][0] + " DROP FOREIGN KEY " + key) self.commit() #end drop_referential_inegrity - + def recreate_tables(self): """(Re-)creates the tables of the current DB""" - + self.drop_tables() self.create_tables() self.createAllIndexes() @@ -1068,7 +1068,7 @@ class Database: self.rollback() raise #end def disconnect - + def drop_tables(self): """Drops the fpdb tables from the current db""" try: @@ -1202,7 +1202,7 @@ class Database: "FROM information_schema.KEY_COLUMN_USAGE " + #"WHERE REFERENCED_TABLE_SCHEMA = 'fpdb' "WHERE 1=1 " + - "AND table_name = %s AND column_name = %s " + + "AND table_name = %s AND column_name = %s " + "AND referenced_table_name = %s " + "AND referenced_column_name = %s ", (fk['fktab'], fk['fkcol'], fk['rtab'], fk['rcol']) ) @@ -1213,8 +1213,8 @@ class Database: else: print "creating fk ", fk['fktab'], fk['fkcol'], "->", fk['rtab'], fk['rcol'] try: - c.execute("alter table " + fk['fktab'] + " add foreign key (" - + fk['fkcol'] + ") references " + fk['rtab'] + "(" + c.execute("alter table " + fk['fktab'] + " add foreign key (" + + fk['fkcol'] + ") references " + fk['rtab'] + "(" + fk['rcol'] + ")") except: print " create fk failed: " + str(sys.exc_info()) @@ -1251,7 +1251,7 @@ class Database: "FROM information_schema.KEY_COLUMN_USAGE " + #"WHERE REFERENCED_TABLE_SCHEMA = 'fpdb' "WHERE 1=1 " + - "AND table_name = %s AND column_name = %s " + + "AND table_name = %s AND column_name = %s " + "AND referenced_table_name = %s " + "AND referenced_column_name = %s ", (fk['fktab'], fk['fkcol'], fk['rtab'], fk['rcol']) ) @@ -1268,7 +1268,7 @@ class Database: print "dropping pg fk", fk['fktab'], fk['fkcol'] try: # try to lock table to see if index drop will work: - # hmmm, tested by commenting out rollback in grapher. lock seems to work but + # hmmm, tested by commenting out rollback in grapher. lock seems to work but # then drop still hangs :-( does work in some tests though?? # will leave code here for now pending further tests/enhancement ... c.execute( "lock table %s in exclusive mode nowait" % (fk['fktab'],) ) @@ -1286,14 +1286,14 @@ class Database: % (fk['fktab'],fk['fkcol'], str(sys.exc_value).rstrip('\n')) else: print "Only MySQL and Postgres supported so far" - + if self.backend == self.PGSQL: self.connection.set_isolation_level(1) # go back to normal isolation level #end def dropAllForeignKeys - + def fillDefaultData(self): - c = self.get_cursor() + c = self.get_cursor() c.execute("INSERT INTO Settings (version) VALUES (118);") c.execute("INSERT INTO Sites (name,currency) VALUES ('Full Tilt Poker', 'USD')") c.execute("INSERT INTO Sites (name,currency) VALUES ('PokerStars', 'USD')") @@ -1343,7 +1343,7 @@ class Database: p_id = self.get_player_id(self.config, site, self.hero[site_id]) if p_id: self.hero_ids[site_id] = int(p_id) - + if start is None: start = self.hero_hudstart_def if self.hero_ids == {}: @@ -1381,7 +1381,7 @@ class Database: p_id = self.get_player_id(self.config, site, self.hero[site_id]) if p_id: self.hero_ids[site_id] = int(p_id) - + q = self.sql.query['get_hero_hudcache_start'].replace("", str(tuple(self.hero_ids.values()))) c = self.get_cursor() c.execute(q) @@ -1458,7 +1458,7 @@ class Database: if h.isTourney: ranks = map(lambda x: 0, h.names) # create an array of 0's equal to the length of names payin_amounts = fpdb_simple.calcPayin(len(h.names), h.buyin, h.fee) - + if h.base == "hold": result = self.tourney_holdem_omaha( h.config, h.settings, h.base, h.category, h.siteTourneyNo, h.buyin @@ -1520,19 +1520,19 @@ class Database: c = self.get_cursor() c.execute(q, ( - p['tableName'], - p['gameTypeId'], - p['siteHandNo'], - p['handStart'], + p['tableName'], + p['gameTypeId'], + p['siteHandNo'], + p['handStart'], datetime.today(), #importtime p['seats'], p['maxSeats'], p['texture'], p['playersVpi'], - p['boardcard1'], - p['boardcard2'], - p['boardcard3'], - p['boardcard4'], + p['boardcard1'], + p['boardcard2'], + p['boardcard3'], + p['boardcard4'], p['boardcard5'], p['playersAtStreet1'], p['playersAtStreet2'], @@ -1858,7 +1858,7 @@ class Database: 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'], + 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): @@ -1875,7 +1875,7 @@ class Database: 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: @@ -1935,7 +1935,7 @@ class Database: #stores into table hands: try: c = self.get_cursor() - c.execute ("""INSERT INTO Hands + c.execute ("""INSERT INTO Hands (siteHandNo, gametypeId, handStart, seats, tableName, importTime, maxSeats ,boardcard1,boardcard2,boardcard3,boardcard4,boardcard5 ,playersVpi, playersAtStreet1, playersAtStreet2 @@ -1944,8 +1944,8 @@ class Database: ,street3Raises, street4Raises, street1Pot ,street2Pot, street3Pot, street4Pot ,showdownPot - ) - VALUES + ) + 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) """.replace('%s', self.sql.query['placeholder']) @@ -1965,7 +1965,7 @@ class Database: return ret #end def storeHands - + def store_hands_players_holdem_omaha(self, backend, category, hands_id, player_ids, start_cashes ,positions, card_values, card_suits, winnings, rakes, seatNos, hudCache): result=[] @@ -2002,27 +2002,27 @@ class Database: hands_id, player_ids[i], start_cashes[i], positions[i], 1, # tourneytypeid - needed for hudcache card1, card2, card3, card4, startCards, winnings[i], rakes[i], seatNos[i], hudCache['totalProfit'][i], - hudCache['street0VPI'][i], hudCache['street0Aggr'][i], + hudCache['street0VPI'][i], hudCache['street0Aggr'][i], hudCache['street0_3BChance'][i], hudCache['street0_3BDone'][i], - hudCache['street1Seen'][i], hudCache['street2Seen'][i], hudCache['street3Seen'][i], + hudCache['street1Seen'][i], hudCache['street2Seen'][i], hudCache['street3Seen'][i], hudCache['street4Seen'][i], hudCache['sawShowdown'][i], hudCache['street1Aggr'][i], hudCache['street2Aggr'][i], hudCache['street3Aggr'][i], hudCache['street4Aggr'][i], - hudCache['otherRaisedStreet1'][i], hudCache['otherRaisedStreet2'][i], + hudCache['otherRaisedStreet1'][i], hudCache['otherRaisedStreet2'][i], hudCache['otherRaisedStreet3'][i], hudCache['otherRaisedStreet4'][i], - hudCache['foldToOtherRaisedStreet1'][i], hudCache['foldToOtherRaisedStreet2'][i], + hudCache['foldToOtherRaisedStreet1'][i], hudCache['foldToOtherRaisedStreet2'][i], hudCache['foldToOtherRaisedStreet3'][i], hudCache['foldToOtherRaisedStreet4'][i], hudCache['wonWhenSeenStreet1'][i], hudCache['wonAtSD'][i], - hudCache['stealAttemptChance'][i], hudCache['stealAttempted'][i], hudCache['foldBbToStealChance'][i], + hudCache['stealAttemptChance'][i], hudCache['stealAttempted'][i], hudCache['foldBbToStealChance'][i], hudCache['foldedBbToSteal'][i], hudCache['foldSbToStealChance'][i], hudCache['foldedSbToSteal'][i], hudCache['street1CBChance'][i], hudCache['street1CBDone'][i], hudCache['street2CBChance'][i], hudCache['street2CBDone'][i], hudCache['street3CBChance'][i], hudCache['street3CBDone'][i], hudCache['street4CBChance'][i], hudCache['street4CBDone'][i], - hudCache['foldToStreet1CBChance'][i], hudCache['foldToStreet1CBDone'][i], + hudCache['foldToStreet1CBChance'][i], hudCache['foldToStreet1CBDone'][i], hudCache['foldToStreet2CBChance'][i], hudCache['foldToStreet2CBDone'][i], - hudCache['foldToStreet3CBChance'][i], hudCache['foldToStreet3CBDone'][i], + hudCache['foldToStreet3CBChance'][i], hudCache['foldToStreet3CBDone'][i], hudCache['foldToStreet4CBChance'][i], hudCache['foldToStreet4CBDone'][i], - hudCache['street1CheckCallRaiseChance'][i], hudCache['street1CheckCallRaiseDone'][i], + hudCache['street1CheckCallRaiseChance'][i], hudCache['street1CheckCallRaiseDone'][i], hudCache['street2CheckCallRaiseChance'][i], hudCache['street2CheckCallRaiseDone'][i], - hudCache['street3CheckCallRaiseChance'][i], hudCache['street3CheckCallRaiseDone'][i], + hudCache['street3CheckCallRaiseChance'][i], hudCache['street3CheckCallRaiseDone'][i], hudCache['street4CheckCallRaiseChance'][i], hudCache['street4CheckCallRaiseDone'][i], hudCache['street0Calls'][i], hudCache['street1Calls'][i], hudCache['street2Calls'][i], hudCache['street3Calls'][i], hudCache['street4Calls'][i], hudCache['street0Bets'][i], hudCache['street1Bets'][i], hudCache['street2Bets'][i], hudCache['street3Bets'][i], hudCache['street4Bets'][i] @@ -2045,12 +2045,12 @@ class Database: foldToStreet3CBChance, foldToStreet3CBDone, foldToStreet4CBChance, foldToStreet4CBDone, street1CheckCallRaiseChance, street1CheckCallRaiseDone, street2CheckCallRaiseChance, street2CheckCallRaiseDone, street3CheckCallRaiseChance, street3CheckCallRaiseDone, street4CheckCallRaiseChance, street4CheckCallRaiseDone, - street0Calls, street1Calls, street2Calls, street3Calls, street4Calls, + street0Calls, street1Calls, street2Calls, street3Calls, street4Calls, street0Bets, street1Bets, street2Bets, street3Bets, street4Bets ) 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, %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, %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, %s, %s, %s, %s, %s, %s, %s, %s)""".replace('%s', self.sql.query['placeholder']) ,inserts ) result.append( self.get_last_insert_id(c) ) # wrong? not used currently @@ -2084,7 +2084,7 @@ class Database: card5, card6, card7, winnings, rake, seatNo) VALUES (%s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s)""".replace('%s', self.sql.query['placeholder']), - (hands_id, player_ids[i], start_cashes[i], antes[i], 1, + (hands_id, player_ids[i], start_cashes[i], antes[i], 1, card1, card2, card3, card4, card5, card6, @@ -2097,7 +2097,7 @@ class Database: return result #end def store_hands_players_stud - + def store_hands_players_holdem_omaha_tourney(self, backend, category, hands_id, player_ids ,start_cashes, positions, card_values, card_suits ,winnings, rakes, seatNos, tourneys_players_ids @@ -2126,31 +2126,31 @@ class Database: inserts.append( (hands_id, player_ids[i], start_cashes[i], positions[i], tourneyTypeId, card1, card2, card3, card4, startCards, winnings[i], rakes[i], tourneys_players_ids[i], seatNos[i], hudCache['totalProfit'][i], - hudCache['street0VPI'][i], hudCache['street0Aggr'][i], + hudCache['street0VPI'][i], hudCache['street0Aggr'][i], hudCache['street0_3BChance'][i], hudCache['street0_3BDone'][i], - hudCache['street1Seen'][i], hudCache['street2Seen'][i], hudCache['street3Seen'][i], + hudCache['street1Seen'][i], hudCache['street2Seen'][i], hudCache['street3Seen'][i], hudCache['street4Seen'][i], hudCache['sawShowdown'][i], hudCache['street1Aggr'][i], hudCache['street2Aggr'][i], hudCache['street3Aggr'][i], hudCache['street4Aggr'][i], - hudCache['otherRaisedStreet1'][i], hudCache['otherRaisedStreet2'][i], + hudCache['otherRaisedStreet1'][i], hudCache['otherRaisedStreet2'][i], hudCache['otherRaisedStreet3'][i], hudCache['otherRaisedStreet4'][i], - hudCache['foldToOtherRaisedStreet1'][i], hudCache['foldToOtherRaisedStreet2'][i], + hudCache['foldToOtherRaisedStreet1'][i], hudCache['foldToOtherRaisedStreet2'][i], hudCache['foldToOtherRaisedStreet3'][i], hudCache['foldToOtherRaisedStreet4'][i], hudCache['wonWhenSeenStreet1'][i], hudCache['wonAtSD'][i], - hudCache['stealAttemptChance'][i], hudCache['stealAttempted'][i], hudCache['foldBbToStealChance'][i], + hudCache['stealAttemptChance'][i], hudCache['stealAttempted'][i], hudCache['foldBbToStealChance'][i], hudCache['foldedBbToSteal'][i], hudCache['foldSbToStealChance'][i], hudCache['foldedSbToSteal'][i], hudCache['street1CBChance'][i], hudCache['street1CBDone'][i], hudCache['street2CBChance'][i], hudCache['street2CBDone'][i], hudCache['street3CBChance'][i], hudCache['street3CBDone'][i], hudCache['street4CBChance'][i], hudCache['street4CBDone'][i], - hudCache['foldToStreet1CBChance'][i], hudCache['foldToStreet1CBDone'][i], + hudCache['foldToStreet1CBChance'][i], hudCache['foldToStreet1CBDone'][i], hudCache['foldToStreet2CBChance'][i], hudCache['foldToStreet2CBDone'][i], - hudCache['foldToStreet3CBChance'][i], hudCache['foldToStreet3CBDone'][i], + hudCache['foldToStreet3CBChance'][i], hudCache['foldToStreet3CBDone'][i], hudCache['foldToStreet4CBChance'][i], hudCache['foldToStreet4CBDone'][i], - hudCache['street1CheckCallRaiseChance'][i], hudCache['street1CheckCallRaiseDone'][i], + hudCache['street1CheckCallRaiseChance'][i], hudCache['street1CheckCallRaiseDone'][i], hudCache['street2CheckCallRaiseChance'][i], hudCache['street2CheckCallRaiseDone'][i], - hudCache['street3CheckCallRaiseChance'][i], hudCache['street3CheckCallRaiseDone'][i], + hudCache['street3CheckCallRaiseChance'][i], hudCache['street3CheckCallRaiseDone'][i], hudCache['street4CheckCallRaiseChance'][i], hudCache['street4CheckCallRaiseDone'][i], - hudCache['street0Calls'][i], hudCache['street1Calls'][i], hudCache['street2Calls'][i], + hudCache['street0Calls'][i], hudCache['street1Calls'][i], hudCache['street2Calls'][i], hudCache['street3Calls'][i], hudCache['street4Calls'][i], - hudCache['street0Bets'][i], hudCache['street1Bets'][i], hudCache['street2Bets'][i], + hudCache['street0Bets'][i], hudCache['street1Bets'][i], hudCache['street2Bets'][i], hudCache['street3Bets'][i], hudCache['street4Bets'][i] ) ) @@ -2172,13 +2172,13 @@ class Database: foldToStreet3CBChance, foldToStreet3CBDone, foldToStreet4CBChance, foldToStreet4CBDone, street1CheckCallRaiseChance, street1CheckCallRaiseDone, street2CheckCallRaiseChance, street2CheckCallRaiseDone, street3CheckCallRaiseChance, street3CheckCallRaiseDone, street4CheckCallRaiseChance, street4CheckCallRaiseDone, - street0Calls, street1Calls, street2Calls, street3Calls, street4Calls, + street0Calls, street1Calls, street2Calls, street3Calls, street4Calls, street0Bets, street1Bets, street2Bets, street3Bets, street4Bets ) - VALUES + 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, %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, %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, %s, %s, %s, %s, %s, %s, %s, %s, %s)""".replace('%s', self.sql.query['placeholder']) ,inserts ) @@ -2189,10 +2189,10 @@ class Database: err = traceback.extract_tb(sys.exc_info()[2])[-1] print "***Error storing hand: "+err[2]+"("+str(err[1])+"): "+str(sys.exc_info()[1]) raise FpdbError( "store_hands_players_holdem_omaha_tourney error: " + str(sys.exc_value) ) - + return result #end def store_hands_players_holdem_omaha_tourney - + def store_hands_players_stud_tourney(self, backend, hands_id, player_ids, start_cashes, antes, card_values, card_suits, winnings, rakes, seatNos, tourneys_players_ids, tourneyTypeId): #stores hands_players for tourney stud/razz hands @@ -2219,10 +2219,10 @@ class Database: result.append( self.get_last_insert_id(c) ) except: raise FpdbError( "store_hands_players_stud_tourney error: " + str(sys.exc_value) ) - + return result #end def store_hands_players_stud_tourney - + def storeHudCache(self, backend, base, category, gametypeId, hand_start_time, playerIds, hudImportData): """Update cached statistics. If update fails because no record exists, do an insert. Can't use array updates here (not easily anyway) because we need to insert any rows @@ -2236,11 +2236,11 @@ class Database: else: # hard-code styleKey as 'A000000' (all-time cache, no key) for now styleKey = 'A000000' - + #print "storeHudCache, len(playerIds)=", len(playerIds), " len(vpip)=" \ #, len(hudImportData['street0VPI']), " len(totprof)=", len(hudImportData['totalProfit']) for player in xrange(len(playerIds)): - + # Set up a clean row row=[] row.append(0)#blank for id @@ -2249,7 +2249,7 @@ class Database: row.append(len(playerIds))#seats for i in xrange(len(hudImportData)+2): row.append(0) - + if base=="hold": row[4]=hudImportData['position'][player] else: @@ -2285,7 +2285,7 @@ class Database: if hudImportData['foldedBbToSteal'][player]: row[33]+=1 if hudImportData['foldSbToStealChance'][player]: row[34]+=1 if hudImportData['foldedSbToSteal'][player]: row[35]+=1 - + if hudImportData['street1CBChance'][player]: row[36]+=1 if hudImportData['street1CBDone'][player]: row[37]+=1 if hudImportData['street2CBChance'][player]: row[38]+=1 @@ -2294,7 +2294,7 @@ class Database: if hudImportData['street3CBDone'][player]: row[41]+=1 if hudImportData['street4CBChance'][player]: row[42]+=1 if hudImportData['street4CBDone'][player]: row[43]+=1 - + if hudImportData['foldToStreet1CBChance'][player]: row[44]+=1 if hudImportData['foldToStreet1CBDone'][player]: row[45]+=1 if hudImportData['foldToStreet2CBChance'][player]: row[46]+=1 @@ -2303,12 +2303,12 @@ class Database: if hudImportData['foldToStreet3CBDone'][player]: row[49]+=1 if hudImportData['foldToStreet4CBChance'][player]: row[50]+=1 if hudImportData['foldToStreet4CBDone'][player]: row[51]+=1 - + #print "player=", player #print "len(totalProfit)=", len(hudImportData['totalProfit']) if hudImportData['totalProfit'][player]: row[52]+=hudImportData['totalProfit'][player] - + if hudImportData['street1CheckCallRaiseChance'][player]: row[53]+=1 if hudImportData['street1CheckCallRaiseDone'][player]: row[54]+=1 if hudImportData['street2CheckCallRaiseChance'][player]: row[55]+=1 @@ -2317,7 +2317,7 @@ class Database: if hudImportData['street3CheckCallRaiseDone'][player]: row[58]+=1 if hudImportData['street4CheckCallRaiseChance'][player]: row[59]+=1 if hudImportData['street4CheckCallRaiseDone'][player]: row[60]+=1 - + # Try to do the update first: cursor = self.get_cursor() num = cursor.execute("""UPDATE HudCache @@ -2348,10 +2348,10 @@ class Database: street2CheckCallRaiseDone=street2CheckCallRaiseDone+%s, street3CheckCallRaiseChance=street3CheckCallRaiseChance+%s, street3CheckCallRaiseDone=street3CheckCallRaiseDone+%s, street4CheckCallRaiseChance=street4CheckCallRaiseChance+%s, street4CheckCallRaiseDone=street4CheckCallRaiseDone+%s - WHERE gametypeId+0=%s - AND playerId=%s - AND activeSeats=%s - AND position=%s + WHERE gametypeId+0=%s + AND playerId=%s + AND activeSeats=%s + AND position=%s AND tourneyTypeId+0=%s AND styleKey=%s """.replace('%s', self.sql.query['placeholder']) @@ -2371,8 +2371,8 @@ class Database: #print "storehud2, upd num =", num.rowcount # num is a cursor in sqlite if ( (backend == self.PGSQL and cursor.statusmessage != "UPDATE 1") - or (backend == self.MYSQL_INNODB and num == 0) - or (backend == self.SQLITE and num.rowcount == 0) + or (backend == self.MYSQL_INNODB and num == 0) + or (backend == self.SQLITE and num.rowcount == 0) ): #print "playerid before insert:",row[2]," num = ", num num = cursor.execute("""INSERT INTO HudCache @@ -2416,9 +2416,9 @@ class Database: except: raise FpdbError( "storeHudCache error: " + str(sys.exc_value) ) - + #end def storeHudCache - + def store_tourneys(self, tourneyTypeId, siteTourneyNo, entries, prizepool, startTime): ret = -1 try: @@ -2471,7 +2471,7 @@ class Database: cursor.execute("""INSERT INTO TourneysPlayers (tourneyId, playerId, payinAmount, rank, winnings) VALUES (%s, %s, %s, %s, %s)""".replace('%s', self.sql.query['placeholder']), (tourney_id, player_ids[i], payin_amounts[i], ranks[i], winnings[i])) - + tmp = self.get_last_insert_id(cursor) result.append(tmp) #print "created new tourneys_players.id:", tmp @@ -2527,7 +2527,7 @@ class Database: sendFinal = True else: self.store_the_hand(h) - # optional commit, could be every hand / every N hands / every time a + # optional commit, could be every hand / every N hands / every time a # commit message received?? mark flag to indicate if commits outstanding if commitEachHand: self.commit() @@ -2581,7 +2581,7 @@ class Database: ) result=cursor.fetchone() - expectedValues = { 1 : "buyin", 2 : "fee", 4 : "isKO", 5 : "isRebuy", 6 : "speed", + expectedValues = { 1 : "buyin", 2 : "fee", 4 : "isKO", 5 : "isRebuy", 6 : "speed", 7 : "isHU", 8 : "isShootout", 9 : "isMatrix" } typeIdMatch = True @@ -2597,17 +2597,17 @@ class Database: except: # Tourney not found : a TourneyTypeId has to be found or created for that specific tourney typeIdMatch = False - + if typeIdMatch == False : # Check for an existing TTypeId that matches tourney info (buyin/fee, knockout, rebuy, speed, matrix, shootout) # if not found create it logging.debug("Searching for a TourneyTypeId matching TourneyType data") - cursor.execute (self.sql.query['getTourneyTypeId'].replace('%s', self.sql.query['placeholder']), + cursor.execute (self.sql.query['getTourneyTypeId'].replace('%s', self.sql.query['placeholder']), (tourney.siteId, tourney.buyin, tourney.fee, tourney.isKO, tourney.isRebuy, tourney.speed, tourney.isHU, tourney.isShootout, tourney.isMatrix) ) result=cursor.fetchone() - + try: len(result) typeId = result[0] @@ -2623,7 +2623,7 @@ class Database: return typeId #end def tRecogniseTourneyType - + def tRecognizeTourney(self, tourney, dbTourneyTypeId): logging.debug("Database.tRecognizeTourney") tourneyID = 1 @@ -2635,8 +2635,8 @@ class Database: ) result=cursor.fetchone() - expectedValuesDecimal = { 2 : "entries", 3 : "prizepool", 6 : "buyInChips", 9 : "rebuyChips", - 10 : "addOnChips", 11 : "rebuyAmount", 12 : "addOnAmount", 13 : "totalRebuys", + expectedValuesDecimal = { 2 : "entries", 3 : "prizepool", 6 : "buyInChips", 9 : "rebuyChips", + 10 : "addOnChips", 11 : "rebuyAmount", 12 : "addOnAmount", 13 : "totalRebuys", 14 : "totalAddOns", 15 : "koBounty" } expectedValues = { 7 : "tourneyName", 16 : "tourneyComment" } @@ -2671,7 +2671,7 @@ class Database: #break # TO DO : Deal with matrix summary mutliple parsings - + except: # Tourney not found : create logging.debug("Tourney is not found : create") @@ -2710,10 +2710,10 @@ class Database: return tourneyID #end def tRecognizeTourney - + def tStoreTourneyPlayers(self, tourney, dbTourneyId): logging.debug("Database.tStoreTourneyPlayers") - # First, get playerids for the players and specifically the one for hero : + # First, get playerids for the players and specifically the one for hero : playersIds = self.recognisePlayerIDs(tourney.players, tourney.siteId) # hero may be None for matrix tourneys summaries # hero = [ tourney.hero ] @@ -2723,22 +2723,22 @@ class Database: tourneyPlayersIds=[] try: cursor = self.get_cursor() - + for i in xrange(len(playersIds)): cursor.execute(self.sql.query['getTourneysPlayers'].replace('%s', self.sql.query['placeholder']) ,(dbTourneyId, playersIds[i])) result=cursor.fetchone() #print "tried SELECTing tourneys_players.id:",tmp - + try: len(result) # checking data logging.debug("TourneysPlayers found : checking data") - expectedValuesDecimal = { 1 : "payinAmounts", 2 : "finishPositions", 3 : "winnings", 4 : "countRebuys", + expectedValuesDecimal = { 1 : "payinAmounts", 2 : "finishPositions", 3 : "winnings", 4 : "countRebuys", 5 : "countAddOns", 6 : "countKO" } - + tourneyPlayersIds.append(result[0]); - + tourneysPlayersDataMatch = True for evD in expectedValuesDecimal : if ( Decimal(getattr( tourney, expectedValuesDecimal.get(evD))[tourney.players[i]] ) <> result[evD] ): @@ -2765,10 +2765,10 @@ class Database: None, None) ) tourneyPlayersIds.append(self.get_last_insert_id(cursor)) - + except: raise fpdb_simple.FpdbError( "tStoreTourneyPlayers error: " + str(sys.exc_value) ) - + return tourneyPlayersIds #end def tStoreTourneyPlayers @@ -2803,7 +2803,7 @@ class Database: # Class used to hold all the data needed to write a hand to the db -# mainParser() in fpdb_parse_logic.py creates one of these and then passes it to +# mainParser() in fpdb_parse_logic.py creates one of these and then passes it to # self.insert_queue_hands() class HandToWrite: @@ -2860,7 +2860,7 @@ class HandToWrite: , positions, antes, cardValues, cardSuits, boardValues, boardSuits , winnings, rakes, actionTypes, allIns, actionAmounts , actionNos, hudImportData, maxSeats, tableName, seatNos): - + try: self.config = config self.settings = settings @@ -2906,7 +2906,7 @@ class HandToWrite: def get_finished(self): return( self.finished ) # end def get_finished - + def get_siteHandNo(self): return( self.siteHandNo ) # end def get_siteHandNo @@ -2923,18 +2923,18 @@ if __name__=="__main__": # db_connection.recreate_tables() db_connection.dropAllIndexes() db_connection.createAllIndexes() - + h = db_connection.get_last_hand() print "last hand = ", h - + hero = db_connection.get_player_id(c, 'PokerStars', 'nutOmatic') if hero: print "nutOmatic is id_player = %d" % hero - + stat_dict = db_connection.get_stats_from_hand(h, "ring") for p in stat_dict.keys(): print p, " ", stat_dict[p] - + print "cards =", db_connection.get_cards(u'1') db_connection.close_connection diff --git a/pyfpdb/fpdb.py b/pyfpdb/fpdb.py index b960da05..d363b10f 100755 --- a/pyfpdb/fpdb.py +++ b/pyfpdb/fpdb.py @@ -557,7 +557,7 @@ class fpdb: self.warning_box("MySQL Server reports: Access denied. Are your permissions set correctly?") exit() except Exceptions.FpdbMySQLNoDatabase: - msg = "MySQL client reports: 2002 error. Unable to connect - Please check that the MySQL service has been started" + msg = "MySQL client reports: 2002 or 2003 error. Unable to connect - Please check that the MySQL service has been started" self.warning_box(msg) exit diff --git a/pyfpdb/fpdb_db.py b/pyfpdb/fpdb_db.py index 8a0ec54e..405a142c 100644 --- a/pyfpdb/fpdb_db.py +++ b/pyfpdb/fpdb_db.py @@ -106,7 +106,7 @@ class fpdb_db: except MySQLdb.Error, ex: if ex.args[0] == 1045: raise FpdbMySQLAccessDenied(ex.args[0], ex.args[1]) - elif ex.args[0] == 2002: + elif ex.args[0] == 2002 or ex.args[0] == 2003: # 2002 is no unix socket, 2003 is no tcp socket raise FpdbMySQLNoDatabase(ex.args[0], ex.args[1]) else: print "*** WARNING UNKNOWN MYSQL ERROR", ex From 395f19b5fb681b5f24dc7930fa929cc9b42de4be Mon Sep 17 00:00:00 2001 From: Worros Date: Wed, 2 Dec 2009 14:02:06 +0800 Subject: [PATCH 06/65] Add showdown/non-showdown winnings to Grapher --- pyfpdb/GuiGraphViewer.py | 23 ++++++++++++++++------- pyfpdb/SQL.py | 2 +- 2 files changed, 17 insertions(+), 8 deletions(-) diff --git a/pyfpdb/GuiGraphViewer.py b/pyfpdb/GuiGraphViewer.py index b81f2d5e..816c25fc 100644 --- a/pyfpdb/GuiGraphViewer.py +++ b/pyfpdb/GuiGraphViewer.py @@ -31,6 +31,7 @@ try: from matplotlib.figure import Figure from matplotlib.backends.backend_gtk import FigureCanvasGTK as FigureCanvas from matplotlib.backends.backend_gtkagg import NavigationToolbar2GTKAgg as NavigationToolbar + from matplotlib.font_manager import FontProperties from numpy import arange, cumsum from pylab import * except ImportError, inst: @@ -170,7 +171,7 @@ class GuiGraphViewer (threading.Thread): #Get graph data from DB starttime = time() - line = self.getRingProfitGraph(playerids, sitenos, limits) + (green, blue, red) = self.getRingProfitGraph(playerids, sitenos, limits) print "Graph generated in: %s" %(time() - starttime) self.ax.set_title("Profit graph for ring games") @@ -179,13 +180,13 @@ class GuiGraphViewer (threading.Thread): self.ax.set_xlabel("Hands", fontsize = 12) self.ax.set_ylabel("$", fontsize = 12) self.ax.grid(color='g', linestyle=':', linewidth=0.2) - if line == None or line == []: + if green == None or green == []: #TODO: Do something useful like alert user print "No hands returned by graph query" else: # text = "All Hands, " + sitename + str(name) + "\nProfit: $" + str(line[-1]) + "\nTotal Hands: " + str(len(line)) - text = "All Hands, " + "\nProfit: $" + str(line[-1]) + "\nTotal Hands: " + str(len(line)) + text = "All Hands, " + "\nProfit: $" + str(green[-1]) + "\nTotal Hands: " + str(len(green)) self.ax.annotate(text, xy=(10, -10), @@ -194,7 +195,11 @@ class GuiGraphViewer (threading.Thread): fontsize=10) #Draw plot - self.ax.plot(line,) + self.ax.plot(green, color='green', label='Hands: %d\nProfit: $%.2f' %(len(green), green[-1])) + self.ax.plot(blue, color='blue', label='Showdown: $%.2f' %(blue[-1])) + self.ax.plot(red, color='red', label='Non-showdown: $%.2f' %(red[-1])) + self.ax.legend(loc='best', fancybox=True, shadow=True, prop=FontProperties(size='smaller')) + self.graphBox.add(self.canvas) self.canvas.show() @@ -270,9 +275,13 @@ class GuiGraphViewer (threading.Thread): if winnings == (): return None - y = map(lambda x:float(x[1]), winnings) - line = cumsum(y) - return line/100 + green = map(lambda x:float(x[1]), winnings) + blue = map(lambda x: float(x[1]) if x[2] == True else 0.0, winnings) + red = map(lambda x: float(x[1]) if x[2] == False else 0.0, winnings) + greenline = cumsum(green) + blueline = cumsum(blue) + redline = cumsum(red) + return (greenline/100, blueline/100, redline/100) #end of def getRingProfitGraph def exportGraph (self, widget, data): diff --git a/pyfpdb/SQL.py b/pyfpdb/SQL.py index e38bc122..85b5fd80 100644 --- a/pyfpdb/SQL.py +++ b/pyfpdb/SQL.py @@ -2561,7 +2561,7 @@ class Sql: # self.query['playerStatsByPosition'] = """ """ self.query['getRingProfitAllHandsPlayerIdSite'] = """ - SELECT hp.handId, hp.totalProfit + SELECT hp.handId, hp.totalProfit, hp.sawShowdown FROM HandsPlayers hp INNER JOIN Players pl ON (pl.id = hp.playerId) INNER JOIN Hands h ON (h.id = hp.handId) From 8d95835afef2fa6a0583ab5dee017ab63d3c6454 Mon Sep 17 00:00:00 2001 From: Worros Date: Wed, 2 Dec 2009 14:07:06 +0800 Subject: [PATCH 07/65] Remove annotate from graph. Legend box is smarter and looks better imho --- pyfpdb/GuiGraphViewer.py | 14 ++++++-------- 1 file changed, 6 insertions(+), 8 deletions(-) diff --git a/pyfpdb/GuiGraphViewer.py b/pyfpdb/GuiGraphViewer.py index 816c25fc..76c80f2e 100644 --- a/pyfpdb/GuiGraphViewer.py +++ b/pyfpdb/GuiGraphViewer.py @@ -185,14 +185,12 @@ class GuiGraphViewer (threading.Thread): #TODO: Do something useful like alert user print "No hands returned by graph query" else: - # text = "All Hands, " + sitename + str(name) + "\nProfit: $" + str(line[-1]) + "\nTotal Hands: " + str(len(line)) - text = "All Hands, " + "\nProfit: $" + str(green[-1]) + "\nTotal Hands: " + str(len(green)) - - self.ax.annotate(text, - xy=(10, -10), - xycoords='axes points', - horizontalalignment='left', verticalalignment='top', - fontsize=10) + #text = "Profit: $%.2f\nTotal Hands: %d" %(green[-1], len(green)) + #self.ax.annotate(text, + # xy=(10, -10), + # xycoords='axes points', + # horizontalalignment='left', verticalalignment='top', + # fontsize=10) #Draw plot self.ax.plot(green, color='green', label='Hands: %d\nProfit: $%.2f' %(len(green), green[-1])) From a0a6207810d3f51364f1db57a61ab3bccb4fb484 Mon Sep 17 00:00:00 2001 From: Mika Bostrom Date: Wed, 2 Dec 2009 12:29:48 +0200 Subject: [PATCH 08/65] Fix profit graph query At least postgresql requires to have grouping by hp.sawShowdown as well --- pyfpdb/SQL.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pyfpdb/SQL.py b/pyfpdb/SQL.py index 85b5fd80..eb9296ef 100644 --- a/pyfpdb/SQL.py +++ b/pyfpdb/SQL.py @@ -2572,7 +2572,7 @@ class Sql: AND h.handStart < '' AND hp.tourneysPlayersId IS NULL - GROUP BY h.handStart, hp.handId, hp.totalProfit + GROUP BY h.handStart, hp.handId, hp.sawShowdown, hp.totalProfit ORDER BY h.handStart""" #################################### From 5e3c920e1628519001210a54ba62bad81103551c Mon Sep 17 00:00:00 2001 From: sqlcoder Date: Wed, 2 Dec 2009 15:17:31 +0000 Subject: [PATCH 09/65] add timing info to log --- pyfpdb/HUD_main.py | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/pyfpdb/HUD_main.py b/pyfpdb/HUD_main.py index dfe1c5fa..2bb3a995 100755 --- a/pyfpdb/HUD_main.py +++ b/pyfpdb/HUD_main.py @@ -63,6 +63,9 @@ elif os.name == 'nt': import Hud +log = Configuration.get_logger("logging.conf") + + class HUD_main(object): """A main() object to own both the read_stdin thread and the gui.""" # This class mainly provides state for controlling the multiple HUDs. @@ -192,6 +195,7 @@ class HUD_main(object): while 1: # wait for a new hand number on stdin new_hand_id = sys.stdin.readline() + t0 = time() new_hand_id = string.rstrip(new_hand_id) if new_hand_id == "": # blank line means quit self.destroy() @@ -206,6 +210,7 @@ class HUD_main(object): print "db error: skipping %s" % new_hand_id sys.stderr.write("Database error: could not find hand %s.\n" % new_hand_id) continue + t1 = time() if type == "tour": # hand is from a tournament temp_key = tour_number @@ -217,8 +222,10 @@ class HUD_main(object): # get stats using hud's specific params and get cards 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']) + t2 = time() 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], num_seats) + t3 = time() try: self.hud_dict[temp_key].stat_dict = stat_dict except KeyError: # HUD instance has been killed off, key is stale @@ -239,8 +246,10 @@ class HUD_main(object): else: # get stats using default params--also get cards self.db_connection.init_hud_stat_vars( self.hud_params['hud_days'], self.hud_params['h_hud_days'] ) + t4 = time() stat_dict = self.db_connection.get_stats_from_hand(new_hand_id, type, self.hud_params ,self.hero_ids[site_id], num_seats) + t5 = time() cards = self.db_connection.get_cards(new_hand_id) comm_cards = self.db_connection.get_common_cards(new_hand_id) if comm_cards != {}: # stud! @@ -264,6 +273,9 @@ class HUD_main(object): else: sys.stderr.write('Table "%s" no longer exists\n', table_name) + t6 = time() + log.info("HUD_main.read_stdin: hand read in %4.3f seconds (%4.3f,%4.3f,%4.3f,%4.3f,%4.3f,%4.3f,%4.3f)" + % (t6-t0,t1-t0,t2-t0,t3-t0,t4-t0,t5-t0,t6-t0)) self.db_connection.connection.rollback() if __name__== "__main__": From 76163733ee8b4d2af5360aee09a32b0bf36d4677 Mon Sep 17 00:00:00 2001 From: Worros Date: Thu, 3 Dec 2009 16:46:10 +0800 Subject: [PATCH 10/65] Repair recent damage to Options --- pyfpdb/Options.py | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/pyfpdb/Options.py b/pyfpdb/Options.py index 9859e7d2..ab226124 100644 --- a/pyfpdb/Options.py +++ b/pyfpdb/Options.py @@ -36,8 +36,11 @@ def fpdb_options(): action="store_true", help="Indicates program was restarted with a different path (only allowed once).") parser.add_option("-i", "--infile", - dest="config", default=None, + dest="infile", default="Slartibartfast", help="Input file") + parser.add_option("-k", "--konverter", + dest="hhc", default="PokerStarsToFpdb", + help="Module name for Hand History Converter") (options, argv) = parser.parse_args() return (options, argv) From 247af28f7ebb2b85b14752cd3c3038a7083dabbd Mon Sep 17 00:00:00 2001 From: Worros Date: Thu, 3 Dec 2009 17:26:40 +0800 Subject: [PATCH 11/65] Add a HH anonymiser Usage: python Anonymise.py -i regression-test-files/tour/Stars/Flop/NLHE-USD-MTT-5r-200710.txt At least works for Stars at the moment --- pyfpdb/Anonymise.py | 37 +++++++++++++++++++++++++++++++++++++ 1 file changed, 37 insertions(+) create mode 100644 pyfpdb/Anonymise.py diff --git a/pyfpdb/Anonymise.py b/pyfpdb/Anonymise.py new file mode 100644 index 00000000..32036b1e --- /dev/null +++ b/pyfpdb/Anonymise.py @@ -0,0 +1,37 @@ +import os +import re +import codecs +import Options +import HandHistoryConverter + +(options, argv) = Options.fpdb_options() + +filter = options.hhc + +filter_name = filter.replace("ToFpdb", "") + +mod = __import__(filter) +obj = getattr(mod, filter_name, None) + +hhc = obj(autostart=False) + +if os.path.exists(options.infile): + in_fh = codecs.open(options.infile, 'r', "utf8") + filecontents = in_fh.read() + in_fh.close() +else: + print "Could not find file %s" % options.infile + exit(1) + +m = hhc.re_PlayerInfo.finditer(filecontents) + +players = [] +for a in m: + players = players + [a.group('PNAME')] + +uniq = set(players) + +for i, name in enumerate(uniq, 1): + filecontents = filecontents.replace(name, 'Player%d' %i) + +print filecontents From b7d9a843bdf00bc236bcad22affa335ab13c5538 Mon Sep 17 00:00:00 2001 From: Worros Date: Thu, 3 Dec 2009 17:45:04 +0800 Subject: [PATCH 12/65] Add PLO test file for Betfair, update test to import it --- ...0.05-0.10-200909.All.in.river.splitpot.txt | 55 +++++++++++++++++++ pyfpdb/test_Betfair.py | 41 +++++++++----- 2 files changed, 82 insertions(+), 14 deletions(-) create mode 100644 pyfpdb/regression-test-files/cash/Betfair/Flop/PLO-6max-USD-0.05-0.10-200909.All.in.river.splitpot.txt diff --git a/pyfpdb/regression-test-files/cash/Betfair/Flop/PLO-6max-USD-0.05-0.10-200909.All.in.river.splitpot.txt b/pyfpdb/regression-test-files/cash/Betfair/Flop/PLO-6max-USD-0.05-0.10-200909.All.in.river.splitpot.txt new file mode 100644 index 00000000..f1fc48c0 --- /dev/null +++ b/pyfpdb/regression-test-files/cash/Betfair/Flop/PLO-6max-USD-0.05-0.10-200909.All.in.river.splitpot.txt @@ -0,0 +1,55 @@ +***** Betfair Poker Hand History for Game 100000000 ***** +PL $0.05/$0.10 Omaha - Sunday, October 18, 20:00:00 GMT 2009 +Table Death 1 6-max (Real Money) +Seat 2 is the button +Total number of active players : 6 +Seat 1: Player6 ( $1 ) +Seat 2: Player3 ( $9.38 ) +Seat 3: Player2 ( $2.82 ) +Seat 4: Player4 ( $4.13 ) +Seat 5: Player5 ( $28.77 ) +Seat 6: Player1 ( $6.46 ) +Player2 posts small blind [$0.05] +Player4 posts big blind [$0.10] +Player6 posts big blind [$0.10] +** Dealing down cards ** +Dealt to Player6 [ 7c, 6c, 5h, Jh ] +Player5 folds +Player1 calls [$0.10] +Player6 checks +Player3 calls [$0.10] +Player2 raises to [$0.30] +Player4 calls [$0.20] +Player1 calls [$0.20] +Player6 goes all-in +Player6 raises to [$1] +Player3 calls [$0.90] +Player2 calls [$0.70] +Player4 calls [$0.70] +Player1 calls [$0.70] +** Dealing Flop ** [ 4d, 5d, 6d ] +Player2 checks +Player4 checks +Player1 checks +Player3 checks +** Dealing Turn ** [ 3s ] +Player2 checks +Player4 bets [$0.10] +Player1 calls [$0.10] +Player3 folds +Player2 folds +** Dealing River ** [ 4c ] +Player4 goes all-in +Player4 bets [$3.03] +Player1 calls [$3.03] +** Showdown ** +Player6 shows [ 7c, 6c, 5h, Jh ] a straight, Seven to Three +Player4 shows [ 7d, 8c, 3d, 6h ] a straight flush, Seven to Three +Player1 shows [ 3h, 4h, Td, 4s ] four of a kind, Fours +** Hand Conclusion ** +Player4 wins $6.26 from side pot #1 with a straight flush, Seven to Three +Player4 wins $4.44 from main pot with a straight flush, Seven to Three +************ Game 100000000 ends ************ + + + diff --git a/pyfpdb/test_Betfair.py b/pyfpdb/test_Betfair.py index 50949e93..7c979882 100644 --- a/pyfpdb/test_Betfair.py +++ b/pyfpdb/test_Betfair.py @@ -1,21 +1,34 @@ # -*- coding: utf-8 -*- import BetfairToFpdb +from Hand import * import py +import Configuration +import Database +import SQL +import fpdb_import -def checkGameInfo(hhc, header, info): - assert hhc.determineGameType(header) == info +config = Configuration.Config(file = "HUD_config.test.xml") +db = Database.Database(config) +sql = SQL.Sql(db_server = 'sqlite') -def testGameInfo(): - hhc = BetfairToFpdb.Betfair(autostart=False) - pairs = ( - (u"""***** Betfair Poker Hand History for Game 472386869 ***** -NL $0.02/$0.04 Texas Hold'em - Sunday, January 25, 10:10:42 GMT 2009 -Table Rookie 191 6-max (Real Money) -Seat 1 is the button -Total number of active players : 6""", - {'type':'ring', 'base':"hold", 'category':'holdem', 'limitType':'nl', 'sb':'0.02', 'bb':'0.04', 'currency':'USD'}), - ) +settings = {} +settings.update(config.get_db_parameters()) +settings.update(config.get_tv_parameters()) +settings.update(config.get_import_parameters()) +settings.update(config.get_default_paths()) - for (header, info) in pairs: - yield checkGameInfo, hhc, header, info +def testFlopImport(): + db.recreate_tables() + importer = fpdb_import.Importer(False, settings, config) + importer.setDropIndexes("don't drop") + importer.setFailOnError(True) + importer.setThreads(-1) + importer.addBulkImportImportFileOrDir( + """regression-test-files/cash/Betfair/Flop/PLO-6max-USD-0.05-0.10-200909.All.in.river.splitpot.txt""", site="Betfair") + importer.setCallHud(False) + (stored, dups, partial, errs, ttime) = importer.runImport() + importer.clearFileList() + + # Should actually do some testing here + assert 1 == 1 From 2120257aeed648cc588cd2cd76e12837dc50c032 Mon Sep 17 00:00:00 2001 From: Eric Blade Date: Thu, 3 Dec 2009 07:21:24 -0500 Subject: [PATCH 13/65] whitespace.. sorry guys. --- ...0.05-0.10-200909.All.in.river.splitpot.txt | 108 +++++++++--------- 1 file changed, 54 insertions(+), 54 deletions(-) diff --git a/pyfpdb/regression-test-files/cash/Betfair/Flop/PLO-6max-USD-0.05-0.10-200909.All.in.river.splitpot.txt b/pyfpdb/regression-test-files/cash/Betfair/Flop/PLO-6max-USD-0.05-0.10-200909.All.in.river.splitpot.txt index f1fc48c0..c4685742 100644 --- a/pyfpdb/regression-test-files/cash/Betfair/Flop/PLO-6max-USD-0.05-0.10-200909.All.in.river.splitpot.txt +++ b/pyfpdb/regression-test-files/cash/Betfair/Flop/PLO-6max-USD-0.05-0.10-200909.All.in.river.splitpot.txt @@ -1,55 +1,55 @@ -***** Betfair Poker Hand History for Game 100000000 ***** -PL $0.05/$0.10 Omaha - Sunday, October 18, 20:00:00 GMT 2009 -Table Death 1 6-max (Real Money) -Seat 2 is the button -Total number of active players : 6 -Seat 1: Player6 ( $1 ) -Seat 2: Player3 ( $9.38 ) -Seat 3: Player2 ( $2.82 ) -Seat 4: Player4 ( $4.13 ) -Seat 5: Player5 ( $28.77 ) -Seat 6: Player1 ( $6.46 ) -Player2 posts small blind [$0.05] -Player4 posts big blind [$0.10] -Player6 posts big blind [$0.10] -** Dealing down cards ** -Dealt to Player6 [ 7c, 6c, 5h, Jh ] -Player5 folds -Player1 calls [$0.10] -Player6 checks -Player3 calls [$0.10] -Player2 raises to [$0.30] -Player4 calls [$0.20] -Player1 calls [$0.20] -Player6 goes all-in -Player6 raises to [$1] -Player3 calls [$0.90] -Player2 calls [$0.70] -Player4 calls [$0.70] -Player1 calls [$0.70] -** Dealing Flop ** [ 4d, 5d, 6d ] -Player2 checks -Player4 checks -Player1 checks -Player3 checks -** Dealing Turn ** [ 3s ] -Player2 checks -Player4 bets [$0.10] -Player1 calls [$0.10] -Player3 folds -Player2 folds -** Dealing River ** [ 4c ] -Player4 goes all-in -Player4 bets [$3.03] -Player1 calls [$3.03] -** Showdown ** -Player6 shows [ 7c, 6c, 5h, Jh ] a straight, Seven to Three -Player4 shows [ 7d, 8c, 3d, 6h ] a straight flush, Seven to Three -Player1 shows [ 3h, 4h, Td, 4s ] four of a kind, Fours -** Hand Conclusion ** -Player4 wins $6.26 from side pot #1 with a straight flush, Seven to Three -Player4 wins $4.44 from main pot with a straight flush, Seven to Three -************ Game 100000000 ends ************ - - +***** Betfair Poker Hand History for Game 100000000 ***** +PL $0.05/$0.10 Omaha - Sunday, October 18, 20:00:00 GMT 2009 +Table Death 1 6-max (Real Money) +Seat 2 is the button +Total number of active players : 6 +Seat 1: Player6 ( $1 ) +Seat 2: Player3 ( $9.38 ) +Seat 3: Player2 ( $2.82 ) +Seat 4: Player4 ( $4.13 ) +Seat 5: Player5 ( $28.77 ) +Seat 6: Player1 ( $6.46 ) +Player2 posts small blind [$0.05] +Player4 posts big blind [$0.10] +Player6 posts big blind [$0.10] +** Dealing down cards ** +Dealt to Player6 [ 7c, 6c, 5h, Jh ] +Player5 folds +Player1 calls [$0.10] +Player6 checks +Player3 calls [$0.10] +Player2 raises to [$0.30] +Player4 calls [$0.20] +Player1 calls [$0.20] +Player6 goes all-in +Player6 raises to [$1] +Player3 calls [$0.90] +Player2 calls [$0.70] +Player4 calls [$0.70] +Player1 calls [$0.70] +** Dealing Flop ** [ 4d, 5d, 6d ] +Player2 checks +Player4 checks +Player1 checks +Player3 checks +** Dealing Turn ** [ 3s ] +Player2 checks +Player4 bets [$0.10] +Player1 calls [$0.10] +Player3 folds +Player2 folds +** Dealing River ** [ 4c ] +Player4 goes all-in +Player4 bets [$3.03] +Player1 calls [$3.03] +** Showdown ** +Player6 shows [ 7c, 6c, 5h, Jh ] a straight, Seven to Three +Player4 shows [ 7d, 8c, 3d, 6h ] a straight flush, Seven to Three +Player1 shows [ 3h, 4h, Td, 4s ] four of a kind, Fours +** Hand Conclusion ** +Player4 wins $6.26 from side pot #1 with a straight flush, Seven to Three +Player4 wins $4.44 from main pot with a straight flush, Seven to Three +************ Game 100000000 ends ************ + + From 81adfff93b6b9831dd0a9f0bd24725435f7d1580 Mon Sep 17 00:00:00 2001 From: Eric Blade Date: Thu, 3 Dec 2009 07:22:33 -0500 Subject: [PATCH 14/65] Add some basic error handling at the very beginning of startup, to deal with missing imports and such, update about box --- pyfpdb/fpdb.py | 31 +++++++++++++++++++++---------- 1 file changed, 21 insertions(+), 10 deletions(-) diff --git a/pyfpdb/fpdb.py b/pyfpdb/fpdb.py index 47d3bc55..f6ad7e3f 100755 --- a/pyfpdb/fpdb.py +++ b/pyfpdb/fpdb.py @@ -37,14 +37,20 @@ if os.name == 'nt' and sys.version[0:3] not in ('2.5', '2.6') and '-r' not in sy os.execvpe('python.exe', ('python.exe', 'fpdb.py', '-r'), os.environ) # first arg is ignored (name of program being run) else: print "\npython 2.5 not found, please install python 2.5 or 2.6 for fpdb\n" - exit + raw_input("Press ENTER to continue.") + exit() else: pass #print "debug - not changing path" if os.name == 'nt': - import win32api - import win32con + try: + import win32api + import win32con + except ImportError: + print "We appear to be running in Windows, but the Windows Python Extensions are not loading. Please install the PYWIN32 package from http://sourceforge.net/projects/pywin32/" + raw_input("Press ENTER to continue.") + exit() print "Python " + sys.version[0:3] + '...\n' @@ -62,9 +68,14 @@ if not options.errorsToConsole: import logging -import pygtk -pygtk.require('2.0') -import gtk +try: + import pygtk + pygtk.require('2.0') + import gtk +except: + print "Unable to load PYGTK modules required for GUI. Please install PyCairo, PyGObject, and PyGTK from www.pygtk.org." + raw_input("Press ENTER to continue.") + exit() import interlocks @@ -196,14 +207,14 @@ class fpdb: def dia_about(self, widget, data=None): #self.warning_box("About FPDB:\n\nFPDB was originally created by a guy named Steffen, sometime in 2008, \nand is mostly worked on these days by people named Eratosthenes, s0rrow, _mt, EricBlade, sqlcoder, and other strange people.\n\n", "ABOUT FPDB") dia = gtk.AboutDialog() - dia.set_name("FPDB") + dia.set_name("Free Poker Database (FPDB)") dia.set_version(VERSION) - dia.set_copyright("2008-2009, Steffen, Eratosthenes, s0rrow, EricBlade, _mt, sqlcoder, and others") + dia.set_copyright("2008-2010, Steffen, Eratosthenes, s0rrow, EricBlade, _mt, sqlcoder, Bostik, and others") dia.set_comments("GTK AboutDialog comments here") dia.set_license("GPL v3") dia.set_website("http://fpdb.sourceforge.net/") - dia.set_authors("Steffen, Eratosthenes, s0rrow, EricBlade, _mt, and others") - dia.set_program_name("FPDB") + dia.set_authors("Steffen, Eratosthenes, s0rrow, EricBlade, _mt, sqlcoder, Bostik, and others") + dia.set_program_name("Free Poker Database (FPDB)") dia.run() dia.destroy() From f05b521d6f8d5fb8803382f5a8fbdae9f94db79a Mon Sep 17 00:00:00 2001 From: Eric Blade Date: Thu, 3 Dec 2009 07:24:12 -0500 Subject: [PATCH 15/65] comment out some prints, apparently mysqlcoder and my editors do not agree well with each other on spacing. --- pyfpdb/Hud.py | 38 +++++++++++++++++++------------------- 1 file changed, 19 insertions(+), 19 deletions(-) diff --git a/pyfpdb/Hud.py b/pyfpdb/Hud.py index c9420a8a..b61c17aa 100644 --- a/pyfpdb/Hud.py +++ b/pyfpdb/Hud.py @@ -173,26 +173,26 @@ class Hud: item = gtk.CheckMenuItem(' All Levels') self.aggMenu.append(item) item.connect("activate", self.set_aggregation, ('P',10000)) - setattr(self, 'h_aggBBmultItem10000', item) - # + setattr(self, 'h_aggBBmultItem10000', item) + # item = gtk.MenuItem('For #Seats:') self.aggMenu.append(item) - # + # item = gtk.CheckMenuItem(' Any Number') self.aggMenu.append(item) item.connect("activate", self.set_seats_style, ('P','A')) setattr(self, 'h_seatsStyleOptionA', item) - # + # item = gtk.CheckMenuItem(' Custom') self.aggMenu.append(item) item.connect("activate", self.set_seats_style, ('P','C')) - setattr(self, 'h_seatsStyleOptionC', item) - # + setattr(self, 'h_seatsStyleOptionC', item) + # item = gtk.CheckMenuItem(' Exact') self.aggMenu.append(item) item.connect("activate", self.set_seats_style, ('P','E')) - setattr(self, 'h_seatsStyleOptionE', item) - # + setattr(self, 'h_seatsStyleOptionE', item) + # item = gtk.MenuItem('Since:') self.aggMenu.append(item) # @@ -242,26 +242,26 @@ class Hud: item = gtk.CheckMenuItem(' All Levels') self.aggMenu.append(item) item.connect("activate", self.set_aggregation, ('O',10000)) - setattr(self, 'aggBBmultItem10000', item) - # + setattr(self, 'aggBBmultItem10000', item) + # item = gtk.MenuItem('For #Seats:') self.aggMenu.append(item) - # + # item = gtk.CheckMenuItem(' Any Number') self.aggMenu.append(item) item.connect("activate", self.set_seats_style, ('O','A')) setattr(self, 'seatsStyleOptionA', item) - # + # item = gtk.CheckMenuItem(' Custom') self.aggMenu.append(item) item.connect("activate", self.set_seats_style, ('O','C')) - setattr(self, 'seatsStyleOptionC', item) - # + setattr(self, 'seatsStyleOptionC', item) + # item = gtk.CheckMenuItem(' Exact') self.aggMenu.append(item) item.connect("activate", self.set_seats_style, ('O','E')) - setattr(self, 'seatsStyleOptionE', item) - # + setattr(self, 'seatsStyleOptionE', item) + # item = gtk.MenuItem('Since:') self.aggMenu.append(item) # @@ -358,7 +358,7 @@ class Hud: def change_max_seats(self, widget): if self.max != widget.ms: - print 'change_max_seats', widget.ms + #print 'change_max_seats', widget.ms self.max = widget.ms try: self.kill() @@ -402,7 +402,7 @@ class Hud: else: param = 'seats_style' prefix = '' - + if style == 'A' and getattr(self, prefix+'seatsStyleOptionA').get_active(): self.hud_params[param] = 'A' getattr(self, prefix+'seatsStyleOptionC').set_active(False) @@ -678,7 +678,7 @@ class Stat_Window: return True def kill_popup(self, popup): - print "remove popup", popup + #print "remove popup", popup self.popups.remove(popup) popup.window.destroy() From 3248cb60f21a340ff35414bae9eee6129ae47501 Mon Sep 17 00:00:00 2001 From: Eric Blade Date: Thu, 3 Dec 2009 12:35:00 -0500 Subject: [PATCH 16/65] added checks to see if player has folded when processing wether they've seen streets/showdown (corrects problem of player calling someone's short all in and it not counting as having seen showdown) --- pyfpdb/fpdb_simple.py | 378 +++++++++++++++++++++--------------------- 1 file changed, 190 insertions(+), 188 deletions(-) diff --git a/pyfpdb/fpdb_simple.py b/pyfpdb/fpdb_simple.py index aaf74772..85e60eeb 100644 --- a/pyfpdb/fpdb_simple.py +++ b/pyfpdb/fpdb_simple.py @@ -1,5 +1,5 @@ #!/usr/bin/python - + #Copyright 2008 Steffen Jobbagy-Felso #This program is free software: you can redistribute it and/or modify #it under the terms of the GNU Affero General Public License as published by @@ -14,13 +14,13 @@ #along with this program. If not, see . #In the "official" distribution you can find the license in #agpl-3.0.txt in the docs folder of the package. - + #This file contains simple functions for fpdb #Aiming to eventually remove this module, functions will move to, eg: #fpdb_db db create/re-create/management/etc #Hands or related files for saving hands to db, etc - + import datetime import time import re @@ -29,7 +29,7 @@ from Exceptions import * import locale import Card - + PS = 1 FTP = 2 @@ -52,7 +52,7 @@ def checkPositions(positions): raise FpdbError("invalid position '"+p+"' found in checkPositions") ### RHH modified to allow for "position 9" here (pos==9 is when you're a dead hand before the BB ### eric - position 8 could be valid - if only one blind is posted, but there's still 10 people, ie a sitout is present, and the small is dead... - + def classifyLines(hand, category, lineTypes, lineStreets): """ makes a list of classifications for each line for further processing manipulates passed arrays """ @@ -69,7 +69,7 @@ def classifyLines(hand, category, lineTypes, lineStreets): elif i == 0: lineTypes.append("header") elif line.startswith("Table '"): - lineTypes.append("table") + lineTypes.append("table") elif line.startswith("Seat ") and ( ("in chips" in line) or "($" in line): lineTypes.append("name") elif isActionLine(line): @@ -84,7 +84,7 @@ def classifyLines(hand, category, lineTypes, lineStreets): elif line.startswith("*** TURN *** ["): lineTypes.append("cards") currentStreet="turn" - elif line.startswith("*** RIVER *** ["): + elif line.startswith("*** RIVER *** ["): lineTypes.append("cards") currentStreet="river" elif line.startswith("*** 3"): @@ -115,7 +115,7 @@ def classifyLines(hand, category, lineTypes, lineStreets): else: raise FpdbError("unrecognised linetype in:"+hand[i]) lineStreets.append(currentStreet) - + def convert3B4B(category, limit_type, actionTypes, actionAmounts): """calculates the actual bet amounts in the given amount array and changes it accordingly.""" for i in xrange(len(actionTypes)): @@ -130,7 +130,7 @@ def convert3B4B(category, limit_type, actionTypes, actionAmounts): amount2 = actionAmounts[bets[betNo][0]][bets[betNo][1]][bets[betNo][2]] amount1 = actionAmounts[bets[betNo-1][0]][bets[betNo-1][1]][bets[betNo-1][2]] actionAmounts[bets[betNo][0]][bets[betNo][1]][bets[betNo][2]] = amount2 - amount1 - + def convertBlindBet(actionTypes, actionAmounts): """ Corrects the bet amount if the player had to pay blinds """ i = 0#setting street to pre-flop @@ -140,14 +140,14 @@ def convertBlindBet(actionTypes, actionAmounts): for k in xrange(len(actionTypes[i][j])): if actionTypes[i][j][k] == "blind": blinds.append((i,j,k)) - + if blinds and actionTypes[i][j][k] == "bet": bets.append((i,j,k)) if len(bets) == 1: blind_amount=actionAmounts[blinds[0][0]][blinds[0][1]][blinds[0][2]] bet_amount=actionAmounts[bets[0][0]][bets[0][1]][bets[0][2]] actionAmounts[bets[0][0]][bets[0][1]][bets[0][2]] = bet_amount - blind_amount - + #converts the strings in the given array to ints (changes the passed array, no returning). see table design for conversion details #todo: make this use convertCardValuesBoard def convertCardValues(arr): @@ -156,14 +156,14 @@ def convertCardValues(arr): # a 0-card is one in a stud game that we did not see or was not shown card_map = { 0: 0, "2": 2, "3" : 3, "4" : 4, "5" : 5, "6" : 6, "7" : 7, "8" : 8, "9" : 9, "T" : 10, "J" : 11, "Q" : 12, "K" : 13, "A" : 14} - + def convertCardValuesBoard(arr): """ converts the strings in the given array to ints (changes the passed array, no returning). see table design for conversion details """ for i in xrange(len(arr)): arr[i] = card_map[arr[i]] - + def createArrays(category, seats, card_values, card_suits, antes, winnings, rakes, action_types, allIns, action_amounts, actionNos, actionTypeByNo): @@ -174,10 +174,10 @@ def createArrays(category, seats, card_values, card_suits, antes, winnings, antes.append(0) winnings.append(0) rakes.append(0) - + streetCount = 4 if (category == "holdem" or category == "omahahi" or category == "omahahilo") else 5 - + for i in xrange(streetCount): #build the first dimension array, for streets action_types.append([]) allIns.append([]) @@ -199,13 +199,13 @@ def createArrays(category, seats, card_values, card_suits, antes, winnings, # else: # raise FpdbError("invalid category") #end def createArrays - + def fill_board_cards(board_values, board_suits): """ fill up the two board card arrays """ while len(board_values) < 5: board_values.append(0) board_suits.append("x") - + def fillCardArrays(player_count, base, category, card_values, card_suits): """fills up the two card arrays""" if category == "holdem": @@ -216,13 +216,13 @@ def fillCardArrays(player_count, base, category, card_values, card_suits): cardCount = 7 else: raise FpdbError("invalid category:", category) - + for i in xrange(player_count): while len(card_values[i]) < cardCount: card_values[i].append(0) card_suits[i].append("x") #end def fillCardArrays - + #filters out a player that folded before paying ante or blinds. This should be called #before calling the actual hand parser. manipulates hand, no return. def filterAnteBlindFold(hand): @@ -233,7 +233,7 @@ def filterAnteBlindFold(hand): for i, line in enumerate(hand): if line.startswith("*** 3") or line.startswith("*** HOLE"): pre3rd = hand[0:i] - + foldeeName = None for line in pre3rd: if line.endswith("folds") or line.endswith("is sitting out") or line.endswith(" stands up"): #found ante fold or timeout @@ -249,24 +249,24 @@ def filterAnteBlindFold(hand): pos1 = line.find(": ") + 2 pos2 = line.find(" (") foldeeName = line[pos1:pos2] - + if foldeeName is not None: #print "filterAnteBlindFold, foldeeName:",foldeeName for i, line in enumerate(hand): if foldeeName in line: hand[i] = None - + return [line for line in hand if line] def stripEOLspaces(str): return str.rstrip() - + def filterCrap(hand, isTourney): """ removes useless lines as well as trailing spaces """ #remove trailing spaces at end of line hand = [line.rstrip() for line in hand] - + #general variable position word filter/string filter for i in xrange(len(hand)): if hand[i].startswith("Board ["): @@ -347,10 +347,10 @@ def filterCrap(hand, isTourney): hand[i] = False # python docs say this is identical to filter(None, list) # which removes all false items from the passed list (hand) - hand = [line for line in hand if line] - + hand = [line for line in hand if line] + return hand - + def float2int(string): """ takes a poker float (including , for thousand seperator) and converts it to an int """ @@ -358,11 +358,11 @@ def float2int(string): pos = string.find(",") if pos != -1: #remove , the thousand seperator string = "%s%s" % (string[0:pos], string[pos+1:]) - + pos = string.find(".") if pos != -1: #remove decimal point string = "%s%s" % (string[0:pos], string[pos+1:]) - + result = int(string) if pos == -1: #no decimal point - was in full dollars - need to multiply with 100 result *= 100 @@ -372,7 +372,7 @@ ActionLines = ( "calls $", ": calls ", "brings in for", "completes it to", "posts small blind", "posts the small blind", "posts big blind", "posts the big blind", "posts small & big blinds", "posts $", "posts a dead", "bets $", ": bets ", " raises") - + def isActionLine(line): if line.endswith("folds"): return True @@ -383,44 +383,44 @@ def isActionLine(line): # searches for each member of ActionLines being in line, returns true # on first match .. neat func - return any(x for x in ActionLines if x in line) - + return any(x for x in ActionLines if x in line) + def isAlreadyInDB(db, gametypeID, siteHandNo): c = db.get_cursor() c.execute(db.sql.query['isAlreadyInDB'], (gametypeID, siteHandNo)) result = c.fetchall() if len(result) >= 1: raise DuplicateError ("dupl") - + def isRebuyOrAddon(topline): """isRebuyOrAddon not implemented yet""" return False - + #returns whether the passed topline indicates a tournament or not def isTourney(topline): return "Tournament" in topline - + WinLines = ( "wins the pot", "ties for the ", "wins side pot", "wins the low main pot", "wins the high main pot", "wins the low", "wins the high pot", "wins the high side pot", "wins the main pot", "wins the side pot", "collected" ) def isWinLine(line): """ returns boolean whether the passed line is a win line """ - return any(x for x in WinLines if x in line) - + return any(x for x in WinLines if x in line) + #returns the amount of cash/chips put into the put in the given action line def parseActionAmount(line, atype, isTourney): #if (line.endswith(" and is all-in")): # line=line[:-14] #elif (line.endswith(", and is all in")): # line=line[:-15] - - #ideally we should recognise this as an all-in if category is capXl + + #ideally we should recognise this as an all-in if category is capXl if line.endswith(", and is capped"): line=line[:-15] if line.endswith(" and is capped"): line=line[:-14] - + if atype == "fold" or atype == "check": amount = 0 elif atype == "unbet": @@ -443,12 +443,12 @@ def parseActionAmount(line, atype, isTourney): #print "pos:",pos #print "pos of 20:", line.find("20") amount = int(line[pos:]) - + if atype == "unbet": amount *= -1 return amount #end def parseActionAmount - + #doesnt return anything, simply changes the passed arrays action_types and # action_amounts. For stud this expects numeric streets (3-7), for # holdem/omaha it expects predeal, preflop, flop, turn or river @@ -461,25 +461,25 @@ def parseActionLine(base, isTourney, line, street, playerIDs, names, action_type street = 2 elif street == "river": street = 3 - + nextActionNo = 0 for player in xrange(len(actionNos[street])): for count in xrange(len(actionNos[street][player])): if actionNos[street][player][count]>=nextActionNo: nextActionNo=actionNos[street][player][count]+1 - + (line, allIn) = goesAllInOnThisLine(line) atype = parseActionType(line) playerno = recognisePlayerNo(line, names, atype) amount = parseActionAmount(line, atype, isTourney) - + action_types[street][playerno].append(atype) allIns[street][playerno].append(allIn) action_amounts[street][playerno].append(amount) actionNos[street][playerno].append(nextActionNo) tmp=(playerIDs[playerno], atype) actionTypeByNo[street].append(tmp) - + def goesAllInOnThisLine(line): """returns whether the player went all-in on this line and removes the all-in text from the line.""" isAllIn = False @@ -490,20 +490,20 @@ def goesAllInOnThisLine(line): line = line[:-15] isAllIn = True return (line, isAllIn) - + #returns the action type code (see table design) of the given action line -ActionTypes = { 'brings in for' :"blind", +ActionTypes = { 'brings in for' :"blind", ' posts $' :"blind", - ' posts a dead ' :"blind", - ' posts the small blind of $' :"blind", + ' posts a dead ' :"blind", + ' posts the small blind of $' :"blind", ': posts big blind ' :"blind", - ': posts small blind ' :"blind", - ' posts the big blind of $' :"blind", + ': posts small blind ' :"blind", + ' posts the big blind of $' :"blind", ': posts small & big blinds $' :"blind", ': posts small blind $' :"blind", - 'calls' :"call", - 'completes it to' :"bet", - ' bets' :"bet", + 'calls' :"call", + 'completes it to' :"bet", + ' bets' :"bet", ' raises' :"bet" } def parseActionType(line): @@ -516,9 +516,9 @@ def parseActionType(line): else: for x in ActionTypes: if x in line: - return ActionTypes[x] + return ActionTypes[x] raise FpdbError ("failed to recognise actiontype in parseActionLine in: "+line) - + #parses the ante out of the given line and checks which player paid it, updates antes accordingly. def parseAnteLine(line, isTourney, names, antes): for i, name in enumerate(names): @@ -534,19 +534,19 @@ def parseAnteLine(line, isTourney, names, antes): pos1 = line.rfind("ante") + 5 pos2 = line.find(" ", pos1) antes[i] += int(line[pos1:pos2]) - + #returns the buyin of a tourney in cents def parseBuyin(topline): pos1 = topline.find("$")+1 pos2 = topline.find("+") return float2int(topline[pos1:pos2]) - + #parses a card line and changes the passed arrays accordingly #todo: reorganise this messy method def parseCardLine(category, street, line, names, cardValues, cardSuits, boardValues, boardSuits): if line.startswith("Dealt to") or " shows [" in line or "mucked [" in line: playerNo = recognisePlayerNo(line, names, "card") #anything but unbet will be ok for that string - + pos = line.rfind("[")+1 if category == "holdem": for i in (pos, pos+3): @@ -554,7 +554,7 @@ def parseCardLine(category, street, line, names, cardValues, cardSuits, boardVal cardSuits[playerNo].append(line[i+1:i+2]) if len(cardValues[playerNo]) != 2: if (cardValues[playerNo][0] == cardValues[playerNo][2] and - cardSuits[playerNo][1] == cardSuits[playerNo][3]): + cardSuits[playerNo][1] == cardSuits[playerNo][3]): cardValues[playerNo]=cardValues[playerNo][0:2] cardSuits[playerNo]=cardSuits[playerNo][0:2] else: @@ -617,7 +617,7 @@ def parseCardLine(category, street, line, names, cardValues, cardSuits, boardVal #print boardValues else: raise FpdbError ("unrecognised line:"+line) - + def parseCashesAndSeatNos(lines): """parses the startCashes and seatNos of each player out of the given lines and returns them as a dictionary of two arrays""" cashes = [] @@ -625,21 +625,21 @@ def parseCashesAndSeatNos(lines): for i in xrange (len(lines)): pos2=lines[i].find(":") seatNos.append(int(lines[i][5:pos2])) - + pos1=lines[i].rfind("($")+2 if pos1==1: #for tourneys - it's 1 instead of -1 due to adding 2 above pos1=lines[i].rfind("(")+1 pos2=lines[i].find(" in chips") cashes.append(float2int(lines[i][pos1:pos2])) return {'startCashes':cashes, 'seatNos':seatNos} - + #returns the buyin of a tourney in cents def parseFee(topline): pos1=topline.find("$")+1 pos1=topline.find("$",pos1)+1 pos2=topline.find(" ", pos1) return float2int(topline[pos1:pos2]) - + #returns a datetime object with the starttime indicated in the given topline def parseHandStartTime(topline): #convert x:13:35 to 0x:13:35 @@ -650,7 +650,7 @@ def parseHandStartTime(topline): topline = "%s0%s" % (topline[0:pos+1], topline[pos+1:]) break counter += 1 - + isUTC=False if topline.find("UTC")!=-1: pos1 = topline.find("-")+2 @@ -669,12 +669,12 @@ def parseHandStartTime(topline): rexx = '(?P[0-9]{4})\/(?P[0-9]{2})\/(?P[0-9]{2})[\- ]+(?P
[0-9]+):(?P[0-9]+):(?P[0-9]+)' m = re.search(rexx,tmp) result = datetime.datetime(int(m.group('YEAR')), int(m.group('MON')), int(m.group('DAY')), int(m.group('HR')), int(m.group('MIN')), int(m.group('SEC'))) - + if not isUTC: #these use US ET result += datetime.timedelta(hours=5) - + return result - + #parses the names out of the given lines and returns them as an array def findName(line): pos1 = line.find(":") + 2 @@ -683,11 +683,11 @@ def findName(line): def parseNames(lines): return [findName(line) for line in lines] - + def parsePositions(hand, names): positions = [-1 for i in names] sb, bb = -1, -1 - + for line in hand: if sb == -1 and "small blind" in line and "dead small blind" not in line: sb = line @@ -703,7 +703,7 @@ def parsePositions(hand, names): sbExists = False if bb != -1: bb = recognisePlayerNo(bb, names, "bet") - + # print "sb = ", sb, "bb = ", bb if bb == sb: # if big and small are same, then don't duplicate the small sbExists = False @@ -716,7 +716,7 @@ def parsePositions(hand, names): #fill up rest of array arraypos = sb - 1 if sbExists else bb - 1 - + distFromBtn=0 while arraypos >= 0 and arraypos != bb: #print "parsePositions first while, arraypos:",arraypos,"positions:",positions @@ -732,7 +732,7 @@ def parsePositions(hand, names): i -= 1 ### RHH - Changed to set the null seats before BB to "9" i = sb - 1 if sbExists else bb - 1 - + while positions[i] < 0: positions[i]=9 i-=1 @@ -750,19 +750,19 @@ def parsePositions(hand, names): raise FpdbError ("failed to read positions") # print str(positions), "\n" return positions - + #simply parses the rake amount and returns it as an int def parseRake(line): pos = line.find("Rake")+6 rake = float2int(line[pos:]) return rake - + def parseSiteHandNo(topline): """returns the hand no assigned by the poker site""" pos1 = topline.find("#")+1 pos2 = topline.find(":") return topline[pos1:pos2] - + def parseTableLine(base, line): """returns a dictionary with maxSeats and tableName""" pos1=line.find('\'')+1 @@ -773,14 +773,14 @@ def parseTableLine(base, line): #print "seats:",line[pos3:pos4] return {'maxSeats':int(line[pos3:pos4]), 'tableName':line[pos1:pos2]} #end def parseTableLine - + #returns the hand no assigned by the poker site def parseTourneyNo(topline): pos1 = topline.find("Tournament #")+12 pos2 = topline.find(",", pos1) #print "parseTourneyNo pos1:",pos1," pos2:",pos2, " result:",topline[pos1:pos2] return topline[pos1:pos2] - + #parses a win/collect line. manipulates the passed array winnings, no explicit return def parseWinLine(line, names, winnings, isTourney): #print "parseWinLine: line:",line @@ -795,7 +795,7 @@ def parseWinLine(line, names, winnings, isTourney): pos1 = line.rfind("$") + 1 pos2 = line.find(" ", pos1) winnings[i] += float2int(line[pos1:pos2]) - + #returns the category (as per database) string for the given line def recogniseCategory(line): if "Razz" in line: @@ -814,12 +814,12 @@ def recogniseCategory(line): return "studhilo" else: raise FpdbError("failed to recognise category, line:"+line) - + #returns the int for the gametype_id for the given line def recogniseGametypeID(backend, db, cursor, topline, smallBlindLine, site_id, category, isTourney):#todo: this method is messy #if (topline.find("HORSE")!=-1): # raise FpdbError("recogniseGametypeID: HORSE is not yet supported.") - + #note: the below variable names small_bet and big_bet are misleading, in NL/PL they mean small/big blind if isTourney: type = "tour" @@ -835,27 +835,27 @@ def recogniseGametypeID(backend, db, cursor, topline, smallBlindLine, site_id, c pos1 = topline.find("$")+1 pos2 = topline.find("/$") small_bet = float2int(topline[pos1:pos2]) - + pos1 = pos2+2 if isTourney: pos1 -= 1 pos2 = topline.find(")") - + if pos2 <= pos1: pos2 = topline.find(")", pos1) - + if isTourney: big_bet = int(topline[pos1:pos2]) else: big_bet = float2int(topline[pos1:pos2]) - + if 'No Limit' in topline: limit_type = "nl" if 'Cap No' not in topline else "cn" elif 'Pot Limit' in topline: limit_type = "pl" if 'Cap Pot' not in topline else "cp" else: limit_type = "fl" - + #print "recogniseGametypeID small_bet/blind:",small_bet,"big bet/blind:", big_bet,"limit type:",limit_type if limit_type == "fl": cursor.execute(db.sql.query['getGametypeFL'], (site_id, type, category, @@ -870,7 +870,7 @@ def recogniseGametypeID(backend, db, cursor, topline, smallBlindLine, site_id, c #ret=result[0] #print "recgt1 ret=",ret #print "tried SELECTing gametypes.id, result:",result - + try: len(result) except TypeError: @@ -878,14 +878,14 @@ def recogniseGametypeID(backend, db, cursor, topline, smallBlindLine, site_id, c base="hold" else: base="stud" - + if category=="holdem" or category=="omahahi" or category=="studhi": hiLo='h' elif category=="razz": hiLo='l' else: hiLo='s' - + if (limit_type=="fl"): big_blind=small_bet if base=="hold": @@ -901,17 +901,17 @@ def recogniseGametypeID(backend, db, cursor, topline, smallBlindLine, site_id, c small_blind=0 result = db.insertGameTypes( (site_id, type, base, category, limit_type, hiLo ,small_blind, big_blind, small_bet, big_bet) ) - #cursor.execute ("SELECT id FROM Gametypes WHERE siteId=%s AND type=%s AND category=%s + #cursor.execute ("SELECT id FROM Gametypes WHERE siteId=%s AND type=%s AND category=%s #AND limitType=%s AND smallBet=%s AND bigBet=%s", (site_id, type, category, limit_type, small_bet, big_bet)) else: result = db.insertGameTypes( (site_id, type, base, category, limit_type, hiLo ,small_bet, big_bet, 0, 0) )#remember, for these bet means blind #cursor.execute ("SELECT id FROM Gametypes WHERE siteId=%s AND type=%s AND category=%s #AND limitType=%s AND smallBlind=%s AND bigBlind=%s", (site_id, type, category, limit_type, small_bet, big_bet)) - + return result[0] #end def recogniseGametypeID - + def recogniseTourneyTypeId(db, siteId, tourneySiteId, buyin, fee, knockout, rebuyOrAddon): ret = -1 cursor = db.get_cursor() @@ -920,32 +920,32 @@ def recogniseTourneyTypeId(db, siteId, tourneySiteId, buyin, fee, knockout, rebu #TODO: When the summary file will be dumped to BD, if the tourney is already in, Buy-In/Fee may need an update (e.g. creation of a new type and link to the Tourney) cursor.execute (db.sql.query['getTourneyTypeIdByTourneyNo'].replace('%s', db.sql.query['placeholder']), (tourneySiteId, siteId)) result = cursor.fetchone() - + try: len(result) ret = result[0] except: - cursor.execute( """SELECT id FROM TourneyTypes - WHERE siteId=%s AND buyin=%s AND fee=%s + cursor.execute( """SELECT id FROM TourneyTypes + WHERE siteId=%s AND buyin=%s AND fee=%s AND knockout=%s AND rebuyOrAddon=%s""".replace('%s', db.sql.query['placeholder']) , (siteId, buyin, fee, knockout, rebuyOrAddon) ) result = cursor.fetchone() #print "tried selecting tourneytypes.id, result:", result - + try: len(result) ret = result[0] except TypeError:#this means we need to create a new entry #print "insert new tourneytype record ..." try: - cursor.execute( """INSERT INTO TourneyTypes (siteId, buyin, fee, knockout, rebuyOrAddon) + cursor.execute( """INSERT INTO TourneyTypes (siteId, buyin, fee, knockout, rebuyOrAddon) VALUES (%s, %s, %s, %s, %s)""".replace('%s', db.sql.query['placeholder']) , (siteId, buyin, fee, knockout, rebuyOrAddon) ) ret = db.get_last_insert_id(cursor) except: #print "maybe tourneytype was created since select, try selecting again ..." - cursor.execute( """SELECT id FROM TourneyTypes - WHERE siteId=%s AND buyin=%s AND fee=%s + cursor.execute( """SELECT id FROM TourneyTypes + WHERE siteId=%s AND buyin=%s AND fee=%s AND knockout=%s AND rebuyOrAddon=%s""".replace('%s', db.sql.query['placeholder']) , (siteId, buyin, fee, knockout, rebuyOrAddon) ) result = cursor.fetchone() @@ -956,12 +956,12 @@ def recogniseTourneyTypeId(db, siteId, tourneySiteId, buyin, fee, knockout, rebu print "Failed to find or insert TourneyTypes record" ret = -1 # failed to find or insert record #print "tried selecting tourneytypes.id again, result:", result - + #print "recogniseTourneyTypeId: returning", ret return ret #end def recogniseTourneyTypeId - - + + #recognises the name in the given line and returns its array position in the given array def recognisePlayerNo(line, names, atype): #print "recogniseplayerno, names:",names @@ -981,7 +981,7 @@ def recognisePlayerNo(line, names, atype): tmp=line[9:] else: tmp=line[8:] - + if (tmp.startswith(encodedName)): return (i) else: @@ -990,8 +990,8 @@ def recognisePlayerNo(line, names, atype): #if we're here we mustve failed raise FpdbError ("failed to recognise player in: "+line+" atype:"+atype) #end def recognisePlayerNo - - + + #removes trailing \n from the given array def removeTrailingEOL(arr): for i in xrange(len(arr)): @@ -1001,7 +1001,7 @@ def removeTrailingEOL(arr): #print "arr[i] after removetrailingEOL:", arr[i] return arr #end def removeTrailingEOL - + #splits the rake according to the proportion of pot won. manipulates the second passed array. def splitRake(winnings, rakes, totalRake): winnercnt=0 @@ -1020,7 +1020,7 @@ def splitRake(winnings, rakes, totalRake): winPortion=winnings[i]/totalWin rakes[i]=totalRake*winPortion #end def splitRake - + def generateHudCacheData(player_ids, base, category, action_types, allIns, actionTypeByNo ,winnings, totalWinnings, positions, actionTypes, actionAmounts, antes): """calculates data for the HUD during import. IMPORTANT: if you change this method make @@ -1050,12 +1050,12 @@ sure to also change the following storage method and table_viewer.prepare_data i foldToOtherRaisedStreet3=[] foldToOtherRaisedStreet4=[] wonWhenSeenStreet1=[] - + wonAtSD=[] stealAttemptChance=[] stealAttempted=[] hudDataPositions=[] - + street0Calls=[] street1Calls=[] street2Calls=[] @@ -1071,7 +1071,7 @@ sure to also change the following storage method and table_viewer.prepare_data i #street2Raises=[] #street3Raises=[] #street4Raises=[] - + # Summary figures for hand table: result={} result['playersVpi']=0 @@ -1090,13 +1090,13 @@ sure to also change the following storage method and table_viewer.prepare_data i result['street3Pot']=0 result['street4Pot']=0 result['showdownPot']=0 - + firstPfRaiseByNo=-1 firstPfRaiserId=-1 firstPfRaiserNo=-1 firstPfCallByNo=-1 firstPfCallerId=-1 - + for i, action in enumerate(actionTypeByNo[0]): if action[1] == "bet": firstPfRaiseByNo = i @@ -1116,7 +1116,7 @@ sure to also change the following storage method and table_viewer.prepare_data i if firstPfRaiseByNo < firstPfCallByNo or firstPfCallByNo == -1: firstPlayId = firstPfRaiserId - + cutoffId=-1 buttonId=-1 sbId=-1 @@ -1131,9 +1131,9 @@ sure to also change the following storage method and table_viewer.prepare_data i sbId = player_ids[player] if pos == 'B': bbId = player_ids[player] - + someoneStole=False - + #run a loop for each player preparing the actual values that will be commited to SQL for player in xrange(len(player_ids)): #set default values @@ -1177,7 +1177,7 @@ sure to also change the following storage method and table_viewer.prepare_data i #myStreet2Raises=0 #myStreet3Raises=0 #myStreet4Raises=0 - + #calculate VPIP and PFR street=0 heroPfRaiseCount=0 @@ -1186,14 +1186,14 @@ sure to also change the following storage method and table_viewer.prepare_data i myStreet0Aggr = True if currentAction == "bet" or currentAction == "call": myStreet0VPI = True - + if myStreet0VPI: result['playersVpi'] += 1 myStreet0Calls = action_types[street][player].count('call') myStreet0Bets = action_types[street][player].count('bet') # street0Raises = action_types[street][player].count('raise') bet count includes raises for now result['street0Raises'] += myStreet0Bets - + #PF3BChance and PF3B pfFold=-1 pfRaise=-1 @@ -1208,7 +1208,7 @@ sure to also change the following storage method and table_viewer.prepare_data i myStreet0_3BChance = True if pfRaise > firstPfRaiseByNo: myStreet0_3BDone = True - + #steal calculations if base=="hold": if len(player_ids)>=3: # no point otherwise # was 5, use 3 to match pokertracker definition @@ -1235,30 +1235,32 @@ sure to also change the following storage method and table_viewer.prepare_data i myStealAttemptChance=True if positions[player]=='B': pass - + if myStealAttempted: someoneStole=True - - + + #calculate saw* values isAllIn = False if any(i for i in allIns[0][player]): isAllIn = True - if (len(action_types[1][player])>0 or isAllIn): + if isAllIn or len(action_types[1][player]) > 0: myStreet1Seen = True - + if any(i for i in allIns[1][player]): isAllIn = True - if (len(action_types[2][player])>0 or isAllIn): - myStreet2Seen = True - + if isAllIn or len(action_types[2][player]) > 0: + if all(actiontype != "fold" for actiontype in action_types[1][player]): + myStreet2Seen = True + if any(i for i in allIns[2][player]): isAllIn = True - if (len(action_types[3][player])>0 or isAllIn): - myStreet3Seen = True - + if isAllIn or len(action_types[3][player]) > 0: + if all(actiontype != "fold" for actiontype in action_types[2][player]): + myStreet3Seen = True + #print "base:", base - if base=="hold": + if base == "hold": mySawShowdown = True if any(actiontype == "fold" for actiontype in action_types[3][player]): mySawShowdown = False @@ -1266,10 +1268,10 @@ sure to also change the following storage method and table_viewer.prepare_data i #print "in else" if any(i for i in allIns[3][player]): isAllIn = True - if (len(action_types[4][player])>0 or isAllIn): + if isAllIn or len(action_types[4][player]) > 0: #print "in if" myStreet4Seen = True - + mySawShowdown = True if any(actiontype == "fold" for actiontype in action_types[4][player]): mySawShowdown = False @@ -1284,18 +1286,18 @@ sure to also change the following storage method and table_viewer.prepare_data i result['playersAtStreet4'] += 1 if mySawShowdown: result['playersAtShowdown'] += 1 - + #flop stuff street=1 if myStreet1Seen: if any(actiontype == "bet" for actiontype in action_types[street][player]): myStreet1Aggr = True - + myStreet1Calls = action_types[street][player].count('call') myStreet1Bets = action_types[street][player].count('bet') # street1Raises = action_types[street][player].count('raise') bet count includes raises for now result['street1Raises'] += myStreet1Bets - + for otherPlayer in xrange(len(player_ids)): if player==otherPlayer: pass @@ -1306,18 +1308,18 @@ sure to also change the following storage method and table_viewer.prepare_data i for countOtherFold in xrange(len(action_types[street][player])): if action_types[street][player][countOtherFold]=="fold": myFoldToOtherRaisedStreet1=True - + #turn stuff - copy of flop with different vars street=2 if myStreet2Seen: if any(actiontype == "bet" for actiontype in action_types[street][player]): myStreet2Aggr = True - + myStreet2Calls = action_types[street][player].count('call') myStreet2Bets = action_types[street][player].count('bet') # street2Raises = action_types[street][player].count('raise') bet count includes raises for now result['street2Raises'] += myStreet2Bets - + for otherPlayer in xrange(len(player_ids)): if player==otherPlayer: pass @@ -1328,18 +1330,18 @@ sure to also change the following storage method and table_viewer.prepare_data i for countOtherFold in xrange(len(action_types[street][player])): if action_types[street][player][countOtherFold]=="fold": myFoldToOtherRaisedStreet2=True - + #river stuff - copy of flop with different vars street=3 if myStreet3Seen: if any(actiontype == "bet" for actiontype in action_types[street][player]): myStreet3Aggr = True - + myStreet3Calls = action_types[street][player].count('call') myStreet3Bets = action_types[street][player].count('bet') # street3Raises = action_types[street][player].count('raise') bet count includes raises for now result['street3Raises'] += myStreet3Bets - + for otherPlayer in xrange(len(player_ids)): if player==otherPlayer: pass @@ -1350,18 +1352,18 @@ sure to also change the following storage method and table_viewer.prepare_data i for countOtherFold in xrange(len(action_types[street][player])): if action_types[street][player][countOtherFold]=="fold": myFoldToOtherRaisedStreet3=True - + #stud river stuff - copy of flop with different vars street=4 if myStreet4Seen: if any(actiontype == "bet" for actiontype in action_types[street][player]): myStreet4Aggr=True - + myStreet4Calls = action_types[street][player].count('call') myStreet4Bets = action_types[street][player].count('bet') # street4Raises = action_types[street][player].count('raise') bet count includes raises for now result['street4Raises'] += myStreet4Bets - + for otherPlayer in xrange(len(player_ids)): if player==otherPlayer: pass @@ -1372,13 +1374,13 @@ sure to also change the following storage method and table_viewer.prepare_data i for countOtherFold in xrange(len(action_types[street][player])): if action_types[street][player][countOtherFold]=="fold": myFoldToOtherRaisedStreet4=True - + if winnings[player] != 0: if myStreet1Seen: myWonWhenSeenStreet1 = winnings[player] / float(totalWinnings) if mySawShowdown: myWonAtSD=myWonWhenSeenStreet1 - + #add each value to the appropriate array street0VPI.append(myStreet0VPI) street0Aggr.append(myStreet0Aggr) @@ -1443,7 +1445,7 @@ sure to also change the following storage method and table_viewer.prepare_data i #street2Raises.append(myStreet2Raises) #street3Raises.append(myStreet3Raises) #street4Raises.append(myStreet4Raises) - + #add each array to the to-be-returned dictionary result['street0VPI']=street0VPI result['street0Aggr']=street0Aggr @@ -1454,7 +1456,7 @@ sure to also change the following storage method and table_viewer.prepare_data i result['street3Seen']=street3Seen result['street4Seen']=street4Seen result['sawShowdown']=sawShowdown - + result['street1Aggr']=street1Aggr result['otherRaisedStreet1']=otherRaisedStreet1 result['foldToOtherRaisedStreet1']=foldToOtherRaisedStreet1 @@ -1486,7 +1488,7 @@ sure to also change the following storage method and table_viewer.prepare_data i #result['street2Raises']=street2Raises #result['street3Raises']=street3Raises #result['street4Raises']=street4Raises - + #now the various steal values foldBbToStealChance=[] foldedBbToSteal=[] @@ -1497,7 +1499,7 @@ sure to also change the following storage method and table_viewer.prepare_data i myFoldedBbToSteal=False myFoldSbToStealChance=False myFoldedSbToSteal=False - + if base=="hold": if someoneStole and (positions[player]=='B' or positions[player]=='S') and firstPfRaiserId!=player_ids[player]: street=0 @@ -1510,8 +1512,8 @@ sure to also change the following storage method and table_viewer.prepare_data i myFoldSbToStealChance=True if action_types[street][player][count]=="fold": myFoldedSbToSteal=True - - + + foldBbToStealChance.append(myFoldBbToStealChance) foldedBbToSteal.append(myFoldedBbToSteal) foldSbToStealChance.append(myFoldSbToStealChance) @@ -1520,7 +1522,7 @@ sure to also change the following storage method and table_viewer.prepare_data i result['foldedBbToSteal']=foldedBbToSteal result['foldSbToStealChance']=foldSbToStealChance result['foldedSbToSteal']=foldedSbToSteal - + #now CB street1CBChance=[] street1CBDone=[] @@ -1528,18 +1530,18 @@ sure to also change the following storage method and table_viewer.prepare_data i for player in xrange(len(player_ids)): myStreet1CBChance=False myStreet1CBDone=False - + if street0VPI[player]: myStreet1CBChance=True if street1Aggr[player]: myStreet1CBDone=True didStreet1CB.append(player_ids[player]) - + street1CBChance.append(myStreet1CBChance) street1CBDone.append(myStreet1CBDone) result['street1CBChance']=street1CBChance result['street1CBDone']=street1CBDone - + #now 2B street2CBChance=[] street2CBDone=[] @@ -1547,18 +1549,18 @@ sure to also change the following storage method and table_viewer.prepare_data i for player in xrange(len(player_ids)): myStreet2CBChance=False myStreet2CBDone=False - + if street1CBDone[player]: myStreet2CBChance=True if street2Aggr[player]: myStreet2CBDone=True didStreet2CB.append(player_ids[player]) - + street2CBChance.append(myStreet2CBChance) street2CBDone.append(myStreet2CBDone) result['street2CBChance']=street2CBChance result['street2CBDone']=street2CBDone - + #now 3B street3CBChance=[] street3CBDone=[] @@ -1566,18 +1568,18 @@ sure to also change the following storage method and table_viewer.prepare_data i for player in xrange(len(player_ids)): myStreet3CBChance=False myStreet3CBDone=False - + if street2CBDone[player]: myStreet3CBChance=True if street3Aggr[player]: myStreet3CBDone=True didStreet3CB.append(player_ids[player]) - + street3CBChance.append(myStreet3CBChance) street3CBDone.append(myStreet3CBDone) result['street3CBChance']=street3CBChance result['street3CBDone']=street3CBDone - + #and 4B street4CBChance=[] street4CBDone=[] @@ -1585,21 +1587,21 @@ sure to also change the following storage method and table_viewer.prepare_data i for player in xrange(len(player_ids)): myStreet4CBChance=False myStreet4CBDone=False - + if street3CBDone[player]: myStreet4CBChance=True if street4Aggr[player]: myStreet4CBDone=True didStreet4CB.append(player_ids[player]) - + street4CBChance.append(myStreet4CBChance) street4CBDone.append(myStreet4CBDone) result['street4CBChance']=street4CBChance result['street4CBDone']=street4CBDone - - + + result['position']=hudDataPositions - + foldToStreet1CBChance=[] foldToStreet1CBDone=[] foldToStreet2CBChance=[] @@ -1608,40 +1610,40 @@ sure to also change the following storage method and table_viewer.prepare_data i foldToStreet3CBDone=[] foldToStreet4CBChance=[] foldToStreet4CBDone=[] - + for player in xrange(len(player_ids)): myFoldToStreet1CBChance=False myFoldToStreet1CBDone=False foldToStreet1CBChance.append(myFoldToStreet1CBChance) foldToStreet1CBDone.append(myFoldToStreet1CBDone) - + myFoldToStreet2CBChance=False myFoldToStreet2CBDone=False foldToStreet2CBChance.append(myFoldToStreet2CBChance) foldToStreet2CBDone.append(myFoldToStreet2CBDone) - + myFoldToStreet3CBChance=False myFoldToStreet3CBDone=False foldToStreet3CBChance.append(myFoldToStreet3CBChance) foldToStreet3CBDone.append(myFoldToStreet3CBDone) - + myFoldToStreet4CBChance=False myFoldToStreet4CBDone=False foldToStreet4CBChance.append(myFoldToStreet4CBChance) foldToStreet4CBDone.append(myFoldToStreet4CBDone) - + if len(didStreet1CB)>=1: generateFoldToCB(1, player_ids, didStreet1CB, street1CBDone, foldToStreet1CBChance, foldToStreet1CBDone, actionTypeByNo) - + if len(didStreet2CB)>=1: generateFoldToCB(2, player_ids, didStreet2CB, street2CBDone, foldToStreet2CBChance, foldToStreet2CBDone, actionTypeByNo) - + if len(didStreet3CB)>=1: generateFoldToCB(3, player_ids, didStreet3CB, street3CBDone, foldToStreet3CBChance, foldToStreet3CBDone, actionTypeByNo) - + if len(didStreet4CB)>=1: generateFoldToCB(4, player_ids, didStreet4CB, street4CBDone, foldToStreet4CBChance, foldToStreet4CBDone, actionTypeByNo) - + result['foldToStreet1CBChance']=foldToStreet1CBChance result['foldToStreet1CBDone']=foldToStreet1CBDone result['foldToStreet2CBChance']=foldToStreet2CBChance @@ -1650,10 +1652,10 @@ sure to also change the following storage method and table_viewer.prepare_data i result['foldToStreet3CBDone']=foldToStreet3CBDone result['foldToStreet4CBChance']=foldToStreet4CBChance result['foldToStreet4CBDone']=foldToStreet4CBDone - - + + totalProfit=[] - + street1CheckCallRaiseChance=[] street1CheckCallRaiseDone=[] street2CheckCallRaiseChance=[] @@ -1672,7 +1674,7 @@ sure to also change the following storage method and table_viewer.prepare_data i #for j in xrange(len(actionTypes[i])): #iterate through names (using pl loop above) for k in xrange(len(actionTypes[i][pl])): #iterate through individual actions of that player on that street myTotalProfit -= actionAmounts[i][pl][k] - + myStreet1CheckCallRaiseChance=False myStreet1CheckCallRaiseDone=False myStreet2CheckCallRaiseChance=False @@ -1681,11 +1683,11 @@ sure to also change the following storage method and table_viewer.prepare_data i myStreet3CheckCallRaiseDone=False myStreet4CheckCallRaiseChance=False myStreet4CheckCallRaiseDone=False - + #print "myTotalProfit=", myTotalProfit totalProfit.append(myTotalProfit) #print "totalProfit[]=", totalProfit - + street1CheckCallRaiseChance.append(myStreet1CheckCallRaiseChance) street1CheckCallRaiseDone.append(myStreet1CheckCallRaiseDone) street2CheckCallRaiseChance.append(myStreet2CheckCallRaiseChance) @@ -1694,10 +1696,10 @@ sure to also change the following storage method and table_viewer.prepare_data i street3CheckCallRaiseDone.append(myStreet3CheckCallRaiseDone) street4CheckCallRaiseChance.append(myStreet4CheckCallRaiseChance) street4CheckCallRaiseDone.append(myStreet4CheckCallRaiseDone) - + result['totalProfit']=totalProfit #print "res[totalProfit]=", result['totalProfit'] - + result['street1CheckCallRaiseChance']=street1CheckCallRaiseChance result['street1CheckCallRaiseDone']=street1CheckCallRaiseDone result['street2CheckCallRaiseChance']=street2CheckCallRaiseChance @@ -1708,7 +1710,7 @@ sure to also change the following storage method and table_viewer.prepare_data i result['street4CheckCallRaiseDone']=street4CheckCallRaiseDone return result #end def generateHudCacheData - + def generateFoldToCB(street, playerIDs, didStreetCB, streetCBDone, foldToStreetCBChance, foldToStreetCBDone, actionTypeByNo): """fills the passed foldToStreetCB* arrays appropriately depending on the given street""" #print "beginning of generateFoldToCB, street:", street, "len(actionTypeByNo):", len(actionTypeByNo) @@ -1720,7 +1722,7 @@ def generateFoldToCB(street, playerIDs, didStreetCB, streetCBDone, foldToStreetC if player==actionTypeByNo[street][action][0] and firstCBReaction==0: firstCBReaction=action+1 break - + for action in actionTypeByNo[street][firstCBReaction:]: for player in xrange(len(playerIDs)): if playerIDs[player]==action[0]: From adadb7defad98d3c1bffe20063ceaa618c83992e Mon Sep 17 00:00:00 2001 From: Eric Blade Date: Thu, 3 Dec 2009 12:51:10 -0500 Subject: [PATCH 17/65] slight optimizations --- pyfpdb/fpdb_simple.py | 96 ++++++++++++++++++------------------------- 1 file changed, 41 insertions(+), 55 deletions(-) diff --git a/pyfpdb/fpdb_simple.py b/pyfpdb/fpdb_simple.py index 85e60eeb..a6071a83 100644 --- a/pyfpdb/fpdb_simple.py +++ b/pyfpdb/fpdb_simple.py @@ -1241,40 +1241,34 @@ sure to also change the following storage method and table_viewer.prepare_data i #calculate saw* values - isAllIn = False - if any(i for i in allIns[0][player]): - isAllIn = True + isAllIn = any(i for i in AllIns[0][player]) if isAllIn or len(action_types[1][player]) > 0: myStreet1Seen = True - if any(i for i in allIns[1][player]): - isAllIn = True - if isAllIn or len(action_types[2][player]) > 0: + if not isAllIn: + isAllIn = any(i for i in allins[1][player]) + elif len(action_types[2][player]) > 0: if all(actiontype != "fold" for actiontype in action_types[1][player]): myStreet2Seen = True - if any(i for i in allIns[2][player]): - isAllIn = True - if isAllIn or len(action_types[3][player]) > 0: + if not isAllIn: + isAllAin = any(i for i in allIns[2][player]) + elif len(action_types[3][player]) > 0: if all(actiontype != "fold" for actiontype in action_types[2][player]): myStreet3Seen = True #print "base:", base if base == "hold": - mySawShowdown = True - if any(actiontype == "fold" for actiontype in action_types[3][player]): - mySawShowdown = False + mySawShowdown = not any(actiontype == "fold" for actiontype in action_types[3][player]) else: #print "in else" - if any(i for i in allIns[3][player]): - isAllIn = True - if isAllIn or len(action_types[4][player]) > 0: + if not isAllIn: + isAllIn = any(i for i in allins[3][player]) + elif len(action_types[4][player]) > 0: #print "in if" myStreet4Seen = True - mySawShowdown = True - if any(actiontype == "fold" for actiontype in action_types[4][player]): - mySawShowdown = False + mySawShowdown = not any(actiontype == "fold" for actiontype in action_types[4][player]) if myStreet1Seen: result['playersAtStreet1'] += 1 @@ -1288,98 +1282,90 @@ sure to also change the following storage method and table_viewer.prepare_data i result['playersAtShowdown'] += 1 #flop stuff - street=1 + street = 1 if myStreet1Seen: - if any(actiontype == "bet" for actiontype in action_types[street][player]): - myStreet1Aggr = True - + myStreet1Aggr = any(actiontype == "bet" for actiontype in action_types[street][player]) myStreet1Calls = action_types[street][player].count('call') myStreet1Bets = action_types[street][player].count('bet') # street1Raises = action_types[street][player].count('raise') bet count includes raises for now result['street1Raises'] += myStreet1Bets for otherPlayer in xrange(len(player_ids)): - if player==otherPlayer: + if player == otherPlayer: pass else: for countOther in xrange(len(action_types[street][otherPlayer])): - if action_types[street][otherPlayer][countOther]=="bet": - myOtherRaisedStreet1=True + if action_types[street][otherPlayer][countOther] == "bet": + myOtherRaisedStreet1 = True for countOtherFold in xrange(len(action_types[street][player])): - if action_types[street][player][countOtherFold]=="fold": - myFoldToOtherRaisedStreet1=True + if action_types[street][player][countOtherFold] == "fold": + myFoldToOtherRaisedStreet1 = True #turn stuff - copy of flop with different vars - street=2 + street = 2 if myStreet2Seen: - if any(actiontype == "bet" for actiontype in action_types[street][player]): - myStreet2Aggr = True - + myStreet2Aggr = any(actiontype == "bet" for actiontype in action_types[street][player]) myStreet2Calls = action_types[street][player].count('call') myStreet2Bets = action_types[street][player].count('bet') # street2Raises = action_types[street][player].count('raise') bet count includes raises for now result['street2Raises'] += myStreet2Bets for otherPlayer in xrange(len(player_ids)): - if player==otherPlayer: + if player == otherPlayer: pass else: for countOther in xrange(len(action_types[street][otherPlayer])): - if action_types[street][otherPlayer][countOther]=="bet": - myOtherRaisedStreet2=True + if action_types[street][otherPlayer][countOther] == "bet": + myOtherRaisedStreet2 = True for countOtherFold in xrange(len(action_types[street][player])): - if action_types[street][player][countOtherFold]=="fold": - myFoldToOtherRaisedStreet2=True + if action_types[street][player][countOtherFold] == "fold": + myFoldToOtherRaisedStreet2 = True #river stuff - copy of flop with different vars - street=3 + street = 3 if myStreet3Seen: - if any(actiontype == "bet" for actiontype in action_types[street][player]): - myStreet3Aggr = True - + myStreet3Aggr = any(actiontype == "bet" for actiontype in action_types[street][player]) myStreet3Calls = action_types[street][player].count('call') myStreet3Bets = action_types[street][player].count('bet') # street3Raises = action_types[street][player].count('raise') bet count includes raises for now result['street3Raises'] += myStreet3Bets for otherPlayer in xrange(len(player_ids)): - if player==otherPlayer: + if player == otherPlayer: pass else: for countOther in xrange(len(action_types[street][otherPlayer])): - if action_types[street][otherPlayer][countOther]=="bet": - myOtherRaisedStreet3=True + if action_types[street][otherPlayer][countOther] == "bet": + myOtherRaisedStreet3 = True for countOtherFold in xrange(len(action_types[street][player])): - if action_types[street][player][countOtherFold]=="fold": - myFoldToOtherRaisedStreet3=True + if action_types[street][player][countOtherFold] == "fold": + myFoldToOtherRaisedStreet3 = True #stud river stuff - copy of flop with different vars - street=4 + street = 4 if myStreet4Seen: - if any(actiontype == "bet" for actiontype in action_types[street][player]): - myStreet4Aggr=True - + myStreet4Aggr = any(actiontype == "bet" for actiontype in action_types[street][player]) myStreet4Calls = action_types[street][player].count('call') myStreet4Bets = action_types[street][player].count('bet') # street4Raises = action_types[street][player].count('raise') bet count includes raises for now result['street4Raises'] += myStreet4Bets for otherPlayer in xrange(len(player_ids)): - if player==otherPlayer: + if player == otherPlayer: pass else: for countOther in xrange(len(action_types[street][otherPlayer])): - if action_types[street][otherPlayer][countOther]=="bet": - myOtherRaisedStreet4=True + if action_types[street][otherPlayer][countOther] == "bet": + myOtherRaisedStreet4 = True for countOtherFold in xrange(len(action_types[street][player])): - if action_types[street][player][countOtherFold]=="fold": - myFoldToOtherRaisedStreet4=True + if action_types[street][player][countOtherFold] == "fold": + myFoldToOtherRaisedStreet4 = True if winnings[player] != 0: if myStreet1Seen: myWonWhenSeenStreet1 = winnings[player] / float(totalWinnings) if mySawShowdown: - myWonAtSD=myWonWhenSeenStreet1 + myWonAtSD = myWonWhenSeenStreet1 #add each value to the appropriate array street0VPI.append(myStreet0VPI) From 6195397c88b397f40939746d2f392be4d4b34c85 Mon Sep 17 00:00:00 2001 From: Eric Blade Date: Thu, 3 Dec 2009 12:52:57 -0500 Subject: [PATCH 18/65] fix typos.. durrr --- pyfpdb/fpdb_simple.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/pyfpdb/fpdb_simple.py b/pyfpdb/fpdb_simple.py index a6071a83..aa9421f6 100644 --- a/pyfpdb/fpdb_simple.py +++ b/pyfpdb/fpdb_simple.py @@ -1241,12 +1241,12 @@ sure to also change the following storage method and table_viewer.prepare_data i #calculate saw* values - isAllIn = any(i for i in AllIns[0][player]) + isAllIn = any(i for i in allIns[0][player]) if isAllIn or len(action_types[1][player]) > 0: myStreet1Seen = True if not isAllIn: - isAllIn = any(i for i in allins[1][player]) + isAllIn = any(i for i in allIns[1][player]) elif len(action_types[2][player]) > 0: if all(actiontype != "fold" for actiontype in action_types[1][player]): myStreet2Seen = True @@ -1263,7 +1263,7 @@ sure to also change the following storage method and table_viewer.prepare_data i else: #print "in else" if not isAllIn: - isAllIn = any(i for i in allins[3][player]) + isAllIn = any(i for i in allIns[3][player]) elif len(action_types[4][player]) > 0: #print "in if" myStreet4Seen = True From cd65aae3743ec91f2e67818364cb8db879deff74 Mon Sep 17 00:00:00 2001 From: sqlcoder Date: Thu, 3 Dec 2009 20:20:42 +0000 Subject: [PATCH 19/65] allow legend box to work in python 2.5 --- pyfpdb/GuiGraphViewer.py | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/pyfpdb/GuiGraphViewer.py b/pyfpdb/GuiGraphViewer.py index 76c80f2e..9daa940f 100644 --- a/pyfpdb/GuiGraphViewer.py +++ b/pyfpdb/GuiGraphViewer.py @@ -196,7 +196,10 @@ class GuiGraphViewer (threading.Thread): self.ax.plot(green, color='green', label='Hands: %d\nProfit: $%.2f' %(len(green), green[-1])) self.ax.plot(blue, color='blue', label='Showdown: $%.2f' %(blue[-1])) self.ax.plot(red, color='red', label='Non-showdown: $%.2f' %(red[-1])) - self.ax.legend(loc='best', fancybox=True, shadow=True, prop=FontProperties(size='smaller')) + if sys.version[0:3] == '2.5': + self.ax.legend(loc='best', shadow=True, prop=FontProperties(size='smaller')) + else: + self.ax.legend(loc='best', fancybox=True, shadow=True, prop=FontProperties(size='smaller')) self.graphBox.add(self.canvas) From c9b99273156346a72901448c47582c72bdd47600 Mon Sep 17 00:00:00 2001 From: sqlcoder Date: Thu, 3 Dec 2009 21:02:05 +0000 Subject: [PATCH 20/65] fix new timing code so it actually works\! --- pyfpdb/HUD_main.py | 17 +++++++++-------- 1 file changed, 9 insertions(+), 8 deletions(-) diff --git a/pyfpdb/HUD_main.py b/pyfpdb/HUD_main.py index c3c66d70..c3599a3b 100755 --- a/pyfpdb/HUD_main.py +++ b/pyfpdb/HUD_main.py @@ -195,7 +195,8 @@ class HUD_main(object): while 1: # wait for a new hand number on stdin new_hand_id = sys.stdin.readline() - t0 = time() + t0 = time.time() + t1 = t2 = t3 = t4 = t5 = t6 = t0 new_hand_id = string.rstrip(new_hand_id) if new_hand_id == "": # blank line means quit self.destroy() @@ -210,7 +211,7 @@ class HUD_main(object): print "db error: skipping %s" % new_hand_id sys.stderr.write("Database error: could not find hand %s.\n" % new_hand_id) continue - t1 = time() + t1 = time.time() if type == "tour": # hand is from a tournament temp_key = tour_number @@ -222,10 +223,10 @@ class HUD_main(object): # get stats using hud's specific params and get cards 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']) - t2 = time() + t2 = time.time() 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], num_seats) - t3 = time() + t3 = time.time() try: 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']) @@ -249,10 +250,10 @@ class HUD_main(object): else: # get stats using default params--also get cards self.db_connection.init_hud_stat_vars( self.hud_params['hud_days'], self.hud_params['h_hud_days'] ) - t4 = time() + t4 = time.time() stat_dict = self.db_connection.get_stats_from_hand(new_hand_id, type, self.hud_params ,self.hero_ids[site_id], num_seats) - t5 = time() + t5 = time.time() cards = self.db_connection.get_cards(new_hand_id) comm_cards = self.db_connection.get_common_cards(new_hand_id) if comm_cards != {}: # stud! @@ -276,8 +277,8 @@ class HUD_main(object): else: sys.stderr.write('Table "%s" no longer exists\n' % table_name) - t6 = time() - log.info("HUD_main.read_stdin: hand read in %4.3f seconds (%4.3f,%4.3f,%4.3f,%4.3f,%4.3f,%4.3f,%4.3f)" + t6 = time.time() + log.info("HUD_main.read_stdin: hand read in %4.3f seconds (%4.3f,%4.3f,%4.3f,%4.3f,%4.3f,%4.3f)" % (t6-t0,t1-t0,t2-t0,t3-t0,t4-t0,t5-t0,t6-t0)) self.db_connection.connection.rollback() From ee205c3b29f72d57566099c83628e9ce94db9af0 Mon Sep 17 00:00:00 2001 From: Worros Date: Fri, 4 Dec 2009 17:56:56 +0800 Subject: [PATCH 21/65] [NEWIMPORT] Partially fix number of hands parsed reporting --- pyfpdb/HandHistoryConverter.py | 16 +++++++++------- pyfpdb/fpdb_import.py | 4 ++++ 2 files changed, 13 insertions(+), 7 deletions(-) diff --git a/pyfpdb/HandHistoryConverter.py b/pyfpdb/HandHistoryConverter.py index 41b7b3d0..27bb9b1a 100644 --- a/pyfpdb/HandHistoryConverter.py +++ b/pyfpdb/HandHistoryConverter.py @@ -71,6 +71,8 @@ follow : whether to tail -f the input""" self.out_path = out_path self.processedHands = [] + self.numHands = 0 + self.numErrors = 0 # Tourney object used to store TourneyInfo when called to deal with a Summary file self.tourney = None @@ -135,17 +137,17 @@ Otherwise, finish at EOF. return try: - numHands = 0 - numErrors = 0 + self.numHands = 0 + self.numErrors = 0 if self.follow: #TODO: See how summary files can be handled on the fly (here they should be rejected as before) log.info("Tailing '%s'" % self.in_path) for handText in self.tailHands(): try: self.processHand(handText) - numHands += 1 + self.numHands += 1 except FpdbParseError, e: - numErrors += 1 + self.numErrors += 1 log.warning("Failed to convert hand %s" % e.hid) log.warning("Exception msg: '%s'" % str(e)) log.debug(handText) @@ -160,13 +162,13 @@ Otherwise, finish at EOF. try: self.processedHands.append(self.processHand(handText)) except FpdbParseError, e: - numErrors += 1 + self.numErrors += 1 log.warning("Failed to convert hand %s" % e.hid) log.warning("Exception msg: '%s'" % str(e)) log.debug(handText) - numHands = len(handsList) + self.numHands = len(handsList) endtime = time.time() - log.info("Read %d hands (%d failed) in %.3f seconds" % (numHands, numErrors, endtime - starttime)) + log.info("Read %d hands (%d failed) in %.3f seconds" % (self.numHands, self.numErrors, endtime - starttime)) else: self.parsedObjectType = "Summary" summaryParsingStatus = self.readSummaryInfo(handsList) diff --git a/pyfpdb/fpdb_import.py b/pyfpdb/fpdb_import.py index 19bf18d1..5b5ddca0 100644 --- a/pyfpdb/fpdb_import.py +++ b/pyfpdb/fpdb_import.py @@ -427,8 +427,12 @@ class Importer: self.pos_in_file[file] = hhc.getLastCharacterRead() for hand in handlist: + #try, except duplicates here? #hand.prepInsert() hand.insert(self.database) + + errors = getattr(hhc, 'numErrors') + stored = getattr(hhc, 'numHands') else: # conversion didn't work # TODO: appropriate response? From c40d6657009ac535fa68860f1fa7fa80a55a3ce1 Mon Sep 17 00:00:00 2001 From: Worros Date: Sat, 5 Dec 2009 20:15:28 +0800 Subject: [PATCH 22/65] Newimport - comments for a getPosition function. Decided that I needed some test functions before I kick on --- pyfpdb/DerivedStats.py | 36 ++++++++++++++++++++++++++++++++++++ 1 file changed, 36 insertions(+) diff --git a/pyfpdb/DerivedStats.py b/pyfpdb/DerivedStats.py index c244f019..a63a3636 100644 --- a/pyfpdb/DerivedStats.py +++ b/pyfpdb/DerivedStats.py @@ -149,6 +149,42 @@ class DerivedStats(): for i, card in enumerate(hcs[:7], 1): self.handsplayers[player[1]]['card%s' % i] = Card.encodeCard(card) + # position, + #Stud 3rd street card test + # denny501: brings in for $0.02 + # s0rrow: calls $0.02 + # TomSludge: folds + # Soroka69: calls $0.02 + # rdiezchang: calls $0.02 (Seat 8) + # u.pressure: folds (Seat 1) + # 123smoothie: calls $0.02 + # gashpor: calls $0.02 + # tourneyTypeId, + # startCards, + # street0_3BChance,street0_3BDone, + # otherRaisedStreet1-4 + # foldToOtherRaisedStreet1-4 + # stealAttemptChance,stealAttempted, + # foldBbToStealChance,foldedBbToSteal, + # foldSbToStealChance,foldedSbToSteal, + # foldToStreet1-4CBChance, foldToStreet1-4CBDone, + # street1-4CheckCallRaiseChance, street1-4CheckCallRaiseDone, + + # Additional stats + # 3betSB, 3betBB + # Squeeze, Ratchet? + + + def getPosition(hand, seat): + """Returns position value like 'B', 'S', 0, 1, ...""" + # Flop/Draw games with blinds + # Need a better system??? + # -2 BB - B (all) + # -1 SB - S (all) + # 0 Button + # 1 Cutoff + # 2 Hijack + def assembleHudCache(self, hand): pass From 61840e73c6731d6fe1a9e54aa83ce6ce7370940b Mon Sep 17 00:00:00 2001 From: Worros Date: Sat, 5 Dec 2009 20:18:47 +0800 Subject: [PATCH 23/65] Add beginings of test for sawShowdown - unfinished. Some sort of weird commit problem going on. Conmmitiing to work on htat --- pyfpdb/test_PokerStars.py | 44 +++++++++++++++++++++++++++++++++++++-- 1 file changed, 42 insertions(+), 2 deletions(-) diff --git a/pyfpdb/test_PokerStars.py b/pyfpdb/test_PokerStars.py index 6c97c2d4..f7959134 100644 --- a/pyfpdb/test_PokerStars.py +++ b/pyfpdb/test_PokerStars.py @@ -74,12 +74,52 @@ def testFlopImport(): # """regression-test-files/tour/Stars/Flop/NLHE-USD-MTT-5r-200710.txt""", site="PokerStars") importer.addBulkImportImportFileOrDir( """regression-test-files/cash/Stars/Flop/PLO8-6max-USD-0.01-0.02-200911.txt""", site="PokerStars") + #HID - 36185273365 + # Besides the horrible play it contains lots of useful cases + # Preflop: raise, then 3bet chance for seat 2 + # Flop: Checkraise by hero, 4bet chance not taken by villain + # Turn: Turn continuation bet by hero, called + # River: hero (continuation bets?) all-in and is not called + importer.addBulkImportImportFileOrDir( + """regression-test-files/cash/Stars/Flop/NLHE-6max-USD-0.05-0.10-200912.Stats-comparision.txt""", site="PokerStars") importer.setCallHud(False) (stored, dups, partial, errs, ttime) = importer.runImport() + print "DEBUG: stored: %s dups: %s partial: %s errs: %s ttime: %s" %(stored, dups, partial, errs, ttime) importer.clearFileList() - # Should actually do some testing here - assert 1 == 1 + q = """SELECT + s.name, + g.category, + g.base, + g.type, + g.limitType, + g.hilo, + round(g.smallBlind / 100.0,2) as sb, + round(g.bigBlind / 100.0,2) as bb, + round(g.smallBet / 100.0,2) as SB, + round(g.bigBet / 100.0,2) as BB, + s.currency, + hp.playerId, + hp.sawShowdown +FROM + Hands as h, + Sites as s, + Gametypes as g, + HandsPlayers as hp, + Players as p +WHERE + h.siteHandNo = 36185273365 +and g.id = h.gametypeid +and hp.handid = h.id +and p.id = hp.playerid +and s.id = p.siteid""" + c = db.get_cursor() + c.execute(q) + result = c.fetchall() + print "DEBUG: result: %s" %result + + + assert 1 == 0 def testStudImport(): db.recreate_tables() From 6826d0157a82cf7811396aac6b90d4a0626378c5 Mon Sep 17 00:00:00 2001 From: sqlcoder Date: Sat, 5 Dec 2009 15:54:49 +0000 Subject: [PATCH 24/65] create gui option to view the log --- pyfpdb/GuiLogView.py | 129 +++++++++++++++++++++++++++++++++++++++++++ pyfpdb/fpdb.py | 31 ++++++++++- pyfpdb/logging.conf | 14 ++++- 3 files changed, 172 insertions(+), 2 deletions(-) create mode 100755 pyfpdb/GuiLogView.py diff --git a/pyfpdb/GuiLogView.py b/pyfpdb/GuiLogView.py new file mode 100755 index 00000000..77f09b06 --- /dev/null +++ b/pyfpdb/GuiLogView.py @@ -0,0 +1,129 @@ +#!/usr/bin/python +# -*- coding: utf-8 -*- + +#Copyright 2008 Carl Gherardi +#This program is free software: you can redistribute it and/or modify +#it under the terms of the GNU Affero General Public License as published by +#the Free Software Foundation, version 3 of the License. +# +#This program is distributed in the hope that it will be useful, +#but WITHOUT ANY WARRANTY; without even the implied warranty of +#MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +#GNU General Public License for more details. +# +#You should have received a copy of the GNU Affero General Public License +#along with this program. If not, see . +#In the "official" distribution you can find the license in +#agpl-3.0.txt in the docs folder of the package. + + +import xml.dom.minidom +from xml.dom.minidom import Node + +import pygtk +pygtk.require('2.0') +import gtk +import gobject +import pango + +import Configuration + +log = Configuration.get_logger("logging.conf", "logview") + +class GuiLogView: + + def __init__(self, config, mainwin, vbox): + self.config = config + self.main_window = mainwin + self.vbox = vbox + gtk.Widget.set_size_request(self.vbox, 700, 400); + + self.liststore = gtk.ListStore(str, str, str, str) # date, module, level, text + self.listview = gtk.TreeView(model=self.liststore) + self.listview.set_grid_lines(gtk.TREE_VIEW_GRID_LINES_BOTH) + + scrolledwindow = gtk.ScrolledWindow() + scrolledwindow.set_policy(gtk.POLICY_AUTOMATIC, gtk.POLICY_AUTOMATIC) + self.vbox.pack_start(scrolledwindow, expand=True, fill=True, padding=0) + scrolledwindow.add(self.listview) + + self.listview.show() + scrolledwindow.show() + self.vbox.show() + + self.loadLog() + self.vbox.show_all() + + def loadLog(self): + + #self.configStore = gtk.TreeStore(gobject.TYPE_PYOBJECT, gobject.TYPE_STRING, gobject.TYPE_STRING) + #self.configView = gtk.TreeView(self.configStore) + #self.configView.set_enable_tree_lines(True) + self.liststore.clear() + + col = gtk.TreeViewColumn("Date/Time") + self.listview.append_column(col) + cRender = gtk.CellRendererText() + cRender.set_property("wrap-mode", pango.WRAP_WORD_CHAR) + col.pack_start(cRender, True) + col.add_attribute(cRender, 'text', 0) + col.set_max_width(1000) + + col = gtk.TreeViewColumn("Module") + self.listview.append_column(col) + cRender = gtk.CellRendererText() + cRender.set_property("wrap-mode", pango.WRAP_WORD_CHAR) + col.pack_start(cRender, True) + col.add_attribute(cRender, 'text', 1) + col.set_max_width(1000) + + col = gtk.TreeViewColumn("Level") + self.listview.append_column(col) + cRender = gtk.CellRendererText() + cRender.set_property("wrap-mode", pango.WRAP_WORD_CHAR) + col.pack_start(cRender, True) + col.add_attribute(cRender, 'text', 2) + col.set_max_width(1000) + + col = gtk.TreeViewColumn("Text") + self.listview.append_column(col) + cRender = gtk.CellRendererText() + cRender.set_property("wrap-mode", pango.WRAP_WORD_CHAR) + col.pack_start(cRender, True) + col.add_attribute(cRender, 'text', 3) + col.set_max_width(1000) + + l = 0 + for line in open('logging.out', 'r'): + #self.addLogText(line) + iter = self.liststore.append([line.strip(), "", "", ""]) + l = l + 1 + if l >= 100: + break + + + +if __name__=="__main__": + + config = Configuration.Config() + + win = gtk.Window(gtk.WINDOW_TOPLEVEL) + win.set_title("Test Log Viewer") + win.set_border_width(1) + win.set_default_size(600, 500) + win.set_resizable(True) + + dia = gtk.Dialog("Log Viewer", + win, + gtk.DIALOG_MODAL | gtk.DIALOG_DESTROY_WITH_PARENT, + (gtk.STOCK_CLOSE, gtk.RESPONSE_OK)) + dia.set_default_size(500, 500) + log = GuiLogView(config, win, dia.vbox) + response = dia.run() + if response == gtk.RESPONSE_ACCEPT: + pass + dia.destroy() + + + + diff --git a/pyfpdb/fpdb.py b/pyfpdb/fpdb.py index faaf4fdc..79567578 100755 --- a/pyfpdb/fpdb.py +++ b/pyfpdb/fpdb.py @@ -60,7 +60,8 @@ if not options.errorsToConsole: errorFile = open('fpdb-error-log.txt', 'w', 0) sys.stderr = errorFile -import logging +#import logging +import logging, logging.config import pygtk pygtk.require('2.0') @@ -70,6 +71,7 @@ import interlocks import GuiPrefs +import GuiLogView import GuiBulkImport import GuiPlayerStats import GuiPositionalStats @@ -85,6 +87,8 @@ import Exceptions VERSION = "0.12" +log = Configuration.get_logger("logging.conf", "fpdb") + class fpdb: def tab_clicked(self, widget, tab_name): """called when a tab button is clicked to activate that tab""" @@ -413,6 +417,29 @@ class fpdb: self.release_global_lock() + def dia_logs(self, widget, data=None): + lock_set = False + if self.obtain_global_lock(): + lock_set = True + + dia = gtk.Dialog(title="Log Messages" + ,parent=None + ,flags=0 + ,buttons=(gtk.STOCK_CLOSE,gtk.RESPONSE_OK)) + logviewer = GuiLogView.GuiLogView(self.config, self.window, dia.vbox) + response = dia.run() + if response == gtk.RESPONSE_ACCEPT: + pass + dia.destroy() + + if lock_set: + self.release_global_lock() + + def addLogText(self, text): + end_iter = self.logbuffer.get_end_iter() + self.logbuffer.insert(end_iter, text) + self.logview.scroll_to_mark(self.logbuffer.get_insert(), 0) + def __calendar_dialog(self, widget, entry): self.dia_confirm.set_modal(False) d = gtk.Window(gtk.WINDOW_TOPLEVEL) @@ -515,6 +542,7 @@ class fpdb: + @@ -556,6 +584,7 @@ class fpdb: ('stats', None, '_Statistics (todo)', None, 'View Database Statistics', self.dia_database_stats), ('help', None, '_Help'), ('Abbrev', None, '_Abbrevations (todo)', None, 'List of Abbrevations', self.tab_abbreviations), + ('Logs', None, '_Log Messages', None, 'Log and Debug Messages', self.dia_logs), ('About', None, 'A_bout', None, 'About the program', self.dia_about), ('License', None, '_License and Copying (todo)', None, 'License and Copying', self.dia_licensing), ]) diff --git a/pyfpdb/logging.conf b/pyfpdb/logging.conf index 124b509d..1b54b453 100644 --- a/pyfpdb/logging.conf +++ b/pyfpdb/logging.conf @@ -11,6 +11,18 @@ keys=fileFormatter,stderrFormatter level=INFO handlers=consoleHandler,fileHandler +[logger_fpdb] +level=INFO +handlers=consoleHandler,fileHandler +qualname=fpdb +propagate=0 + +[logger_logview] +level=INFO +handlers=consoleHandler,fileHandler +qualname=logview +propagate=0 + [logger_parser] level=INFO handlers=consoleHandler,fileHandler @@ -24,7 +36,7 @@ qualname=importer propagate=0 [logger_config] -level=DEBUG +level=INFO handlers=consoleHandler,fileHandler qualname=config propagate=0 From 2d8c44110c5a77bac5823e301b9bc74dac4d42f1 Mon Sep 17 00:00:00 2001 From: sqlcoder Date: Sat, 5 Dec 2009 20:10:00 +0000 Subject: [PATCH 25/65] refine log viewer --- pyfpdb/GuiLogView.py | 90 +++++++++++++++++++++++++++----------------- 1 file changed, 55 insertions(+), 35 deletions(-) diff --git a/pyfpdb/GuiLogView.py b/pyfpdb/GuiLogView.py index 77f09b06..646ccb0e 100755 --- a/pyfpdb/GuiLogView.py +++ b/pyfpdb/GuiLogView.py @@ -30,6 +30,8 @@ import Configuration log = Configuration.get_logger("logging.conf", "logview") +MAX_LINES = 1000 + class GuiLogView: def __init__(self, config, mainwin, vbox): @@ -38,9 +40,19 @@ class GuiLogView: self.vbox = vbox gtk.Widget.set_size_request(self.vbox, 700, 400); - self.liststore = gtk.ListStore(str, str, str, str) # date, module, level, text + self.liststore = gtk.ListStore(str, str, str, str, gobject.TYPE_BOOLEAN) # date, module, level, text + + # this is how to add a filter: + # + # # Creation of the filter, from the model + # filter = self.liststore.filter_new() + # filter.set_visible_column(1) + # + # # The TreeView gets the filter as model + # self.listview = gtk.TreeView(filter) + self.listview = gtk.TreeView(model=self.liststore) - self.listview.set_grid_lines(gtk.TREE_VIEW_GRID_LINES_BOTH) + self.listview.set_grid_lines(gtk.TREE_VIEW_GRID_LINES_NONE) scrolledwindow = gtk.ScrolledWindow() scrolledwindow.set_policy(gtk.POLICY_AUTOMATIC, gtk.POLICY_AUTOMATIC) @@ -60,47 +72,55 @@ class GuiLogView: #self.configView = gtk.TreeView(self.configStore) #self.configView.set_enable_tree_lines(True) self.liststore.clear() + self.listcols = [] - col = gtk.TreeViewColumn("Date/Time") - self.listview.append_column(col) - cRender = gtk.CellRendererText() - cRender.set_property("wrap-mode", pango.WRAP_WORD_CHAR) - col.pack_start(cRender, True) - col.add_attribute(cRender, 'text', 0) - col.set_max_width(1000) + col = self.addColumn("Date/Time", 0) - col = gtk.TreeViewColumn("Module") - self.listview.append_column(col) - cRender = gtk.CellRendererText() - cRender.set_property("wrap-mode", pango.WRAP_WORD_CHAR) - col.pack_start(cRender, True) - col.add_attribute(cRender, 'text', 1) - col.set_max_width(1000) - - col = gtk.TreeViewColumn("Level") - self.listview.append_column(col) - cRender = gtk.CellRendererText() - cRender.set_property("wrap-mode", pango.WRAP_WORD_CHAR) - col.pack_start(cRender, True) - col.add_attribute(cRender, 'text', 2) - col.set_max_width(1000) - - col = gtk.TreeViewColumn("Text") - self.listview.append_column(col) - cRender = gtk.CellRendererText() - cRender.set_property("wrap-mode", pango.WRAP_WORD_CHAR) - col.pack_start(cRender, True) - col.add_attribute(cRender, 'text', 3) - col.set_max_width(1000) + col = self.addColumn("Module", 1) + col = self.addColumn("Level", 2) + col = self.addColumn("Text", 3) l = 0 for line in open('logging.out', 'r'): - #self.addLogText(line) - iter = self.liststore.append([line.strip(), "", "", ""]) + # 2009-12-02 15:23:21,716 - config DEBUG config logger initialised + if len(line) > 49: + iter = self.liststore.append( (line[0:23], line[26:32], line[39:46], line[48:].strip(), True) ) l = l + 1 - if l >= 100: + if l >= MAX_LINES: break + def addColumn(self, title, n): + col = gtk.TreeViewColumn(title) + self.listview.append_column(col) + cRender = gtk.CellRendererText() + cRender.set_property("wrap-mode", pango.WRAP_WORD_CHAR) + col.pack_start(cRender, True) + col.add_attribute(cRender, 'text', n) + col.set_max_width(1000) + col.set_spacing(0) # no effect + self.listcols.append(col) + col.set_clickable(True) + col.connect("clicked", self.sortCols, n) + return(col) + + def sortCols(self, col, n): + try: + if not col.get_sort_indicator() or col.get_sort_order() == gtk.SORT_ASCENDING: + col.set_sort_order(gtk.SORT_DESCENDING) + else: + col.set_sort_order(gtk.SORT_ASCENDING) + self.liststore.set_sort_column_id(n, col.get_sort_order()) + #self.liststore.set_sort_func(n, self.sortnums, (n,grid)) + for i in xrange(len(self.listcols)): + self.listcols[i].set_sort_indicator(False) + self.listcols[n].set_sort_indicator(True) + # use this listcols[col].set_sort_indicator(True) + # to turn indicator off for other cols + except: + err = traceback.extract_tb(sys.exc_info()[2]) + print "***sortCols error: " + str(sys.exc_info()[1]) + print "\n".join( [e[0]+':'+str(e[1])+" "+e[2] for e in err] ) + if __name__=="__main__": From 2934c3213265813859bd097a818dfc4660b202d1 Mon Sep 17 00:00:00 2001 From: sqlcoder Date: Sat, 5 Dec 2009 20:31:37 +0000 Subject: [PATCH 26/65] limit number of lines displayed in log viewer --- pyfpdb/GuiLogView.py | 34 ++++++++++++++++++++++++++-------- 1 file changed, 26 insertions(+), 8 deletions(-) diff --git a/pyfpdb/GuiLogView.py b/pyfpdb/GuiLogView.py index 646ccb0e..0f7f03c7 100755 --- a/pyfpdb/GuiLogView.py +++ b/pyfpdb/GuiLogView.py @@ -17,8 +17,7 @@ #agpl-3.0.txt in the docs folder of the package. -import xml.dom.minidom -from xml.dom.minidom import Node +import mmap import pygtk pygtk.require('2.0') @@ -30,7 +29,7 @@ import Configuration log = Configuration.get_logger("logging.conf", "logview") -MAX_LINES = 1000 +MAX_LINES = 100000 class GuiLogView: @@ -80,14 +79,33 @@ class GuiLogView: col = self.addColumn("Level", 2) col = self.addColumn("Text", 3) + # count number of lines in file + f = open('logging.out', "r+") + buf = mmap.mmap(f.fileno(), 0) + readline = buf.readline + lines = 0 + while readline(): + lines += 1 + f.close() + + startline = 0 + if lines > MAX_LINES: + # only display from startline if log file is large + startline = lines - MAX_LINES + + f = open('logging.out', "r+") + buf = mmap.mmap(f.fileno(), 0) + readline = buf.readline l = 0 - for line in open('logging.out', 'r'): + line = readline() + while line: + # eg line: # 2009-12-02 15:23:21,716 - config DEBUG config logger initialised - if len(line) > 49: - iter = self.liststore.append( (line[0:23], line[26:32], line[39:46], line[48:].strip(), True) ) l = l + 1 - if l >= MAX_LINES: - break + if l > startline and len(line) > 49: + iter = self.liststore.append( (line[0:23], line[26:32], line[39:46], line[48:].strip(), True) ) + line = readline() + f.close() def addColumn(self, title, n): col = gtk.TreeViewColumn(title) From 85242f13cb1a4d66d564d9368f1034d33c730bdf Mon Sep 17 00:00:00 2001 From: sqlcoder Date: Sat, 5 Dec 2009 21:59:42 +0000 Subject: [PATCH 27/65] fix bug with hud stats, must use ORDER BY in the selects --- pyfpdb/SQL.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/pyfpdb/SQL.py b/pyfpdb/SQL.py index eb9296ef..5a0d1965 100644 --- a/pyfpdb/SQL.py +++ b/pyfpdb/SQL.py @@ -1317,6 +1317,7 @@ class Sql: 1.25 would be a config value so user could change it) */ GROUP BY hc.PlayerId, hp.seatNo, p.name + ORDER BY hc.PlayerId, hp.seatNo, p.name """ # same as above except stats are aggregated for all blind/limit levels @@ -1418,6 +1419,7 @@ class Sql: ) ) GROUP BY hc.PlayerId, p.name + ORDER BY hc.PlayerId, p.name """ # NOTES on above cursor: # - Do NOT include %s inside query in a comment - the db api thinks From 18b0a47555fd96246f4ad1db4134a9fd90b817e4 Mon Sep 17 00:00:00 2001 From: sqlcoder Date: Sat, 5 Dec 2009 22:20:44 +0000 Subject: [PATCH 28/65] move print message to log --- pyfpdb/Database.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/pyfpdb/Database.py b/pyfpdb/Database.py index 1c44bb61..36fdd2d2 100755 --- a/pyfpdb/Database.py +++ b/pyfpdb/Database.py @@ -474,8 +474,9 @@ class Database: else: h_seats_min, h_seats_max = 0, 10 print "bad h_seats_style value:", h_seats_style - print "opp seats style", seats_style, "hero seats style", h_seats_style - print "opp seats:", seats_min, seats_max, " hero seats:", h_seats_min, h_seats_max + log.info("opp seats style %s %d %d hero seats style %s %d %d" + % (seats_style, seats_min, seats_max + ,h_seats_style, h_seats_min, h_seats_max) ) if hud_style == 'S' or h_hud_style == 'S': self.get_stats_from_hand_session(hand, stat_dict, hero_id From 66b4ed35e538967073456cc9a0c0d148dadbc146 Mon Sep 17 00:00:00 2001 From: sqlcoder Date: Sat, 5 Dec 2009 22:48:41 +0000 Subject: [PATCH 29/65] add refresh button to log viewer --- pyfpdb/GuiLogView.py | 50 +++++++++++++++++++++++++------------------- 1 file changed, 29 insertions(+), 21 deletions(-) diff --git a/pyfpdb/GuiLogView.py b/pyfpdb/GuiLogView.py index 0f7f03c7..3b7b8aa6 100755 --- a/pyfpdb/GuiLogView.py +++ b/pyfpdb/GuiLogView.py @@ -52,19 +52,44 @@ class GuiLogView: self.listview = gtk.TreeView(model=self.liststore) self.listview.set_grid_lines(gtk.TREE_VIEW_GRID_LINES_NONE) + self.listcols = [] scrolledwindow = gtk.ScrolledWindow() scrolledwindow.set_policy(gtk.POLICY_AUTOMATIC, gtk.POLICY_AUTOMATIC) - self.vbox.pack_start(scrolledwindow, expand=True, fill=True, padding=0) scrolledwindow.add(self.listview) + self.vbox.pack_start(scrolledwindow, expand=True, fill=True, padding=0) + + refreshbutton = gtk.Button("Refresh") + refreshbutton.connect("clicked", self.refresh, None) + self.vbox.pack_start(refreshbutton, False, False, 3) + refreshbutton.show() self.listview.show() scrolledwindow.show() self.vbox.show() + col = self.addColumn("Date/Time", 0) + col = self.addColumn("Module", 1) + col = self.addColumn("Level", 2) + col = self.addColumn("Text", 3) + self.loadLog() self.vbox.show_all() + def addColumn(self, title, n): + col = gtk.TreeViewColumn(title) + self.listview.append_column(col) + cRender = gtk.CellRendererText() + cRender.set_property("wrap-mode", pango.WRAP_WORD_CHAR) + col.pack_start(cRender, True) + col.add_attribute(cRender, 'text', n) + col.set_max_width(1000) + col.set_spacing(0) # no effect + self.listcols.append(col) + col.set_clickable(True) + col.connect("clicked", self.sortCols, n) + return(col) + def loadLog(self): #self.configStore = gtk.TreeStore(gobject.TYPE_PYOBJECT, gobject.TYPE_STRING, gobject.TYPE_STRING) @@ -73,12 +98,6 @@ class GuiLogView: self.liststore.clear() self.listcols = [] - col = self.addColumn("Date/Time", 0) - - col = self.addColumn("Module", 1) - col = self.addColumn("Level", 2) - col = self.addColumn("Text", 3) - # count number of lines in file f = open('logging.out', "r+") buf = mmap.mmap(f.fileno(), 0) @@ -107,20 +126,6 @@ class GuiLogView: line = readline() f.close() - def addColumn(self, title, n): - col = gtk.TreeViewColumn(title) - self.listview.append_column(col) - cRender = gtk.CellRendererText() - cRender.set_property("wrap-mode", pango.WRAP_WORD_CHAR) - col.pack_start(cRender, True) - col.add_attribute(cRender, 'text', n) - col.set_max_width(1000) - col.set_spacing(0) # no effect - self.listcols.append(col) - col.set_clickable(True) - col.connect("clicked", self.sortCols, n) - return(col) - def sortCols(self, col, n): try: if not col.get_sort_indicator() or col.get_sort_order() == gtk.SORT_ASCENDING: @@ -139,6 +144,9 @@ class GuiLogView: print "***sortCols error: " + str(sys.exc_info()[1]) print "\n".join( [e[0]+':'+str(e[1])+" "+e[2] for e in err] ) + def refresh(self, widget, data): + self.loadLog() + if __name__=="__main__": From 128fa2f356f4db56100f43a24d9dca3ffd894652 Mon Sep 17 00:00:00 2001 From: Mika Bostrom Date: Sun, 6 Dec 2009 14:08:27 +0200 Subject: [PATCH 30/65] Enclose dict key lookup in try-except block Some recent changes moved the dictionary access outside try-except block again. Widen the block enough again. --- pyfpdb/HUD_main.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pyfpdb/HUD_main.py b/pyfpdb/HUD_main.py index 7e2d5fa6..108b89c7 100755 --- a/pyfpdb/HUD_main.py +++ b/pyfpdb/HUD_main.py @@ -159,10 +159,10 @@ class HUD_main(object): # function idle_func() to be run by the gui thread, at its leisure. def idle_func(): gtk.gdk.threads_enter() - self.hud_dict[table_name].update(new_hand_id, config) + try: + self.hud_dict[table_name].update(new_hand_id, config) # The HUD could get destroyed in the above call ^^, which leaves us with a KeyError here vv # if we ever get an error we need to expect ^^ then we need to handle it vv - Eric - try: [aw.update_gui(new_hand_id) for aw in self.hud_dict[table_name].aux_windows] except KeyError: pass From 63f04908beab47949209fd5c57b54be4aa5cbeb0 Mon Sep 17 00:00:00 2001 From: sqlcoder Date: Sun, 6 Dec 2009 14:17:22 +0000 Subject: [PATCH 31/65] add simple test scripts for python and gtk --- pyfpdb/test1.py | 29 +++++++++++++++++++++++++ pyfpdb/test2.py | 57 +++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 86 insertions(+) create mode 100755 pyfpdb/test1.py create mode 100755 pyfpdb/test2.py diff --git a/pyfpdb/test1.py b/pyfpdb/test1.py new file mode 100755 index 00000000..76bde20e --- /dev/null +++ b/pyfpdb/test1.py @@ -0,0 +1,29 @@ +#!/usr/bin/env python +"""test1.py + +Test if python is working. +""" +# Copyright 2008, Ray E. Barker +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + +######################################################################## + +import sys + +print "\npython is working!" +print "\npress return to finish" + +sys.stdin.readline() diff --git a/pyfpdb/test2.py b/pyfpdb/test2.py new file mode 100755 index 00000000..c52d0a6c --- /dev/null +++ b/pyfpdb/test2.py @@ -0,0 +1,57 @@ +#!/usr/bin/env python +"""test2.py + +Test if gtk is working. +""" +# Copyright 2008, Ray E. Barker +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + +######################################################################## + +import sys + +try: + import pygtk + pygtk.require('2.0') + import gtk + + + win = gtk.Window(gtk.WINDOW_TOPLEVEL) + win.set_title("Test GTK") + win.set_border_width(1) + win.set_default_size(600, 500) + win.set_resizable(True) + #win.show() + + dia = gtk.Dialog("Test GTK", + win, + gtk.DIALOG_MODAL | gtk.DIALOG_DESTROY_WITH_PARENT, + (gtk.STOCK_CLOSE, gtk.RESPONSE_OK)) + dia.set_default_size(500, 300) + + l = gtk.Label("GTK is working!") + dia.vbox.add(l) + l.show() + + response = dia.run() + if response == gtk.RESPONSE_ACCEPT: + pass + dia.destroy() + +except: + print "\nError:", sys.exc_info() + print "\npress return to finish" + sys.stdin.readline() From 4d38488f26bc21352a537b94081a512f44302c8b Mon Sep 17 00:00:00 2001 From: Worros Date: Sun, 6 Dec 2009 22:52:45 +0800 Subject: [PATCH 32/65] [NEWIMPORT] Fix sawShowdown stat --- pyfpdb/DerivedStats.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/pyfpdb/DerivedStats.py b/pyfpdb/DerivedStats.py index a63a3636..e4072d8a 100644 --- a/pyfpdb/DerivedStats.py +++ b/pyfpdb/DerivedStats.py @@ -231,8 +231,9 @@ class DerivedStats(): pas = set.union(self.pfba(actions) - self.pfba(actions, l=('folds',)), alliners) self.hands['playersAtShowdown'] = len(pas) - for player in pas: - self.handsplayers[player]['sawShowdown'] = True + if self.hands['playersAtShowdown'] > 1: + for player in pas: + self.handsplayers[player]['sawShowdown'] = True def streetXRaises(self, hand): # self.actions[street] is a list of all actions in a tuple, contining the action as the second element From 8f787b2d44697578414257335ca0038637d17125 Mon Sep 17 00:00:00 2001 From: Worros Date: Sun, 6 Dec 2009 22:56:29 +0800 Subject: [PATCH 33/65] Make test file use real database. Please note this could be destructive --- pyfpdb/HUD_config.test.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pyfpdb/HUD_config.test.xml b/pyfpdb/HUD_config.test.xml index 52905a70..1a5f77fa 100644 --- a/pyfpdb/HUD_config.test.xml +++ b/pyfpdb/HUD_config.test.xml @@ -574,7 +574,7 @@ Left-Drag to Move" - + From 909c2bd0fcc8e483ab4967310efdc32c71fdfb61 Mon Sep 17 00:00:00 2001 From: Worros Date: Sun, 6 Dec 2009 22:57:27 +0800 Subject: [PATCH 34/65] Add test for Stars sawShowdown. Test currently fails in the old import code and passes on NEWIMPORT Tests for uncalled allin bet on river, which has been erronously marked as showdown previously --- pyfpdb/test_PokerStars.py | 23 ++++++++--------------- 1 file changed, 8 insertions(+), 15 deletions(-) diff --git a/pyfpdb/test_PokerStars.py b/pyfpdb/test_PokerStars.py index f7959134..e3e45c35 100644 --- a/pyfpdb/test_PokerStars.py +++ b/pyfpdb/test_PokerStars.py @@ -87,19 +87,12 @@ def testFlopImport(): print "DEBUG: stored: %s dups: %s partial: %s errs: %s ttime: %s" %(stored, dups, partial, errs, ttime) importer.clearFileList() + col = { 'sawShowdown': 2 + } + q = """SELECT s.name, - g.category, - g.base, - g.type, - g.limitType, - g.hilo, - round(g.smallBlind / 100.0,2) as sb, - round(g.bigBlind / 100.0,2) as bb, - round(g.smallBet / 100.0,2) as SB, - round(g.bigBet / 100.0,2) as BB, - s.currency, - hp.playerId, + p.name, hp.sawShowdown FROM Hands as h, @@ -116,10 +109,10 @@ and s.id = p.siteid""" c = db.get_cursor() c.execute(q) result = c.fetchall() - print "DEBUG: result: %s" %result - - - assert 1 == 0 + for row, data in enumerate(result): + print "DEBUG: result[%s]: %s" %(row, result[row]) + # Assert if any sawShowdown = True + assert result[row][col['sawShowdown']] == 0 def testStudImport(): db.recreate_tables() From 0061bd0644e08324ad9506141df2d8ea458b377e Mon Sep 17 00:00:00 2001 From: Worros Date: Sun, 6 Dec 2009 23:02:07 +0800 Subject: [PATCH 35/65] [NEWIMPORT] Add call to HUD for auto import Make sure the matching db_handid is recorded in the Hand object for later use --- pyfpdb/Hand.py | 5 +++-- pyfpdb/fpdb_import.py | 5 +++++ 2 files changed, 8 insertions(+), 2 deletions(-) diff --git a/pyfpdb/Hand.py b/pyfpdb/Hand.py index efa9c0b6..9ff78249 100644 --- a/pyfpdb/Hand.py +++ b/pyfpdb/Hand.py @@ -54,6 +54,7 @@ class Hand(object): self.starttime = 0 self.handText = handText self.handid = 0 + self.dbid_hands = 0 self.tablename = "" self.hero = "" self.maxseats = None @@ -218,8 +219,8 @@ db: a connected fpdb_db object""" # seats TINYINT NOT NULL, hh['seats'] = len(sqlids) - handid = db.storeHand(hh) - db.storeHandsPlayers(handid, sqlids, self.stats.getHandsPlayers()) + self.dbid_hands = db.storeHand(hh) + db.storeHandsPlayers(self.dbid_hands, sqlids, self.stats.getHandsPlayers()) # HandsActions - all actions for all players for all streets - self.actions # HudCache data can be generated from HandsActions (HandsPlayers?) # Tourneys ? diff --git a/pyfpdb/fpdb_import.py b/pyfpdb/fpdb_import.py index 5b5ddca0..bca7f94b 100644 --- a/pyfpdb/fpdb_import.py +++ b/pyfpdb/fpdb_import.py @@ -430,6 +430,11 @@ class Importer: #try, except duplicates here? #hand.prepInsert() hand.insert(self.database) + if self.callHud and hand.dbid_hands != 0: + #print "DEBUG: call to HUD: handsId: %s" % hand.dbid_hands + #pipe the Hands.id out to the HUD + # print "fpdb_import: sending hand to hud", handsId, "pipe =", self.caller.pipe_to_hud + self.caller.pipe_to_hud.stdin.write("%s" % (hand.dbid_hands) + os.linesep) errors = getattr(hhc, 'numErrors') stored = getattr(hhc, 'numHands') From cd5b5b468ce204b81fc6edadfde9dd69ea1761d6 Mon Sep 17 00:00:00 2001 From: Worros Date: Mon, 7 Dec 2009 12:07:43 +0800 Subject: [PATCH 36/65] Forgot to add actual test file --- ...USD-0.05-0.10-200912.Stats-comparision.txt | 43 +++++++++++++++++++ 1 file changed, 43 insertions(+) create mode 100644 pyfpdb/regression-test-files/cash/Stars/Flop/NLHE-6max-USD-0.05-0.10-200912.Stats-comparision.txt diff --git a/pyfpdb/regression-test-files/cash/Stars/Flop/NLHE-6max-USD-0.05-0.10-200912.Stats-comparision.txt b/pyfpdb/regression-test-files/cash/Stars/Flop/NLHE-6max-USD-0.05-0.10-200912.Stats-comparision.txt new file mode 100644 index 00000000..5f140759 --- /dev/null +++ b/pyfpdb/regression-test-files/cash/Stars/Flop/NLHE-6max-USD-0.05-0.10-200912.Stats-comparision.txt @@ -0,0 +1,43 @@ +PokerStars Game #36185273365: Hold'em No Limit ($0.05/$0.10 USD) - 2009/12/03 9:16:10 ET +Table 'Eurynome IV' 6-max Seat #3 is the button +Seat 1: s0rrow ($16.10 in chips) +Seat 2: chrisbiz ($9.45 in chips) +Seat 3: papajohn77 ($6.55 in chips) +Seat 4: WSOFish ($21.05 in chips) +Seat 5: drefron ($10 in chips) +Seat 6: garegerret ($10.60 in chips) +WSOFish: posts small blind $0.05 +drefron: posts big blind $0.10 +*** HOLE CARDS *** +Dealt to s0rrow [5s As] +garegerret: folds +s0rrow: raises $0.20 to $0.30 +chrisbiz: calls $0.30 +papajohn77: folds +WSOFish: folds +drefron: folds +*** FLOP *** [8c 4c 4d] +s0rrow: checks +chrisbiz: bets $0.40 +s0rrow: raises $1 to $1.40 +chrisbiz: calls $1 +*** TURN *** [8c 4c 4d] [Kc] +s0rrow: bets $3.20 +chrisbiz: calls $3.20 +*** RIVER *** [8c 4c 4d Kc] [2s] +s0rrow: bets $11.20 and is all-in +chrisbiz: folds +Uncalled bet ($11.20) returned to s0rrow +s0rrow collected $9.50 from pot +*** SUMMARY *** +Total pot $9.95 | Rake $0.45 +Board [8c 4c 4d Kc 2s] +Seat 1: s0rrow collected ($9.50) +Seat 2: chrisbiz folded on the River +Seat 3: papajohn77 (button) folded before Flop (didn't bet) +Seat 4: WSOFish (small blind) folded before Flop +Seat 5: drefron (big blind) folded before Flop +Seat 6: garegerret folded before Flop (didn't bet) + + + From 09b0e02c37fbf4c260eab611b2661581ea3586b5 Mon Sep 17 00:00:00 2001 From: Worros Date: Mon, 7 Dec 2009 12:14:19 +0800 Subject: [PATCH 37/65] Add Makefile and a couple of test HH's --- Makefile | 11 + .../Flop/PLO8-6max-USD-0.01-0.02-200911.txt | 602 ++++++++++++++++++ ...7-StudHL-USD-0.04-0.08-200911.Cardtest.txt | 96 +++ 3 files changed, 709 insertions(+) create mode 100644 Makefile create mode 100644 pyfpdb/regression-test-files/cash/Stars/Flop/PLO8-6max-USD-0.01-0.02-200911.txt create mode 100644 pyfpdb/regression-test-files/cash/Stars/Stud/7-StudHL-USD-0.04-0.08-200911.Cardtest.txt diff --git a/Makefile b/Makefile new file mode 100644 index 00000000..3d8ec313 --- /dev/null +++ b/Makefile @@ -0,0 +1,11 @@ +# Variable definitions +VERSION = 0.12 +DATE = $(shell date +%Y%m%d) + +all: + @echo "Usage:" + @echo " make snapshot - Tags the repository with $(VERSION)-$(DATE) and creates a tarball from that" + +snapshot: + git tag $(VERSION)-$(DATE) + git archive --prefix=fpdb-$(VERSION)-$(DATE)/ $(VERSION)-$(DATE) | gzip -9 > ../fpdb-$(VERSION)-$(DATE).tar.gz diff --git a/pyfpdb/regression-test-files/cash/Stars/Flop/PLO8-6max-USD-0.01-0.02-200911.txt b/pyfpdb/regression-test-files/cash/Stars/Flop/PLO8-6max-USD-0.01-0.02-200911.txt new file mode 100644 index 00000000..fb96f3f9 --- /dev/null +++ b/pyfpdb/regression-test-files/cash/Stars/Flop/PLO8-6max-USD-0.01-0.02-200911.txt @@ -0,0 +1,602 @@ +PokerStars Game #35874998500: Omaha Hi/Lo Pot Limit ($0.01/$0.02 USD) - 2009/11/26 10:36:51 ET +Table 'Gaby II' 6-max Seat #3 is the button +Seat 1: EricSteph261 ($11.27 in chips) +Seat 2: UnderMeSensi ($3.33 in chips) +Seat 3: supermeXXX ($1.19 in chips) +Seat 4: xgz520 ($1.81 in chips) +Seat 5: s0rrow ($3 in chips) +Seat 6: tiger48475 ($5 in chips) +xgz520: posts small blind $0.01 +s0rrow: posts big blind $0.02 +*** HOLE CARDS *** +Dealt to s0rrow [2h 2c 3s 9h] +tiger48475: folds +EricSteph261: folds +UnderMeSensi: raises $0.05 to $0.07 +supermeXXX: folds +xgz520: folds +s0rrow: calls $0.05 +*** FLOP *** [Jd 5c Kc] +s0rrow: checks +UnderMeSensi: checks +*** TURN *** [Jd 5c Kc] [4c] +s0rrow: checks +UnderMeSensi: bets $0.08 +s0rrow: calls $0.08 +*** RIVER *** [Jd 5c Kc 4c] [Th] +s0rrow: checks +UnderMeSensi: bets $0.31 +EricSteph261 is sitting out +s0rrow: folds +Uncalled bet ($0.31) returned to UnderMeSensi +UnderMeSensi collected $0.31 from pot +UnderMeSensi: doesn't show hand +*** SUMMARY *** +Total pot $0.31 | Rake $0 +Board [Jd 5c Kc 4c Th] +Seat 1: EricSteph261 folded before Flop (didn't bet) +Seat 2: UnderMeSensi collected ($0.31) +Seat 3: supermeXXX (button) folded before Flop (didn't bet) +Seat 4: xgz520 (small blind) folded before Flop +Seat 5: s0rrow (big blind) folded on the River +Seat 6: tiger48475 folded before Flop (didn't bet) + + + +PokerStars Game #35875026976: Omaha Hi/Lo Pot Limit ($0.01/$0.02 USD) - 2009/11/26 10:37:39 ET +Table 'Gaby II' 6-max Seat #4 is the button +Seat 2: UnderMeSensi ($3.49 in chips) +Seat 3: supermeXXX ($1.19 in chips) +Seat 4: xgz520 ($1.80 in chips) +Seat 5: s0rrow ($2.85 in chips) +Seat 6: tiger48475 ($5 in chips) +s0rrow: posts small blind $0.01 +tiger48475: posts big blind $0.02 +*** HOLE CARDS *** +Dealt to s0rrow [4d 3s 8d Jd] +UnderMeSensi: raises $0.05 to $0.07 +supermeXXX: folds +xgz520: folds +s0rrow: folds +tiger48475: folds +Uncalled bet ($0.05) returned to UnderMeSensi +xgz520 leaves the table +UnderMeSensi collected $0.05 from pot +UnderMeSensi: doesn't show hand +*** SUMMARY *** +Total pot $0.05 | Rake $0 +Seat 2: UnderMeSensi collected ($0.05) +Seat 3: supermeXXX folded before Flop (didn't bet) +Seat 4: xgz520 (button) folded before Flop (didn't bet) +Seat 5: s0rrow (small blind) folded before Flop +Seat 6: tiger48475 (big blind) folded before Flop + + + +PokerStars Game #35875034981: Omaha Hi/Lo Pot Limit ($0.01/$0.02 USD) - 2009/11/26 10:37:53 ET +Table 'Gaby II' 6-max Seat #5 is the button +Seat 2: UnderMeSensi ($3.52 in chips) +Seat 3: supermeXXX ($1.19 in chips) +Seat 5: s0rrow ($2.84 in chips) +Seat 6: tiger48475 ($5 in chips) +tiger48475: posts small blind $0.01 +UnderMeSensi: posts big blind $0.02 +*** HOLE CARDS *** +Dealt to s0rrow [Qh 6c Th 9c] +supermeXXX: raises $0.04 to $0.06 +s0rrow: calls $0.06 +tiger48475: folds +UnderMeSensi: calls $0.04 +*** FLOP *** [5h 4d 2d] +UnderMeSensi: checks +supermeXXX: bets $0.10 +s0rrow: folds +UnderMeSensi: calls $0.10 +*** TURN *** [5h 4d 2d] [Jd] +UnderMeSensi: checks +supermeXXX: checks +*** RIVER *** [5h 4d 2d Jd] [6h] +UnderMeSensi: checks +supermeXXX: checks +*** SHOW DOWN *** +UnderMeSensi: shows [7c 6s 7h As] (HI: a pair of Sevens; LO: 6,5,4,2,A) +supermeXXX: shows [Ah 2h Kh 2s] (HI: three of a kind, Deuces; LO: 6,5,4,2,A) +supermeXXX collected $0.20 from pot +UnderMeSensi collected $0.10 from pot +supermeXXX collected $0.09 from pot +*** SUMMARY *** +Total pot $0.39 | Rake $0 +Board [5h 4d 2d Jd 6h] +Seat 2: UnderMeSensi (big blind) showed [7c 6s 7h As] and won ($0.10) with HI: a pair of Sevens; LO: 6,5,4,2,A +Seat 3: supermeXXX showed [Ah 2h Kh 2s] and won ($0.29) with HI: three of a kind, Deuces; LO: 6,5,4,2,A +Seat 5: s0rrow (button) folded on the Flop +Seat 6: tiger48475 (small blind) folded before Flop + + + +PokerStars Game #35875059163: Omaha Hi/Lo Pot Limit ($0.01/$0.02 USD) - 2009/11/26 10:38:34 ET +Table 'Gaby II' 6-max Seat #6 is the button +Seat 2: UnderMeSensi ($3.46 in chips) +Seat 3: supermeXXX ($1.32 in chips) +Seat 5: s0rrow ($2.78 in chips) +Seat 6: tiger48475 ($5 in chips) +UnderMeSensi: posts small blind $0.01 +supermeXXX: posts big blind $0.02 +*** HOLE CARDS *** +Dealt to s0rrow [Ts Qs 9d 7c] +s0rrow: raises $0.04 to $0.06 +tiger48475: folds +UnderMeSensi: calls $0.05 +diyi69 joins the table at seat #4 +supermeXXX: folds +*** FLOP *** [3h Ah 5d] +UnderMeSensi: checks +s0rrow: checks +*** TURN *** [3h Ah 5d] [Kc] +UnderMeSensi: checks +s0rrow: bets $0.14 +UnderMeSensi: folds +Uncalled bet ($0.14) returned to s0rrow +s0rrow collected $0.14 from pot +*** SUMMARY *** +Total pot $0.14 | Rake $0 +Board [3h Ah 5d Kc] +Seat 2: UnderMeSensi (small blind) folded on the Turn +Seat 3: supermeXXX (big blind) folded before Flop +Seat 5: s0rrow collected ($0.14) +Seat 6: tiger48475 (button) folded before Flop (didn't bet) + + + +PokerStars Game #35875079294: Omaha Hi/Lo Pot Limit ($0.01/$0.02 USD) - 2009/11/26 10:39:09 ET +Table 'Gaby II' 6-max Seat #2 is the button +Seat 2: UnderMeSensi ($3.40 in chips) +Seat 3: supermeXXX ($1.30 in chips) +Seat 4: diyi69 ($1 in chips) +Seat 5: s0rrow ($2.86 in chips) +Seat 6: tiger48475 ($5 in chips) +supermeXXX: posts small blind $0.01 +diyi69: posts big blind $0.02 +*** HOLE CARDS *** +Dealt to s0rrow [8s 6d 7s 2s] +s0rrow: folds +tiger48475: folds +UnderMeSensi: folds +supermeXXX: calls $0.01 +diyi69 has timed out +diyi69: checks +*** FLOP *** [As Js 5h] +supermeXXX: bets $0.04 +diyi69 has timed out +diyi69: folds +Uncalled bet ($0.04) returned to supermeXXX +diyi69 is sitting out +supermeXXX collected $0.04 from pot +*** SUMMARY *** +Total pot $0.04 | Rake $0 +Board [As Js 5h] +Seat 2: UnderMeSensi (button) folded before Flop (didn't bet) +Seat 3: supermeXXX (small blind) collected ($0.04) +Seat 4: diyi69 (big blind) folded on the Flop +Seat 5: s0rrow folded before Flop (didn't bet) +Seat 6: tiger48475 folded before Flop (didn't bet) + + + +PokerStars Game #35875131707: Omaha Hi/Lo Pot Limit ($0.01/$0.02 USD) - 2009/11/26 10:40:40 ET +Table 'Gaby II' 6-max Seat #3 is the button +Seat 2: UnderMeSensi ($3.40 in chips) +Seat 3: supermeXXX ($1.32 in chips) +Seat 5: s0rrow ($2.86 in chips) +Seat 6: tiger48475 ($5 in chips) +s0rrow: posts small blind $0.01 +tiger48475: posts big blind $0.02 +*** HOLE CARDS *** +Dealt to s0rrow [7c As 4d 4h] +UnderMeSensi: calls $0.02 +supermeXXX: folds +s0rrow: calls $0.01 +tiger48475: checks +*** FLOP *** [Ks 9d Ts] +s0rrow: checks +tiger48475: bets $0.06 +UnderMeSensi: calls $0.06 +s0rrow: folds +*** TURN *** [Ks 9d Ts] [7h] +tiger48475: checks +EricSteph261 has returned +UnderMeSensi: checks +*** RIVER *** [Ks 9d Ts 7h] [4s] +tiger48475: checks +UnderMeSensi: bets $0.10 +tiger48475: folds +Uncalled bet ($0.10) returned to UnderMeSensi +UnderMeSensi collected $0.18 from pot +UnderMeSensi: doesn't show hand +*** SUMMARY *** +Total pot $0.18 | Rake $0 +Board [Ks 9d Ts 7h 4s] +Seat 2: UnderMeSensi collected ($0.18) +Seat 3: supermeXXX (button) folded before Flop (didn't bet) +Seat 5: s0rrow (small blind) folded on the Flop +Seat 6: tiger48475 (big blind) folded on the River + + + +PokerStars Game #35875159084: Omaha Hi/Lo Pot Limit ($0.01/$0.02 USD) - 2009/11/26 10:41:27 ET +Table 'Gaby II' 6-max Seat #5 is the button +Seat 1: EricSteph261 ($11.27 in chips) +Seat 2: UnderMeSensi ($3.50 in chips) +Seat 3: supermeXXX ($1.32 in chips) +Seat 5: s0rrow ($2.84 in chips) +Seat 6: tiger48475 ($5 in chips) +tiger48475: posts small blind $0.01 +EricSteph261: posts big blind $0.02 +*** HOLE CARDS *** +Dealt to s0rrow [Jc 3h 2s Qc] +UnderMeSensi: calls $0.02 +supermeXXX: calls $0.02 +s0rrow: raises $0.08 to $0.10 +tiger48475: folds +EricSteph261: folds +UnderMeSensi: calls $0.08 +supermeXXX: folds +*** FLOP *** [Ac 5s Js] +UnderMeSensi: checks +s0rrow: bets $0.20 +UnderMeSensi: calls $0.20 +*** TURN *** [Ac 5s Js] [8c] +UnderMeSensi: checks +s0rrow: bets $0.50 +UnderMeSensi: calls $0.50 +*** RIVER *** [Ac 5s Js 8c] [Jd] +UnderMeSensi: bets $1.60 +s0rrow: calls $1.60 +*** SHOW DOWN *** +UnderMeSensi: shows [7s 9s Jh 3c] (HI: three of a kind, Jacks; LO: 8,7,5,3,A) +s0rrow: shows [Jc 3h 2s Qc] (HI: three of a kind, Jacks - Ace+Queen kicker; LO: 8,5,3,2,A) +s0rrow collected $2.33 from pot +s0rrow collected $2.32 from pot +*** SUMMARY *** +Total pot $4.85 | Rake $0.20 +Board [Ac 5s Js 8c Jd] +Seat 1: EricSteph261 (big blind) folded before Flop +Seat 2: UnderMeSensi showed [7s 9s Jh 3c] and lost with HI: three of a kind, Jacks; LO: 8,7,5,3,A +Seat 3: supermeXXX folded before Flop +Seat 5: s0rrow (button) showed [Jc 3h 2s Qc] and won ($4.65) with HI: three of a kind, Jacks; LO: 8,5,3,2,A +Seat 6: tiger48475 (small blind) folded before Flop + + + +PokerStars Game #35875194885: Omaha Hi/Lo Pot Limit ($0.01/$0.02 USD) - 2009/11/26 10:42:28 ET +Table 'Gaby II' 6-max Seat #6 is the button +Seat 1: EricSteph261 ($11.25 in chips) +Seat 2: UnderMeSensi ($1.10 in chips) +Seat 3: supermeXXX ($1.30 in chips) +Seat 5: s0rrow ($5.09 in chips) +Seat 6: tiger48475 ($5 in chips) +EricSteph261: posts small blind $0.01 +UnderMeSensi: posts big blind $0.02 +*** HOLE CARDS *** +Dealt to s0rrow [7s 3c 3h 8d] +supermeXXX: folds +s0rrow: raises $0.02 to $0.04 +tiger48475: calls $0.04 +EricSteph261: calls $0.03 +UnderMeSensi: calls $0.02 +*** FLOP *** [8c 3s 4s] +EricSteph261: checks +UnderMeSensi: checks +s0rrow: bets $0.14 +tiger48475: folds +EricSteph261: folds +UnderMeSensi: folds +Uncalled bet ($0.14) returned to s0rrow +s0rrow collected $0.16 from pot +*** SUMMARY *** +Total pot $0.16 | Rake $0 +Board [8c 3s 4s] +Seat 1: EricSteph261 (small blind) folded on the Flop +Seat 2: UnderMeSensi (big blind) folded on the Flop +Seat 3: supermeXXX folded before Flop (didn't bet) +Seat 5: s0rrow collected ($0.16) +Seat 6: tiger48475 (button) folded on the Flop + + + +PokerStars Game #35875219121: Omaha Hi/Lo Pot Limit ($0.01/$0.02 USD) - 2009/11/26 10:43:08 ET +Table 'Gaby II' 6-max Seat #1 is the button +Seat 1: EricSteph261 ($11.21 in chips) +Seat 2: UnderMeSensi ($1.06 in chips) +Seat 3: supermeXXX ($1.30 in chips) +Seat 5: s0rrow ($5.21 in chips) +Seat 6: tiger48475 ($5 in chips) +UnderMeSensi: posts small blind $0.01 +supermeXXX: posts big blind $0.02 +*** HOLE CARDS *** +Dealt to s0rrow [Ks Qd Kd Kc] +s0rrow: raises $0.04 to $0.06 +tiger48475: folds +EricSteph261: calls $0.06 +UnderMeSensi: calls $0.05 +supermeXXX: calls $0.04 +*** FLOP *** [2d Jh 5h] +UnderMeSensi: checks +supermeXXX: checks +s0rrow: checks +EricSteph261: checks +*** TURN *** [2d Jh 5h] [Js] +UnderMeSensi: checks +supermeXXX: checks +s0rrow: checks +EricSteph261: checks +*** RIVER *** [2d Jh 5h Js] [7s] +UnderMeSensi: checks +supermeXXX: checks +s0rrow: checks +EricSteph261: checks +*** SHOW DOWN *** +UnderMeSensi: shows [5d 6c As 9d] (HI: two pair, Jacks and Fives; LO: 7,6,5,2,A) +supermeXXX: shows [6s Th 7c Ac] (HI: two pair, Jacks and Sevens; LO: 7,6,5,2,A) +s0rrow: shows [Ks Qd Kd Kc] (HI: two pair, Kings and Jacks) +EricSteph261: shows [4s 9c 3d 2c] (HI: two pair, Jacks and Deuces; LO: 7,5,4,3,2) +s0rrow collected $0.12 from pot +EricSteph261 collected $0.12 from pot +*** SUMMARY *** +Total pot $0.24 | Rake $0 +Board [2d Jh 5h Js 7s] +Seat 1: EricSteph261 (button) showed [4s 9c 3d 2c] and won ($0.12) with HI: two pair, Jacks and Deuces; LO: 7,5,4,3,2 +Seat 2: UnderMeSensi (small blind) showed [5d 6c As 9d] and lost with HI: two pair, Jacks and Fives; LO: 7,6,5,2,A +Seat 3: supermeXXX (big blind) showed [6s Th 7c Ac] and lost with HI: two pair, Jacks and Sevens; LO: 7,6,5,2,A +Seat 5: s0rrow showed [Ks Qd Kd Kc] and won ($0.12) with HI: two pair, Kings and Jacks +Seat 6: tiger48475 folded before Flop (didn't bet) + + + +PokerStars Game #35875246335: Omaha Hi/Lo Pot Limit ($0.01/$0.02 USD) - 2009/11/26 10:43:54 ET +Table 'Gaby II' 6-max Seat #2 is the button +Seat 1: EricSteph261 ($11.27 in chips) +Seat 2: UnderMeSensi ($1 in chips) +Seat 3: supermeXXX ($1.24 in chips) +Seat 5: s0rrow ($5.27 in chips) +Seat 6: tiger48475 ($5 in chips) +supermeXXX: posts small blind $0.01 +s0rrow: posts big blind $0.02 +*** HOLE CARDS *** +Dealt to s0rrow [Jd Kc 6h Jc] +tiger48475: folds +EricSteph261: calls $0.02 +UnderMeSensi is disconnected +UnderMeSensi has timed out while disconnected +UnderMeSensi: folds +UnderMeSensi is sitting out +supermeXXX: calls $0.01 +s0rrow: checks +*** FLOP *** [8d 7s Qh] +supermeXXX: bets $0.02 +s0rrow: folds +EricSteph261: calls $0.02 +*** TURN *** [8d 7s Qh] [As] +supermeXXX: bets $0.04 +EricSteph261: calls $0.04 +*** RIVER *** [8d 7s Qh As] [5d] +supermeXXX: checks +EricSteph261: checks +*** SHOW DOWN *** +supermeXXX: shows [Kh Qd 9s Th] (HI: a pair of Queens) +EricSteph261: shows [Jh 2d 5s 6c] (HI: a pair of Fives; LO: 7,6,5,2,A) +supermeXXX collected $0.09 from pot +EricSteph261 collected $0.09 from pot +*** SUMMARY *** +Total pot $0.18 | Rake $0 +Board [8d 7s Qh As 5d] +Seat 1: EricSteph261 showed [Jh 2d 5s 6c] and won ($0.09) with HI: a pair of Fives; LO: 7,6,5,2,A +Seat 2: UnderMeSensi (button) folded before Flop (didn't bet) +Seat 3: supermeXXX (small blind) showed [Kh Qd 9s Th] and won ($0.09) with HI: a pair of Queens +Seat 5: s0rrow (big blind) folded on the Flop +Seat 6: tiger48475 folded before Flop (didn't bet) + + + +PokerStars Game #35875293439: Omaha Hi/Lo Pot Limit ($0.01/$0.02 USD) - 2009/11/26 10:45:14 ET +Table 'Gaby II' 6-max Seat #3 is the button +Seat 1: EricSteph261 ($11.28 in chips) +Seat 3: supermeXXX ($1.25 in chips) +Seat 5: s0rrow ($5.25 in chips) +Seat 6: tiger48475 ($5 in chips) +s0rrow: posts small blind $0.01 +tiger48475: posts big blind $0.02 +*** HOLE CARDS *** +Dealt to s0rrow [9c 8h 8s 3c] +EricSteph261: calls $0.02 +supermeXXX: calls $0.02 +s0rrow: calls $0.01 +tiger48475: checks +*** FLOP *** [Ah 2d Qc] +s0rrow: checks +tiger48475: checks +EricSteph261: checks +supermeXXX: checks +*** TURN *** [Ah 2d Qc] [3d] +s0rrow: checks +tiger48475: checks +EricSteph261: checks +supermeXXX: checks +*** RIVER *** [Ah 2d Qc 3d] [6s] +s0rrow: checks +tiger48475: checks +EricSteph261: checks +supermeXXX: checks +*** SHOW DOWN *** +s0rrow: shows [9c 8h 8s 3c] (HI: a pair of Eights; LO: 8,6,3,2,A) +tiger48475: shows [3s 5s Ts Th] (HI: a pair of Tens; LO: 6,5,3,2,A) +EricSteph261: shows [As Ks Jh 7h] (HI: a pair of Aces; LO: 7,6,3,2,A) +supermeXXX: mucks hand +EricSteph261 collected $0.04 from pot +tiger48475 collected $0.04 from pot +*** SUMMARY *** +Total pot $0.08 | Rake $0 +Board [Ah 2d Qc 3d 6s] +Seat 1: EricSteph261 showed [As Ks Jh 7h] and won ($0.04) with HI: a pair of Aces; LO: 7,6,3,2,A +Seat 3: supermeXXX (button) mucked [9h 9s 4c Kc] +Seat 5: s0rrow (small blind) showed [9c 8h 8s 3c] and lost with HI: a pair of Eights; LO: 8,6,3,2,A +Seat 6: tiger48475 (big blind) showed [3s 5s Ts Th] and won ($0.04) with HI: a pair of Tens; LO: 6,5,3,2,A + + + +PokerStars Game #35875328026: Omaha Hi/Lo Pot Limit ($0.01/$0.02 USD) - 2009/11/26 10:46:13 ET +Table 'Gaby II' 6-max Seat #5 is the button +Seat 1: EricSteph261 ($11.30 in chips) +Seat 3: supermeXXX ($1.23 in chips) +Seat 5: s0rrow ($5.23 in chips) +Seat 6: tiger48475 ($5.02 in chips) +tiger48475: posts small blind $0.01 +EricSteph261: posts big blind $0.02 +*** HOLE CARDS *** +Dealt to s0rrow [Qd 6h 8s 6c] +supermeXXX: calls $0.02 +s0rrow: folds +tiger48475: calls $0.01 +EricSteph261: checks +*** FLOP *** [Kc Ac 5s] +tiger48475: checks +EricSteph261: checks +supermeXXX: checks +*** TURN *** [Kc Ac 5s] [3h] +tiger48475: checks +EricSteph261: checks +supermeXXX: checks +*** RIVER *** [Kc Ac 5s 3h] [Qh] +tiger48475: bets $0.06 +EricSteph261: folds +EricSteph261 is sitting out +supermeXXX: folds +Uncalled bet ($0.06) returned to tiger48475 +tiger48475 collected $0.06 from pot +*** SUMMARY *** +Total pot $0.06 | Rake $0 +Board [Kc Ac 5s 3h Qh] +Seat 1: EricSteph261 (big blind) folded on the River +Seat 3: supermeXXX folded on the River +Seat 5: s0rrow (button) folded before Flop (didn't bet) +Seat 6: tiger48475 (small blind) collected ($0.06) + + + +PokerStars Game #35875356253: Omaha Hi/Lo Pot Limit ($0.01/$0.02 USD) - 2009/11/26 10:47:00 ET +Table 'Gaby II' 6-max Seat #6 is the button +Seat 3: supermeXXX ($1.21 in chips) +Seat 5: s0rrow ($5.23 in chips) +Seat 6: tiger48475 ($5.06 in chips) +supermeXXX: posts small blind $0.01 +s0rrow: posts big blind $0.02 +*** HOLE CARDS *** +Dealt to s0rrow [8h Jd 5d 8d] +tiger48475: folds +supermeXXX: calls $0.01 +s0rrow: checks +*** FLOP *** [Ks 9s 6c] +supermeXXX: bets $0.02 +s0rrow: calls $0.02 +*** TURN *** [Ks 9s 6c] [Qc] +supermeXXX: bets $0.02 +s0rrow: calls $0.02 +*** RIVER *** [Ks 9s 6c Qc] [Ad] +supermeXXX: checks +s0rrow: checks +*** SHOW DOWN *** +supermeXXX: shows [Tc 7d 8c 3s] (HI: high card Ace) +s0rrow: shows [8h Jd 5d 8d] (HI: a pair of Eights) +s0rrow collected $0.12 from pot +No low hand qualified +*** SUMMARY *** +Total pot $0.12 | Rake $0 +Board [Ks 9s 6c Qc Ad] +Seat 3: supermeXXX (small blind) showed [Tc 7d 8c 3s] and lost with HI: high card Ace +Seat 5: s0rrow (big blind) showed [8h Jd 5d 8d] and won ($0.12) with HI: a pair of Eights +Seat 6: tiger48475 (button) folded before Flop (didn't bet) + + + +PokerStars Game #35875379792: Omaha Hi/Lo Pot Limit ($0.01/$0.02 USD) - 2009/11/26 10:47:39 ET +Table 'Gaby II' 6-max Seat #3 is the button +Seat 3: supermeXXX ($1.15 in chips) +Seat 5: s0rrow ($5.29 in chips) +Seat 6: tiger48475 ($5.06 in chips) +s0rrow: posts small blind $0.01 +tiger48475: posts big blind $0.02 +*** HOLE CARDS *** +Dealt to s0rrow [9c 5h 3s Th] +supermeXXX: calls $0.02 +s0rrow: calls $0.01 +tiger48475: checks +*** FLOP *** [Jc 3h Jd] +s0rrow: checks +tiger48475: checks +supermeXXX: checks +*** TURN *** [Jc 3h Jd] [6d] +s0rrow: checks +tiger48475: bets $0.06 +supermeXXX: folds +EricSteph261 has returned +s0rrow: calls $0.06 +*** RIVER *** [Jc 3h Jd 6d] [5c] +s0rrow: checks +tiger48475: bets $0.14 +s0rrow: folds +Uncalled bet ($0.14) returned to tiger48475 +tiger48475 collected $0.18 from pot +*** SUMMARY *** +Total pot $0.18 | Rake $0 +Board [Jc 3h Jd 6d 5c] +Seat 3: supermeXXX (button) folded on the Turn +Seat 5: s0rrow (small blind) folded on the River +Seat 6: tiger48475 (big blind) collected ($0.18) + + + +PokerStars Game #35875409365: Omaha Hi/Lo Pot Limit ($0.01/$0.02 USD) - 2009/11/26 10:48:29 ET +Table 'Gaby II' 6-max Seat #5 is the button +Seat 1: EricSteph261 ($11.28 in chips) +Seat 3: supermeXXX ($1.13 in chips) +Seat 5: s0rrow ($5.21 in chips) +Seat 6: tiger48475 ($5.16 in chips) +tiger48475: posts small blind $0.01 +EricSteph261: posts big blind $0.02 +*** HOLE CARDS *** +Dealt to s0rrow [6h 3c Th 2s] +supermeXXX: calls $0.02 +s0rrow: calls $0.02 +tiger48475: calls $0.01 +EricSteph261 has timed out +EricSteph261: checks +*** FLOP *** [9d 5s Jh] +tiger48475: bets $0.06 +EricSteph261 has timed out +EricSteph261: folds +EricSteph261 is sitting out +supermeXXX: calls $0.06 +s0rrow: calls $0.06 +*** TURN *** [9d 5s Jh] [Ks] +tiger48475: checks +supermeXXX: bets $0.10 +s0rrow: folds +tiger48475: calls $0.10 +*** RIVER *** [9d 5s Jh Ks] [9s] +tiger48475: checks +supermeXXX: checks +*** SHOW DOWN *** +tiger48475: shows [6s 9h 9c Ad] (HI: four of a kind, Nines) +supermeXXX: mucks hand +tiger48475 collected $0.46 from pot +No low hand qualified +*** SUMMARY *** +Total pot $0.46 | Rake $0 +Board [9d 5s Jh Ks 9s] +Seat 1: EricSteph261 (big blind) folded on the Flop +Seat 3: supermeXXX mucked [Qd Tc 5h Ts] +Seat 5: s0rrow (button) folded on the Turn +Seat 6: tiger48475 (small blind) showed [6s 9h 9c Ad] and won ($0.46) with HI: four of a kind, Nines + + + diff --git a/pyfpdb/regression-test-files/cash/Stars/Stud/7-StudHL-USD-0.04-0.08-200911.Cardtest.txt b/pyfpdb/regression-test-files/cash/Stars/Stud/7-StudHL-USD-0.04-0.08-200911.Cardtest.txt new file mode 100644 index 00000000..0ffdcc3d --- /dev/null +++ b/pyfpdb/regression-test-files/cash/Stars/Stud/7-StudHL-USD-0.04-0.08-200911.Cardtest.txt @@ -0,0 +1,96 @@ +PokerStars Game #35874676388: 7 Card Stud Hi/Lo Limit ($0.04/$0.08 USD) - 2009/11/26 10:27:46 ET +Table 'Dawn II' 8-max +Seat 1: u.pressure ($11.17 in chips) +Seat 2: 123smoothie ($0.99 in chips) +Seat 3: gashpor ($1.40 in chips) +Seat 4: denny501 ($0.71 in chips) +Seat 5: s0rrow ($1.52 in chips) +Seat 6: TomSludge ($1.58 in chips) +Seat 7: Soroka69 ($0.83 in chips) +Seat 8: rdiezchang ($2.05 in chips) +u.pressure: posts the ante $0.01 +123smoothie: posts the ante $0.01 +gashpor: posts the ante $0.01 +denny501: posts the ante $0.01 +s0rrow: posts the ante $0.01 +TomSludge: posts the ante $0.01 +Soroka69: posts the ante $0.01 +rdiezchang: posts the ante $0.01 +*** 3rd STREET *** +Dealt to u.pressure [Td] +Dealt to 123smoothie [4c] +Dealt to gashpor [5d] +Dealt to denny501 [2c] +Dealt to s0rrow [7c 3s 5h] +Dealt to TomSludge [8s] +Dealt to Soroka69 [7d] +Dealt to rdiezchang [Ad] +denny501: brings in for $0.02 +s0rrow: calls $0.02 +TomSludge: folds +Soroka69: calls $0.02 +rdiezchang: calls $0.02 +u.pressure: folds +123smoothie: calls $0.02 +gashpor: calls $0.02 +*** 4th STREET *** +Dealt to 123smoothie [4c] [3c] +Dealt to gashpor [5d] [Qd] +Dealt to denny501 [2c] [7s] +Dealt to s0rrow [7c 3s 5h] [Qc] +Dealt to Soroka69 [7d] [5s] +Dealt to rdiezchang [Ad] [Js] +rdiezchang: checks +123smoothie: checks +gashpor: checks +denny501: folds +denny501 leaves the table +s0rrow: checks +Soroka69: checks +*** 5th STREET *** +Dealt to 123smoothie [4c 3c] [9s] +Dealt to gashpor [5d Qd] [Jd] +Dealt to s0rrow [7c 3s 5h Qc] [Kc] +Dealt to Soroka69 [7d 5s] [5c] +Dealt to rdiezchang [Ad Js] [Ts] +LainaRahat joins the table at seat #4 +Soroka69: checks +rdiezchang: checks +123smoothie: checks +gashpor: bets $0.08 +s0rrow: calls $0.08 +Soroka69: calls $0.08 +rdiezchang: folds +123smoothie: folds +*** 6th STREET *** +Dealt to gashpor [5d Qd Jd] [9d] +Dealt to s0rrow [7c 3s 5h Qc Kc] [6d] +Dealt to Soroka69 [7d 5s 5c] [2s] +Soroka69: checks +gashpor: bets $0.08 +s0rrow: calls $0.08 +Soroka69: calls $0.08 +*** RIVER *** +Dealt to s0rrow [7c 3s 5h Qc Kc 6d] [4d] +Soroka69: checks +gashpor: bets $0.08 +s0rrow: calls $0.08 +Soroka69: folds +*** SHOW DOWN *** +gashpor: shows [4h 3d 5d Qd Jd 9d 6h] (HI: a flush, Queen high) +s0rrow: shows [7c 3s 5h Qc Kc 6d 4d] (HI: a straight, Three to Seven; LO: 7,6,5,4,3) +gashpor collected $0.40 from pot +s0rrow collected $0.40 from pot +*** SUMMARY *** +Total pot $0.84 | Rake $0.04 +Seat 1: u.pressure folded on the 3rd Street (didn't bet) +Seat 2: 123smoothie folded on the 5th Street +Seat 3: gashpor showed [4h 3d 5d Qd Jd 9d 6h] and won ($0.40) with HI: a flush, Queen high +Seat 4: denny501 folded on the 4th Street +Seat 5: s0rrow showed [7c 3s 5h Qc Kc 6d 4d] and won ($0.40) with HI: a straight, Three to Seven; LO: 7,6,5,4,3 +Seat 6: TomSludge folded on the 3rd Street (didn't bet) +Seat 7: Soroka69 folded on the River +Seat 8: rdiezchang folded on the 5th Street + + + From 68835dd9b809cdd99165c511d4b750f6ebdc7287 Mon Sep 17 00:00:00 2001 From: sqlcoder Date: Mon, 7 Dec 2009 22:55:12 +0000 Subject: [PATCH 38/65] tidy up log viewer some more --- pyfpdb/GuiLogView.py | 25 ++++++++++++++++---- pyfpdb/fpdb.py | 55 ++++++++++++++++++++++++-------------------- 2 files changed, 51 insertions(+), 29 deletions(-) diff --git a/pyfpdb/GuiLogView.py b/pyfpdb/GuiLogView.py index 3b7b8aa6..8f4cd834 100755 --- a/pyfpdb/GuiLogView.py +++ b/pyfpdb/GuiLogView.py @@ -18,6 +18,7 @@ import mmap +import threading import pygtk pygtk.require('2.0') @@ -33,14 +34,20 @@ MAX_LINES = 100000 class GuiLogView: - def __init__(self, config, mainwin, vbox): + def __init__(self, config, mainwin): self.config = config self.main_window = mainwin - self.vbox = vbox + + self.dia = gtk.Dialog(title="Log Messages" + ,parent=None + ,flags=gtk.DIALOG_DESTROY_WITH_PARENT + ,buttons=(gtk.STOCK_CLOSE,gtk.RESPONSE_OK)) + self.dia.set_modal(False) + + self.vbox = self.dia.vbox gtk.Widget.set_size_request(self.vbox, 700, 400); self.liststore = gtk.ListStore(str, str, str, str, gobject.TYPE_BOOLEAN) # date, module, level, text - # this is how to add a filter: # # # Creation of the filter, from the model @@ -49,7 +56,6 @@ class GuiLogView: # # # The TreeView gets the filter as model # self.listview = gtk.TreeView(filter) - self.listview = gtk.TreeView(model=self.liststore) self.listview.set_grid_lines(gtk.TREE_VIEW_GRID_LINES_NONE) self.listcols = [] @@ -67,6 +73,7 @@ class GuiLogView: self.listview.show() scrolledwindow.show() self.vbox.show() + self.dia.set_focus(self.listview) col = self.addColumn("Date/Time", 0) col = self.addColumn("Module", 1) @@ -75,6 +82,16 @@ class GuiLogView: self.loadLog() self.vbox.show_all() + self.dia.show() + + self.dia.connect('response', self.dialog_response_cb) + + def dialog_response_cb(self, dialog, response_id): + # this is called whether close button is pressed or window is closed + dialog.destroy() + + def get_dialog(self): + return self.dia def addColumn(self, title, n): col = gtk.TreeViewColumn(title) diff --git a/pyfpdb/fpdb.py b/pyfpdb/fpdb.py index 79567578..2266a981 100755 --- a/pyfpdb/fpdb.py +++ b/pyfpdb/fpdb.py @@ -101,12 +101,12 @@ class fpdb: def add_tab(self, new_page, new_tab_name): """adds a tab, namely creates the button and displays it and appends all the relevant arrays""" - for name in self.nb_tabs: #todo: check this is valid + for name in self.nb_tab_names: #todo: check this is valid if name == new_tab_name: return # if tab already exists, just go to it used_before = False - for i, name in enumerate(self.tab_names): #todo: check this is valid + for i, name in enumerate(self.tab_names): if name == new_tab_name: used_before = True event_box = self.tabs[i] @@ -122,13 +122,13 @@ class fpdb: #self.nb.append_page(new_page, gtk.Label(new_tab_name)) self.nb.append_page(page, event_box) - self.nb_tabs.append(new_tab_name) + self.nb_tab_names.append(new_tab_name) page.show() def display_tab(self, new_tab_name): """displays the indicated tab""" tab_no = -1 - for i, name in enumerate(self.nb_tabs): + for i, name in enumerate(self.nb_tab_names): if new_tab_name == name: tab_no = i break @@ -179,13 +179,13 @@ class fpdb: (nb, text) = data page = -1 #print "\n remove_tab: start", text - for i, tab in enumerate(self.nb_tabs): + for i, tab in enumerate(self.nb_tab_names): if text == tab: page = i #print " page =", page if page >= 0 and page < self.nb.get_n_pages(): #print " removing page", page - del self.nb_tabs[page] + del self.nb_tab_names[page] nb.remove_page(page) # Need to refresh the widget -- # This forces the widget to redraw itself. @@ -210,6 +210,9 @@ class fpdb: dia.set_program_name("FPDB") dia.run() dia.destroy() + log.debug("Threads: ") + for t in self.threads: + log.debug("........." + str(t.__class__)) def dia_preferences(self, widget, data=None): dia = gtk.Dialog("Preferences", @@ -418,22 +421,23 @@ class fpdb: self.release_global_lock() def dia_logs(self, widget, data=None): - lock_set = False - if self.obtain_global_lock(): - lock_set = True + """opens the log viewer window""" - dia = gtk.Dialog(title="Log Messages" - ,parent=None - ,flags=0 - ,buttons=(gtk.STOCK_CLOSE,gtk.RESPONSE_OK)) - logviewer = GuiLogView.GuiLogView(self.config, self.window, dia.vbox) - response = dia.run() - if response == gtk.RESPONSE_ACCEPT: - pass - dia.destroy() + #lock_set = False + #if self.obtain_global_lock(): + # lock_set = True - if lock_set: - self.release_global_lock() + for i, t in enumerate(self.threads): + if str(t.__class__) == 'GuiLogView.GuiLogView': + # show existing log window + t.get_dialog().present() + return + + new_thread = GuiLogView.GuiLogView(self.config, self.window) + self.threads.append(new_thread) + + #if lock_set: + # self.release_global_lock() def addLogText(self, text): end_iter = self.logbuffer.get_end_iter() @@ -758,7 +762,6 @@ This program is licensed under the AGPL3, see docs"""+os.sep+"agpl-3.0.txt") self.add_and_display_tab(gv_tab, "Graphs") def __init__(self): - self.threads = [] # no more than 1 process can this lock at a time: self.lock = interlocks.InterProcessLock(name="fpdb_global_lock") self.db = None @@ -782,14 +785,16 @@ This program is licensed under the AGPL3, see docs"""+os.sep+"agpl-3.0.txt") menubar.show() #done menubar + self.threads = [] # objects used by tabs - no need for threads, gtk handles it + self.nb = gtk.Notebook() self.nb.set_show_tabs(True) self.nb.show() self.main_vbox.pack_start(self.nb, True, True, 0) - self.pages=[] - self.tabs=[] - self.tab_names=[] - self.nb_tabs=[] + self.tabs=[] # the event_boxes forming the actual tabs + self.tab_names=[] # names of tabs used since program started, not removed if tab is closed + self.pages=[] # the contents of the page, not removed if tab is closed + self.nb_tab_names=[] # list of tab names currently displayed in notebook self.tab_main_help(None, None) From bbaecc1697fee02b3d937b07e9228ebb97599775 Mon Sep 17 00:00:00 2001 From: sqlcoder Date: Tue, 8 Dec 2009 22:17:55 +0000 Subject: [PATCH 39/65] add package version info to About dialog --- pyfpdb/fpdb.py | 49 +++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 49 insertions(+) diff --git a/pyfpdb/fpdb.py b/pyfpdb/fpdb.py index d40f65bd..8b21a8c7 100755 --- a/pyfpdb/fpdb.py +++ b/pyfpdb/fpdb.py @@ -73,6 +73,7 @@ try: import pygtk pygtk.require('2.0') import gtk + import pango except: print "Unable to load PYGTK modules required for GUI. Please install PyCairo, PyGObject, and PyGTK from www.pygtk.org." raw_input("Press ENTER to continue.") @@ -80,6 +81,24 @@ except: import interlocks +# these imports not required in this module, imported here to report version in About dialog +try: + import matplotlib + matplotlib_version = matplotlib.__version__ +except: + matplotlib_version = 'not found' +try: + import numpy + numpy_version = numpy.__version__ +except: + numpy_version = 'not found' +try: + import sqlite3 + sqlite3_version = sqlite3.version + sqlite_version = sqlite3.sqlite_version +except: + sqlite3_version = 'not found' + sqlite_version = 'not found' import GuiPrefs import GuiLogView @@ -219,6 +238,34 @@ class fpdb: dia.set_website("http://fpdb.sourceforge.net/") dia.set_authors("Steffen, Eratosthenes, s0rrow, EricBlade, _mt, sqlcoder, Bostik, and others") dia.set_program_name("Free Poker Database (FPDB)") + + db_version = "" + #if self.db is not None: + # db_version = self.db.get_version() + nums = [ ('Operating System', os.name) + , ('Python', sys.version[0:3]) + , ('GTK+', '.'.join([str(x) for x in gtk.gtk_version])) + , ('PyGTK', '.'.join([str(x) for x in gtk.pygtk_version])) + , ('matplotlib', matplotlib_version) + , ('numpy', numpy_version) + , ('sqlite3', sqlite3_version) + , ('sqlite', sqlite_version) + , ('database', self.settings['db-server'] + db_version) + ] + versions = gtk.TextBuffer() + w = 20 # width used for module names and version numbers + versions.set_text( '\n'.join( [x[0].rjust(w)+' '+ x[1].ljust(w) for x in nums] ) ) + view = gtk.TextView(versions) + view.set_editable(False) + view.set_justification(gtk.JUSTIFY_CENTER) + view.modify_font(pango.FontDescription('monospace 10')) + view.show() + dia.vbox.pack_end(view, True, True, 2) + l = gtk.Label('Version Information:') + l.set_alignment(0.5, 0.5) + l.show() + dia.vbox.pack_end(l, True, True, 2) + dia.run() dia.destroy() log.debug("Threads: ") @@ -636,9 +683,11 @@ class fpdb: try: self.db = Database.Database(self.config, sql = self.sql) except Exceptions.FpdbMySQLAccessDenied: + #self.db = None self.warning_box("MySQL Server reports: Access denied. Are your permissions set correctly?") exit() except Exceptions.FpdbMySQLNoDatabase: + #self.db = None msg = "MySQL client reports: 2002 or 2003 error. Unable to connect - Please check that the MySQL service has been started" self.warning_box(msg) exit From fc95de82f475ae1fb8818107d94d92bf064cdfe0 Mon Sep 17 00:00:00 2001 From: sqlcoder Date: Wed, 9 Dec 2009 21:58:56 +0000 Subject: [PATCH 40/65] logviewer: avoid memory-mapped files, make it work when opened a second time --- pyfpdb/GuiLogView.py | 57 +++++++++++++++++++------------------------- pyfpdb/fpdb.py | 35 +++++++++++++++++++++++---- 2 files changed, 55 insertions(+), 37 deletions(-) diff --git a/pyfpdb/GuiLogView.py b/pyfpdb/GuiLogView.py index 8f4cd834..29385fa0 100755 --- a/pyfpdb/GuiLogView.py +++ b/pyfpdb/GuiLogView.py @@ -17,8 +17,8 @@ #agpl-3.0.txt in the docs folder of the package. -import mmap -import threading +import os +import Queue import pygtk pygtk.require('2.0') @@ -30,13 +30,16 @@ import Configuration log = Configuration.get_logger("logging.conf", "logview") -MAX_LINES = 100000 +MAX_LINES = 100000 # max lines to display in window +EST_CHARS_PER_LINE = 150 # used to guesstimate number of lines in log file +logfile = 'logging.out' # name of logfile class GuiLogView: - def __init__(self, config, mainwin): + def __init__(self, config, mainwin, closeq): self.config = config self.main_window = mainwin + self.closeq = closeq self.dia = gtk.Dialog(title="Log Messages" ,parent=None @@ -88,6 +91,7 @@ class GuiLogView: def dialog_response_cb(self, dialog, response_id): # this is called whether close button is pressed or window is closed + self.closeq.put(self.__class__) dialog.destroy() def get_dialog(self): @@ -109,39 +113,28 @@ class GuiLogView: def loadLog(self): - #self.configStore = gtk.TreeStore(gobject.TYPE_PYOBJECT, gobject.TYPE_STRING, gobject.TYPE_STRING) - #self.configView = gtk.TreeView(self.configStore) - #self.configView.set_enable_tree_lines(True) self.liststore.clear() self.listcols = [] - # count number of lines in file - f = open('logging.out', "r+") - buf = mmap.mmap(f.fileno(), 0) - readline = buf.readline - lines = 0 - while readline(): - lines += 1 - f.close() + # guesstimate number of lines in file + if os.path.exists(logfile): + stat_info = os.stat(logfile) + lines = stat_info.st_size / EST_CHARS_PER_LINE + print "logview: size =", stat_info.st_size, "lines =", lines - startline = 0 - if lines > MAX_LINES: - # only display from startline if log file is large - startline = lines - MAX_LINES + # set startline to line number to start display from + startline = 0 + if lines > MAX_LINES: + # only display from startline if log file is large + startline = lines - MAX_LINES - f = open('logging.out', "r+") - buf = mmap.mmap(f.fileno(), 0) - readline = buf.readline - l = 0 - line = readline() - while line: - # eg line: - # 2009-12-02 15:23:21,716 - config DEBUG config logger initialised - l = l + 1 - if l > startline and len(line) > 49: - iter = self.liststore.append( (line[0:23], line[26:32], line[39:46], line[48:].strip(), True) ) - line = readline() - f.close() + l = 0 + for line in open(logfile): + # eg line: + # 2009-12-02 15:23:21,716 - config DEBUG config logger initialised + l = l + 1 + if l > startline and len(line) > 49: + iter = self.liststore.append( (line[0:23], line[26:32], line[39:46], line[48:].strip(), True) ) def sortCols(self, col, n): try: diff --git a/pyfpdb/fpdb.py b/pyfpdb/fpdb.py index 8b21a8c7..b7013a92 100755 --- a/pyfpdb/fpdb.py +++ b/pyfpdb/fpdb.py @@ -18,6 +18,7 @@ import os import sys import re +import Queue # if path is set to use an old version of python look for a new one: # (does this work in linux?) @@ -485,14 +486,22 @@ class fpdb: #if self.obtain_global_lock(): # lock_set = True + # remove members from self.threads if close messages received + self.process_close_messages() + + viewer = None for i, t in enumerate(self.threads): if str(t.__class__) == 'GuiLogView.GuiLogView': - # show existing log window - t.get_dialog().present() - return + viewer = t + break - new_thread = GuiLogView.GuiLogView(self.config, self.window) - self.threads.append(new_thread) + if viewer is None: + #print "creating new log viewer" + new_thread = GuiLogView.GuiLogView(self.config, self.window, self.closeq) + self.threads.append(new_thread) + else: + #print "showing existing log viewer" + viewer.get_dialog().present() #if lock_set: # self.release_global_lock() @@ -502,6 +511,21 @@ class fpdb: self.logbuffer.insert(end_iter, text) self.logview.scroll_to_mark(self.logbuffer.get_insert(), 0) + + def process_close_messages(self): + # check for close messages + try: + while True: + name = self.closeq.get(False) + for i, t in enumerate(self.threads): + if str(t.__class__) == str(name): + # thread has ended so remove from list: + del self.threads[i] + break + except Queue.Empty: + # no close messages on queue, do nothing + pass + def __calendar_dialog(self, widget, entry): self.dia_confirm.set_modal(False) d = gtk.Window(gtk.WINDOW_TOPLEVEL) @@ -846,6 +870,7 @@ This program is licensed under the AGPL3, see docs"""+os.sep+"agpl-3.0.txt") #done menubar self.threads = [] # objects used by tabs - no need for threads, gtk handles it + self.closeq = Queue.Queue(20) # used to signal ending of a thread (only logviewer for now) self.nb = gtk.Notebook() self.nb.set_show_tabs(True) From 835fc98f6f0228345943882c8c4cbc0b8fa1405b Mon Sep 17 00:00:00 2001 From: Mika Bostrom Date: Thu, 10 Dec 2009 06:34:19 +0200 Subject: [PATCH 41/65] Cosmetic fix About -> Credits takes a list of strings in .set_authors() as opposed to a single string. Now the credit popup looks about right. --- pyfpdb/fpdb.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/pyfpdb/fpdb.py b/pyfpdb/fpdb.py index d5f4faec..f35e0d24 100755 --- a/pyfpdb/fpdb.py +++ b/pyfpdb/fpdb.py @@ -202,7 +202,8 @@ class fpdb: dia.set_comments("GTK AboutDialog comments here") dia.set_license("GPL v3") dia.set_website("http://fpdb.sourceforge.net/") - dia.set_authors("Steffen, Eratosthenes, s0rrow, EricBlade, _mt, and others") + dia.set_authors(['Steffen', 'Eratosthenes', 's0rrow', + 'EricBlade', '_mt', 'and others']) dia.set_program_name("FPDB") dia.run() dia.destroy() From ab89f9f603fa8ecb2d8a5e93fd2c30aa63b8db41 Mon Sep 17 00:00:00 2001 From: sqlcoder Date: Sat, 12 Dec 2009 09:51:07 +0000 Subject: [PATCH 42/65] show message dialog if pg connect fails --- pyfpdb/Database.py | 12 +++++++++++- pyfpdb/Exceptions.py | 14 ++++++++++++++ pyfpdb/fpdb.py | 37 ++++++++++++++++++++++--------------- pyfpdb/fpdb_db.py | 15 ++++++++++----- 4 files changed, 57 insertions(+), 21 deletions(-) diff --git a/pyfpdb/Database.py b/pyfpdb/Database.py index 36fdd2d2..ad376453 100644 --- a/pyfpdb/Database.py +++ b/pyfpdb/Database.py @@ -187,6 +187,7 @@ class Database: def __init__(self, c, sql = None): log.info("Creating Database instance, sql = %s" % sql) self.config = c + self.__connected = False self.fdb = fpdb_db.fpdb_db() # sets self.fdb.db self.fdb.cursor and self.fdb.sql self.do_connect(c) @@ -237,7 +238,12 @@ class Database: self.hud_style = style def do_connect(self, c): - self.fdb.do_connect(c) + try: + self.fdb.do_connect(c) + except: + # error during connect + self.__connected = False + raise self.connection = self.fdb.db self.wrongDbVersion = self.fdb.wrongDbVersion @@ -247,6 +253,7 @@ class Database: self.db_server = db_params['db-server'] self.database = db_params['db-databaseName'] self.host = db_params['db-host'] + self.__connected = True def commit(self): self.fdb.db.commit() @@ -254,6 +261,9 @@ class Database: def rollback(self): self.fdb.db.rollback() + def connected(self): + return self.__connected + def get_cursor(self): return self.connection.cursor() diff --git a/pyfpdb/Exceptions.py b/pyfpdb/Exceptions.py index 5b4f4391..fd7c20e3 100644 --- a/pyfpdb/Exceptions.py +++ b/pyfpdb/Exceptions.py @@ -34,5 +34,19 @@ class FpdbMySQLNoDatabase(FpdbDatabaseError): def __str__(self): return repr(self.value +" " + self.errmsg) +class FpdbPostgresqlAccessDenied(FpdbDatabaseError): + def __init__(self, value='', errmsg=''): + self.value = value + self.errmsg = errmsg + def __str__(self): + return repr(self.value +" " + self.errmsg) + +class FpdbPostgresqlNoDatabase(FpdbDatabaseError): + def __init__(self, value='', errmsg=''): + self.value = value + self.errmsg = errmsg + def __str__(self): + return repr(self.value +" " + self.errmsg) + class DuplicateError(FpdbError): pass diff --git a/pyfpdb/fpdb.py b/pyfpdb/fpdb.py index b7013a92..da03b2cc 100755 --- a/pyfpdb/fpdb.py +++ b/pyfpdb/fpdb.py @@ -700,21 +700,26 @@ class fpdb: self.settings.update(self.config.get_import_parameters()) self.settings.update(self.config.get_default_paths()) - if self.db is not None and self.db.fdb is not None: + if self.db is not None and self.db.connected: self.db.disconnect() self.sql = SQL.Sql(db_server = self.settings['db-server']) + err_msg = None try: self.db = Database.Database(self.config, sql = self.sql) except Exceptions.FpdbMySQLAccessDenied: - #self.db = None - self.warning_box("MySQL Server reports: Access denied. Are your permissions set correctly?") - exit() + err_msg = "MySQL Server reports: Access denied. Are your permissions set correctly?" except Exceptions.FpdbMySQLNoDatabase: - #self.db = None - msg = "MySQL client reports: 2002 or 2003 error. Unable to connect - Please check that the MySQL service has been started" - self.warning_box(msg) - exit + err_msg = "MySQL client reports: 2002 or 2003 error. Unable to connect - " \ + + "Please check that the MySQL service has been started" + except Exceptions.FpdbPostgresqlAccessDenied: + err_msg = "Postgres Server reports: Access denied. Are your permissions set correctly?" + except Exceptions.FpdbPostgresqlNoDatabase: + err_msg = "Postgres client reports: Unable to connect - " \ + + "Please check that the Postgres service has been started" + if err_msg is not None: + self.db = None + self.warning_box(err_msg) # except FpdbMySQLFailedError: # self.warning_box("Unable to connect to MySQL! Is the MySQL server running?!", "FPDB ERROR") @@ -732,7 +737,7 @@ class fpdb: # print "*** Error: " + err[2] + "(" + str(err[1]) + "): " + str(sys.exc_info()[1]) # sys.stderr.write("Failed to connect to %s database with username %s." % (self.settings['db-server'], self.settings['db-user'])) - if self.db.wrongDbVersion: + if self.db is not None and self.db.wrongDbVersion: diaDbVersionWarning = gtk.Dialog(title="Strong Warning - Invalid database version", parent=None, flags=0, buttons=(gtk.STOCK_OK,gtk.RESPONSE_OK)) label = gtk.Label("An invalid DB version or missing tables have been detected.") @@ -751,14 +756,15 @@ class fpdb: diaDbVersionWarning.destroy() if self.status_bar is None: - self.status_bar = gtk.Label("Status: Connected to %s database named %s on host %s"%(self.db.get_backend_name(),self.db.database, self.db.host)) + self.status_bar = gtk.Label("") self.main_vbox.pack_end(self.status_bar, False, True, 0) self.status_bar.show() - else: - self.status_bar.set_text("Status: Connected to %s database named %s on host %s" % (self.db.get_backend_name(),self.db.database, self.db.host)) - # Database connected to successfully, load queries to pass on to other classes - self.db.rollback() + if self.db is not None and self.db.connected: + self.status_bar.set_text("Status: Connected to %s database named %s on host %s" + % (self.db.get_backend_name(),self.db.database, self.db.host)) + # rollback to make sure any locks are cleared: + self.db.rollback() self.validate_config() @@ -779,7 +785,8 @@ class fpdb: # TODO: can we get some / all of the stuff done in this function to execute on any kind of abort? print "Quitting normally" # TODO: check if current settings differ from profile, if so offer to save or abort - self.db.disconnect() + if self.db is not None and self.db.connected: + self.db.disconnect() self.statusIcon.set_visible(False) gtk.main_quit() diff --git a/pyfpdb/fpdb_db.py b/pyfpdb/fpdb_db.py index 405a142c..baabb4bf 100644 --- a/pyfpdb/fpdb_db.py +++ b/pyfpdb/fpdb_db.py @@ -129,18 +129,22 @@ class fpdb_db: self.db = psycopg2.connect(database = database) connected = True except: + # direct connection failed so try user/pass/... version pass - #msg = "PostgreSQL direct connection to database (%s) failed, trying with user ..." % (database,) - #print msg - #raise FpdbError(msg) if not connected: try: self.db = psycopg2.connect(host = host, user = user, password = password, database = database) - except: - msg = "PostgreSQL connection to database (%s) user (%s) failed. Are you sure the DB is running?" % (database, user) + except Exception, ex: + if 'Connection refused' in ex.args[0]: + # meaning eg. db not running + raise FpdbPostgresqlNoDatabase(errmsg = ex.args[0]) + elif 'password authentication' in ex.args[0]: + raise FpdbPostgresqlAccessDenied(errmsg = ex.args[0]) + else: + msg = ex.args[0] print msg raise FpdbError(msg) elif backend == fpdb_db.SQLITE: @@ -167,6 +171,7 @@ class fpdb_db: logging.warning("Some database functions will not work without NumPy support") else: raise FpdbError("unrecognised database backend:"+backend) + self.cursor = self.db.cursor() # Set up query dictionary as early in the connection process as we can. self.sql = FpdbSQLQueries.FpdbSQLQueries(self.get_backend_name()) From c7e11a8cc3a5e2ee287ae296ebe92c07e36a1f78 Mon Sep 17 00:00:00 2001 From: sqlcoder Date: Sat, 12 Dec 2009 12:08:48 +0000 Subject: [PATCH 43/65] default guiprefs window to larger size --- pyfpdb/fpdb.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pyfpdb/fpdb.py b/pyfpdb/fpdb.py index da03b2cc..e11cca9f 100755 --- a/pyfpdb/fpdb.py +++ b/pyfpdb/fpdb.py @@ -279,7 +279,7 @@ class fpdb: gtk.DIALOG_MODAL | gtk.DIALOG_DESTROY_WITH_PARENT, (gtk.STOCK_CANCEL, gtk.RESPONSE_REJECT, gtk.STOCK_SAVE, gtk.RESPONSE_ACCEPT)) - dia.set_default_size(500, 500) + dia.set_default_size(700, 500) prefs = GuiPrefs.GuiPrefs(self.config, self.window, dia.vbox) response = dia.run() if response == gtk.RESPONSE_ACCEPT: From 4cc1c4cfe6ac0690b77813e88463c23416d28112 Mon Sep 17 00:00:00 2001 From: sqlcoder Date: Sat, 12 Dec 2009 12:09:58 +0000 Subject: [PATCH 44/65] add name to nodes --- pyfpdb/GuiPrefs.py | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/pyfpdb/GuiPrefs.py b/pyfpdb/GuiPrefs.py index ada9cb51..b85b3f6a 100755 --- a/pyfpdb/GuiPrefs.py +++ b/pyfpdb/GuiPrefs.py @@ -91,10 +91,15 @@ class GuiPrefs: #iter = self.configStore.append( parent, [node.nodeValue, None] ) iter = None if node.nodeType != node.TEXT_NODE and node.nodeType != node.COMMENT_NODE: + name = "" iter = self.configStore.append( parent, [node, setting, value] ) if node.hasAttributes(): for i in xrange(node.attributes.length): self.configStore.append( iter, [node, node.attributes.item(i).localName, node.attributes.item(i).value] ) + if node.attributes.item(i).localName in ('site_name', 'game_name', 'stat_name', 'name', 'db_server', 'site'): + name = " " + node.attributes.item(i).value + if name != "": + self.configStore.set_value(iter, 1, setting+name) if node.hasChildNodes(): for elem in node.childNodes: self.addTreeRows(iter, elem) @@ -156,7 +161,7 @@ if __name__=="__main__": gtk.DIALOG_MODAL | gtk.DIALOG_DESTROY_WITH_PARENT, (gtk.STOCK_CANCEL, gtk.RESPONSE_REJECT, gtk.STOCK_SAVE, gtk.RESPONSE_ACCEPT)) - dia.set_default_size(500, 500) + dia.set_default_size(700, 500) prefs = GuiPrefs(config, win, dia.vbox) response = dia.run() if response == gtk.RESPONSE_ACCEPT: From 40cbb55f7f708592a372e5f2e113eb64b2f4a4fd Mon Sep 17 00:00:00 2001 From: Carl Gherardi Date: Sun, 13 Dec 2009 13:47:14 +0800 Subject: [PATCH 45/65] [NEWIMPORT] Enable printInsert, disable hud pipe --- pyfpdb/fpdb_import.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/pyfpdb/fpdb_import.py b/pyfpdb/fpdb_import.py index 760e1f01..ca321de1 100644 --- a/pyfpdb/fpdb_import.py +++ b/pyfpdb/fpdb_import.py @@ -435,13 +435,13 @@ class Importer: for hand in handlist: #try, except duplicates here? - #hand.prepInsert() + hand.prepInsert(self.database) hand.insert(self.database) if self.callHud and hand.dbid_hands != 0: #print "DEBUG: call to HUD: handsId: %s" % hand.dbid_hands #pipe the Hands.id out to the HUD - # print "fpdb_import: sending hand to hud", handsId, "pipe =", self.caller.pipe_to_hud - self.caller.pipe_to_hud.stdin.write("%s" % (hand.dbid_hands) + os.linesep) + print "fpdb_import: sending hand to hud", handsId, "pipe =", self.caller.pipe_to_hud + #self.caller.pipe_to_hud.stdin.write("%s" % (hand.dbid_hands) + os.linesep) errors = getattr(hhc, 'numErrors') stored = getattr(hhc, 'numHands') From e08afeecb1333f1ab2a82107edbe586185ad0503 Mon Sep 17 00:00:00 2001 From: Carl Gherardi Date: Sun, 13 Dec 2009 13:48:17 +0800 Subject: [PATCH 46/65] [NEWIMPORT] Move database prep into prepInsert --- pyfpdb/Hand.py | 29 +++++++++++++++-------------- 1 file changed, 15 insertions(+), 14 deletions(-) diff --git a/pyfpdb/Hand.py b/pyfpdb/Hand.py index 9ff78249..6901340e 100644 --- a/pyfpdb/Hand.py +++ b/pyfpdb/Hand.py @@ -55,6 +55,8 @@ class Hand(object): self.handText = handText self.handid = 0 self.dbid_hands = 0 + self.dbid_pids = None + self.dbid_gt = 0 self.tablename = "" self.hero = "" self.maxseats = None @@ -189,22 +191,21 @@ dealt whether they were seen in a 'dealt to' line self.holecards[street][player] = [open, closed] def prepInsert(self, db): - pass + ##### + # 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 + self.dbid_pids = db.getSqlPlayerIDs([p[1] for p in self.players], self.siteId) + + #Gametypes + self.dbid_gt = db.getGameTypeId(self.siteId, self.gametype) def insert(self, db): """ 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""" - ##### - # 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.getStats(self) @@ -213,14 +214,14 @@ db: a connected fpdb_db object""" ##### hh = self.stats.getHands() - if not db.isDuplicate(gtid, hh['siteHandNo']): + if not db.isDuplicate(self.dbid_gt, hh['siteHandNo']): # Hands - Summary information of hand indexed by handId - gameinfo - hh['gameTypeId'] = gtid + hh['gameTypeId'] = self.dbid_gt # seats TINYINT NOT NULL, - hh['seats'] = len(sqlids) + hh['seats'] = len(self.dbid_pids) self.dbid_hands = db.storeHand(hh) - db.storeHandsPlayers(self.dbid_hands, sqlids, self.stats.getHandsPlayers()) + db.storeHandsPlayers(self.dbid_hands, self.dbid_pids, self.stats.getHandsPlayers()) # HandsActions - all actions for all players for all streets - self.actions # HudCache data can be generated from HandsActions (HandsPlayers?) # Tourneys ? From 05d0d02df407e23ab3ae5dabae15592e39916c9a Mon Sep 17 00:00:00 2001 From: sqlcoder Date: Sun, 13 Dec 2009 12:55:15 +0000 Subject: [PATCH 47/65] reload profile after editing Prefs if no other tabs are open, otherwise suggest restart --- pyfpdb/fpdb.py | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/pyfpdb/fpdb.py b/pyfpdb/fpdb.py index e11cca9f..e93c9c03 100755 --- a/pyfpdb/fpdb.py +++ b/pyfpdb/fpdb.py @@ -280,11 +280,19 @@ class fpdb: (gtk.STOCK_CANCEL, gtk.RESPONSE_REJECT, gtk.STOCK_SAVE, gtk.RESPONSE_ACCEPT)) dia.set_default_size(700, 500) + prefs = GuiPrefs.GuiPrefs(self.config, self.window, dia.vbox) response = dia.run() if response == gtk.RESPONSE_ACCEPT: # save updated config self.config.save() + if len(self.nb_tab_names) == 1: + # only main tab open, reload profile + self.load_profile() + else: + self.warning_box("Updated preferences have not been loaded because " + + "windows are open. Re-start fpdb to load them.") + dia.destroy() def dia_create_del_database(self, widget, data=None): @@ -646,7 +654,7 @@ class fpdb: ('LoadProf', None, '_Load Profile (broken)', 'L', 'Load your profile', self.dia_load_profile), ('EditProf', None, '_Edit Profile (todo)', 'E', 'Edit your profile', self.dia_edit_profile), ('SaveProf', None, '_Save Profile (todo)', 'S', 'Save your profile', self.dia_save_profile), - ('Preferences', None, '_Preferences', None, 'Edit your preferences', self.dia_preferences), + ('Preferences', None, 'Pre_ferences', 'F', 'Edit your preferences', self.dia_preferences), ('import', None, '_Import'), ('sethharchive', None, '_Set HandHistory Archive Directory', None, 'Set HandHistory Archive Directory', self.select_hhArchiveBase), ('bulkimp', None, '_Bulk Import', 'B', 'Bulk Import', self.tab_bulk_import), From 69168ff86887b25c4e7283a90b946d4c0429dcee Mon Sep 17 00:00:00 2001 From: sqlcoder Date: Sun, 13 Dec 2009 12:57:46 +0000 Subject: [PATCH 48/65] unwind change that stopped mysawshowdown being set unless all-in (which I hardly ever am, since I play limit ... so my WtSD was displaying as 0) --- pyfpdb/fpdb_simple.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/pyfpdb/fpdb_simple.py b/pyfpdb/fpdb_simple.py index aa9421f6..1c22f6e6 100644 --- a/pyfpdb/fpdb_simple.py +++ b/pyfpdb/fpdb_simple.py @@ -1247,13 +1247,13 @@ sure to also change the following storage method and table_viewer.prepare_data i if not isAllIn: isAllIn = any(i for i in allIns[1][player]) - elif len(action_types[2][player]) > 0: + if isAllIn or len(action_types[2][player]) > 0: if all(actiontype != "fold" for actiontype in action_types[1][player]): myStreet2Seen = True if not isAllIn: isAllAin = any(i for i in allIns[2][player]) - elif len(action_types[3][player]) > 0: + if isAllIn or len(action_types[3][player]) > 0: if all(actiontype != "fold" for actiontype in action_types[2][player]): myStreet3Seen = True @@ -1264,7 +1264,7 @@ sure to also change the following storage method and table_viewer.prepare_data i #print "in else" if not isAllIn: isAllIn = any(i for i in allIns[3][player]) - elif len(action_types[4][player]) > 0: + if isAllIn or len(action_types[4][player]) > 0: #print "in if" myStreet4Seen = True From 20de6fe7305a67bf57a940c74e6dba2290fe9cc9 Mon Sep 17 00:00:00 2001 From: Mika Bostrom Date: Sun, 13 Dec 2009 16:12:29 +0200 Subject: [PATCH 49/65] Clean up about window Remove duplicates --- pyfpdb/fpdb.py | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/pyfpdb/fpdb.py b/pyfpdb/fpdb.py index 9085c4f5..e4c5f22d 100755 --- a/pyfpdb/fpdb.py +++ b/pyfpdb/fpdb.py @@ -218,9 +218,7 @@ class fpdb: dia.set_license("GPL v3") dia.set_website("http://fpdb.sourceforge.net/") dia.set_authors(['Steffen', 'Eratosthenes', 's0rrow', - 'EricBlade', '_mt', 'and others']) - dia.set_program_name("FPDB") - dia.set_authors("Steffen, Eratosthenes, s0rrow, EricBlade, _mt, sqlcoder, Bostik, and others") + 'EricBlade', '_mt', 'sqlcoder', 'Bostik', 'and others']) dia.set_program_name("Free Poker Database (FPDB)") dia.run() dia.destroy() From fb92ee294196f57e30a204af311dc87330433cdf Mon Sep 17 00:00:00 2001 From: Worros Date: Mon, 14 Dec 2009 17:52:08 +0800 Subject: [PATCH 50/65] [NEWIMPORT] Stub remaining HandsPlayers stats --- pyfpdb/Database.py | 113 +++++++++++++++++++++++++++-------------- pyfpdb/DerivedStats.py | 32 ++++++++---- 2 files changed, 98 insertions(+), 47 deletions(-) diff --git a/pyfpdb/Database.py b/pyfpdb/Database.py index ad376453..6de0d567 100644 --- a/pyfpdb/Database.py +++ b/pyfpdb/Database.py @@ -1618,6 +1618,40 @@ class Database: pdata[p]['street2Bets'], pdata[p]['street3Bets'], pdata[p]['street4Bets'], + pdata[p]['position'], + pdata[p]['tourneyTypeId'], + pdata[p]['startCards'], + pdata[p]['street0_3BChance'], + pdata[p]['street0_3BDone'], + pdata[p]['otherRaisedStreet1'], + pdata[p]['otherRaisedStreet2'], + pdata[p]['otherRaisedStreet3'], + pdata[p]['otherRaisedStreet4'], + pdata[p]['foldToOtherRaisedStreet1'], + pdata[p]['foldToOtherRaisedStreet2'], + pdata[p]['foldToOtherRaisedStreet3'], + pdata[p]['foldToOtherRaisedStreet4'], + pdata[p]['stealAttemptChance'], + pdata[p]['stealAttempted'], + pdata[p]['foldBbToStealChance'], + pdata[p]['foldedBbToSteal'], + pdata[p]['foldSbToStealChance'], + pdata[p]['foldedSbToSteal'], + pdata[p]['foldToStreet1CBChance'], + pdata[p]['foldToStreet1CBDone'], + pdata[p]['foldToStreet2CBChance'], + pdata[p]['foldToStreet2CBDone'], + pdata[p]['foldToStreet3CBChance'], + pdata[p]['foldToStreet3CBDone'], + pdata[p]['foldToStreet4CBChance'], + pdata[p]['foldToStreet4CBDone'], + pdata[p]['street1CheckCallRaiseChance'], + pdata[p]['street1CheckCallRaiseDone'], + pdata[p]['street2CheckCallRaiseChance'], + pdata[p]['street2CheckCallRaiseDone'], + pdata[p]['street3CheckCallRaiseChance'], + pdata[p]['street3CheckCallRaiseDone'], + pdata[p]['street4CheckCallRaiseChance'] ) ) q = """INSERT INTO HandsPlayers ( @@ -1665,9 +1699,50 @@ class Database: street1Bets, street2Bets, street3Bets, - street4Bets + street4Bets, + position, + tourneyTypeId, + startCards, + street0_3BChance, + street0_3BDone, + otherRaisedStreet1, + otherRaisedStreet2, + otherRaisedStreet3, + otherRaisedStreet4, + foldToOtherRaisedStreet1, + foldToOtherRaisedStreet2, + foldToOtherRaisedStreet3, + foldToOtherRaisedStreet4, + stealAttemptChance, + stealAttempted, + foldBbToStealChance, + foldedBbToSteal, + foldSbToStealChance, + foldedSbToSteal, + foldToStreet1CBChance, + foldToStreet1CBDone, + foldToStreet2CBChance, + foldToStreet2CBDone, + foldToStreet3CBChance, + foldToStreet3CBDone, + foldToStreet4CBChance, + foldToStreet4CBDone, + street1CheckCallRaiseChance, + street1CheckCallRaiseDone, + street2CheckCallRaiseChance, + street2CheckCallRaiseDone, + street3CheckCallRaiseChance, + street3CheckCallRaiseDone, + street4CheckCallRaiseChance ) 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, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, @@ -1679,42 +1754,6 @@ class Database: %s, %s, %s, %s, %s )""" -# position, -# tourneyTypeId, -# startCards, -# street0_3BChance, -# street0_3BDone, -# otherRaisedStreet1, -# otherRaisedStreet2, -# otherRaisedStreet3, -# otherRaisedStreet4, -# foldToOtherRaisedStreet1, -# foldToOtherRaisedStreet2, -# foldToOtherRaisedStreet3, -# foldToOtherRaisedStreet4, -# stealAttemptChance, -# stealAttempted, -# foldBbToStealChance, -# foldedBbToSteal, -# foldSbToStealChance, -# foldedSbToSteal, -# foldToStreet1CBChance, -# foldToStreet1CBDone, -# foldToStreet2CBChance, -# foldToStreet2CBDone, -# foldToStreet3CBChance, -# foldToStreet3CBDone, -# foldToStreet4CBChance, -# foldToStreet4CBDone, -# street1CheckCallRaiseChance, -# street1CheckCallRaiseDone, -# street2CheckCallRaiseChance, -# street2CheckCallRaiseDone, -# street3CheckCallRaiseChance, -# street3CheckCallRaiseDone, -# street4CheckCallRaiseChance, -# street4CheckCallRaiseDone, - q = q.replace('%s', self.sql.query['placeholder']) #print "DEBUG: inserts: %s" %inserts diff --git a/pyfpdb/DerivedStats.py b/pyfpdb/DerivedStats.py index e4072d8a..c1edb737 100644 --- a/pyfpdb/DerivedStats.py +++ b/pyfpdb/DerivedStats.py @@ -53,6 +53,27 @@ class DerivedStats(): self.handsplayers[player[1]]['street%dCBChance' %i] = False self.handsplayers[player[1]]['street%dCBDone' %i] = False + #FIXME - Everything below this point is incomplete. + self.handsplayers[player[1]]['position'] = 2 + self.handsplayers[player[1]]['tourneyTypeId'] = 0 + self.handsplayers[player[1]]['startCards'] = 0 + self.handsplayers[player[1]]['street0_3BChance'] = False + self.handsplayers[player[1]]['street0_3BDone'] = False + self.handsplayers[player[1]]['stealAttemptChance'] = False + self.handsplayers[player[1]]['stealAttempted'] = False + self.handsplayers[player[1]]['foldBbToStealChance'] = False + self.handsplayers[player[1]]['foldBbToStealChance'] = False + self.handsplayers[player[1]]['foldSbToStealChance'] = False + self.handsplayers[player[1]]['foldedSbToSteal'] = False + self.handsplayers[player[1]]['foldedBbToSteal'] = False + for i in range(1,5): + self.handsplayers[player[1]]['otherRaisedStreet%d' %i] = False + self.handsplayers[player[1]]['foldToOtherRaisedStreet%d' %i] = False + self.handsplayers[player[1]]['foldToStreet%dCBChance' %i] = False + self.handsplayers[player[1]]['foldToStreet%dCBDone' %i] = False + self.handsplayers[player[1]]['street%dCheckCallRaiseChance' %i] = False + self.handsplayers[player[1]]['street%dCheckCallRaiseDone' %i] = False + self.assembleHands(self.hand) self.assembleHandsPlayers(self.hand) @@ -149,6 +170,7 @@ class DerivedStats(): for i, card in enumerate(hcs[:7], 1): self.handsplayers[player[1]]['card%s' % i] = Card.encodeCard(card) + # position, #Stud 3rd street card test # denny501: brings in for $0.02 @@ -159,16 +181,6 @@ class DerivedStats(): # u.pressure: folds (Seat 1) # 123smoothie: calls $0.02 # gashpor: calls $0.02 - # tourneyTypeId, - # startCards, - # street0_3BChance,street0_3BDone, - # otherRaisedStreet1-4 - # foldToOtherRaisedStreet1-4 - # stealAttemptChance,stealAttempted, - # foldBbToStealChance,foldedBbToSteal, - # foldSbToStealChance,foldedSbToSteal, - # foldToStreet1-4CBChance, foldToStreet1-4CBDone, - # street1-4CheckCallRaiseChance, street1-4CheckCallRaiseDone, # Additional stats # 3betSB, 3betBB From 56c5521e6a06af38ce44b14b14fb5721d666f6d1 Mon Sep 17 00:00:00 2001 From: Worros Date: Mon, 14 Dec 2009 18:01:24 +0800 Subject: [PATCH 51/65] [NEWIMPORT] Move HandsPlayers insert statement into SQL.py --- pyfpdb/Database.py | 101 +-------------------------------------------- pyfpdb/SQL.py | 101 ++++++++++++++++++++++++++++++++++++++++++++- 2 files changed, 100 insertions(+), 102 deletions(-) diff --git a/pyfpdb/Database.py b/pyfpdb/Database.py index 6de0d567..c5cd156a 100644 --- a/pyfpdb/Database.py +++ b/pyfpdb/Database.py @@ -1654,106 +1654,7 @@ class Database: pdata[p]['street4CheckCallRaiseChance'] ) ) - q = """INSERT INTO HandsPlayers ( - handId, - playerId, - startCash, - seatNo, - card1, - card2, - card3, - card4, - card5, - card6, - card7, - winnings, - rake, - totalProfit, - street0VPI, - street1Seen, - street2Seen, - street3Seen, - street4Seen, - sawShowdown, - wonAtSD, - street0Aggr, - street1Aggr, - street2Aggr, - street3Aggr, - street4Aggr, - street1CBChance, - street2CBChance, - street3CBChance, - street4CBChance, - street1CBDone, - street2CBDone, - street3CBDone, - street4CBDone, - wonWhenSeenStreet1, - street0Calls, - street1Calls, - street2Calls, - street3Calls, - street4Calls, - street0Bets, - street1Bets, - street2Bets, - street3Bets, - street4Bets, - position, - tourneyTypeId, - startCards, - street0_3BChance, - street0_3BDone, - otherRaisedStreet1, - otherRaisedStreet2, - otherRaisedStreet3, - otherRaisedStreet4, - foldToOtherRaisedStreet1, - foldToOtherRaisedStreet2, - foldToOtherRaisedStreet3, - foldToOtherRaisedStreet4, - stealAttemptChance, - stealAttempted, - foldBbToStealChance, - foldedBbToSteal, - foldSbToStealChance, - foldedSbToSteal, - foldToStreet1CBChance, - foldToStreet1CBDone, - foldToStreet2CBChance, - foldToStreet2CBDone, - foldToStreet3CBChance, - foldToStreet3CBDone, - foldToStreet4CBChance, - foldToStreet4CBDone, - street1CheckCallRaiseChance, - street1CheckCallRaiseDone, - street2CheckCallRaiseChance, - street2CheckCallRaiseDone, - street3CheckCallRaiseChance, - street3CheckCallRaiseDone, - street4CheckCallRaiseChance - ) - 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, %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, %s, %s, - %s, %s, %s, %s, %s, - %s, %s, %s, %s, %s, - %s, %s, %s, %s, %s - )""" - + q = self.sql.query['store_hands_players'] q = q.replace('%s', self.sql.query['placeholder']) #print "DEBUG: inserts: %s" %inserts diff --git a/pyfpdb/SQL.py b/pyfpdb/SQL.py index 5a0d1965..73d380c0 100644 --- a/pyfpdb/SQL.py +++ b/pyfpdb/SQL.py @@ -3327,8 +3327,105 @@ class Sql: %s, %s, %s, %s, %s, %s, %s, %s, %s)""" - - + self.query['store_hands_players'] = """INSERT INTO HandsPlayers ( + handId, + playerId, + startCash, + seatNo, + card1, + card2, + card3, + card4, + card5, + card6, + card7, + winnings, + rake, + totalProfit, + street0VPI, + street1Seen, + street2Seen, + street3Seen, + street4Seen, + sawShowdown, + wonAtSD, + street0Aggr, + street1Aggr, + street2Aggr, + street3Aggr, + street4Aggr, + street1CBChance, + street2CBChance, + street3CBChance, + street4CBChance, + street1CBDone, + street2CBDone, + street3CBDone, + street4CBDone, + wonWhenSeenStreet1, + street0Calls, + street1Calls, + street2Calls, + street3Calls, + street4Calls, + street0Bets, + street1Bets, + street2Bets, + street3Bets, + street4Bets, + position, + tourneyTypeId, + startCards, + street0_3BChance, + street0_3BDone, + otherRaisedStreet1, + otherRaisedStreet2, + otherRaisedStreet3, + otherRaisedStreet4, + foldToOtherRaisedStreet1, + foldToOtherRaisedStreet2, + foldToOtherRaisedStreet3, + foldToOtherRaisedStreet4, + stealAttemptChance, + stealAttempted, + foldBbToStealChance, + foldedBbToSteal, + foldSbToStealChance, + foldedSbToSteal, + foldToStreet1CBChance, + foldToStreet1CBDone, + foldToStreet2CBChance, + foldToStreet2CBDone, + foldToStreet3CBChance, + foldToStreet3CBDone, + foldToStreet4CBChance, + foldToStreet4CBDone, + street1CheckCallRaiseChance, + street1CheckCallRaiseDone, + street2CheckCallRaiseChance, + street2CheckCallRaiseDone, + street3CheckCallRaiseChance, + street3CheckCallRaiseDone, + street4CheckCallRaiseChance + ) + 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, %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, %s, %s, + %s, %s, %s, %s, %s, + %s, %s, %s, %s, %s, + %s, %s, %s, %s, %s + )""" if db_server == 'mysql': self.query['placeholder'] = u'%s' From 4746ddb33dbcc7bf3522aebe0c1a3b908c7b633e Mon Sep 17 00:00:00 2001 From: Worros Date: Mon, 14 Dec 2009 19:03:01 +0800 Subject: [PATCH 52/65] Fix thinko in stub --- pyfpdb/DerivedStats.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pyfpdb/DerivedStats.py b/pyfpdb/DerivedStats.py index c1edb737..1064a600 100644 --- a/pyfpdb/DerivedStats.py +++ b/pyfpdb/DerivedStats.py @@ -55,7 +55,7 @@ class DerivedStats(): #FIXME - Everything below this point is incomplete. self.handsplayers[player[1]]['position'] = 2 - self.handsplayers[player[1]]['tourneyTypeId'] = 0 + self.handsplayers[player[1]]['tourneyTypeId'] = 1 self.handsplayers[player[1]]['startCards'] = 0 self.handsplayers[player[1]]['street0_3BChance'] = False self.handsplayers[player[1]]['street0_3BDone'] = False From be0cb6fc2abebc5cb787c01dc1409d0420632291 Mon Sep 17 00:00:00 2001 From: Worros Date: Tue, 15 Dec 2009 22:56:18 +0800 Subject: [PATCH 53/65] Fix a couple of typos --- pyfpdb/fpdb_db.py | 2 +- pyfpdb/fpdb_import.py | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/pyfpdb/fpdb_db.py b/pyfpdb/fpdb_db.py index baabb4bf..2d7f2e0c 100644 --- a/pyfpdb/fpdb_db.py +++ b/pyfpdb/fpdb_db.py @@ -158,7 +158,7 @@ class fpdb_db: if not os.path.isdir(Configuration.DIR_DATABASES) and not database == ":memory:": print "Creating directory: '%s'" % (Configuration.DIR_DATABASES) os.mkdir(Configuration.DIR_DATABASES) - database = os.path.join(Configuration.DIR_DATABASE, database) + database = os.path.join(Configuration.DIR_DATABASES, database) self.db = sqlite3.connect(database, detect_types=sqlite3.PARSE_DECLTYPES ) sqlite3.register_converter("bool", lambda x: bool(int(x))) sqlite3.register_adapter(bool, lambda x: "1" if x else "0") diff --git a/pyfpdb/fpdb_import.py b/pyfpdb/fpdb_import.py index ca321de1..dd46d7c6 100644 --- a/pyfpdb/fpdb_import.py +++ b/pyfpdb/fpdb_import.py @@ -440,8 +440,8 @@ class Importer: if self.callHud and hand.dbid_hands != 0: #print "DEBUG: call to HUD: handsId: %s" % hand.dbid_hands #pipe the Hands.id out to the HUD - print "fpdb_import: sending hand to hud", handsId, "pipe =", self.caller.pipe_to_hud - #self.caller.pipe_to_hud.stdin.write("%s" % (hand.dbid_hands) + os.linesep) + print "fpdb_import: sending hand to hud", hand.dbid_hands, "pipe =", self.caller.pipe_to_hud + self.caller.pipe_to_hud.stdin.write("%s" % (hand.dbid_hands) + os.linesep) errors = getattr(hhc, 'numErrors') stored = getattr(hhc, 'numHands') From 1d531965684b305d2528a9d7c55795bae7d75238 Mon Sep 17 00:00:00 2001 From: Worros Date: Wed, 16 Dec 2009 20:04:10 +0800 Subject: [PATCH 54/65] Fix loal variable scope bug Never have been quite sure of local variable scope using python indentation, this didn't appear to affect anyone until a poster on 2+2 --- pyfpdb/Filters.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pyfpdb/Filters.py b/pyfpdb/Filters.py index c74d5579..dc2e4859 100644 --- a/pyfpdb/Filters.py +++ b/pyfpdb/Filters.py @@ -479,7 +479,8 @@ class Filters(threading.Thread): self.cursor.execute(self.sql.query['getLimits2']) # selects limitType, bigBlind result = self.db.cursor.fetchall() - fl, nl = False, False + found = {'nl':False, 'fl':False, 'ring':False, 'tour':False} + if len(result) >= 1: hbox = gtk.HBox(True, 0) vbox1.pack_start(hbox, False, False, 0) @@ -487,7 +488,6 @@ class Filters(threading.Thread): hbox.pack_start(vbox2, False, False, 0) vbox3 = gtk.VBox(False, 0) hbox.pack_start(vbox3, False, False, 0) - found = {'nl':False, 'fl':False, 'ring':False, 'tour':False} for i, line in enumerate(result): if "UseType" in self.display: if line[0] != self.display["UseType"]: From 353fec235f00c036b1b0bf23e8f28919b16ed6c6 Mon Sep 17 00:00:00 2001 From: Worros Date: Wed, 16 Dec 2009 22:41:48 +0800 Subject: [PATCH 55/65] [NEWIMPORT] Convert start stack to cents --- pyfpdb/DerivedStats.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pyfpdb/DerivedStats.py b/pyfpdb/DerivedStats.py index 1064a600..aaaea60a 100644 --- a/pyfpdb/DerivedStats.py +++ b/pyfpdb/DerivedStats.py @@ -135,7 +135,7 @@ class DerivedStats(): #hand.players = [[seat, name, chips],[seat, name, chips]] for player in hand.players: self.handsplayers[player[1]]['seatNo'] = player[0] - self.handsplayers[player[1]]['startCash'] = player[2] + self.handsplayers[player[1]]['startCash'] = int(100 * player[2]) for i, street in enumerate(hand.actionStreets[2:]): self.seen(self.hand, i+1) From c50addf8679b347a2aa08448328d39a6ba2b86f0 Mon Sep 17 00:00:00 2001 From: Worros Date: Wed, 16 Dec 2009 22:48:38 +0800 Subject: [PATCH 56/65] [NEWIMPORT] Fix startCash fix --- pyfpdb/DerivedStats.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/pyfpdb/DerivedStats.py b/pyfpdb/DerivedStats.py index aaaea60a..c6216306 100644 --- a/pyfpdb/DerivedStats.py +++ b/pyfpdb/DerivedStats.py @@ -17,6 +17,7 @@ #fpdb modules import Card +from decimal import Decimal DEBUG = False @@ -135,7 +136,7 @@ class DerivedStats(): #hand.players = [[seat, name, chips],[seat, name, chips]] for player in hand.players: self.handsplayers[player[1]]['seatNo'] = player[0] - self.handsplayers[player[1]]['startCash'] = int(100 * player[2]) + self.handsplayers[player[1]]['startCash'] = int(100 * Decimal(player[2])) for i, street in enumerate(hand.actionStreets[2:]): self.seen(self.hand, i+1) From 52d1ce1402e6e4a1b11dd857586e76c4ba15ec4d Mon Sep 17 00:00:00 2001 From: Worros Date: Wed, 16 Dec 2009 22:58:54 +0800 Subject: [PATCH 57/65] [NEWIMPOR] Fix insert type for wonAtSD --- pyfpdb/DerivedStats.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pyfpdb/DerivedStats.py b/pyfpdb/DerivedStats.py index c6216306..88d8b452 100644 --- a/pyfpdb/DerivedStats.py +++ b/pyfpdb/DerivedStats.py @@ -46,7 +46,7 @@ class DerivedStats(): self.handsplayers[player[1]]['street4Aggr'] = False self.handsplayers[player[1]]['wonWhenSeenStreet1'] = False self.handsplayers[player[1]]['sawShowdown'] = False - self.handsplayers[player[1]]['wonAtSD'] = False + self.handsplayers[player[1]]['wonAtSD'] = 0.0 for i in range(5): self.handsplayers[player[1]]['street%dCalls' % i] = 0 self.handsplayers[player[1]]['street%dBets' % i] = 0 @@ -158,7 +158,7 @@ class DerivedStats(): if self.handsplayers[player]['street1Seen'] == True: self.handsplayers[player]['wonWhenSeenStreet1'] = True if self.handsplayers[player]['sawShowdown'] == True: - self.handsplayers[player]['wonAtSD'] = True + self.handsplayers[player]['wonAtSD'] = 1.0 for player in hand.pot.committed: self.handsplayers[player]['totalProfit'] = int(self.handsplayers[player]['winnings'] - (100*hand.pot.committed[player])) From 826ca4b2c7fa4d607ad431fbdfec52463f64936a Mon Sep 17 00:00:00 2001 From: Worros Date: Wed, 16 Dec 2009 23:11:08 +0800 Subject: [PATCH 58/65] [NEWIMPORT] 'correct' the type for wonWhenSeenStreet1 --- pyfpdb/DerivedStats.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pyfpdb/DerivedStats.py b/pyfpdb/DerivedStats.py index 88d8b452..1a34db1e 100644 --- a/pyfpdb/DerivedStats.py +++ b/pyfpdb/DerivedStats.py @@ -44,7 +44,7 @@ class DerivedStats(): self.handsplayers[player[1]]['totalProfit'] = 0 self.handsplayers[player[1]]['street4Seen'] = False self.handsplayers[player[1]]['street4Aggr'] = False - self.handsplayers[player[1]]['wonWhenSeenStreet1'] = False + self.handsplayers[player[1]]['wonWhenSeenStreet1'] = 0.0 self.handsplayers[player[1]]['sawShowdown'] = False self.handsplayers[player[1]]['wonAtSD'] = 0.0 for i in range(5): @@ -156,7 +156,7 @@ class DerivedStats(): # Should be fine for split-pots, but won't be accurate for multi-way pots self.handsplayers[player]['rake'] = int(100* hand.rake)/len(hand.collectees) if self.handsplayers[player]['street1Seen'] == True: - self.handsplayers[player]['wonWhenSeenStreet1'] = True + self.handsplayers[player]['wonWhenSeenStreet1'] = 1.0 if self.handsplayers[player]['sawShowdown'] == True: self.handsplayers[player]['wonAtSD'] = 1.0 From 5c0323c842bcc0034c4d9d569d0e40eef04a867a Mon Sep 17 00:00:00 2001 From: Worros Date: Thu, 17 Dec 2009 00:12:53 +0800 Subject: [PATCH 59/65] Add PartyPoker 10 seat hud layout to example file --- pyfpdb/HUD_config.xml.example | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/pyfpdb/HUD_config.xml.example b/pyfpdb/HUD_config.xml.example index b0f26c53..b1ebd761 100644 --- a/pyfpdb/HUD_config.xml.example +++ b/pyfpdb/HUD_config.xml.example @@ -387,6 +387,18 @@ Left-Drag to Move" + + + + + + + + + + + + From 80c324c8e15d4da5de39b734ea8549fff7a70047 Mon Sep 17 00:00:00 2001 From: Worros Date: Thu, 17 Dec 2009 00:40:36 +0800 Subject: [PATCH 60/65] [NEWIMPORT] Add a commit at the end of the fpdb_import cycle --- pyfpdb/fpdb_import.py | 1 + 1 file changed, 1 insertion(+) diff --git a/pyfpdb/fpdb_import.py b/pyfpdb/fpdb_import.py index dd46d7c6..3fc35339 100644 --- a/pyfpdb/fpdb_import.py +++ b/pyfpdb/fpdb_import.py @@ -442,6 +442,7 @@ class Importer: #pipe the Hands.id out to the HUD print "fpdb_import: sending hand to hud", hand.dbid_hands, "pipe =", self.caller.pipe_to_hud self.caller.pipe_to_hud.stdin.write("%s" % (hand.dbid_hands) + os.linesep) + self.database.commit() errors = getattr(hhc, 'numErrors') stored = getattr(hhc, 'numHands') From 1f70a9ad8a4d2381b2f71564b3f48836f9f0b4ce Mon Sep 17 00:00:00 2001 From: Worros Date: Thu, 17 Dec 2009 01:55:48 +0800 Subject: [PATCH 61/65] [NEWIMPORT] Fix thinko on insertPlayer Was returning the player name instead of id in the case where the player exists in the database, but wasn't cached already Removing some merge gunge too --- pyfpdb/Database.py | 6 ++++-- pyfpdb/SQL.py | 2 -- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/pyfpdb/Database.py b/pyfpdb/Database.py index c5cd156a..9d1f3f85 100644 --- a/pyfpdb/Database.py +++ b/pyfpdb/Database.py @@ -1867,8 +1867,10 @@ class Database: ,(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] + result = self.get_last_insert_id(c) + else: + result = tmp[1] + return result def insertGameTypes(self, row): c = self.get_cursor() diff --git a/pyfpdb/SQL.py b/pyfpdb/SQL.py index 73d380c0..c0319dfe 100644 --- a/pyfpdb/SQL.py +++ b/pyfpdb/SQL.py @@ -2789,8 +2789,6 @@ class Sql: ,hp.tourneyTypeId ,date_format(h.handStart, 'd%y%m%d') """ -#>>>>>>> 28ca49d592c8e706ad6ee58dd26655bcc33fc5fb:pyfpdb/SQL.py -#""" elif db_server == 'postgresql': self.query['rebuildHudCache'] = """ INSERT INTO HudCache From f7616c6ee883c8b65a56fc367f5e6145af5254df Mon Sep 17 00:00:00 2001 From: Worros Date: Thu, 17 Dec 2009 02:24:57 +0800 Subject: [PATCH 62/65] [NEWIMPORT] Move hud call to after database commit HUD still doesn't quite work, but getting closer - suspect hud_cache rebuild isn't happening --- pyfpdb/fpdb_import.py | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/pyfpdb/fpdb_import.py b/pyfpdb/fpdb_import.py index 3fc35339..7b3dd4f1 100644 --- a/pyfpdb/fpdb_import.py +++ b/pyfpdb/fpdb_import.py @@ -432,18 +432,21 @@ class Importer: #This code doesn't do anything yet handlist = hhc.getProcessedHands() self.pos_in_file[file] = hhc.getLastCharacterRead() + to_hud = [] for hand in handlist: #try, except duplicates here? hand.prepInsert(self.database) hand.insert(self.database) if self.callHud and hand.dbid_hands != 0: - #print "DEBUG: call to HUD: handsId: %s" % hand.dbid_hands - #pipe the Hands.id out to the HUD - print "fpdb_import: sending hand to hud", hand.dbid_hands, "pipe =", self.caller.pipe_to_hud - self.caller.pipe_to_hud.stdin.write("%s" % (hand.dbid_hands) + os.linesep) + to_hud.append(hand.dbid_hands) self.database.commit() + #pipe the Hands.id out to the HUD + for hid in to_hud: + print "fpdb_import: sending hand to hud", hand.dbid_hands, "pipe =", self.caller.pipe_to_hud + self.caller.pipe_to_hud.stdin.write("%s" % (hid) + os.linesep) + errors = getattr(hhc, 'numErrors') stored = getattr(hhc, 'numHands') else: From 1fb99e459568dc0448dc7b346f6cbc334361b57f Mon Sep 17 00:00:00 2001 From: Worros Date: Thu, 17 Dec 2009 15:59:29 +0800 Subject: [PATCH 63/65] Add test hand - Hand cancelled --- ...LO8-6max-USD-0.05-0.10-20090315.Hand-cancelled.txt | 11 +++++++++++ 1 file changed, 11 insertions(+) create mode 100644 pyfpdb/regression-test-files/cash/Stars/Flop/LO8-6max-USD-0.05-0.10-20090315.Hand-cancelled.txt diff --git a/pyfpdb/regression-test-files/cash/Stars/Flop/LO8-6max-USD-0.05-0.10-20090315.Hand-cancelled.txt b/pyfpdb/regression-test-files/cash/Stars/Flop/LO8-6max-USD-0.05-0.10-20090315.Hand-cancelled.txt new file mode 100644 index 00000000..9959180c --- /dev/null +++ b/pyfpdb/regression-test-files/cash/Stars/Flop/LO8-6max-USD-0.05-0.10-20090315.Hand-cancelled.txt @@ -0,0 +1,11 @@ +PokerStars Game #25979907808: Omaha Pot Limit ($0.05/$0.10 USD) - 2009/03/15 6:20:33 ET +Table 'Waterman' 6-max Seat #1 is the button +Seat 1: s0rrow ($11.65 in chips) +s0rrow: posts small blind $0.05 +ritalinIV: is sitting out +Hand cancelled +*** SUMMARY *** +Seat 1: s0rrow (button) collected ($0) + + + From 22f98ab1c5203af4df5e38477f3dd7e41b112d74 Mon Sep 17 00:00:00 2001 From: Worros Date: Thu, 17 Dec 2009 15:53:12 +0800 Subject: [PATCH 64/65] Add some code to kinda detect hand cancellation hhc.readHandInfo(self) hhc.readPlayerStacks(self) hhc.compilePlayerRegexs(self) hhc.markStreets(self) Is the order, the first correctly failing regex is markStreets --- pyfpdb/Hand.py | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/pyfpdb/Hand.py b/pyfpdb/Hand.py index 6901340e..32140256 100644 --- a/pyfpdb/Hand.py +++ b/pyfpdb/Hand.py @@ -54,6 +54,7 @@ class Hand(object): self.starttime = 0 self.handText = handText self.handid = 0 + self.cancelled = False self.dbid_hands = 0 self.dbid_pids = None self.dbid_gt = 0 @@ -263,6 +264,8 @@ If a player has None chips he won't be added.""" log.debug("markStreets:\n"+ str(self.streets)) else: log.error("markstreets didn't match") + log.error(" - Assuming hand cancelled") + self.cancelled = True def checkPlayerExists(self,player): if player not in [p[1] for p in self.players]: @@ -613,6 +616,8 @@ class HoldemOmahaHand(Hand): hhc.readPlayerStacks(self) hhc.compilePlayerRegexs(self) hhc.markStreets(self) + if self.cancelled: + return hhc.readBlinds(self) hhc.readAntes(self) hhc.readButton(self) From ba8f61d14ac5af3a180ba5815ab52b8b403775ef Mon Sep 17 00:00:00 2001 From: Worros Date: Thu, 17 Dec 2009 18:42:50 +0800 Subject: [PATCH 65/65] Add ability to import Stars archive files. PokerStars support can provide a HH archive. The format is similar but not the same as a a standard hh format as it contains an additional line "Hand #X" between each hand. Patch adds an option -s to GuiBulkImport, which when specified will strip these lines out and continue parsing. --- pyfpdb/GuiBulkImport.py | 4 ++++ pyfpdb/Hand.py | 1 + pyfpdb/HandHistoryConverter.py | 8 +++++++- pyfpdb/fpdb_import.py | 19 +++++++++++++------ 4 files changed, 25 insertions(+), 7 deletions(-) diff --git a/pyfpdb/GuiBulkImport.py b/pyfpdb/GuiBulkImport.py index 7db420c7..16131ab2 100755 --- a/pyfpdb/GuiBulkImport.py +++ b/pyfpdb/GuiBulkImport.py @@ -326,6 +326,8 @@ def main(argv=None): help="How often to print a one-line status report (0 (default) means never)") parser.add_option("-u", "--usage", action="store_true", dest="usage", default=False, help="Print some useful one liners") + parser.add_option("-s", "--starsarchive", action="store_true", dest="starsArchive", default=False, + help="Do the required conversion for Stars Archive format (ie. as provided by support") (options, argv) = parser.parse_args(args = argv) if options.usage == True: @@ -369,6 +371,8 @@ def main(argv=None): importer.setThreads(-1) importer.addBulkImportImportFileOrDir(os.path.expanduser(options.filename), site=options.filtername) importer.setCallHud(False) + if options.starsArchive: + importer.setStarsArchive(True) (stored, dups, partial, errs, ttime) = importer.runImport() importer.clearFileList() print 'GuiBulkImport done: Stored: %d \tDuplicates: %d \tPartial: %d \tErrors: %d in %s seconds - %.0f/sec'\ diff --git a/pyfpdb/Hand.py b/pyfpdb/Hand.py index 32140256..3467216a 100644 --- a/pyfpdb/Hand.py +++ b/pyfpdb/Hand.py @@ -266,6 +266,7 @@ If a player has None chips he won't be added.""" log.error("markstreets didn't match") log.error(" - Assuming hand cancelled") self.cancelled = True + raise FpdbParseError def checkPlayerExists(self,player): if player not in [p[1] for p in self.players]: diff --git a/pyfpdb/HandHistoryConverter.py b/pyfpdb/HandHistoryConverter.py index 27bb9b1a..a18797df 100644 --- a/pyfpdb/HandHistoryConverter.py +++ b/pyfpdb/HandHistoryConverter.py @@ -57,7 +57,7 @@ class HandHistoryConverter(): codepage = "cp1252" - def __init__(self, in_path = '-', out_path = '-', follow=False, index=0, autostart=True): + def __init__(self, in_path = '-', out_path = '-', follow=False, index=0, autostart=True, starsArchive=False): """\ in_path (default '-' = sys.stdin) out_path (default '-' = sys.stdout) @@ -66,6 +66,7 @@ follow : whether to tail -f the input""" log.info("HandHistory init - %s subclass, in_path '%s'; out_path '%s'" % (self.sitename, in_path, out_path) ) self.index = 0 + self.starsArchive = starsArchive self.in_path = in_path self.out_path = out_path @@ -254,6 +255,11 @@ which it expects to find at self.re_TailSplitHands -- see for e.g. Everleaf.py. self.readFile() self.obs = self.obs.strip() self.obs = self.obs.replace('\r\n', '\n') + if self.starsArchive == True: + log.debug("Converting starsArchive format to readable") + m = re.compile('^Hand #\d+', re.MULTILINE) + self.obs = m.sub('', self.obs) + if self.obs is None or self.obs == "": log.info("Read no hands.") return [] diff --git a/pyfpdb/fpdb_import.py b/pyfpdb/fpdb_import.py index 7b3dd4f1..8921d9d8 100644 --- a/pyfpdb/fpdb_import.py +++ b/pyfpdb/fpdb_import.py @@ -91,6 +91,7 @@ class Importer: self.settings.setdefault("writeQMaxWait", 10) # not used self.settings.setdefault("dropIndexes", "don't drop") self.settings.setdefault("dropHudCache", "don't drop") + self.settings.setdefault("starsArchive", False) self.writeq = None self.database = Database.Database(self.config, sql = self.sql) @@ -134,6 +135,9 @@ class Importer: def setDropHudCache(self, value): self.settings['dropHudCache'] = value + def setStarsArchive(self, value): + self.settings['starsArchive'] = value + # def setWatchTime(self): # self.updated = time() @@ -425,7 +429,7 @@ class Importer: mod = __import__(filter) obj = getattr(mod, filter_name, None) if callable(obj): - hhc = obj(in_path = file, out_path = out_path, index = 0) # Index into file 0 until changeover + hhc = obj(in_path = file, out_path = out_path, index = 0, starsArchive = self.settings['starsArchive']) # Index into file 0 until changeover if hhc.getStatus() and self.NEWIMPORT == False: (stored, duplicates, partial, errors, ttime) = self.import_fpdb_file(db, out_path, site, q) elif hhc.getStatus() and self.NEWIMPORT == True: @@ -435,11 +439,14 @@ class Importer: to_hud = [] for hand in handlist: - #try, except duplicates here? - hand.prepInsert(self.database) - hand.insert(self.database) - if self.callHud and hand.dbid_hands != 0: - to_hud.append(hand.dbid_hands) + if hand is not None: + #try, except duplicates here? + hand.prepInsert(self.database) + hand.insert(self.database) + if self.callHud and hand.dbid_hands != 0: + to_hud.append(hand.dbid_hands) + else: + log.error("Hand processed but empty") self.database.commit() #pipe the Hands.id out to the HUD