From 16d53f1502171647a1eb5625a49d0cd2e30b955b Mon Sep 17 00:00:00 2001 From: PassThePeas Date: Sat, 12 Sep 2009 23:14:55 +0200 Subject: [PATCH 01/56] Patch for HUD and FTP tourneys modified: Hand.py - writeTableLine : adds the tourneyNo in tourney context modified: Tables.py - discover_nt_by_name : add filter for HUD and chat windows --- pyfpdb/Hand.py | 6 +++++- pyfpdb/Tables.py | 4 ++++ 2 files changed, 9 insertions(+), 1 deletion(-) diff --git a/pyfpdb/Hand.py b/pyfpdb/Hand.py index 7a95f78a..31b9ec89 100644 --- a/pyfpdb/Hand.py +++ b/pyfpdb/Hand.py @@ -596,7 +596,11 @@ Map the tuple self.gametype onto the pokerstars string describing it def writeTableLine(self): - table_string = "Table \'%s\' %s-max" % (self.tablename, self.maxseats) + table_string = "Table " + if self.gametype['type'] == 'tour': + table_string = table_string + "\'%s %s\' %s-max" % (self.tourNo, self.tablename, self.maxseats) + else: + table_string = table_string + "\'%s\' %s-max" % (self.tablename, self.maxseats) if self.gametype['currency'] == 'play': table_string = table_string + " (Play Money)" if self.buttonpos != None and self.buttonpos != 0: diff --git a/pyfpdb/Tables.py b/pyfpdb/Tables.py index 082bc171..09510536 100755 --- a/pyfpdb/Tables.py +++ b/pyfpdb/Tables.py @@ -253,6 +253,10 @@ def discover_nt_tournament(c, tour_number, tab_number): titles ={} win32gui.EnumWindows(win_enum_handler, titles) for hwnd in titles: + if 'Chat:' in titles[hwnd]: continue # Some sites (FTP? PS? Others?) have seperable or seperately constructed chat windows + if 'History for table:' in titles[hwnd]: continue # Everleaf Network HH viewer window + if 'HUD:' in titles[hwnd]: continue # FPDB HUD window + if re.search(search_string, titles[hwnd]): return decode_windows(c, titles[hwnd], hwnd) return None From 23f56ea2ae26f7226218dda47fef9a261f165c23 Mon Sep 17 00:00:00 2001 From: sqlcoder Date: Wed, 23 Sep 2009 23:03:34 +0100 Subject: [PATCH 02/56] 2 changes: move recognisePlayerIDs from fpdb_simple into Database, and make index on siteTourneyNo on Tourneys table unique and refine store_tourneys function to handle this --- pyfpdb/Database.py | 111 +++++++++++++++++++++++++++++-------- pyfpdb/SQL.py | 6 +- pyfpdb/fpdb_parse_logic.py | 2 +- pyfpdb/fpdb_simple.py | 62 --------------------- 4 files changed, 91 insertions(+), 90 deletions(-) diff --git a/pyfpdb/Database.py b/pyfpdb/Database.py index 9c506afa..57776be9 100755 --- a/pyfpdb/Database.py +++ b/pyfpdb/Database.py @@ -77,7 +77,7 @@ class Database: , {'tab':'HandsPlayers', 'col':'playerId', 'drop':0} # not needed, handled by fk , {'tab':'HandsPlayers', 'col':'tourneyTypeId', 'drop':0} , {'tab':'HandsPlayers', 'col':'tourneysPlayersId', 'drop':0} - , {'tab':'Tourneys', 'col':'siteTourneyNo', 'drop':0} + #, {'tab':'Tourneys', 'col':'siteTourneyNo', 'drop':0} created elsewhere - needs to be unique ] , [ # indexes for postgres (list index 3) {'tab':'Gametypes', 'col':'siteId', 'drop':0} @@ -93,7 +93,7 @@ class Database: , {'tab':'Players', 'col':'siteId', 'drop':1} , {'tab':'Players', 'col':'name', 'drop':0} , {'tab':'Tourneys', 'col':'tourneyTypeId', 'drop':1} - , {'tab':'Tourneys', 'col':'siteTourneyNo', 'drop':0} + #, {'tab':'Tourneys', 'col':'siteTourneyNo', 'drop':0} created elsewhere - needs to be unique , {'tab':'TourneysPlayers', 'col':'playerId', 'drop':0} , {'tab':'TourneysPlayers', 'col':'tourneyId', 'drop':0} , {'tab':'TourneyTypes', 'col':'siteId', 'drop':0} @@ -106,7 +106,7 @@ class Database: , {'tab':'HandsPlayers', 'col':'playerId', 'drop':0} , {'tab':'HandsPlayers', 'col':'tourneyTypeId', 'drop':0} , {'tab':'HandsPlayers', 'col':'tourneysPlayersId', 'drop':0} - , {'tab':'Tourneys', 'col':'siteTourneyNo', 'drop':0} + #, {'tab':'Tourneys', 'col':'siteTourneyNo', 'drop':0} created elsewhere - needs to be unique ] ] @@ -494,6 +494,69 @@ class Database: else: return None + #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 + # then this can be reduced in complexity a bit + + #def recognisePlayerIDs(cursor, names, site_id): + # result = [] + # for i in xrange(len(names)): + # cursor.execute ("SELECT id FROM Players WHERE name=%s", (names[i],)) + # tmp=cursor.fetchall() + # if (len(tmp)==0): #new player + # cursor.execute ("INSERT INTO Players (name, siteId) VALUES (%s, %s)", (names[i], site_id)) + # #print "Number of players rows inserted: %d" % cursor.rowcount + # cursor.execute ("SELECT id FROM Players WHERE name=%s", (names[i],)) + # tmp=cursor.fetchall() + # #print "recognisePlayerIDs, names[i]:",names[i],"tmp:",tmp + # result.append(tmp[0][0]) + # return result + + def recognisePlayerIDs(self, names, site_id): + c = self.get_cursor() + q = "SELECT name,id FROM Players WHERE siteid=%d and (name=%s)" %(site_id, " OR name=".join([self.sql.query['placeholder'] for n in names])) + c.execute(q, names) # get all playerids by the names passed in + ids = dict(c.fetchall()) # convert to dict + if len(ids) != len(names): + notfound = [n for n in names if n not in ids] # make list of names not in database + if notfound: # insert them into database + q_ins = "INSERT INTO Players (name, siteId) VALUES (%s, "+str(site_id)+")" + q_ins = q_ins.replace('%s', self.sql.query['placeholder']) + c.executemany(q_ins, [(n,) for n in notfound]) + q2 = "SELECT name,id FROM Players WHERE siteid=%d and (name=%s)" % (site_id, " OR name=".join(["%s" for n in notfound])) + q2 = q2.replace('%s', self.sql.query['placeholder']) + c.execute(q2, notfound) # get their new ids + tmp = c.fetchall() + for n,id in tmp: # put them all into the same dict + ids[n] = id + # return them in the SAME ORDER that they came in in the names argument, rather than the order they came out of the DB + return [ids[n] for n in names] + #end def recognisePlayerIDs + + # Here's a version that would work if it wasn't for the fact that it needs to have the output in the same order as input + # this version could also be improved upon using list comprehensions, etc + + #def recognisePlayerIDs(cursor, names, site_id): + # result = [] + # notfound = [] + # cursor.execute("SELECT name,id FROM Players WHERE name='%s'" % "' OR name='".join(names)) + # tmp = dict(cursor.fetchall()) + # for n in names: + # if n not in tmp: + # notfound.append(n) + # else: + # result.append(tmp[n]) + # if notfound: + # cursor.executemany("INSERT INTO Players (name, siteId) VALUES (%s, "+str(site_id)+")", (notfound)) + # cursor.execute("SELECT id FROM Players WHERE name='%s'" % "' OR name='".join(notfound)) + # tmp = cursor.fetchall() + # for n in tmp: + # result.append(n[0]) + # + # return result + + def get_site_id(self, site): c = self.get_cursor() c.execute(self.sql.query['getSiteId'], (site,)) @@ -870,7 +933,7 @@ class Database: c.execute(self.sql.query['createHandsPlayersTable']) c.execute(self.sql.query['createHandsActionsTable']) c.execute(self.sql.query['createHudCacheTable']) - #c.execute(self.sql.query['addTourneyIndex']) + c.execute(self.sql.query['addTourneyIndex']) #c.execute(self.sql.query['addHandsIndex']) #c.execute(self.sql.query['addPlayersIndex']) self.fillDefaultData() @@ -1752,26 +1815,26 @@ class Database: def store_tourneys(self, tourneyTypeId, siteTourneyNo, entries, prizepool, startTime): try: - cursor = self.get_cursor() - cursor.execute("SELECT id FROM Tourneys WHERE siteTourneyNo=%s AND tourneyTypeId+0=%s".replace('%s', self.sql.query['placeholder']) - , (siteTourneyNo, tourneyTypeId)) - tmp=cursor.fetchone() - #print "tried SELECTing tourneys.id, result:",tmp - - try: - len(tmp) - except TypeError:#means we have to create new one - cursor.execute("""INSERT INTO Tourneys - (tourneyTypeId, siteTourneyNo, entries, prizepool, startTime) - VALUES (%s, %s, %s, %s, %s)""".replace('%s', self.sql.query['placeholder']) - ,(tourneyTypeId, siteTourneyNo, entries, prizepool, startTime)) - cursor.execute("SELECT id FROM Tourneys WHERE siteTourneyNo=%s AND tourneyTypeId+0=%s", (siteTourneyNo, tourneyTypeId)) - tmp=cursor.fetchone() - #print "created new tourneys.id:",tmp + # try and create tourney record, fetch id if it already exists + # avoids race condition when doing the select first + cursor.execute("""INSERT INTO Tourneys + (tourneyTypeId, siteTourneyNo, entries, prizepool, startTime) + VALUES (%s, %s, %s, %s, %s)""".replace('%s', self.sql.query['placeholder']) + ,(tourneyTypeId, siteTourneyNo, entries, prizepool, startTime)) + tmp = self.get_last_insert_id(cursor) + #cursor.execute("SELECT id FROM Tourneys WHERE siteTourneyNo=%s AND tourneyTypeId+0=%s", (siteTourneyNo, tourneyTypeId)) + #tmp=cursor.fetchone() + #print "created new tourneys.id:",tmp except: - raise FpdbError( "store_tourneys error: " + str(sys.exc_value) ) + #if str(sys.exc_value) .... not unique index error: + # raise FpdbError( "store_tourneys error: " + str(sys.exc_value) ) + #else: + cursor = self.get_cursor() + cursor.execute( "SELECT id FROM Tourneys WHERE siteTourneyNo=%s AND tourneyTypeId+0=%s".replace('%s', self.sql.query['placeholder']) + , (siteTourneyNo, tourneyTypeId) ) + tmp = cursor.fetchone()[0] - return tmp[0] + return tmp #end def store_tourneys def store_tourneys_players(self, tourney_id, player_ids, payin_amounts, ranks, winnings): @@ -2026,10 +2089,10 @@ class Database: def tStoreTourneyPlayers(self, tourney, dbTourneyId): logging.debug("Database.tStoreTourneyPlayers") # First, get playerids for the players and specifically the one for hero : - playersIds = fpdb_simple.recognisePlayerIDs(self, tourney.players, tourney.siteId) + playersIds = self.recognisePlayerIDs(tourney.players, tourney.siteId) # hero may be None for matrix tourneys summaries # hero = [ tourney.hero ] -# heroId = fpdb_simple.recognisePlayerIDs(self, hero , tourney.siteId) +# heroId = self.recognisePlayerIDs(hero , tourney.siteId) # logging.debug("hero Id = %s - playersId = %s" % (heroId , playersIds)) tourneyPlayersIds=[] diff --git a/pyfpdb/SQL.py b/pyfpdb/SQL.py index 986f9762..af9af079 100644 --- a/pyfpdb/SQL.py +++ b/pyfpdb/SQL.py @@ -1160,11 +1160,11 @@ class Sql: if db_server == 'mysql': - self.query['addTourneyIndex'] = """ALTER TABLE Tourneys ADD INDEX siteTourneyNo(siteTourneyNo)""" + self.query['addTourneyIndex'] = """ALTER TABLE Tourneys ADD UNIQUE INDEX siteTourneyNo(siteTourneyNo)""" elif db_server == 'postgresql': - self.query['addTourneyIndex'] = """CREATE INDEX siteTourneyNo ON Tourneys (siteTourneyNo)""" + self.query['addTourneyIndex'] = """CREATE UNIQUE INDEX siteTourneyNo ON Tourneys (siteTourneyNo)""" elif db_server == 'sqlite': - self.query['addHandsIndex'] = """ """ + self.query['addTourneyIndex'] = """CREATE UNIQUE INDEX siteTourneyNo ON Tourneys (siteTourneyNo)""" if db_server == 'mysql': self.query['addHandsIndex'] = """ALTER TABLE Hands ADD INDEX siteHandNo(siteHandNo)""" diff --git a/pyfpdb/fpdb_parse_logic.py b/pyfpdb/fpdb_parse_logic.py index da6f644d..ed48ab04 100644 --- a/pyfpdb/fpdb_parse_logic.py +++ b/pyfpdb/fpdb_parse_logic.py @@ -95,7 +95,7 @@ def mainParser(settings, siteID, category, hand, config, db = None, writeq = Non seatLines.append(line) names = fpdb_simple.parseNames(seatLines) - playerIDs = fpdb_simple.recognisePlayerIDs(db, names, siteID) # inserts players as needed + playerIDs = db.recognisePlayerIDs(names, siteID) # inserts players as needed tmp = fpdb_simple.parseCashesAndSeatNos(seatLines) startCashes = tmp['startCashes'] seatNos = tmp['seatNos'] diff --git a/pyfpdb/fpdb_simple.py b/pyfpdb/fpdb_simple.py index 3c5f6bca..42b1de5e 100644 --- a/pyfpdb/fpdb_simple.py +++ b/pyfpdb/fpdb_simple.py @@ -968,68 +968,6 @@ def recogniseTourneyTypeId(db, siteId, tourneySiteId, buyin, fee, knockout, rebu return result[0] #end def recogniseTourneyTypeId -#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 -# then this can be reduced in complexity a bit - -#def recognisePlayerIDs(cursor, names, site_id): -# result = [] -# for i in xrange(len(names)): -# cursor.execute ("SELECT id FROM Players WHERE name=%s", (names[i],)) -# tmp=cursor.fetchall() -# if (len(tmp)==0): #new player -# cursor.execute ("INSERT INTO Players (name, siteId) VALUES (%s, %s)", (names[i], site_id)) -# #print "Number of players rows inserted: %d" % cursor.rowcount -# cursor.execute ("SELECT id FROM Players WHERE name=%s", (names[i],)) -# tmp=cursor.fetchall() -# #print "recognisePlayerIDs, names[i]:",names[i],"tmp:",tmp -# result.append(tmp[0][0]) -# return result - -def recognisePlayerIDs(db, names, site_id): - c = db.get_cursor() - q = "SELECT name,id FROM Players WHERE siteid=%d and (name=%s)" %(site_id, " OR name=".join([db.sql.query['placeholder'] for n in names])) - c.execute(q, names) # get all playerids by the names passed in - ids = dict(c.fetchall()) # convert to dict - if len(ids) != len(names): - notfound = [n for n in names if n not in ids] # make list of names not in database - if notfound: # insert them into database - q_ins = "INSERT INTO Players (name, siteId) VALUES (%s, "+str(site_id)+")" - q_ins = q_ins.replace('%s', db.sql.query['placeholder']) - c.executemany(q_ins, [(n,) for n in notfound]) - q2 = "SELECT name,id FROM Players WHERE siteid=%d and (name=%s)" % (site_id, " OR name=".join(["%s" for n in notfound])) - q2 = q2.replace('%s', db.sql.query['placeholder']) - c.execute(q2, notfound) # get their new ids - tmp = c.fetchall() - for n,id in tmp: # put them all into the same dict - ids[n] = id - # return them in the SAME ORDER that they came in in the names argument, rather than the order they came out of the DB - return [ids[n] for n in names] -#end def recognisePlayerIDs - - -# Here's a version that would work if it wasn't for the fact that it needs to have the output in the same order as input -# this version could also be improved upon using list comprehensions, etc - -#def recognisePlayerIDs(cursor, names, site_id): -# result = [] -# notfound = [] -# cursor.execute("SELECT name,id FROM Players WHERE name='%s'" % "' OR name='".join(names)) -# tmp = dict(cursor.fetchall()) -# for n in names: -# if n not in tmp: -# notfound.append(n) -# else: -# result.append(tmp[n]) -# if notfound: -# cursor.executemany("INSERT INTO Players (name, siteId) VALUES (%s, "+str(site_id)+")", (notfound)) -# cursor.execute("SELECT id FROM Players WHERE name='%s'" % "' OR name='".join(notfound)) -# tmp = cursor.fetchall() -# for n in tmp: -# result.append(n[0]) -# -# return result #recognises the name in the given line and returns its array position in the given array def recognisePlayerNo(line, names, atype): From daeefd7d8ac788d99e4a301e2a9b1d0b5c19b0b5 Mon Sep 17 00:00:00 2001 From: sqlcoder Date: Wed, 23 Sep 2009 23:04:38 +0100 Subject: [PATCH 03/56] hide regular exception when closing hud --- pyfpdb/HUD_main.py | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/pyfpdb/HUD_main.py b/pyfpdb/HUD_main.py index ecc96429..6723db2b 100755 --- a/pyfpdb/HUD_main.py +++ b/pyfpdb/HUD_main.py @@ -104,7 +104,11 @@ class HUD_main(object): # called by an event in the HUD, to kill this specific HUD if table in self.hud_dict: self.hud_dict[table].kill() - self.hud_dict[table].main_window.destroy() + try: + # throws exception in windows sometimes (when closing using main_window menu?) + self.hud_dict[table].main_window.destroy() + except: + pass self.vb.remove(self.hud_dict[table].tablehudlabel) del(self.hud_dict[table]) self.main_window.resize(1,1) From a67830d92e36a83b4ae9aa3b81918fe2287691ab Mon Sep 17 00:00:00 2001 From: sqlcoder Date: Wed, 23 Sep 2009 23:03:34 +0100 Subject: [PATCH 04/56] 2 changes: move recognisePlayerIDs from fpdb_simple into Database, and make index on siteTourneyNo on Tourneys table unique and refine store_tourneys function to handle this --- pyfpdb/Database.py | 111 +++++++++++++++++++++++++++++-------- pyfpdb/SQL.py | 6 +- pyfpdb/fpdb_parse_logic.py | 2 +- pyfpdb/fpdb_simple.py | 62 --------------------- 4 files changed, 91 insertions(+), 90 deletions(-) diff --git a/pyfpdb/Database.py b/pyfpdb/Database.py index 341a1434..b3adde0c 100755 --- a/pyfpdb/Database.py +++ b/pyfpdb/Database.py @@ -77,7 +77,7 @@ class Database: , {'tab':'HandsPlayers', 'col':'playerId', 'drop':0} # not needed, handled by fk , {'tab':'HandsPlayers', 'col':'tourneyTypeId', 'drop':0} , {'tab':'HandsPlayers', 'col':'tourneysPlayersId', 'drop':0} - , {'tab':'Tourneys', 'col':'siteTourneyNo', 'drop':0} + #, {'tab':'Tourneys', 'col':'siteTourneyNo', 'drop':0} created elsewhere - needs to be unique ] , [ # indexes for postgres (list index 3) {'tab':'Gametypes', 'col':'siteId', 'drop':0} @@ -93,7 +93,7 @@ class Database: , {'tab':'Players', 'col':'siteId', 'drop':1} , {'tab':'Players', 'col':'name', 'drop':0} , {'tab':'Tourneys', 'col':'tourneyTypeId', 'drop':1} - , {'tab':'Tourneys', 'col':'siteTourneyNo', 'drop':0} + #, {'tab':'Tourneys', 'col':'siteTourneyNo', 'drop':0} created elsewhere - needs to be unique , {'tab':'TourneysPlayers', 'col':'playerId', 'drop':0} , {'tab':'TourneysPlayers', 'col':'tourneyId', 'drop':0} , {'tab':'TourneyTypes', 'col':'siteId', 'drop':0} @@ -106,7 +106,7 @@ class Database: , {'tab':'HandsPlayers', 'col':'playerId', 'drop':0} , {'tab':'HandsPlayers', 'col':'tourneyTypeId', 'drop':0} , {'tab':'HandsPlayers', 'col':'tourneysPlayersId', 'drop':0} - , {'tab':'Tourneys', 'col':'siteTourneyNo', 'drop':0} + #, {'tab':'Tourneys', 'col':'siteTourneyNo', 'drop':0} created elsewhere - needs to be unique ] ] @@ -491,6 +491,69 @@ class Database: else: return None + #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 + # then this can be reduced in complexity a bit + + #def recognisePlayerIDs(cursor, names, site_id): + # result = [] + # for i in xrange(len(names)): + # cursor.execute ("SELECT id FROM Players WHERE name=%s", (names[i],)) + # tmp=cursor.fetchall() + # if (len(tmp)==0): #new player + # cursor.execute ("INSERT INTO Players (name, siteId) VALUES (%s, %s)", (names[i], site_id)) + # #print "Number of players rows inserted: %d" % cursor.rowcount + # cursor.execute ("SELECT id FROM Players WHERE name=%s", (names[i],)) + # tmp=cursor.fetchall() + # #print "recognisePlayerIDs, names[i]:",names[i],"tmp:",tmp + # result.append(tmp[0][0]) + # return result + + def recognisePlayerIDs(self, names, site_id): + c = self.get_cursor() + q = "SELECT name,id FROM Players WHERE siteid=%d and (name=%s)" %(site_id, " OR name=".join([self.sql.query['placeholder'] for n in names])) + c.execute(q, names) # get all playerids by the names passed in + ids = dict(c.fetchall()) # convert to dict + if len(ids) != len(names): + notfound = [n for n in names if n not in ids] # make list of names not in database + if notfound: # insert them into database + q_ins = "INSERT INTO Players (name, siteId) VALUES (%s, "+str(site_id)+")" + q_ins = q_ins.replace('%s', self.sql.query['placeholder']) + c.executemany(q_ins, [(n,) for n in notfound]) + q2 = "SELECT name,id FROM Players WHERE siteid=%d and (name=%s)" % (site_id, " OR name=".join(["%s" for n in notfound])) + q2 = q2.replace('%s', self.sql.query['placeholder']) + c.execute(q2, notfound) # get their new ids + tmp = c.fetchall() + for n,id in tmp: # put them all into the same dict + ids[n] = id + # return them in the SAME ORDER that they came in in the names argument, rather than the order they came out of the DB + return [ids[n] for n in names] + #end def recognisePlayerIDs + + # Here's a version that would work if it wasn't for the fact that it needs to have the output in the same order as input + # this version could also be improved upon using list comprehensions, etc + + #def recognisePlayerIDs(cursor, names, site_id): + # result = [] + # notfound = [] + # cursor.execute("SELECT name,id FROM Players WHERE name='%s'" % "' OR name='".join(names)) + # tmp = dict(cursor.fetchall()) + # for n in names: + # if n not in tmp: + # notfound.append(n) + # else: + # result.append(tmp[n]) + # if notfound: + # cursor.executemany("INSERT INTO Players (name, siteId) VALUES (%s, "+str(site_id)+")", (notfound)) + # cursor.execute("SELECT id FROM Players WHERE name='%s'" % "' OR name='".join(notfound)) + # tmp = cursor.fetchall() + # for n in tmp: + # result.append(n[0]) + # + # return result + + def get_site_id(self, site): c = self.get_cursor() c.execute(self.sql.query['getSiteId'], (site,)) @@ -867,7 +930,7 @@ class Database: c.execute(self.sql.query['createHandsPlayersTable']) c.execute(self.sql.query['createHandsActionsTable']) c.execute(self.sql.query['createHudCacheTable']) - #c.execute(self.sql.query['addTourneyIndex']) + c.execute(self.sql.query['addTourneyIndex']) #c.execute(self.sql.query['addHandsIndex']) #c.execute(self.sql.query['addPlayersIndex']) self.fillDefaultData() @@ -1858,26 +1921,26 @@ class Database: def store_tourneys(self, tourneyTypeId, siteTourneyNo, entries, prizepool, startTime): try: - cursor = self.get_cursor() - cursor.execute("SELECT id FROM Tourneys WHERE siteTourneyNo=%s AND tourneyTypeId+0=%s".replace('%s', self.sql.query['placeholder']) - , (siteTourneyNo, tourneyTypeId)) - tmp=cursor.fetchone() - #print "tried SELECTing tourneys.id, result:",tmp - - try: - len(tmp) - except TypeError:#means we have to create new one - cursor.execute("""INSERT INTO Tourneys - (tourneyTypeId, siteTourneyNo, entries, prizepool, startTime) - VALUES (%s, %s, %s, %s, %s)""".replace('%s', self.sql.query['placeholder']) - ,(tourneyTypeId, siteTourneyNo, entries, prizepool, startTime)) - cursor.execute("SELECT id FROM Tourneys WHERE siteTourneyNo=%s AND tourneyTypeId+0=%s", (siteTourneyNo, tourneyTypeId)) - tmp=cursor.fetchone() - #print "created new tourneys.id:",tmp + # try and create tourney record, fetch id if it already exists + # avoids race condition when doing the select first + cursor.execute("""INSERT INTO Tourneys + (tourneyTypeId, siteTourneyNo, entries, prizepool, startTime) + VALUES (%s, %s, %s, %s, %s)""".replace('%s', self.sql.query['placeholder']) + ,(tourneyTypeId, siteTourneyNo, entries, prizepool, startTime)) + tmp = self.get_last_insert_id(cursor) + #cursor.execute("SELECT id FROM Tourneys WHERE siteTourneyNo=%s AND tourneyTypeId+0=%s", (siteTourneyNo, tourneyTypeId)) + #tmp=cursor.fetchone() + #print "created new tourneys.id:",tmp except: - raise FpdbError( "store_tourneys error: " + str(sys.exc_value) ) + #if str(sys.exc_value) .... not unique index error: + # raise FpdbError( "store_tourneys error: " + str(sys.exc_value) ) + #else: + cursor = self.get_cursor() + cursor.execute( "SELECT id FROM Tourneys WHERE siteTourneyNo=%s AND tourneyTypeId+0=%s".replace('%s', self.sql.query['placeholder']) + , (siteTourneyNo, tourneyTypeId) ) + tmp = cursor.fetchone()[0] - return tmp[0] + return tmp #end def store_tourneys def store_tourneys_players(self, tourney_id, player_ids, payin_amounts, ranks, winnings): @@ -2132,10 +2195,10 @@ class Database: def tStoreTourneyPlayers(self, tourney, dbTourneyId): logging.debug("Database.tStoreTourneyPlayers") # First, get playerids for the players and specifically the one for hero : - playersIds = fpdb_simple.recognisePlayerIDs(self, tourney.players, tourney.siteId) + playersIds = self.recognisePlayerIDs(tourney.players, tourney.siteId) # hero may be None for matrix tourneys summaries # hero = [ tourney.hero ] -# heroId = fpdb_simple.recognisePlayerIDs(self, hero , tourney.siteId) +# heroId = self.recognisePlayerIDs(hero , tourney.siteId) # logging.debug("hero Id = %s - playersId = %s" % (heroId , playersIds)) tourneyPlayersIds=[] diff --git a/pyfpdb/SQL.py b/pyfpdb/SQL.py index 986f9762..af9af079 100644 --- a/pyfpdb/SQL.py +++ b/pyfpdb/SQL.py @@ -1160,11 +1160,11 @@ class Sql: if db_server == 'mysql': - self.query['addTourneyIndex'] = """ALTER TABLE Tourneys ADD INDEX siteTourneyNo(siteTourneyNo)""" + self.query['addTourneyIndex'] = """ALTER TABLE Tourneys ADD UNIQUE INDEX siteTourneyNo(siteTourneyNo)""" elif db_server == 'postgresql': - self.query['addTourneyIndex'] = """CREATE INDEX siteTourneyNo ON Tourneys (siteTourneyNo)""" + self.query['addTourneyIndex'] = """CREATE UNIQUE INDEX siteTourneyNo ON Tourneys (siteTourneyNo)""" elif db_server == 'sqlite': - self.query['addHandsIndex'] = """ """ + self.query['addTourneyIndex'] = """CREATE UNIQUE INDEX siteTourneyNo ON Tourneys (siteTourneyNo)""" if db_server == 'mysql': self.query['addHandsIndex'] = """ALTER TABLE Hands ADD INDEX siteHandNo(siteHandNo)""" diff --git a/pyfpdb/fpdb_parse_logic.py b/pyfpdb/fpdb_parse_logic.py index 4ce1f678..1334a8ac 100644 --- a/pyfpdb/fpdb_parse_logic.py +++ b/pyfpdb/fpdb_parse_logic.py @@ -118,7 +118,7 @@ def mainParser(settings, siteID, category, hand, config, db = None, writeq = Non seatLines.append(line) names = fpdb_simple.parseNames(seatLines) - playerIDs = fpdb_simple.recognisePlayerIDs(db, names, siteID) # inserts players as needed + playerIDs = db.recognisePlayerIDs(names, siteID) # inserts players as needed tmp = fpdb_simple.parseCashesAndSeatNos(seatLines) startCashes = tmp['startCashes'] seatNos = tmp['seatNos'] diff --git a/pyfpdb/fpdb_simple.py b/pyfpdb/fpdb_simple.py index 084949d6..40204ee9 100644 --- a/pyfpdb/fpdb_simple.py +++ b/pyfpdb/fpdb_simple.py @@ -937,68 +937,6 @@ def recogniseTourneyTypeId(db, siteId, tourneySiteId, buyin, fee, knockout, rebu return result[0] #end def recogniseTourneyTypeId -#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 -# then this can be reduced in complexity a bit - -#def recognisePlayerIDs(cursor, names, site_id): -# result = [] -# for i in xrange(len(names)): -# cursor.execute ("SELECT id FROM Players WHERE name=%s", (names[i],)) -# tmp=cursor.fetchall() -# if (len(tmp)==0): #new player -# cursor.execute ("INSERT INTO Players (name, siteId) VALUES (%s, %s)", (names[i], site_id)) -# #print "Number of players rows inserted: %d" % cursor.rowcount -# cursor.execute ("SELECT id FROM Players WHERE name=%s", (names[i],)) -# tmp=cursor.fetchall() -# #print "recognisePlayerIDs, names[i]:",names[i],"tmp:",tmp -# result.append(tmp[0][0]) -# return result - -def recognisePlayerIDs(db, names, site_id): - c = db.get_cursor() - q = "SELECT name,id FROM Players WHERE siteid=%d and (name=%s)" %(site_id, " OR name=".join([db.sql.query['placeholder'] for n in names])) - c.execute(q, names) # get all playerids by the names passed in - ids = dict(c.fetchall()) # convert to dict - if len(ids) != len(names): - notfound = [n for n in names if n not in ids] # make list of names not in database - if notfound: # insert them into database - q_ins = "INSERT INTO Players (name, siteId) VALUES (%s, "+str(site_id)+")" - q_ins = q_ins.replace('%s', db.sql.query['placeholder']) - c.executemany(q_ins, [(n,) for n in notfound]) - q2 = "SELECT name,id FROM Players WHERE siteid=%d and (name=%s)" % (site_id, " OR name=".join(["%s" for n in notfound])) - q2 = q2.replace('%s', db.sql.query['placeholder']) - c.execute(q2, notfound) # get their new ids - tmp = c.fetchall() - for n,id in tmp: # put them all into the same dict - ids[n] = id - # return them in the SAME ORDER that they came in in the names argument, rather than the order they came out of the DB - return [ids[n] for n in names] -#end def recognisePlayerIDs - - -# Here's a version that would work if it wasn't for the fact that it needs to have the output in the same order as input -# this version could also be improved upon using list comprehensions, etc - -#def recognisePlayerIDs(cursor, names, site_id): -# result = [] -# notfound = [] -# cursor.execute("SELECT name,id FROM Players WHERE name='%s'" % "' OR name='".join(names)) -# tmp = dict(cursor.fetchall()) -# for n in names: -# if n not in tmp: -# notfound.append(n) -# else: -# result.append(tmp[n]) -# if notfound: -# cursor.executemany("INSERT INTO Players (name, siteId) VALUES (%s, "+str(site_id)+")", (notfound)) -# cursor.execute("SELECT id FROM Players WHERE name='%s'" % "' OR name='".join(notfound)) -# tmp = cursor.fetchall() -# for n in tmp: -# result.append(n[0]) -# -# return result #recognises the name in the given line and returns its array position in the given array def recognisePlayerNo(line, names, atype): From c519756a49dbc9f4cb65bd84f2103fa8926c3820 Mon Sep 17 00:00:00 2001 From: sqlcoder Date: Fri, 25 Sep 2009 20:18:13 +0100 Subject: [PATCH 05/56] look for sqlite db in 'database' dir, create dir first if required --- pyfpdb/fpdb_db.py | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/pyfpdb/fpdb_db.py b/pyfpdb/fpdb_db.py index 1e74865e..e67a071f 100644 --- a/pyfpdb/fpdb_db.py +++ b/pyfpdb/fpdb_db.py @@ -39,6 +39,8 @@ class fpdb_db: MYSQL_INNODB = 2 PGSQL = 3 SQLITE = 4 + sqlite_db_dir = ".." + os.sep + "database" + def __init__(self): """Simple constructor, doesnt really do anything""" self.db = None @@ -120,7 +122,12 @@ class fpdb_db: sqlite3 = pool.manage(sqlite3, pool_size=1) else: logging.warning("SQLite won't work well without 'sqlalchemy' installed.") - self.db = sqlite3.connect(database,detect_types=sqlite3.PARSE_DECLTYPES) + + if not os.path.isdir(self.sqlite_db_dir): + print "Creating directory: '%s'" % (self.sqlite_db_dir) + os.mkdir(self.sqlite_db_dir) + self.db = sqlite3.connect( self.sqlite_db_dir + os.sep + 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") else: From 3d301718aedca4b8a5e187fe29a773f5c261b2aa Mon Sep 17 00:00:00 2001 From: sqlcoder Date: Fri, 25 Sep 2009 23:10:58 +0100 Subject: [PATCH 06/56] create/alter unique indexes and change inserts into tourneytypes and tourneysplayers --- pyfpdb/Database.py | 54 ++++++++++++++++--------------- pyfpdb/SQL.py | 74 ++++++++++++++++++++++++++++++++++--------- pyfpdb/fpdb_simple.py | 12 ++++--- 3 files changed, 95 insertions(+), 45 deletions(-) diff --git a/pyfpdb/Database.py b/pyfpdb/Database.py index 57776be9..8e29cce9 100755 --- a/pyfpdb/Database.py +++ b/pyfpdb/Database.py @@ -70,19 +70,19 @@ class Database: [ ] # no db with index 0 , [ ] # no db with index 1 , [ # indexes for mysql (list index 2) - {'tab':'Players', 'col':'name', 'drop':0} - , {'tab':'Hands', 'col':'siteHandNo', 'drop':0} - , {'tab':'Hands', 'col':'gametypeId', 'drop':0} # mct 22/3/09 + # {'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} # mct 22/3/09 , {'tab':'HandsPlayers', 'col':'handId', 'drop':0} # not needed, handled by fk , {'tab':'HandsPlayers', 'col':'playerId', 'drop':0} # not needed, handled by fk , {'tab':'HandsPlayers', 'col':'tourneyTypeId', 'drop':0} , {'tab':'HandsPlayers', 'col':'tourneysPlayersId', 'drop':0} - #, {'tab':'Tourneys', 'col':'siteTourneyNo', 'drop':0} created elsewhere - needs to be unique + #, {'tab':'Tourneys', 'col':'siteTourneyNo', 'drop':0} unique indexes not dropped ] , [ # indexes for postgres (list index 3) {'tab':'Gametypes', 'col':'siteId', 'drop':0} , {'tab':'Hands', 'col':'gametypeId', 'drop':0} # mct 22/3/09 - , {'tab':'Hands', 'col':'siteHandNo', 'drop':0} + #, {'tab':'Hands', 'col':'siteHandNo', 'drop':0} unique indexes not dropped , {'tab':'HandsActions', 'col':'handsPlayerId', 'drop':0} , {'tab':'HandsPlayers', 'col':'handId', 'drop':1} , {'tab':'HandsPlayers', 'col':'playerId', 'drop':1} @@ -91,22 +91,22 @@ class Database: , {'tab':'HudCache', 'col':'playerId', 'drop':0} , {'tab':'HudCache', 'col':'tourneyTypeId', 'drop':0} , {'tab':'Players', 'col':'siteId', 'drop':1} - , {'tab':'Players', 'col':'name', 'drop':0} + #, {'tab':'Players', 'col':'name', 'drop':0} unique indexes not dropped , {'tab':'Tourneys', 'col':'tourneyTypeId', 'drop':1} - #, {'tab':'Tourneys', 'col':'siteTourneyNo', 'drop':0} created elsewhere - needs to be unique + #, {'tab':'Tourneys', 'col':'siteTourneyNo', 'drop':0} unique indexes not dropped , {'tab':'TourneysPlayers', 'col':'playerId', 'drop':0} - , {'tab':'TourneysPlayers', 'col':'tourneyId', 'drop':0} + #, {'tab':'TourneysPlayers', 'col':'tourneyId', 'drop':0} unique indexes not dropped , {'tab':'TourneyTypes', 'col':'siteId', 'drop':0} ] , [ # indexes for sqlite (list index 4) - {'tab':'Players', 'col':'name', 'drop':0} - , {'tab':'Hands', 'col':'siteHandNo', 'drop':0} - , {'tab':'Hands', 'col':'gametypeId', 'drop':0} + # {'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':'playerId', 'drop':0} , {'tab':'HandsPlayers', 'col':'tourneyTypeId', 'drop':0} , {'tab':'HandsPlayers', 'col':'tourneysPlayersId', 'drop':0} - #, {'tab':'Tourneys', 'col':'siteTourneyNo', 'drop':0} created elsewhere - needs to be unique + #, {'tab':'Tourneys', 'col':'siteTourneyNo', 'drop':0} unique indexes not dropped ] ] @@ -921,6 +921,7 @@ class Database: log.debug(self.sql.query['createSettingsTable']) c = self.get_cursor() c.execute(self.sql.query['createSettingsTable']) + log.debug(self.sql.query['createSitesTable']) c.execute(self.sql.query['createSitesTable']) c.execute(self.sql.query['createGametypesTable']) @@ -933,9 +934,14 @@ class Database: c.execute(self.sql.query['createHandsPlayersTable']) c.execute(self.sql.query['createHandsActionsTable']) c.execute(self.sql.query['createHudCacheTable']) + + # create unique indexes: c.execute(self.sql.query['addTourneyIndex']) - #c.execute(self.sql.query['addHandsIndex']) - #c.execute(self.sql.query['addPlayersIndex']) + c.execute(self.sql.query['addHandsIndex']) + c.execute(self.sql.query['addPlayersIndex']) + c.execute(self.sql.query['addTPlayersIndex']) + c.execute(self.sql.query['addTTypesIndex']) + self.fillDefaultData() self.commit() except: @@ -1847,23 +1853,19 @@ class Database: #print "ranks:",ranks #print "winnings:",winnings for i in xrange(len(player_ids)): - cursor.execute("SELECT id FROM TourneysPlayers WHERE tourneyId=%s AND playerId+0=%s".replace('%s', self.sql.query['placeholder']) - ,(tourney_id, player_ids[i])) - tmp=cursor.fetchone() - #print "tried SELECTing tourneys_players.id:",tmp - try: - len(tmp) - except TypeError: cursor.execute("""INSERT INTO TourneysPlayers - (tourneyId, playerId, payinAmount, rank, winnings) VALUES (%s, %s, %s, %s, %s)""".replace('%s', self.sql.query['placeholder']), + (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])) - cursor.execute("SELECT id FROM TourneysPlayers WHERE tourneyId=%s AND playerId+0=%s".replace('%s', self.sql.query['placeholder']), - (tourney_id, player_ids[i])) - tmp=cursor.fetchone() + tmp = self.get_last_insert_id(cursor) #print "created new tourneys_players.id:",tmp - result.append(tmp[0]) + except: + cursor.execute("SELECT id FROM TourneysPlayers WHERE tourneyId=%s AND playerId+0=%s".replace('%s', self.sql.query['placeholder']) + ,(tourney_id, player_ids[i])) + tmp=cursor.fetchone()[0] + #print "tried SELECTing tourneys_players.id:",tmp + result.append(tmp) except: raise FpdbError( "store_tourneys_players error: " + str(sys.exc_value) ) diff --git a/pyfpdb/SQL.py b/pyfpdb/SQL.py index af9af079..c0bbabd5 100644 --- a/pyfpdb/SQL.py +++ b/pyfpdb/SQL.py @@ -331,7 +331,8 @@ class Sql: speed varchar(10), headsUp BOOLEAN NOT NULL DEFAULT False, shootout BOOLEAN NOT NULL DEFAULT False, - matrix BOOLEAN NOT NULL DEFAULT False + matrix BOOLEAN NOT NULL DEFAULT False, + sng BOOLEAN NOT NULL DEFAULT False ) ENGINE=INNODB""" elif db_server == 'postgresql': @@ -346,7 +347,8 @@ class Sql: speed varchar(10), headsUp BOOLEAN NOT NULL DEFAULT False, shootout BOOLEAN NOT NULL DEFAULT False, - matrix BOOLEAN NOT NULL DEFAULT False + matrix BOOLEAN NOT NULL DEFAULT False, + sng BOOLEAN NOT NULL DEFAULT False )""" elif db_server == 'sqlite': self.query['createTourneyTypesTable'] = """CREATE TABLE TourneyTypes ( @@ -360,7 +362,8 @@ class Sql: speed TEXT, headsUp BOOLEAN NOT NULL DEFAULT 0, shootout BOOLEAN NOT NULL DEFAULT 0, - matrix BOOLEAN NOT NULL DEFAULT 0 + matrix BOOLEAN NOT NULL DEFAULT 0, + sng BOOLEAN NOT NULL DEFAULT 0 )""" ################################ @@ -820,7 +823,21 @@ class Sql: comment TEXT, commentTs timestamp without time zone)""" elif db_server == 'sqlite': - self.query['createTourneysPlayersTable'] = """ """ + self.query['createTourneysPlayersTable'] = """CREATE TABLE TourneysPlayers ( + id INT PRIMARY KEY, + tourneyId INT, + playerId INT, + payinAmount INT, + rank INT, + winnings INT, + nbRebuys INT DEFAULT 0, + nbAddons INT DEFAULT 0, + nbKO INT DEFAULT 0, + comment TEXT, + commentTs timestamp without time zone, + FOREIGN KEY (tourneyId) REFERENCES Tourneys(id), + FOREIGN KEY (playerId) REFERENCES Players(id) + )""" ################################ @@ -851,7 +868,18 @@ class Sql: comment TEXT, commentTs timestamp without time zone)""" elif db_server == 'sqlite': - self.query['createHandsActionsTable'] = """ """ + self.query['createHandsActionsTable'] = """CREATE TABLE HandsActions ( + id INT PRIMARY KEY, + handsPlayerId BIGINT, + street SMALLINT, + actionNo SMALLINT, + action CHAR(5), + allIn INT, + amount INT, + comment TEXT, + commentTs timestamp without time zone, + FOREIGN KEY (handsPlayerId) REFERENCES HandsPlayers(id) + )""" ################################ @@ -1160,26 +1188,42 @@ class Sql: if db_server == 'mysql': - self.query['addTourneyIndex'] = """ALTER TABLE Tourneys ADD UNIQUE INDEX siteTourneyNo(siteTourneyNo)""" + self.query['addTourneyIndex'] = """ALTER TABLE Tourneys ADD UNIQUE INDEX siteTourneyNo(siteTourneyNo, tourneyTypeId)""" elif db_server == 'postgresql': - self.query['addTourneyIndex'] = """CREATE UNIQUE INDEX siteTourneyNo ON Tourneys (siteTourneyNo)""" + self.query['addTourneyIndex'] = """CREATE UNIQUE INDEX siteTourneyNo ON Tourneys (siteTourneyNo, tourneyTypeId)""" elif db_server == 'sqlite': - self.query['addTourneyIndex'] = """CREATE UNIQUE INDEX siteTourneyNo ON Tourneys (siteTourneyNo)""" + self.query['addTourneyIndex'] = """CREATE UNIQUE INDEX siteTourneyNo ON Tourneys (siteTourneyNo, tourneyTypeId)""" if db_server == 'mysql': - self.query['addHandsIndex'] = """ALTER TABLE Hands ADD INDEX siteHandNo(siteHandNo)""" + self.query['addHandsIndex'] = """ALTER TABLE Hands ADD UNIQUE INDEX siteHandNo(siteHandNo, gameTypeId)""" elif db_server == 'postgresql': - self.query['addHandsIndex'] = """CREATE INDEX siteHandNo ON Hands (siteHandNo)""" + self.query['addHandsIndex'] = """CREATE UNIQUE INDEX siteHandNo ON Hands (siteHandNo, gameTypeId)""" elif db_server == 'sqlite': - self.query['addHandsIndex'] = """ """ + self.query['addHandsIndex'] = """CREATE UNIQUE INDEX siteHandNo ON Hands (siteHandNo, gameTypeId)""" if db_server == 'mysql': - self.query['addPlayersIndex'] = """ALTER TABLE Players ADD INDEX name(name)""" + self.query['addPlayersIndex'] = """ALTER TABLE Players ADD UNIQUE INDEX name(name, siteId)""" elif db_server == 'postgresql': - self.query['addPlayersIndex'] = """CREATE INDEX name ON Players (name)""" + self.query['addPlayersIndex'] = """CREATE UNIQUE INDEX name ON Players (name, siteId)""" elif db_server == 'sqlite': - self.query['addPlayersIndex'] = """ """ + self.query['addPlayersIndex'] = """CREATE UNIQUE INDEX name ON Players (name, siteId)""" + if db_server == 'mysql': + self.query['addTPlayersIndex'] = """ALTER TABLE TourneysPlayers ADD UNIQUE INDEX tourneyId(tourneyId, playerId)""" + elif db_server == 'postgresql': + self.query['addTPlayersIndex'] = """CREATE UNIQUE INDEX tourneyId ON TourneysPlayers (tourneyId, playerId)""" + elif db_server == 'sqlite': + self.query['addTPlayersIndex'] = """CREATE UNIQUE INDEX tourneyId ON TourneysPlayers (tourneyId, playerId)""" + + if db_server == 'mysql': + self.query['addTTypesIndex'] = """ALTER TABLE TourneyTypes ADD UNIQUE INDEX tourneytypes_all(buyin, fee + , maxSeats, knockout, rebuyOrAddon, speed, headsUp, shootout, matrix, sng)""" + elif db_server == 'postgresql': + self.query['addTTypesIndex'] = """CREATE UNIQUE INDEX tourneyTypes_all ON TourneyTypes (buyin, fee + , maxSeats, knockout, rebuyOrAddon, speed, headsUp, shootout, matrix, sng)""" + elif db_server == 'sqlite': + self.query['addTTypesIndex'] = """CREATE UNIQUE INDEX tourneyTypes_all ON TourneyTypes (buyin, fee + , maxSeats, knockout, rebuyOrAddon, speed, headsUp, shootout, matrix, sng)""" self.query['get_last_hand'] = "select max(id) from Hands" @@ -1188,7 +1232,7 @@ class Sql: from Players, Sites where Players.name = %s and Sites.name = %s - and Players.SiteId = Sites.id + and Players.siteId = Sites.id """ self.query['getSiteId'] = """SELECT id from Sites where name = %s""" diff --git a/pyfpdb/fpdb_simple.py b/pyfpdb/fpdb_simple.py index 42b1de5e..e85655af 100644 --- a/pyfpdb/fpdb_simple.py +++ b/pyfpdb/fpdb_simple.py @@ -954,16 +954,20 @@ def recogniseTourneyTypeId(db, siteId, tourneySiteId, buyin, fee, knockout, rebu try: len(result) except: - cursor.execute ("SELECT id FROM TourneyTypes WHERE siteId=%s AND buyin=%s AND fee=%s AND knockout=%s AND rebuyOrAddon=%s", (siteId, buyin, fee, knockout, rebuyOrAddon)) + cursor.execute( """SELECT id FROM TourneyTypes + WHERE siteId=%s AND buyin=%s AND fee=%s + AND knockout=%s AND rebuyOrAddon=%s""" + , (siteId, buyin, fee, knockout, rebuyOrAddon) ) result=cursor.fetchone() #print "tried SELECTing gametypes.id, result:",result try: len(result) except TypeError:#this means we need to create a new entry - cursor.execute("""INSERT INTO TourneyTypes (siteId, buyin, fee, knockout, rebuyOrAddon) VALUES (%s, %s, %s, %s, %s)""", (siteId, buyin, fee, knockout, rebuyOrAddon)) - cursor.execute("SELECT id FROM TourneyTypes WHERE siteId=%s AND buyin=%s AND fee=%s AND knockout=%s AND rebuyOrAddon=%s", (siteId, buyin, fee, knockout, rebuyOrAddon)) - result=cursor.fetchone() + cursor.execute( """INSERT INTO TourneyTypes (siteId, buyin, fee, knockout, rebuyOrAddon) + VALUES (%s, %s, %s, %s, %s)""" + , (siteId, buyin, fee, knockout, rebuyOrAddon) ) + result = db.get_last_insert_id(cursor) return result[0] #end def recogniseTourneyTypeId From ea74862a5ab47403771db77ed04b63b103432442 Mon Sep 17 00:00:00 2001 From: sqlcoder Date: Sat, 26 Sep 2009 11:30:12 +0100 Subject: [PATCH 07/56] start changes to allow different hud choices for hero and opponents --- pyfpdb/Database.py | 59 +++++++++------ pyfpdb/HUD_main.py | 147 ++++++++++++++++++++++-------------- pyfpdb/Hud.py | 59 ++++++++++++++- pyfpdb/SQL.py | 9 ++- pyfpdb/TournamentTracker.py | 2 +- pyfpdb/fpdb_import.py | 2 +- 6 files changed, 188 insertions(+), 90 deletions(-) diff --git a/pyfpdb/Database.py b/pyfpdb/Database.py index 8e29cce9..235c423f 100755 --- a/pyfpdb/Database.py +++ b/pyfpdb/Database.py @@ -406,10 +406,19 @@ class Database: err = traceback.extract_tb(sys.exc_info()[2])[-1] print "***Error: "+err[2]+"("+str(err[1])+"): "+str(sys.exc_info()[1]) - def get_stats_from_hand(self, hand, aggregate = False, hud_style = 'A', agg_bb_mult = 100): + def get_stats_from_hand( self, hand + , hud_params = {'aggregate_tour':False, 'aggregate_ring':False, 'hud_style':'A', 'agg_bb_mult':100} + , hero_ids = {} + ): + aggregate = hud_params['aggregate_tour'] if type == "tour" else hud_params['aggregate_ring'] + hud_style = hud_params['hud_style'] + agg_bb_mult = hud_params['agg_bb_mult'] + stat_dict = {} + if hud_style == 'S': - return( self.get_stats_from_hand_session(hand) ) + self.get_stats_from_hand_session(hand, stat_dict) + return stat_dict else: # hud_style == A @@ -433,7 +442,6 @@ class Database: # now get the stats c.execute(self.sql.query[query], subs) colnames = [desc[0] for desc in c.description] - stat_dict = {} for row in c.fetchall(): t_dict = {} for name, val in zip(colnames, row): @@ -444,7 +452,7 @@ class Database: return stat_dict # uses query on handsplayers instead of hudcache to get stats on just this session - def get_stats_from_hand_session(self, hand): + def get_stats_from_hand_session(self, hand, stat_dict): query = self.sql.query['get_stats_from_hand_session'] if self.db_server == 'mysql': @@ -459,31 +467,32 @@ class Database: #print "sess_stats: subs =", subs, "subs[0] =", subs[0] c.execute(query, subs) colnames = [desc[0] for desc in c.description] - n,stat_dict = 0,{} - row = c.fetchone() - while row: - if colnames[0].lower() == 'player_id': - playerid = row[0] - else: - log.error("ERROR: query %s result does not have player_id as first column" % (query,)) - break + n = 0 + + row = c.fetchone() + if colnames[0].lower() == 'player_id': + playerid = row[0] + + while row: + for name, val in zip(colnames, row): + if not playerid in stat_dict: + stat_dict[playerid] = {} + stat_dict[playerid][name.lower()] = val + elif not name.lower() in stat_dict[playerid]: + stat_dict[playerid][name.lower()] = val + 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 + # for now - comment out or remove? + row = c.fetchone() + else: + log.error("ERROR: query %s result does not have player_id as first column" % (query,)) - for name, val in zip(colnames, row): - if not playerid in stat_dict: - stat_dict[playerid] = {} - stat_dict[playerid][name.lower()] = val - elif not name.lower() in stat_dict[playerid]: - stat_dict[playerid][name.lower()] = val - elif name.lower() not in ('hand_id', 'player_id', 'seat', 'screen_name', 'seats'): - stat_dict[playerid][name.lower()] += val - n += 1 - if n >= 4000: break # todo: don't think this is needed so set nice and high - # for now - comment out or remove? - row = c.fetchone() #print " %d rows fetched, len(stat_dict) = %d" % (n, len(stat_dict)) #print "session stat_dict =", stat_dict - return stat_dict + #return stat_dict def get_player_id(self, config, site, player_name): c = self.connection.cursor() diff --git a/pyfpdb/HUD_main.py b/pyfpdb/HUD_main.py index 6723db2b..cc23be96 100755 --- a/pyfpdb/HUD_main.py +++ b/pyfpdb/HUD_main.py @@ -74,6 +74,22 @@ hud_session_gap = 30 # Gap (minutes) between hands that indicates a change of s # a new session) #hud_hands = 0 # Max number of hands from each player to use for hud stats (not used) +def_hud_params = { 'aggregate_ring' : False + , 'aggregate_tour' : False + , 'hud_style' : 'A' + , 'hud_days ' : 90 + , 'agg_bb_mult' : 100 + , 'hud_session_gap' : 30 + # second set of variables for hero + , 'h_aggregate_ring' : False + , 'h_aggreagte_tour' : False + , 'h_hud_style' : 'A' + , 'h_hud_days ' : 90 + , 'h_agg_bb_mult' : 100 + , 'h_hud_session_gap' : 30 + } + + 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. @@ -82,6 +98,7 @@ class HUD_main(object): self.db_name = db_name self.config = Configuration.Config(file=options.config, dbname=options.dbname) self.hud_dict = {} + self.hud_params = def_hud_params # a thread to read stdin gobject.threads_init() # this is required @@ -164,68 +181,84 @@ class HUD_main(object): # be passed to HUDs for use in the gui thread. HUD objects should not # need their own access to the database, but should open their own # if it is required. - self.db_connection = Database.Database(self.config, self.db_name, 'temp') - self.db_connection.init_hud_stat_vars(hud_days) - tourny_finder = re.compile('(\d+) (\d+)') - - while 1: # wait for a new hand number on stdin - new_hand_id = sys.stdin.readline() - new_hand_id = string.rstrip(new_hand_id) - if new_hand_id == "": # blank line means quit - self.destroy() - break # this thread is not always killed immediately with gtk.main_quit() -# get basic info about the new hand from the db -# if there is a db error, complain, skip hand, and proceed - try: - (table_name, max, poker_game, type) = self.db_connection.get_table_name(new_hand_id) - stat_dict = self.db_connection.get_stats_from_hand(new_hand_id, aggregate_stats[type] - ,hud_style, agg_bb_mult) + try: + self.db_connection = Database.Database(self.config, self.db_name, 'temp') + self.db_connection.init_hud_stat_vars(hud_days) + tourny_finder = re.compile('(\d+) (\d+)') + +# get hero's screen names and player ids + self.hero, self.hero_ids = {}, {} + for site in self.config.get_supported_sites(): + result = self.db_connection.get_site_id(site) + if result: + site_id = result[0][0] + self.hero[site_id] = self.config.supported_sites[site].screen_name + self.hero_ids[site_id] = self.db_connection.get_player_id(self.config, site, self.hero[site_id]) + + while 1: # wait for a new hand number on stdin + new_hand_id = sys.stdin.readline() + new_hand_id = string.rstrip(new_hand_id) + if new_hand_id == "": # blank line means quit + self.destroy() + break # this thread is not always killed immediately with gtk.main_quit() +# get basic info about the new hand from the db +# if there is a db error, complain, skip hand, and proceed + try: + (table_name, max, poker_game, type, site_id) = self.db_connection.get_table_name(new_hand_id) + stat_dict = self.db_connection.get_stats_from_hand(new_hand_id, self.hud_params, self.hero_ids) + #self.hud_params['aggregate_tour'] if type = "tour" + # else self.hud_params['aggregate_ring'], + #hud_style, + #agg_bb_mult) - cards = self.db_connection.get_cards(new_hand_id) - comm_cards = self.db_connection.get_common_cards(new_hand_id) - if comm_cards != {}: # stud! - cards['common'] = comm_cards['common'] - except Exception, err: - err = traceback.extract_tb(sys.exc_info()[2])[-1] - print "db error: skipping "+str(new_hand_id)+" "+err[2]+"("+str(err[1])+"): "+str(sys.exc_info()[1]) - if new_hand_id: # new_hand_id is none if we had an error prior to the store - sys.stderr.write("Database error %s in hand %d. Skipping.\n" % (err, int(new_hand_id))) - continue - - if type == "tour": # hand is from a tournament - mat_obj = tourny_finder.search(table_name) - if mat_obj: - (tour_number, tab_number) = mat_obj.group(1, 2) - temp_key = tour_number - else: # tourney, but can't get number and table - print "could not find tournament: skipping " - #sys.stderr.write("Could not find tournament %d in hand %d. Skipping.\n" % (int(tour_number), int(new_hand_id))) + cards = self.db_connection.get_cards(new_hand_id) + comm_cards = self.db_connection.get_common_cards(new_hand_id) + if comm_cards != {}: # stud! + cards['common'] = comm_cards['common'] + except Exception, err: + err = traceback.extract_tb(sys.exc_info()[2])[-1] + print "db error: skipping "+str(new_hand_id)+" "+err[2]+"("+str(err[1])+"): "+str(sys.exc_info()[1]) + if new_hand_id: # new_hand_id is none if we had an error prior to the store + sys.stderr.write("Database error %s in hand %d. Skipping.\n" % (err, int(new_hand_id))) continue - - else: - temp_key = table_name -# Update an existing HUD - if temp_key in self.hud_dict: - self.hud_dict[temp_key].stat_dict = stat_dict - self.hud_dict[temp_key].cards = cards - [aw.update_data(new_hand_id, self.db_connection) for aw in self.hud_dict[temp_key].aux_windows] - self.update_HUD(new_hand_id, temp_key, self.config) - -# Or create a new HUD - else: - if type == "tour": - tablewindow = Tables.discover_tournament_table(self.config, tour_number, tab_number) + if type == "tour": # hand is from a tournament + mat_obj = tourny_finder.search(table_name) + if mat_obj: + (tour_number, tab_number) = mat_obj.group(1, 2) + temp_key = tour_number + else: # tourney, but can't get number and table + print "could not find tournament: skipping " + #sys.stderr.write("Could not find tournament %d in hand %d. Skipping.\n" % (int(tour_number), int(new_hand_id))) + continue + + else: + temp_key = table_name + +# Update an existing HUD + if temp_key in self.hud_dict: + self.hud_dict[temp_key].stat_dict = stat_dict + self.hud_dict[temp_key].cards = cards + [aw.update_data(new_hand_id, self.db_connection) for aw in self.hud_dict[temp_key].aux_windows] + self.update_HUD(new_hand_id, temp_key, self.config) + +# Or create a new HUD else: - tablewindow = Tables.discover_table_by_name(self.config, table_name) - if tablewindow == None: -# If no client window is found on the screen, complain and continue if type == "tour": - table_name = "%s %s" % (tour_number, tab_number) - sys.stderr.write("table name "+table_name+" not found, skipping.\n") - else: - self.create_HUD(new_hand_id, tablewindow, temp_key, max, poker_game, stat_dict, cards) - self.db_connection.connection.rollback() + tablewindow = Tables.discover_tournament_table(self.config, tour_number, tab_number) + else: + tablewindow = Tables.discover_table_by_name(self.config, table_name) + if tablewindow == None: +# If no client window is found on the screen, complain and continue + if type == "tour": + table_name = "%s %s" % (tour_number, tab_number) + sys.stderr.write("table name "+table_name+" not found, skipping.\n") + else: + self.create_HUD(new_hand_id, tablewindow, temp_key, max, poker_game, stat_dict, cards) + self.db_connection.connection.rollback() + except: + err = traceback.extract_tb(sys.exc_info()[2])[-1] + print "***Error: "+err[2]+"("+str(err[1])+"): "+str(sys.exc_info()[1]) if __name__== "__main__": diff --git a/pyfpdb/Hud.py b/pyfpdb/Hud.py index 43b8731b..e773a8a1 100644 --- a/pyfpdb/Hud.py +++ b/pyfpdb/Hud.py @@ -73,6 +73,7 @@ class Hud: self.stacked = True self.site = table.site self.mw_created = False + self.hud_params = parent.hud_params self.stat_windows = {} self.popup_windows = {} @@ -218,7 +219,11 @@ class Hud: # heap dead, burnt bodies, blood 'n guts, veins between my teeth for s in self.stat_windows.itervalues(): s.kill_popups() - s.window.destroy() + try: + # throws "invalid window handle" in WinXP (sometimes?) + s.window.destroy() + except: + pass self.stat_windows = {} # also kill any aux windows for aux in self.aux_windows: @@ -621,7 +626,57 @@ class Popup_window: # window.window.reparent(self.table.gdkhandle, 0, 0) window.window.set_transient_for(self.table.gdkhandle) # window.present() - + + + +class HUD_Params: + + def __init__(self, hud): + self.aggregate_stats = hud.def_aggregate_stats + self.hud_style = hud.def_hud_style + self.hud_days = hud.def_hud_days + self.agg_bb_mult = hud.def_agg_bb_mult + self.hud_session_gap = hud.def_hud_session_gap + + self.h_aggregate_stats = hud.def_h_aggregate_stats + self.h_hud_style = hud.def_h_hud_style + self.h_hud_days = hud.def_h_hud_days + self.h_agg_bb_mult = hud.def_h_agg_bb_mult + self.h_hud_session_gap = hud.def_h_hud_session_gap + + def set_aggregate_stats(self, agg): + self.aggregate_stats = agg + def set_hud_style(self, style): + self.hud_style = style + def set_hud_days(self, days): + self.hud_days = days + def set_agg_bb_mult(self, mult): + self.agg_bb_mult = mult + def set_hud_session_gap(self, gap): + self.hud_session_gap = gap + + def set_aggregate_stats(self, agg): + self.aggregate_stats = agg + def set_hud_style(self, style): + self.hud_style = style + def set_hud_days(self, days): + self.hud_days = days + def set_agg_bb_mult(self, mult): + self.agg_bb_mult = mult + def set_hud_session_gap(self, gap): + self.hud_session_gap = gap + + def get_aggregate_stats(self): + return self.aggregate_stats + def get_hud_style(self): + return self.hud_style + def get_hud_days(self): + return self.hud_days + def get_agg_bb_mult(self): + return self.agg_bb_mult + def get_hud_session_gap(self): + return self.hud_session_gap + if __name__== "__main__": main_window = gtk.Window() diff --git a/pyfpdb/SQL.py b/pyfpdb/SQL.py index c0bbabd5..71b697f5 100644 --- a/pyfpdb/SQL.py +++ b/pyfpdb/SQL.py @@ -1581,10 +1581,11 @@ class Sql: """ self.query['get_table_name'] = """ - select tableName, maxSeats, category, type - from Hands,Gametypes - where Hands.id = %s - and Gametypes.id = Hands.gametypeId + select h.tableName, h.maxSeats, gt.category, gt.type, gt.siteId + from Hands h + ,Gametypes gt + where h.id = %s + and gt.id = h.gametypeId """ self.query['get_actual_seat'] = """ diff --git a/pyfpdb/TournamentTracker.py b/pyfpdb/TournamentTracker.py index 7a68a644..2ac95b24 100644 --- a/pyfpdb/TournamentTracker.py +++ b/pyfpdb/TournamentTracker.py @@ -248,7 +248,7 @@ class ttracker_main(object): # get basic info about the new hand from the db # if there is a db error, complain, skip hand, and proceed try: - (table_name, max, poker_game, type) = self.db_connection.get_table_name(new_hand_id) + (table_name, max, poker_game, type, site_id) = self.db_connection.get_table_name(new_hand_id) stat_dict = self.db_connection.get_stats_from_hand(new_hand_id, aggregate_stats[type] ,hud_style, agg_bb_mult) diff --git a/pyfpdb/fpdb_import.py b/pyfpdb/fpdb_import.py index 2e299c5f..9198c4fd 100644 --- a/pyfpdb/fpdb_import.py +++ b/pyfpdb/fpdb_import.py @@ -549,7 +549,7 @@ class Importer: if self.callHud: #print "call to HUD here. handsId:",handsId #pipe the Hands.id out to the HUD - #print "sending hand to hud", handsId, "pipe =", self.caller.pipe_to_hud + print "sending hand to hud", handsId, "pipe =", self.caller.pipe_to_hud self.caller.pipe_to_hud.stdin.write("%s" % (handsId) + os.linesep) except Exceptions.DuplicateError: duplicates += 1 From e75d91512022d258dfc6cefec88167ceb62e6fb9 Mon Sep 17 00:00:00 2001 From: sqlcoder Date: Sat, 26 Sep 2009 23:32:44 +0100 Subject: [PATCH 08/56] allow hudcache rebuild to only start Hero's stats from chosen date :-) --- pyfpdb/Database.py | 23 +++++++++++++++-- pyfpdb/SQL.py | 3 +++ pyfpdb/fpdb.py | 62 ++++++++++++++++++++++++++++++++++++++++------ 3 files changed, 79 insertions(+), 9 deletions(-) diff --git a/pyfpdb/Database.py b/pyfpdb/Database.py index 1b351f86..3c8b4246 100755 --- a/pyfpdb/Database.py +++ b/pyfpdb/Database.py @@ -49,12 +49,15 @@ import logging, logging.config logging.config.fileConfig(os.path.join(sys.path[0],"logging.conf")) log = logging.getLogger('db') + class Database: MYSQL_INNODB = 2 PGSQL = 3 SQLITE = 4 + hero_hudstart_def = '1999-12-31' # default for length of Hero'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 # 1 - drop during bulk import @@ -183,6 +186,7 @@ class Database: 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.fdb.do_connect(c) self.connection = self.fdb.db @@ -1098,13 +1102,28 @@ class Database: #end def fillDefaultData - def rebuild_hudcache(self): + def rebuild_hudcache(self, start=None): """clears hudcache and rebuilds from the individual handsplayers records""" try: stime = time() + # get hero's screen names and player ids + self.hero, self.hero_ids = {}, {} + if start == None: + start = self.hero_hudstart_def + for site in self.config.get_supported_sites(): + result = self.get_site_id(site) + if result: + site_id = result[0][0] + self.hero[site_id] = self.config.supported_sites[site].screen_name + self.hero_ids[site_id] = self.get_player_id(self.config, site, self.hero[site_id]) + + where = "where hp.playerId not in (-53, " + ", ".join(map(str, self.hero_ids.values())) \ + + ") or h.handStart > '" + start + "'" + rebuild_sql = self.sql.query['rebuildHudCache'].replace('', where) + self.get_cursor().execute(self.sql.query['clearHudCache']) - self.get_cursor().execute(self.sql.query['rebuildHudCache']) + self.get_cursor().execute(rebuild_sql) self.commit() print "Rebuild hudcache took %.1f seconds" % (time() - stime,) except: diff --git a/pyfpdb/SQL.py b/pyfpdb/SQL.py index 71b697f5..d4350ad5 100644 --- a/pyfpdb/SQL.py +++ b/pyfpdb/SQL.py @@ -2511,6 +2511,7 @@ class Sql: ,sum(street4CheckCallRaiseDone) FROM HandsPlayers hp INNER JOIN Hands h ON (h.id = hp.handId) + GROUP BY h.gametypeId ,hp.playerId ,h.seats @@ -2659,6 +2660,7 @@ class Sql: ,sum(CAST(street4CheckCallRaiseDone as integer)) FROM HandsPlayers hp INNER JOIN Hands h ON (h.id = hp.handId) + GROUP BY h.gametypeId ,hp.playerId ,h.seats @@ -2807,6 +2809,7 @@ class Sql: ,sum(CAST(street4CheckCallRaiseDone as integer)) FROM HandsPlayers hp INNER JOIN Hands h ON (h.id = hp.handId) + GROUP BY h.gametypeId ,hp.playerId ,h.seats diff --git a/pyfpdb/fpdb.py b/pyfpdb/fpdb.py index fd2feca2..05121474 100755 --- a/pyfpdb/fpdb.py +++ b/pyfpdb/fpdb.py @@ -257,17 +257,65 @@ class fpdb: def dia_recreate_hudcache(self, widget, data=None): if self.obtain_global_lock(): - dia_confirm = gtk.MessageDialog(parent=None, flags=0, type=gtk.MESSAGE_WARNING, buttons=(gtk.BUTTONS_YES_NO), message_format="Confirm recreating HUD cache") + self.dia_confirm = gtk.MessageDialog(parent=None, flags=0, type=gtk.MESSAGE_WARNING, buttons=(gtk.BUTTONS_YES_NO), message_format="Confirm recreating HUD cache") diastring = "Please confirm that you want to re-create the HUD cache." - dia_confirm.format_secondary_text(diastring) - - response = dia_confirm.run() - dia_confirm.destroy() + self.dia_confirm.format_secondary_text(diastring) + + hb = gtk.HBox(True, 1) + self.start_date = gtk.Entry(max=12) + self.start_date.set_text(self.db.hero_hudstart_def) + 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.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() + + response = self.dia_confirm.run() + self.dia_confirm.destroy() if response == gtk.RESPONSE_YES: - self.db.rebuild_hudcache() - elif response == gtk.REPSONSE_NO: + self.db.rebuild_hudcache( self.start_date.get_text() ) + elif response == gtk.RESPONSE_NO: print 'User cancelled rebuilding hud cache' + self.release_global_lock() + + def __calendar_dialog(self, widget, entry): + self.dia_confirm.set_modal(False) + d = gtk.Window(gtk.WINDOW_TOPLEVEL) + d.set_title('Pick a date') + + vb = gtk.VBox() + cal = gtk.Calendar() + vb.pack_start(cal, expand=False, padding=0) + + btn = gtk.Button('Done') + btn.connect('clicked', self.__get_date, cal, entry, d) + + vb.pack_start(btn, expand=False, padding=4) + + d.add(vb) + d.set_position(gtk.WIN_POS_MOUSE) + d.show_all() + + def __get_dates(self): + t1 = self.start_date.get_text() + if t1 == '': + t1 = '1970-01-01' + return (t1) + + def __get_date(self, widget, calendar, entry, win): + # year and day are correct, month is 0..11 + (year, month, day) = calendar.get_date() + month += 1 + ds = '%04d-%02d-%02d' % (year, month, day) + entry.set_text(ds) + win.destroy() + self.dia_confirm.set_modal(True) def dia_regression_test(self, widget, data=None): self.warning_box("Unimplemented: Regression Test") From b054a9c09ac34aa11a35b881ee3517ee3f2c427e Mon Sep 17 00:00:00 2001 From: sqlcoder Date: Sun, 27 Sep 2009 00:06:06 +0100 Subject: [PATCH 09/56] fix params when creating Database instance --- pyfpdb/HUD_main.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pyfpdb/HUD_main.py b/pyfpdb/HUD_main.py index cc23be96..9e9f2cfa 100755 --- a/pyfpdb/HUD_main.py +++ b/pyfpdb/HUD_main.py @@ -182,7 +182,7 @@ class HUD_main(object): # need their own access to the database, but should open their own # if it is required. try: - self.db_connection = Database.Database(self.config, self.db_name, 'temp') + self.db_connection = Database.Database(self.config) self.db_connection.init_hud_stat_vars(hud_days) tourny_finder = re.compile('(\d+) (\d+)') From c1711c4e2eea43cbc57f49bbc372c28d46bb5c48 Mon Sep 17 00:00:00 2001 From: sqlcoder Date: Sun, 27 Sep 2009 01:42:26 +0100 Subject: [PATCH 10/56] refine new date option on hudcache rebuild --- pyfpdb/Database.py | 26 ++++++++++++++++++++++++++ pyfpdb/SQL.py | 7 ++++++- pyfpdb/fpdb.py | 2 +- 3 files changed, 33 insertions(+), 2 deletions(-) diff --git a/pyfpdb/Database.py b/pyfpdb/Database.py index 3c8b4246..354081f5 100755 --- a/pyfpdb/Database.py +++ b/pyfpdb/Database.py @@ -1132,6 +1132,32 @@ class Database: print err #end def rebuild_hudcache + def get_hero_hudcache_start(self): + """fetches earliest stylekey from hudcache for one of hero's player ids""" + + try: + self.hero, self.hero_ids = {}, {'dummy':-53} # make sure at least one value is used in sql + for site in self.config.get_supported_sites(): + result = self.get_site_id(site) + if result: + site_id = result[0][0] + self.hero[site_id] = self.config.supported_sites[site].screen_name + self.hero_ids[site_id] = self.get_player_id(self.config, site, self.hero[site_id]) + + q = self.sql.query['get_hero_hudcache_start'].replace("", str(tuple(self.hero_ids.values()))) + c = self.get_cursor() + c.execute(q) + tmp = c.fetchone() + if tmp == None: + return self.hero_hudstart_def + else: + return "20"+tmp[0][1:3] + "-" + tmp[0][3:5] + "-" + tmp[0][5:7] + except: + err = traceback.extract_tb(sys.exc_info()[2])[-1] + print "Error rebuilding hudcache:", str(sys.exc_value) + print err + #end def get_hero_hudcache_start + def analyzeDB(self): """Do whatever the DB can offer to update index/table statistics""" diff --git a/pyfpdb/SQL.py b/pyfpdb/SQL.py index d4350ad5..abef4b76 100644 --- a/pyfpdb/SQL.py +++ b/pyfpdb/SQL.py @@ -2818,9 +2818,14 @@ class Sql: ,'d' || substr(strftime('%Y%m%d', h.handStart),3,7) """ + self.query['get_hero_hudcache_start'] = """select min(hc.styleKey) + from HudCache hc + where hc.playerId in + and hc.styleKey like 'd%'""" + if db_server == 'mysql': self.query['analyze'] = """ - analyze table Autorates, GameTypes, Hands, HandsPlayers, Hudcache, Players + analyze table Autorates, GameTypes, Hands, HandsPlayers, HudCache, Players , Settings, Sites, Tourneys, TourneysPlayers, TourneyTypes """ else: # assume postgres diff --git a/pyfpdb/fpdb.py b/pyfpdb/fpdb.py index 05121474..4703d96d 100755 --- a/pyfpdb/fpdb.py +++ b/pyfpdb/fpdb.py @@ -263,7 +263,7 @@ class fpdb: hb = gtk.HBox(True, 1) self.start_date = gtk.Entry(max=12) - self.start_date.set_text(self.db.hero_hudstart_def) + self.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)) From 6f75719ffe8ce6a48c0ed1d6f0c49d1b400b0b59 Mon Sep 17 00:00:00 2001 From: sqlcoder Date: Sun, 27 Sep 2009 02:06:07 +0100 Subject: [PATCH 11/56] refine hero's player id derivation in empty db's --- pyfpdb/Database.py | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/pyfpdb/Database.py b/pyfpdb/Database.py index 354081f5..7c0add49 100755 --- a/pyfpdb/Database.py +++ b/pyfpdb/Database.py @@ -1116,10 +1116,16 @@ class Database: if result: site_id = result[0][0] self.hero[site_id] = self.config.supported_sites[site].screen_name - self.hero_ids[site_id] = self.get_player_id(self.config, site, self.hero[site_id]) + p_id = self.get_player_id(self.config, site, self.hero[site_id]) + if p_id: + self.hero_ids[site_id] = p_id - where = "where hp.playerId not in (-53, " + ", ".join(map(str, self.hero_ids.values())) \ - + ") or h.handStart > '" + start + "'" + print "hero_ids =", self.hero_ids + if self.hero_ids == {}: + where = "" + else: + where = "where hp.playerId not in (-53, " + ", ".join(map(str, self.hero_ids.values())) \ + + ") or h.handStart > '" + start + "'" rebuild_sql = self.sql.query['rebuildHudCache'].replace('', where) self.get_cursor().execute(self.sql.query['clearHudCache']) From 9a7d7267ff106f4bde27d448adb4f9c13cc5a263 Mon Sep 17 00:00:00 2001 From: sqlcoder Date: Sun, 27 Sep 2009 10:42:33 +0100 Subject: [PATCH 12/56] remove print --- pyfpdb/Database.py | 1 - 1 file changed, 1 deletion(-) diff --git a/pyfpdb/Database.py b/pyfpdb/Database.py index 7c0add49..1c9cbfef 100755 --- a/pyfpdb/Database.py +++ b/pyfpdb/Database.py @@ -1120,7 +1120,6 @@ class Database: if p_id: self.hero_ids[site_id] = p_id - print "hero_ids =", self.hero_ids if self.hero_ids == {}: where = "" else: From d5a1523e597e4cb2b95775c0354f67809d92e45c Mon Sep 17 00:00:00 2001 From: sqlcoder Date: Sun, 27 Sep 2009 11:40:39 +0100 Subject: [PATCH 13/56] fix startCard calcs --- pyfpdb/Card.py | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/pyfpdb/Card.py b/pyfpdb/Card.py index 8e99599b..287a0f6a 100755 --- a/pyfpdb/Card.py +++ b/pyfpdb/Card.py @@ -26,17 +26,17 @@ def twoStartCards(value1, suit1, value2, suit2): if value1 < 2 or value2 < 2: ret = 0 if value1 == value2: # pairs - ret = (13 * (value2-2) + (value2-1) ) + ret = (13 * (value2-2) + (value2-2) ) elif suit1 == suit2: if value1 > value2: - ret = 13 * (value1-2) + (value2-1) + ret = 13 * (value1-2) + (value2-2) else: - ret = 13 * (value2-2) + (value1-1) + ret = 13 * (value2-2) + (value1-2) else: if value1 > value2: - ret = 13 * (value2-2) + (value2-1) + ret = 13 * (value2-2) + (value1-2) else: - ret = 13 * (value1-2) + (value2-1) + ret = 13 * (value1-2) + (value2-2) # print "twoStartCards(", value1, suit1, value2, suit2, ")=", ret return ret @@ -46,7 +46,6 @@ def twoStartCardString(card): into a string like AQo """ ret = 'xx' if card > 0: - card -= 1 s = ('2', '3', '4', '5', '6', '7', '8', '9', 'T', 'J', 'Q', 'K', 'A') x = card / 13 y = card - 13 * x From 8d01caa30f23e82383678aa6ae482c4579af0909 Mon Sep 17 00:00:00 2001 From: sqlcoder Date: Sun, 27 Sep 2009 12:21:22 +0100 Subject: [PATCH 14/56] try to work around Everleaf problem where winning hole cards not always shown - derive from winning hand where possible --- pyfpdb/Hand.py | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/pyfpdb/Hand.py b/pyfpdb/Hand.py index 61533e63..bd905036 100644 --- a/pyfpdb/Hand.py +++ b/pyfpdb/Hand.py @@ -673,7 +673,14 @@ class HoldemOmahaHand(Hand): if shown: self.shown.add(player) if mucked: self.mucked.add(player) else: - self.addHoleCards('PREFLOP', player, open=[], closed=cards, shown=shown, mucked=mucked, dealt=dealt) + if len(cards) in (2, 4): # avoid adding board by mistake (Everleaf problem) + self.addHoleCards('PREFLOP', player, open=[], closed=cards, shown=shown, mucked=mucked, dealt=dealt) + elif len(cards) == 5: # cards holds a winning hand, not hole cards + # filter( lambda x: x not in b, a ) # calcs a - b where a and b are lists + # so diff is set to the winning hand minus the board cards, if we're lucky that leaves the hole cards + diff = filter( lambda x: x not in self.board['FLOP']+self.board['TURN']+self.board['RIVER'], cards ) + if len(diff) == 2 and self.gametype['category'] in ('holdem'): + self.addHoleCards('PREFLOP', player, open=[], closed=diff, shown=shown, mucked=mucked, dealt=dealt) def getStreetTotals(self): # street1Pot INT, /* pot size at flop/street4 */ From 01c33c26f82cf6ca9c73d3a94c96228d4d90ea6f Mon Sep 17 00:00:00 2001 From: sqlcoder Date: Sun, 27 Sep 2009 12:47:21 +0100 Subject: [PATCH 15/56] fix tourneytypes insert for postgres again --- pyfpdb/Database.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pyfpdb/Database.py b/pyfpdb/Database.py index 1c9cbfef..638406f1 100755 --- a/pyfpdb/Database.py +++ b/pyfpdb/Database.py @@ -1094,7 +1094,7 @@ class Database: if self.backend == self.SQLITE: c.execute("INSERT INTO TourneyTypes (id, siteId, buyin, fee) VALUES (NULL, 1, 0, 0);") elif self.backend == self.PGSQL: - c.execute("insert into TourneyTypes values (0,1,0,0,0,False,False,null,False,False,False);") + c.execute("insert into TourneyTypes values (1,1,0,0,0,False,False,null,False,False,False);") else: c.execute("""insert into TourneyTypes(id, siteId, buyin, fee, maxSeats, knockout ,rebuyOrAddon, speed, headsUp, shootout, matrix) From 8353d0739b0b080a3e734615a54e89489019d5eb Mon Sep 17 00:00:00 2001 From: sqlcoder Date: Sun, 27 Sep 2009 13:36:45 +0100 Subject: [PATCH 16/56] improve hudcache recalc when db is empty and avoid mysql long int problem --- pyfpdb/Database.py | 33 ++++++++++++++++++++++----------- 1 file changed, 22 insertions(+), 11 deletions(-) diff --git a/pyfpdb/Database.py b/pyfpdb/Database.py index 638406f1..9fafe68a 100755 --- a/pyfpdb/Database.py +++ b/pyfpdb/Database.py @@ -1107,10 +1107,12 @@ class Database: try: stime = time() - # get hero's screen names and player ids - self.hero, self.hero_ids = {}, {} - if start == None: - start = self.hero_hudstart_def + # derive list of program owner's player ids + self.hero = {} # name of program owner indexed by site id + self.hero_ids = {'dummy':-53, 'dummy2':-52} # playerid of owner indexed by site id + # make sure at least two values in list + # so that tuple generation creates doesn't use + # () or (1,) style for site in self.config.get_supported_sites(): result = self.get_site_id(site) if result: @@ -1118,13 +1120,15 @@ class Database: self.hero[site_id] = self.config.supported_sites[site].screen_name p_id = self.get_player_id(self.config, site, self.hero[site_id]) if p_id: - self.hero_ids[site_id] = p_id - + self.hero_ids[site_id] = int(p_id) + + if start == None: + start = self.hero_hudstart_def if self.hero_ids == {}: where = "" else: - where = "where hp.playerId not in (-53, " + ", ".join(map(str, self.hero_ids.values())) \ - + ") or h.handStart > '" + start + "'" + where = "where hp.playerId not in " + str(tuple(self.hero_ids.values())) \ + + " or h.handStart > '" + start + "'" rebuild_sql = self.sql.query['rebuildHudCache'].replace('', where) self.get_cursor().execute(self.sql.query['clearHudCache']) @@ -1141,19 +1145,26 @@ class Database: """fetches earliest stylekey from hudcache for one of hero's player ids""" try: - self.hero, self.hero_ids = {}, {'dummy':-53} # make sure at least one value is used in sql + # derive list of program owner's player ids + self.hero = {} # name of program owner indexed by site id + self.hero_ids = {'dummy':-53, 'dummy2':-52} # playerid of owner indexed by site id + # make sure at least two values in list + # so that tuple generation creates doesn't use + # () or (1,) style for site in self.config.get_supported_sites(): result = self.get_site_id(site) if result: site_id = result[0][0] self.hero[site_id] = self.config.supported_sites[site].screen_name - self.hero_ids[site_id] = self.get_player_id(self.config, site, self.hero[site_id]) + 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) tmp = c.fetchone() - if tmp == None: + if tmp == (None,): return self.hero_hudstart_def else: return "20"+tmp[0][1:3] + "-" + tmp[0][3:5] + "-" + tmp[0][5:7] From 7f47a753dbe6b1f029c92c037dbd89822ab12c94 Mon Sep 17 00:00:00 2001 From: sqlcoder Date: Sun, 27 Sep 2009 21:21:26 +0100 Subject: [PATCH 17/56] cosmetic change to comment --- pyfpdb/Database.py | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/pyfpdb/Database.py b/pyfpdb/Database.py index 9fafe68a..2a9e0521 100755 --- a/pyfpdb/Database.py +++ b/pyfpdb/Database.py @@ -372,7 +372,10 @@ class Database: return winners def init_hud_stat_vars(self, hud_days): - """Initialise variables used by Hud to fetch stats.""" + """Initialise variables used by Hud to fetch stats: + self.hand_1day_ago handId of latest hand played more than a day ago + self.date_ndays_ago date n days ago + """ self.hand_1day_ago = 1 try: @@ -385,9 +388,10 @@ class Database: else: if row and row[0]: self.hand_1_day_ago = row[0] - d = timedelta(days=hud_days) - now = datetime.utcnow() - d - self.date_ndays_ago = "d%02d%02d%02d" % (now.year - 2000, now.month, now.day) + + d = timedelta(days=hud_days) + now = datetime.utcnow() - d + self.date_ndays_ago = "d%02d%02d%02d" % (now.year - 2000, now.month, now.day) def init_player_hud_stat_vars(self, playerid): # not sure if this is workable, to be continued ... From d6414d211bcf003865f38155b24e7c974fa1e48f Mon Sep 17 00:00:00 2001 From: sqlcoder Date: Sun, 27 Sep 2009 21:23:00 +0100 Subject: [PATCH 18/56] allow separate hud options on each table and add aggregate options to main table menu --- pyfpdb/HUD_main.py | 70 ++++++++++++++++++++---------- pyfpdb/Hud.py | 104 ++++++++++++++++++++++----------------------- 2 files changed, 99 insertions(+), 75 deletions(-) diff --git a/pyfpdb/HUD_main.py b/pyfpdb/HUD_main.py index 9e9f2cfa..7d9a938d 100755 --- a/pyfpdb/HUD_main.py +++ b/pyfpdb/HUD_main.py @@ -57,36 +57,46 @@ import Tables import Hud # To add to config: -aggregate_stats = {"ring": False, "tour": False} # uses agg_bb_mult -hud_style = 'A' # A=All-time +#aggregate_stats = {"ring": False, "tour": False} # uses agg_bb_mult *** this var now replaced by def_hud_params list +#hud_style = 'A' # A=All-time *** this var now replaced by def_hud_params list # S=Session # T=timed (last n days - set hud_days to required value) # Future values may also include: # H=Hands (last n hands) -hud_days = 90 # Max number of days from each player to use for hud stats -agg_bb_mult = 100 # 1 = no aggregation. When aggregating stats across levels larger blinds +#hud_days = 90 # Max number of days from each player to use for hud stats *** this var now replaced by def_hud_params list +#agg_bb_mult = 100 # 1 = no aggregation. When aggregating stats across levels larger blinds *** this var now replaced by def_hud_params list # must be < (agg_bb_mult * smaller blinds) to be aggregated # ie. 100 will aggregate almost everything, 2 will probably agg just the # next higher and lower levels into the current one, try 3/10/30/100 -hud_session_gap = 30 # Gap (minutes) between hands that indicates a change of session +#hud_session_gap = 30 # Gap (minutes) between hands that indicates a change of session # (hands every 2 mins for 1 hour = one session, if followed # by a 40 minute gap and then more hands on same table that is # a new session) #hud_hands = 0 # Max number of hands from each player to use for hud stats (not used) -def_hud_params = { 'aggregate_ring' : False - , 'aggregate_tour' : False - , 'hud_style' : 'A' - , 'hud_days ' : 90 - , 'agg_bb_mult' : 100 - , 'hud_session_gap' : 30 - # second set of variables for hero +# New list to hold all HUD params +# - Set aggregate_ring and/or aggregate_tour to True is you want to include stats from other blind levels in the HUD display +# - If aggregation is used, the value of agg_bb_mult determines how what levels are included, e.g. +# if agg_bb_mult is 100, almost all levels are included in all HUD displays +# if agg_bb_mult is 2.1, levels from half to double the current blind level are included in the HUD +# - Set hud_style to A to see stats for all-time +# Set hud_style to S to only see stats for current session (currently this shows stats for the last 24 hours) +# Set hud_style to T to only see stats for the last N days (uses value in hud_days) +# - Set hud_days to N to see stats for the last N days in the HUD (only applies if hud_style is T) +def_hud_params = { # Settings for all players apart from program owner ('hero') + 'aggregate_ring' : False + , 'aggregate_tour' : True + , 'hud_style' : 'A' + , 'hud_days' : 90 + , 'agg_bb_mult' : 1 # 1 means no aggregation + # , 'hud_session_gap' : 30 not currently used + # Second set of variables for hero - these settings only apply to the program owner , 'h_aggregate_ring' : False - , 'h_aggreagte_tour' : False - , 'h_hud_style' : 'A' - , 'h_hud_days ' : 90 - , 'h_agg_bb_mult' : 100 - , 'h_hud_session_gap' : 30 + , 'h_aggreagte_tour' : True + , 'h_hud_style' : 'A' + , 'h_hud_days' : 90 + , 'h_agg_bb_mult' : 1 # 1 means no aggregation + # , 'h_hud_session_gap' : 30 not currently used } @@ -183,7 +193,6 @@ class HUD_main(object): # if it is required. try: self.db_connection = Database.Database(self.config) - self.db_connection.init_hud_stat_vars(hud_days) tourny_finder = re.compile('(\d+) (\d+)') # get hero's screen names and player ids @@ -205,11 +214,6 @@ class HUD_main(object): # if there is a db error, complain, skip hand, and proceed try: (table_name, max, poker_game, type, site_id) = self.db_connection.get_table_name(new_hand_id) - stat_dict = self.db_connection.get_stats_from_hand(new_hand_id, self.hud_params, self.hero_ids) - #self.hud_params['aggregate_tour'] if type = "tour" - # else self.hud_params['aggregate_ring'], - #hud_style, - #agg_bb_mult) cards = self.db_connection.get_cards(new_hand_id) comm_cards = self.db_connection.get_common_cards(new_hand_id) @@ -237,6 +241,16 @@ class HUD_main(object): # Update an existing HUD if temp_key in self.hud_dict: + try: + # get stats using hud's specific params + self.db_connection.init_hud_stat_vars( self.hud_dict[temp_key].hud_params['hud_days'] ) + stat_dict = self.db_connection.get_stats_from_hand(new_hand_id, self.hud_dict[temp_key].hud_params, self.hero_ids) + except: + err = traceback.extract_tb(sys.exc_info()[2])[-1] + print "db get_stats error: skipping "+str(new_hand_id)+" "+err[2]+"("+str(err[1])+"): "+str(sys.exc_info()[1]) + if new_hand_id: # new_hand_id is none if we had an error prior to the store + sys.stderr.write("Database get_stats error %s in hand %d. Skipping.\n" % (err, int(new_hand_id))) + continue self.hud_dict[temp_key].stat_dict = stat_dict self.hud_dict[temp_key].cards = cards [aw.update_data(new_hand_id, self.db_connection) for aw in self.hud_dict[temp_key].aux_windows] @@ -244,6 +258,16 @@ class HUD_main(object): # Or create a new HUD else: + try: + # get stats using default params + self.db_connection.init_hud_stat_vars( self.hud_params['hud_days'] ) + stat_dict = self.db_connection.get_stats_from_hand(new_hand_id, self.hud_params, self.hero_ids) + except: + err = traceback.extract_tb(sys.exc_info()[2])[-1] + print "db get_stats error: skipping "+str(new_hand_id)+" "+err[2]+"("+str(err[1])+"): "+str(sys.exc_info()[1]) + if new_hand_id: # new_hand_id is none if we had an error prior to the store + sys.stderr.write("Database get_stats error %s in hand %d. Skipping.\n" % (err, int(new_hand_id))) + continue if type == "tour": tablewindow = Tables.discover_tournament_table(self.config, tour_number, tab_number) else: diff --git a/pyfpdb/Hud.py b/pyfpdb/Hud.py index 16c8edc2..6073d619 100644 --- a/pyfpdb/Hud.py +++ b/pyfpdb/Hud.py @@ -144,6 +144,47 @@ class Hud: repositem = gtk.MenuItem('Reposition StatWindows') menu.append(repositem) repositem.connect("activate", self.reposition_windows) + + aggitem = gtk.MenuItem('Show Stats') + menu.append(aggitem) + aggMenu = gtk.Menu() + aggitem.set_submenu(aggMenu) + # set agg_bb_mult to 1 to stop aggregation + item = gtk.MenuItem('For This Blind Level') + item.ms = 1 + aggMenu.append(item) + item.connect("activate", self.set_aggregation) + setattr(self, 'showStatsMenuItem1', item) + # + item = gtk.MenuItem('For Multiple Blind Levels') + aggMenu.append(item) + setattr(self, 'showStatsMenuItem2', item) + # + item = gtk.MenuItem('0.5 to 2.0 x Current Blinds') + item.ms = 2.01 + aggMenu.append(item) + item.connect("activate", self.set_aggregation) + setattr(self, 'showStatsMenuItem3', item) + # + item = gtk.MenuItem('0.33 to 3.0 x Current Blinds') + item.ms = 3.01 + aggMenu.append(item) + item.connect("activate", self.set_aggregation) + setattr(self, 'showStatsMenuItem4', item) + # + item = gtk.MenuItem('0.1 to 10 x Current Blinds') + item.ms = 10.01 + aggMenu.append(item) + item.connect("activate", self.set_aggregation) + setattr(self, 'showStatsMenuItem5', item) + # + item = gtk.MenuItem('All Levels') + item.ms = 10000 + aggMenu.append(item) + item.connect("activate", self.set_aggregation) + setattr(self, 'showStatsMenuItem6', item) + + eventbox.connect_object("button-press-event", self.on_button_press, menu) debugitem = gtk.MenuItem('Debug StatWindows') menu.append(debugitem) @@ -177,9 +218,18 @@ class Hud: self.create(*self.creation_attrs) self.update(self.hand, self.config) except Exception, e: - print "Expcetion:",str(e) + print "Exception:",str(e) pass - + + def set_aggregation(self, widget): + # try setting these to true all the time, and set the multiplier to 1 to turn agg off: + self.hud_params['h_aggregate_ring'] = True + self.hud_params['h_aggregate_tour'] = True + + if self.hud_params['agg_bb_mult'] != widget.ms: + print 'set_aggregation', widget.ms + self.hud_params['agg_bb_mult'] = widget.ms + def update_table_position(self): if os.name == 'nt': if not win32gui.IsWindow(self.table.number): @@ -632,56 +682,6 @@ class Popup_window: window.window.set_transient_for(self.table.gdkhandle) # window.present() - - -class HUD_Params: - - def __init__(self, hud): - self.aggregate_stats = hud.def_aggregate_stats - self.hud_style = hud.def_hud_style - self.hud_days = hud.def_hud_days - self.agg_bb_mult = hud.def_agg_bb_mult - self.hud_session_gap = hud.def_hud_session_gap - - self.h_aggregate_stats = hud.def_h_aggregate_stats - self.h_hud_style = hud.def_h_hud_style - self.h_hud_days = hud.def_h_hud_days - self.h_agg_bb_mult = hud.def_h_agg_bb_mult - self.h_hud_session_gap = hud.def_h_hud_session_gap - - def set_aggregate_stats(self, agg): - self.aggregate_stats = agg - def set_hud_style(self, style): - self.hud_style = style - def set_hud_days(self, days): - self.hud_days = days - def set_agg_bb_mult(self, mult): - self.agg_bb_mult = mult - def set_hud_session_gap(self, gap): - self.hud_session_gap = gap - - def set_aggregate_stats(self, agg): - self.aggregate_stats = agg - def set_hud_style(self, style): - self.hud_style = style - def set_hud_days(self, days): - self.hud_days = days - def set_agg_bb_mult(self, mult): - self.agg_bb_mult = mult - def set_hud_session_gap(self, gap): - self.hud_session_gap = gap - - def get_aggregate_stats(self): - return self.aggregate_stats - def get_hud_style(self): - return self.hud_style - def get_hud_days(self): - return self.hud_days - def get_agg_bb_mult(self): - return self.agg_bb_mult - def get_hud_session_gap(self): - return self.hud_session_gap - if __name__== "__main__": main_window = gtk.Window() From db861292a5c635db0db08756947f24ed8272f33c Mon Sep 17 00:00:00 2001 From: sqlcoder Date: Sun, 27 Sep 2009 23:42:00 +0100 Subject: [PATCH 19/56] use False for boolean so it works in postgres as well as mysql --- pyfpdb/fpdb_parse_logic.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pyfpdb/fpdb_parse_logic.py b/pyfpdb/fpdb_parse_logic.py index 1334a8ac..02300315 100644 --- a/pyfpdb/fpdb_parse_logic.py +++ b/pyfpdb/fpdb_parse_logic.py @@ -81,7 +81,7 @@ def mainParser(settings, siteID, category, hand, config, db = None, writeq = Non fee = fpdb_simple.parseFee(hand[0]) entries = -1 #todo: parse this prizepool = -1 #todo: parse this - knockout = 0 + knockout = False tourneyStartTime= handStartTime #todo: read tourney start time rebuyOrAddon = fpdb_simple.isRebuyOrAddon(hand[0]) From b6ea02fd43d276a22fc63d347c2c99a3e10a100f Mon Sep 17 00:00:00 2001 From: sqlcoder Date: Mon, 28 Sep 2009 00:44:55 +0100 Subject: [PATCH 20/56] improve tourney importing --- pyfpdb/Database.py | 63 ++++++++++++++++++++++++++++++------------- pyfpdb/fpdb_simple.py | 36 +++++++++++++++++++------ 2 files changed, 73 insertions(+), 26 deletions(-) diff --git a/pyfpdb/Database.py b/pyfpdb/Database.py index 2a9e0521..6f1183b6 100755 --- a/pyfpdb/Database.py +++ b/pyfpdb/Database.py @@ -1098,8 +1098,10 @@ class Database: if self.backend == self.SQLITE: c.execute("INSERT INTO TourneyTypes (id, siteId, buyin, fee) VALUES (NULL, 1, 0, 0);") elif self.backend == self.PGSQL: - c.execute("insert into TourneyTypes values (1,1,0,0,0,False,False,null,False,False,False);") - else: + c.execute("""insert into TourneyTypes(siteId, buyin, fee, maxSeats, knockout + ,rebuyOrAddon, speed, headsUp, shootout, matrix) + values (1, 0, 0, 0, False, False, null, False, False, False);""") + elif self.backend == self.MYSQL_INNODB: c.execute("""insert into TourneyTypes(id, siteId, buyin, fee, maxSeats, knockout ,rebuyOrAddon, speed, headsUp, shootout, matrix) values (1, 1, 0, 0, 0, False, False, null, False, False, False);""") @@ -1768,6 +1770,8 @@ class Database: #cursor.execute("SELECT id FROM HandsPlayers WHERE handId=%s AND playerId+0=%s", (hands_id, player_ids[i])) #result.append(cursor.fetchall()[0][0]) except: + 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 @@ -2000,27 +2004,40 @@ class Database: #end def storeHudCache def store_tourneys(self, tourneyTypeId, siteTourneyNo, entries, prizepool, startTime): + ret = -1 try: # try and create tourney record, fetch id if it already exists # avoids race condition when doing the select first + cursor = self.get_cursor() + cursor.execute("savepoint ins_tourney") cursor.execute("""INSERT INTO Tourneys (tourneyTypeId, siteTourneyNo, entries, prizepool, startTime) VALUES (%s, %s, %s, %s, %s)""".replace('%s', self.sql.query['placeholder']) ,(tourneyTypeId, siteTourneyNo, entries, prizepool, startTime)) - tmp = self.get_last_insert_id(cursor) - #cursor.execute("SELECT id FROM Tourneys WHERE siteTourneyNo=%s AND tourneyTypeId+0=%s", (siteTourneyNo, tourneyTypeId)) - #tmp=cursor.fetchone() - #print "created new tourneys.id:",tmp + ret = self.get_last_insert_id(cursor) + #print "created new tourneys.id:",ret except: - #if str(sys.exc_value) .... not unique index error: + #if str(sys.exc_value) contains 'sitetourneyno': # raise FpdbError( "store_tourneys error: " + str(sys.exc_value) ) #else: - cursor = self.get_cursor() - cursor.execute( "SELECT id FROM Tourneys WHERE siteTourneyNo=%s AND tourneyTypeId+0=%s".replace('%s', self.sql.query['placeholder']) - , (siteTourneyNo, tourneyTypeId) ) - tmp = cursor.fetchone()[0] - - return tmp + #print "error insert tourney (%s) trying select ..." % (str(sys.exc_value),) + cursor.execute("rollback to savepoint ins_tourney") + try: + cursor.execute( "SELECT id FROM Tourneys WHERE siteTourneyNo=%s AND tourneyTypeId+0=%s".replace('%s', self.sql.query['placeholder']) + , (siteTourneyNo, tourneyTypeId) ) + rec = cursor.fetchone() + #print "select tourney result: ", rec + try: + len(rec) + ret = rec[0] + except: + print "Tourney id not found" + except: + print "Error selecting tourney id:", str(sys.exc_info()[1]) + + cursor.execute("release savepoint ins_tourney") + #print "store_tourneys returning", ret + return ret #end def store_tourneys def store_tourneys_players(self, tourney_id, player_ids, payin_amounts, ranks, winnings): @@ -2034,21 +2051,31 @@ class Database: #print "winnings:",winnings for i in xrange(len(player_ids)): try: + cursor.execute("savepoint ins_tplayer") 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) - #print "created new tourneys_players.id:",tmp + result.append(tmp) + #print "created new tourneys_players.id:", tmp except: + cursor.execute("rollback to savepoint ins_tplayer") cursor.execute("SELECT id FROM TourneysPlayers WHERE tourneyId=%s AND playerId+0=%s".replace('%s', self.sql.query['placeholder']) ,(tourney_id, player_ids[i])) - tmp=cursor.fetchone()[0] - #print "tried SELECTing tourneys_players.id:",tmp - result.append(tmp) + tmp = cursor.fetchone() + #print "tried SELECTing tourneys_players.id:", tmp + try: + len(tmp) + result.append(tmp[0]) + except: + print "tplayer id not found for tourney,player %s,%s" % (tourney_id, player_ids[i]) + pass except: raise FpdbError( "store_tourneys_players error: " + str(sys.exc_value) ) - + + cursor.execute("release savepoint ins_tplayer") + #print "store_tourneys_players returning", result return result #end def store_tourneys_players diff --git a/pyfpdb/fpdb_simple.py b/pyfpdb/fpdb_simple.py index 3f54d25f..3e2d6f5f 100644 --- a/pyfpdb/fpdb_simple.py +++ b/pyfpdb/fpdb_simple.py @@ -913,32 +913,52 @@ def recogniseGametypeID(backend, db, cursor, topline, smallBlindLine, site_id, c #end def recogniseGametypeID def recogniseTourneyTypeId(db, siteId, tourneySiteId, buyin, fee, knockout, rebuyOrAddon): + ret = -1 cursor = db.get_cursor() # First we try to find the tourney itself (by its tourneySiteId) in case it has already been inserted before (by a summary file for instance) # The reason is that some tourneys may not be identified correctly in the HH toplines (especially Buy-In and Fee which are used to search/create the TourneyTypeId) #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() + 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 AND knockout=%s AND rebuyOrAddon=%s""" , (siteId, buyin, fee, knockout, rebuyOrAddon) ) - result=cursor.fetchone() - #print "tried SELECTing gametypes.id, result:",result + 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 - cursor.execute( """INSERT INTO TourneyTypes (siteId, buyin, fee, knockout, rebuyOrAddon) - VALUES (%s, %s, %s, %s, %s)""" - , (siteId, buyin, fee, knockout, rebuyOrAddon) ) - result = db.get_last_insert_id(cursor) + #print "insert new tourneytype record ..." + try: + cursor.execute( """INSERT INTO TourneyTypes (siteId, buyin, fee, knockout, rebuyOrAddon) + VALUES (%s, %s, %s, %s, %s)""" + , (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 + AND knockout=%s AND rebuyOrAddon=%s""" + , (siteId, buyin, fee, knockout, rebuyOrAddon) ) + result = cursor.fetchone() + try: + len(result) + ret = result[0] + except: + print "Failed to find or insert TourneyTypes record" + ret = -1 # failed to find or insert record + #print "tried selecting tourneytypes.id again, result:", result - return result[0] + #print "recogniseTourneyTypeId: returning", ret + return ret #end def recogniseTourneyTypeId From cb9a972eda6b74e5a68ab7ac4f4b2459fc567d03 Mon Sep 17 00:00:00 2001 From: sqlcoder Date: Mon, 28 Sep 2009 00:51:09 +0100 Subject: [PATCH 21/56] add aggregation options to hud menu --- pyfpdb/HUD_main.py | 12 ++++++------ pyfpdb/Hud.py | 14 +++++++------- 2 files changed, 13 insertions(+), 13 deletions(-) diff --git a/pyfpdb/HUD_main.py b/pyfpdb/HUD_main.py index 7d9a938d..bf1beef3 100755 --- a/pyfpdb/HUD_main.py +++ b/pyfpdb/HUD_main.py @@ -56,15 +56,15 @@ import Database import Tables import Hud -# To add to config: -#aggregate_stats = {"ring": False, "tour": False} # uses agg_bb_mult *** this var now replaced by def_hud_params list -#hud_style = 'A' # A=All-time *** this var now replaced by def_hud_params list +# To add to config: *** these vars now replaced by def_hud_params list +#aggregate_stats = {"ring": False, "tour": False} # uses agg_bb_mult +#hud_style = 'A' # A=All-time # S=Session # T=timed (last n days - set hud_days to required value) # Future values may also include: # H=Hands (last n hands) -#hud_days = 90 # Max number of days from each player to use for hud stats *** this var now replaced by def_hud_params list -#agg_bb_mult = 100 # 1 = no aggregation. When aggregating stats across levels larger blinds *** this var now replaced by def_hud_params list +#hud_days = 90 # Max number of days from each player to use for hud stats +#agg_bb_mult = 100 # 1 = no aggregation. When aggregating stats across levels larger blinds # must be < (agg_bb_mult * smaller blinds) to be aggregated # ie. 100 will aggregate almost everything, 2 will probably agg just the # next higher and lower levels into the current one, try 3/10/30/100 @@ -92,7 +92,7 @@ def_hud_params = { # Settings for all players apart from program owner ('hero') # , 'hud_session_gap' : 30 not currently used # Second set of variables for hero - these settings only apply to the program owner , 'h_aggregate_ring' : False - , 'h_aggreagte_tour' : True + , 'h_aggregate_tour' : True , 'h_hud_style' : 'A' , 'h_hud_days' : 90 , 'h_agg_bb_mult' : 1 # 1 means no aggregation diff --git a/pyfpdb/Hud.py b/pyfpdb/Hud.py index 6073d619..f58d2d79 100644 --- a/pyfpdb/Hud.py +++ b/pyfpdb/Hud.py @@ -156,29 +156,29 @@ class Hud: item.connect("activate", self.set_aggregation) setattr(self, 'showStatsMenuItem1', item) # - item = gtk.MenuItem('For Multiple Blind Levels') + item = gtk.MenuItem('For Multiple Blind Levels:') aggMenu.append(item) setattr(self, 'showStatsMenuItem2', item) # - item = gtk.MenuItem('0.5 to 2.0 x Current Blinds') + item = gtk.MenuItem(' 0.5 to 2.0 x Current Blinds') item.ms = 2.01 aggMenu.append(item) item.connect("activate", self.set_aggregation) setattr(self, 'showStatsMenuItem3', item) # - item = gtk.MenuItem('0.33 to 3.0 x Current Blinds') + item = gtk.MenuItem(' 0.33 to 3.0 x Current Blinds') item.ms = 3.01 aggMenu.append(item) item.connect("activate", self.set_aggregation) setattr(self, 'showStatsMenuItem4', item) # - item = gtk.MenuItem('0.1 to 10 x Current Blinds') + item = gtk.MenuItem(' 0.1 to 10 x Current Blinds') item.ms = 10.01 aggMenu.append(item) item.connect("activate", self.set_aggregation) setattr(self, 'showStatsMenuItem5', item) # - item = gtk.MenuItem('All Levels') + item = gtk.MenuItem(' All Levels') item.ms = 10000 aggMenu.append(item) item.connect("activate", self.set_aggregation) @@ -223,8 +223,8 @@ class Hud: def set_aggregation(self, widget): # try setting these to true all the time, and set the multiplier to 1 to turn agg off: - self.hud_params['h_aggregate_ring'] = True - self.hud_params['h_aggregate_tour'] = True + self.hud_params['aggregate_ring'] = True + self.hud_params['aggregate_tour'] = True if self.hud_params['agg_bb_mult'] != widget.ms: print 'set_aggregation', widget.ms From 16f8fffd6873dfc24b06237e0ae3c3af1294b1ea Mon Sep 17 00:00:00 2001 From: sqlcoder Date: Mon, 28 Sep 2009 23:59:17 +0100 Subject: [PATCH 22/56] add separate hud config for user and allow some user config in HUD menu (opponents still only via editing HUD_main.py) --- pyfpdb/Database.py | 105 ++++++++++++++++++++++++++++----------------- pyfpdb/HUD_main.py | 36 +++++----------- pyfpdb/Hud.py | 47 ++++++++++++++++---- pyfpdb/SQL.py | 57 +++++++++++++++--------- 4 files changed, 152 insertions(+), 93 deletions(-) diff --git a/pyfpdb/Database.py b/pyfpdb/Database.py index 6f1183b6..3fd51c7b 100755 --- a/pyfpdb/Database.py +++ b/pyfpdb/Database.py @@ -227,9 +227,10 @@ class Database: #self.hud_hero_days = 30 # but last T days or last H hands for yourself # vars for hand ids or dates fetched according to above config: - self.hand_1day_ago = 0 # max hand id more than 24 hrs earlier than now - self.date_ndays_ago = 'd000000' # date N days ago ('d' + YYMMDD) - self.date_nhands_ago = {} # dates N hands ago per player - not used yet + self.hand_1day_ago = 0 # max hand id more than 24 hrs earlier than now + self.date_ndays_ago = 'd000000' # date N days ago ('d' + YYMMDD) + self.h_date_ndays_ago = 'd000000' # date N days ago ('d' + YYMMDD) for hero + self.date_nhands_ago = {} # dates N hands ago per player - not used yet self.cursor = self.fdb.cursor @@ -371,10 +372,11 @@ class Database: winners[row[0]] = row[1] return winners - def init_hud_stat_vars(self, hud_days): + def init_hud_stat_vars(self, hud_days, h_hud_days): """Initialise variables used by Hud to fetch stats: - self.hand_1day_ago handId of latest hand played more than a day ago - self.date_ndays_ago date n days ago + self.hand_1day_ago handId of latest hand played more than a day ago + self.date_ndays_ago date n days ago + self.h_date_ndays_ago date n days ago for hero (different n) """ self.hand_1day_ago = 1 @@ -393,6 +395,10 @@ class Database: now = datetime.utcnow() - d self.date_ndays_ago = "d%02d%02d%02d" % (now.year - 2000, now.month, now.day) + d = timedelta(days=h_hud_days) + now = datetime.utcnow() - d + self.h_date_ndays_ago = "d%02d%02d%02d" % (now.year - 2000, now.month, now.day) + def init_player_hud_stat_vars(self, playerid): # not sure if this is workable, to be continued ... try: @@ -413,33 +419,46 @@ class Database: def get_stats_from_hand( self, hand , hud_params = {'aggregate_tour':False, 'aggregate_ring':False, 'hud_style':'A', 'agg_bb_mult':100} - , hero_ids = {} + , hero_id = -1 ): - aggregate = hud_params['aggregate_tour'] if type == "tour" else hud_params['aggregate_ring'] - hud_style = hud_params['hud_style'] - agg_bb_mult = hud_params['agg_bb_mult'] + aggregate = hud_params['aggregate_tour'] if type == "tour" else hud_params['aggregate_ring'] + hud_style = hud_params['hud_style'] + agg_bb_mult = hud_params['agg_bb_mult'] if aggregate else 1 + h_aggregate = hud_params['h_aggregate_tour'] if type == "tour" else hud_params['h_aggregate_ring'] + h_hud_style = hud_params['h_hud_style'] + h_agg_bb_mult = hud_params['h_agg_bb_mult'] if h_aggregate else 1 stat_dict = {} - if hud_style == 'S': + if hud_style == 'S' or h_hud_style == 'S': + self.get_stats_from_hand_session(hand, stat_dict, hero_id, hud_style, h_hud_style) + if hud_style == 'S' and h_hud_style == 'S': + return stat_dict - self.get_stats_from_hand_session(hand, stat_dict) - return stat_dict + if hud_style == 'T': + stylekey = self.date_ndays_ago + elif hud_style == 'A': + stylekey = '0000000' # all stylekey values should be higher than this + elif hud_style == 'S': + stylekey = 'zzzzzzz' # all stylekey values should be lower than this + #elif hud_style == 'H': + # stylekey = date_nhands_ago needs array by player here ... - else: # hud_style == A + if h_hud_style == 'T': + h_stylekey = self.h_date_ndays_ago + elif h_hud_style == 'A': + h_stylekey = '0000000' # all stylekey values should be higher than this + elif h_hud_style == 'S': + h_stylekey = 'zzzzzzz' # all stylekey values should be lower than this + #elif h_hud_style == 'H': + # h_stylekey = date_nhands_ago needs array by player here ... - if hud_style == 'T': - stylekey = self.date_ndays_ago - #elif hud_style == 'H': - # stylekey = date_nhands_ago needs array by player here ... - else: # assume A (all-time) - stylekey = '0000000' # all stylekey values should be higher than this - - if aggregate: - query = 'get_stats_from_hand_aggregated' - subs = (hand, stylekey, agg_bb_mult, agg_bb_mult) - else: - query = 'get_stats_from_hand' - subs = (hand, stylekey) + #if aggregate: always use aggreagte query now: use agg_bb_mult of 1 for no aggregation: + query = 'get_stats_from_hand_aggregated' + subs = (hand, hero_id, stylekey, agg_bb_mult, agg_bb_mult, hero_id, h_stylekey, h_agg_bb_mult, h_agg_bb_mult) + print "agg query subs:", subs + #else: + # query = 'get_stats_from_hand' + # subs = (hand, stylekey) #print "get stats: hud style =", hud_style, "query =", query, "subs =", subs c = self.connection.cursor() @@ -457,7 +476,13 @@ class Database: return stat_dict # uses query on handsplayers instead of hudcache to get stats on just this session - def get_stats_from_hand_session(self, hand, stat_dict): + def get_stats_from_hand_session(self, hand, stat_dict, hero_id, hud_style, h_hud_style): + """Get stats for just this session (currently defined as any play in the last 24 hours - to + be improved at some point ...) + h_hud_style and hud_style params indicate whether to get stats for hero and/or others + - only fetch heros stats if h_hud_style == 'S', + and only fetch others stats if hud_style == 'S' + """ query = self.sql.query['get_stats_from_hand_session'] if self.db_server == 'mysql': @@ -478,18 +503,20 @@ class Database: if colnames[0].lower() == 'player_id': playerid = row[0] + # Loop through stats adding them to appropriate stat_dict: while row: - for name, val in zip(colnames, row): - if not playerid in stat_dict: - stat_dict[playerid] = {} - stat_dict[playerid][name.lower()] = val - elif not name.lower() in stat_dict[playerid]: - stat_dict[playerid][name.lower()] = val - 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 - # for now - comment out or remove? + if (playerid == hero_id and h_hud_style == 'S') or (playerid != hero_id and hud_style == 'S'): + for name, val in zip(colnames, row): + if not playerid in stat_dict: + stat_dict[playerid] = {} + stat_dict[playerid][name.lower()] = val + elif not name.lower() in stat_dict[playerid]: + stat_dict[playerid][name.lower()] = val + 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 + # for now - comment out or remove? row = c.fetchone() else: log.error("ERROR: query %s result does not have player_id as first column" % (query,)) diff --git a/pyfpdb/HUD_main.py b/pyfpdb/HUD_main.py index bf1beef3..0f332b5e 100755 --- a/pyfpdb/HUD_main.py +++ b/pyfpdb/HUD_main.py @@ -56,25 +56,8 @@ import Database import Tables import Hud -# To add to config: *** these vars now replaced by def_hud_params list -#aggregate_stats = {"ring": False, "tour": False} # uses agg_bb_mult -#hud_style = 'A' # A=All-time - # S=Session - # T=timed (last n days - set hud_days to required value) - # Future values may also include: - # H=Hands (last n hands) -#hud_days = 90 # Max number of days from each player to use for hud stats -#agg_bb_mult = 100 # 1 = no aggregation. When aggregating stats across levels larger blinds - # must be < (agg_bb_mult * smaller blinds) to be aggregated - # ie. 100 will aggregate almost everything, 2 will probably agg just the - # next higher and lower levels into the current one, try 3/10/30/100 -#hud_session_gap = 30 # Gap (minutes) between hands that indicates a change of session - # (hands every 2 mins for 1 hour = one session, if followed - # by a 40 minute gap and then more hands on same table that is - # a new session) -#hud_hands = 0 # Max number of hands from each player to use for hud stats (not used) -# New list to hold all HUD params +# HUD params: # - Set aggregate_ring and/or aggregate_tour to True is you want to include stats from other blind levels in the HUD display # - If aggregation is used, the value of agg_bb_mult determines how what levels are included, e.g. # if agg_bb_mult is 100, almost all levels are included in all HUD displays @@ -88,14 +71,14 @@ def_hud_params = { # Settings for all players apart from program owner ('hero') , 'aggregate_tour' : True , 'hud_style' : 'A' , 'hud_days' : 90 - , 'agg_bb_mult' : 1 # 1 means no aggregation + , 'agg_bb_mult' : 1 # 1 means no aggregation # , 'hud_session_gap' : 30 not currently used # Second set of variables for hero - these settings only apply to the program owner , 'h_aggregate_ring' : False , 'h_aggregate_tour' : True - , 'h_hud_style' : 'A' - , 'h_hud_days' : 90 - , 'h_agg_bb_mult' : 1 # 1 means no aggregation + , 'h_hud_style' : 'S' # A(ll) / S(ession) / T(ime in days) + , 'h_hud_days' : 30 + , 'h_agg_bb_mult' : 1 # 1 means no aggregation # , 'h_hud_session_gap' : 30 not currently used } @@ -243,8 +226,9 @@ class HUD_main(object): if temp_key in self.hud_dict: try: # get stats using hud's specific params - self.db_connection.init_hud_stat_vars( self.hud_dict[temp_key].hud_params['hud_days'] ) - stat_dict = self.db_connection.get_stats_from_hand(new_hand_id, self.hud_dict[temp_key].hud_params, self.hero_ids) + self.db_connection.init_hud_stat_vars( self.hud_dict[temp_key].hud_params['hud_days'] + , self.hud_dict[temp_key].hud_params['h_hud_days']) + stat_dict = self.db_connection.get_stats_from_hand(new_hand_id, self.hud_dict[temp_key].hud_params, self.hero_ids[site_id]) except: err = traceback.extract_tb(sys.exc_info()[2])[-1] print "db get_stats error: skipping "+str(new_hand_id)+" "+err[2]+"("+str(err[1])+"): "+str(sys.exc_info()[1]) @@ -260,8 +244,8 @@ class HUD_main(object): else: try: # get stats using default params - self.db_connection.init_hud_stat_vars( self.hud_params['hud_days'] ) - stat_dict = self.db_connection.get_stats_from_hand(new_hand_id, self.hud_params, self.hero_ids) + self.db_connection.init_hud_stat_vars( self.hud_params['hud_days'], self.hud_params['h_hud_days'] ) + stat_dict = self.db_connection.get_stats_from_hand(new_hand_id, self.hud_params, self.hero_ids[site_id]) except: err = traceback.extract_tb(sys.exc_info()[2])[-1] print "db get_stats error: skipping "+str(new_hand_id)+" "+err[2]+"("+str(err[1])+"): "+str(sys.exc_info()[1]) diff --git a/pyfpdb/Hud.py b/pyfpdb/Hud.py index f58d2d79..7e161f4a 100644 --- a/pyfpdb/Hud.py +++ b/pyfpdb/Hud.py @@ -147,42 +147,64 @@ class Hud: aggitem = gtk.MenuItem('Show Stats') menu.append(aggitem) - aggMenu = gtk.Menu() - aggitem.set_submenu(aggMenu) + self.aggMenu = gtk.Menu() + aggitem.set_submenu(self.aggMenu) # set agg_bb_mult to 1 to stop aggregation item = gtk.MenuItem('For This Blind Level') item.ms = 1 - aggMenu.append(item) + self.aggMenu.append(item) item.connect("activate", self.set_aggregation) setattr(self, 'showStatsMenuItem1', item) # item = gtk.MenuItem('For Multiple Blind Levels:') - aggMenu.append(item) + self.aggMenu.append(item) setattr(self, 'showStatsMenuItem2', item) # item = gtk.MenuItem(' 0.5 to 2.0 x Current Blinds') item.ms = 2.01 - aggMenu.append(item) + self.aggMenu.append(item) item.connect("activate", self.set_aggregation) setattr(self, 'showStatsMenuItem3', item) # item = gtk.MenuItem(' 0.33 to 3.0 x Current Blinds') item.ms = 3.01 - aggMenu.append(item) + self.aggMenu.append(item) item.connect("activate", self.set_aggregation) setattr(self, 'showStatsMenuItem4', item) # item = gtk.MenuItem(' 0.1 to 10 x Current Blinds') item.ms = 10.01 - aggMenu.append(item) + self.aggMenu.append(item) item.connect("activate", self.set_aggregation) setattr(self, 'showStatsMenuItem5', item) # item = gtk.MenuItem(' All Levels') item.ms = 10000 - aggMenu.append(item) + self.aggMenu.append(item) item.connect("activate", self.set_aggregation) setattr(self, 'showStatsMenuItem6', item) + # + item = gtk.MenuItem('For Hero:') + self.aggMenu.append(item) + setattr(self, 'showStatsMenuItem7', item) + # + item = gtk.MenuItem(' All Time') + item.ms = 'HA' + self.aggMenu.append(item) + item.connect("activate", self.set_hud_style) + setattr(self, 'showStatsMenuItem8', item) + # + item = gtk.MenuItem(' Session') + item.ms = 'HS' + self.aggMenu.append(item) + item.connect("activate", self.set_hud_style) + setattr(self, 'showStatsMenuItem9', item) + # + item = gtk.MenuItem(' %s Days' % (self.hud_params['h_hud_days'])) + item.ms = 'HT' + self.aggMenu.append(item) + item.connect("activate", self.set_hud_style) + setattr(self, 'showStatsMenuItem11', item) eventbox.connect_object("button-press-event", self.on_button_press, menu) @@ -230,6 +252,15 @@ class Hud: print 'set_aggregation', widget.ms self.hud_params['agg_bb_mult'] = widget.ms + def set_hud_style(self, widget): + # try setting these to true all the time, and set the multiplier to 1 to turn agg off: + if widget.ms[0] == 'H': + param = 'h_hud_style' + else: + param = 'hud_style' + self.hud_params[param] = widget.ms[1] + print "setting self.hud_params[%s] = %s" % (param,widget.ms[1]) + def update_table_position(self): if os.name == 'nt': if not win32gui.IsWindow(self.table.number): diff --git a/pyfpdb/SQL.py b/pyfpdb/SQL.py index abef4b76..0c551634 100644 --- a/pyfpdb/SQL.py +++ b/pyfpdb/SQL.py @@ -1384,28 +1384,45 @@ class Sql: INNER JOIN HudCache hc ON (hc.playerId = hp.playerId) INNER JOIN Players p ON (p.id = hc.playerId) WHERE h.id = %s - AND hc.styleKey > %s - /* styleKey is currently 'd' (for date) followed by a yyyymmdd - date key. Set it to 0000000 or similar to get all records */ - /* Note: s means the placeholder 'percent's but we can't include that - in comments. (db api thinks they are actual arguments) - Could also check activeseats here even if only 3 groups eg 2-3/4-6/7+ - e.g. could use a multiplier: - AND h.seats > s / 1.25 and hp.seats < s * 1.25 - where s is the number of active players at the current table (and - 1.25 would be a config value so user could change it) - */ - AND hc.gametypeId+0 in - (SELECT gt1.id from Gametypes gt1, Gametypes gt2 - WHERE gt1.siteid = gt2.siteid /* find gametypes where these match: */ - AND gt1.type = gt2.type /* ring/tourney */ - AND gt1.category = gt2.category /* holdem/stud*/ - AND gt1.limittype = gt2.limittype /* fl/nl */ - AND gt1.bigblind < gt2.bigblind * %s /* bigblind similar size */ - AND gt1.bigblind > gt2.bigblind / %s - AND gt2.id = h.gametypeId) + AND ( /* 2 separate parts for hero and opponents */ + ( hp.playerId != %s + AND hc.styleKey > %s + AND hc.gametypeId+0 in + (SELECT gt1.id from Gametypes gt1, Gametypes gt2 + WHERE gt1.siteid = gt2.siteid /* find gametypes where these match: */ + AND gt1.type = gt2.type /* ring/tourney */ + AND gt1.category = gt2.category /* holdem/stud*/ + AND gt1.limittype = gt2.limittype /* fl/nl */ + AND gt1.bigblind <= gt2.bigblind * %s /* bigblind similar size */ + AND gt1.bigblind >= gt2.bigblind / %s + AND gt2.id = h.gametypeId) + ) + OR + ( hp.playerId = %s + AND hc.styleKey > %s + AND hc.gametypeId+0 in + (SELECT gt1.id from Gametypes gt1, Gametypes gt2 + WHERE gt1.siteid = gt2.siteid /* find gametypes where these match: */ + AND gt1.type = gt2.type /* ring/tourney */ + AND gt1.category = gt2.category /* holdem/stud*/ + AND gt1.limittype = gt2.limittype /* fl/nl */ + AND gt1.bigblind <= gt2.bigblind * %s /* bigblind similar size */ + AND gt1.bigblind >= gt2.bigblind / %s + AND gt2.id = h.gametypeId) + ) + ) GROUP BY hc.PlayerId, p.name """ + # NOTES on above cursor: + # - Do NOT include %s inside query in a comment - the db api thinks + # they are actual arguments. + # - styleKey is currently 'd' (for date) followed by a yyyymmdd + # date key. Set it to 0000000 or similar to get all records + # Could also check activeseats here even if only 3 groups eg 2-3/4-6/7+ + # e.g. could use a multiplier: + # AND h.seats > %s / 1.25 and hp.seats < %s * 1.25 + # where %s is the number of active players at the current table (and + # 1.25 would be a config value so user could change it) if db_server == 'mysql': self.query['get_stats_from_hand_session'] = """ From 2b7a42bf1d0314e539e7aac2b9216c3d82761b1d Mon Sep 17 00:00:00 2001 From: sqlcoder Date: Tue, 29 Sep 2009 23:34:52 +0100 Subject: [PATCH 23/56] fix bug for tourneys in new code, modify part of hud menu to use checkmenuitems --- pyfpdb/Database.py | 6 ++--- pyfpdb/HUD_main.py | 21 ++++++++++++--- pyfpdb/Hud.py | 64 +++++++++++++++++++++++++++++----------------- 3 files changed, 60 insertions(+), 31 deletions(-) diff --git a/pyfpdb/Database.py b/pyfpdb/Database.py index 3fd51c7b..b9ec62f4 100755 --- a/pyfpdb/Database.py +++ b/pyfpdb/Database.py @@ -417,7 +417,7 @@ class Database: err = traceback.extract_tb(sys.exc_info()[2])[-1] print "***Error: "+err[2]+"("+str(err[1])+"): "+str(sys.exc_info()[1]) - def get_stats_from_hand( self, hand + def get_stats_from_hand( self, hand, type # type is "ring" or "tour" , hud_params = {'aggregate_tour':False, 'aggregate_ring':False, 'hud_style':'A', 'agg_bb_mult':100} , hero_id = -1 ): @@ -2542,12 +2542,12 @@ if __name__=="__main__": if hero: print "nutOmatic is id_player = %d" % hero - stat_dict = db_connection.get_stats_from_hand(h) + stat_dict = db_connection.get_stats_from_hand(h, "ring") for p in stat_dict.keys(): print p, " ", stat_dict[p] #print "nutOmatics stats:" - #stat_dict = db_connection.get_stats_from_hand(h, hero) + #stat_dict = db_connection.get_stats_from_hand(h, "ring") #for p in stat_dict.keys(): # print p, " ", stat_dict[p] diff --git a/pyfpdb/HUD_main.py b/pyfpdb/HUD_main.py index 0f332b5e..23c1ef03 100755 --- a/pyfpdb/HUD_main.py +++ b/pyfpdb/HUD_main.py @@ -123,7 +123,8 @@ class HUD_main(object): del(self.hud_dict[table]) self.main_window.resize(1,1) - def create_HUD(self, new_hand_id, table, table_name, max, poker_game, stat_dict, cards): + def create_HUD(self, new_hand_id, table, table_name, max, poker_game, type, stat_dict, cards): + """type is "ring" or "tour" used to set hud_params""" def idle_func(): @@ -149,6 +150,18 @@ class HUD_main(object): self.hud_dict[table_name].table_name = table_name self.hud_dict[table_name].stat_dict = stat_dict self.hud_dict[table_name].cards = cards + + if type == "tour" and self.hud_params['aggregate_tour'] == False: + self.hud_dict[table_name].hud_params['agg_bb_mult'] = 1 + elif type == "ring" and self.hud_params['aggregate_ring'] == False: + self.hud_dict[table_name].hud_params['agg_bb_mult'] = 1 + if type == "tour" and self.hud_params['h_aggregate_tour'] == False: + self.hud_dict[table_name].hud_params['h_agg_bb_mult'] = 1 + elif type == "ring" and self.hud_params['h_aggregate_ring'] == False: + self.hud_dict[table_name].hud_params['h_agg_bb_mult'] = 1 + self.hud_params['aggregate_ring'] == True + self.hud_params['h_aggregate_ring'] == True + [aw.update_data(new_hand_id, self.db_connection) for aw in self.hud_dict[table_name].aux_windows] gobject.idle_add(idle_func) @@ -228,7 +241,7 @@ class HUD_main(object): # get stats using hud's specific params self.db_connection.init_hud_stat_vars( self.hud_dict[temp_key].hud_params['hud_days'] , self.hud_dict[temp_key].hud_params['h_hud_days']) - stat_dict = self.db_connection.get_stats_from_hand(new_hand_id, self.hud_dict[temp_key].hud_params, self.hero_ids[site_id]) + stat_dict = self.db_connection.get_stats_from_hand(new_hand_id, type, self.hud_dict[temp_key].hud_params, self.hero_ids[site_id]) except: err = traceback.extract_tb(sys.exc_info()[2])[-1] print "db get_stats error: skipping "+str(new_hand_id)+" "+err[2]+"("+str(err[1])+"): "+str(sys.exc_info()[1]) @@ -245,7 +258,7 @@ class HUD_main(object): try: # get stats using default params self.db_connection.init_hud_stat_vars( self.hud_params['hud_days'], self.hud_params['h_hud_days'] ) - stat_dict = self.db_connection.get_stats_from_hand(new_hand_id, self.hud_params, self.hero_ids[site_id]) + stat_dict = self.db_connection.get_stats_from_hand(new_hand_id, type, self.hud_params, self.hero_ids[site_id]) except: err = traceback.extract_tb(sys.exc_info()[2])[-1] print "db get_stats error: skipping "+str(new_hand_id)+" "+err[2]+"("+str(err[1])+"): "+str(sys.exc_info()[1]) @@ -262,7 +275,7 @@ class HUD_main(object): table_name = "%s %s" % (tour_number, tab_number) sys.stderr.write("table name "+table_name+" not found, skipping.\n") else: - self.create_HUD(new_hand_id, tablewindow, temp_key, max, poker_game, stat_dict, cards) + self.create_HUD(new_hand_id, tablewindow, temp_key, max, poker_game, type, stat_dict, cards) self.db_connection.connection.rollback() except: err = traceback.extract_tb(sys.exc_info()[2])[-1] diff --git a/pyfpdb/Hud.py b/pyfpdb/Hud.py index 7e161f4a..cc8994b5 100644 --- a/pyfpdb/Hud.py +++ b/pyfpdb/Hud.py @@ -74,6 +74,7 @@ class Hud: self.site = table.site self.mw_created = False self.hud_params = parent.hud_params + self.stat_windows = {} self.popup_windows = {} @@ -150,7 +151,7 @@ class Hud: self.aggMenu = gtk.Menu() aggitem.set_submenu(self.aggMenu) # set agg_bb_mult to 1 to stop aggregation - item = gtk.MenuItem('For This Blind Level') + item = gtk.CheckMenuItem('For This Blind Level Only') item.ms = 1 self.aggMenu.append(item) item.connect("activate", self.set_aggregation) @@ -160,25 +161,25 @@ class Hud: self.aggMenu.append(item) setattr(self, 'showStatsMenuItem2', item) # - item = gtk.MenuItem(' 0.5 to 2.0 x Current Blinds') - item.ms = 2.01 + item = gtk.CheckMenuItem(' 0.5 to 2.0 x Current Blinds') + item.ms = 2 self.aggMenu.append(item) item.connect("activate", self.set_aggregation) setattr(self, 'showStatsMenuItem3', item) # - item = gtk.MenuItem(' 0.33 to 3.0 x Current Blinds') - item.ms = 3.01 + item = gtk.CheckMenuItem(' 0.33 to 3.0 x Current Blinds') + item.ms = 3 self.aggMenu.append(item) item.connect("activate", self.set_aggregation) setattr(self, 'showStatsMenuItem4', item) # - item = gtk.MenuItem(' 0.1 to 10 x Current Blinds') - item.ms = 10.01 + item = gtk.CheckMenuItem(' 0.1 to 10 x Current Blinds') + item.ms = 10 self.aggMenu.append(item) item.connect("activate", self.set_aggregation) setattr(self, 'showStatsMenuItem5', item) # - item = gtk.MenuItem(' All Levels') + item = gtk.CheckMenuItem(' All Levels') item.ms = 10000 self.aggMenu.append(item) item.connect("activate", self.set_aggregation) @@ -188,23 +189,26 @@ class Hud: self.aggMenu.append(item) setattr(self, 'showStatsMenuItem7', item) # - item = gtk.MenuItem(' All Time') - item.ms = 'HA' + item = gtk.CheckMenuItem(' All Time') self.aggMenu.append(item) - item.connect("activate", self.set_hud_style) - setattr(self, 'showStatsMenuItem8', item) + item.connect("activate", self.set_hud_style, 'HA') + setattr(self, 'HAStyleOption', item) # - item = gtk.MenuItem(' Session') - item.ms = 'HS' + item = gtk.CheckMenuItem(' Session') self.aggMenu.append(item) - item.connect("activate", self.set_hud_style) - setattr(self, 'showStatsMenuItem9', item) + item.connect("activate", self.set_hud_style, 'HS') + setattr(self, 'HSStyleOption', item) # - item = gtk.MenuItem(' %s Days' % (self.hud_params['h_hud_days'])) - item.ms = 'HT' + item = gtk.CheckMenuItem(' %s Days' % (self.hud_params['h_hud_days'])) self.aggMenu.append(item) - item.connect("activate", self.set_hud_style) - setattr(self, 'showStatsMenuItem11', item) + item.connect("activate", self.set_hud_style, 'HT') + setattr(self, 'HTStyleOption', item) + if self.hud_params['h_hud_style'] == 'A': + item.set_active(True) + if self.hud_params['h_hud_style'] == 'S': + item.set_active(True) + if self.hud_params['h_hud_style'] == 'T': + item.set_active(True) eventbox.connect_object("button-press-event", self.on_button_press, menu) @@ -252,14 +256,26 @@ class Hud: print 'set_aggregation', widget.ms self.hud_params['agg_bb_mult'] = widget.ms - def set_hud_style(self, widget): + def set_hud_style(self, widget, val): # try setting these to true all the time, and set the multiplier to 1 to turn agg off: - if widget.ms[0] == 'H': + if val[0] == 'H': param = 'h_hud_style' else: param = 'hud_style' - self.hud_params[param] = widget.ms[1] - print "setting self.hud_params[%s] = %s" % (param,widget.ms[1]) + + if val[1] == 'A' and getattr(self, 'HAStyleOption').get_active(): + self.hud_params[param] = 'A' + getattr(self, 'HSStyleOption').set_active(False) + getattr(self, 'HTStyleOption').set_active(False) + elif val[1] == 'S' and getattr(self, 'HSStyleOption').get_active(): + self.hud_params[param] = 'S' + getattr(self, 'HAStyleOption').set_active(False) + getattr(self, 'HTStyleOption').set_active(False) + elif val[1] == 'T' and self.HTStyleOption.get_active(): + self.hud_params[param] = 'T' + getattr(self, 'HAStyleOption').set_active(False) + getattr(self, 'HSStyleOption').set_active(False) + print "setting self.hud_params[%s] = %s" % (param, val[1]) def update_table_position(self): if os.name == 'nt': From d36d8f4249cf445d7cc3f64b8d0cd2a52fd697c5 Mon Sep 17 00:00:00 2001 From: Worros Date: Thu, 1 Oct 2009 10:49:59 +0800 Subject: [PATCH 24/56] From 7d5a3e81a5d41298ab1fa4d57bef25862a167350 Mon Sep 17 00:00:00 2001 From: lucktard Date: Wed, 30 Sep 2009 12:16:06 -0500 Subject: [PATCH] Detect and import capped 6 max hands on FullTilt and From b35d23aba38935406cf1522ae07a49cd441318b3 Mon Sep 17 00:00:00 2001 From: lucktard Date: Wed, 30 Sep 2009 12:21:34 -0500 Subject: [PATCH] Detect deep 6 max tables for HUD on FT --- pyfpdb/FulltiltToFpdb.py | 8 +++++++- pyfpdb/Tables.py | 2 +- 2 files changed, 8 insertions(+), 2 deletions(-) mode change 100644 => 100755 pyfpdb/FulltiltToFpdb.py diff --git a/pyfpdb/FulltiltToFpdb.py b/pyfpdb/FulltiltToFpdb.py old mode 100644 new mode 100755 index a74d71d3..5ce0a5c8 --- a/pyfpdb/FulltiltToFpdb.py +++ b/pyfpdb/FulltiltToFpdb.py @@ -40,6 +40,7 @@ class Fulltilt(HandHistoryConverter): (?P[.0-9]+)/ \$?(?P[.0-9]+)\s (Ante\s\$?(?P[.0-9]+)\s)?-\s + \$?(?P[.0-9]+\sCap\s)? (?P(No\sLimit|Pot\sLimit|Limit))?\s (?P(Hold\'em|Omaha\sHi|Omaha\sH/L|7\sCard\sStud|Stud\sH/L|Razz|Stud\sHi)) ''', re.VERBOSE) @@ -52,6 +53,7 @@ class Fulltilt(HandHistoryConverter): (?P[-\s\da-zA-Z]+)\s (\((?P.+)\)\s)?-\s \$?(?P[.0-9]+)/\$?(?P[.0-9]+)\s(Ante\s\$?(?P[.0-9]+)\s)?-\s + \$?(?P[.0-9]+\sCap\s)? (?P[a-zA-Z\/\'\s]+)\s-\s (?P\d+:\d+:\d+\s\w+\s-\s\d+/\d+/\d+)\s? (?P\(partial\))?\n @@ -143,6 +145,7 @@ class Fulltilt(HandHistoryConverter): return [["ring", "hold", "nl"], ["ring", "hold", "pl"], ["ring", "hold", "fl"], + ["ring", "hold", "cn"], ["ring", "stud", "fl"], @@ -175,7 +178,10 @@ class Fulltilt(HandHistoryConverter): 'Stud H/L' : ('stud','studhilo') } currencies = { u' €':'EUR', '$':'USD', '':'T$' } - info['limitType'] = limits[mg['LIMIT']] + if mg['CAP']: + info['limitType'] = 'cn' + else: + info['limitType'] = limits[mg['LIMIT']] info['sb'] = mg['SB'] info['bb'] = mg['BB'] if mg['GAME'] != None: diff --git a/pyfpdb/Tables.py b/pyfpdb/Tables.py index 6bc9e57d..d9efff6a 100755 --- a/pyfpdb/Tables.py +++ b/pyfpdb/Tables.py @@ -376,7 +376,7 @@ def clean_title(name): """Clean the little info strings from the table name.""" # these strings could go in a config file for pattern in [' \(6 max\)', ' \(heads up\)', ' \(deep\)', - ' \(deep hu\)', ' \(deep 6\)', ' \(2\)', + ' \(deep hu\)', ' \(deep 6\)', '\(6 max, deep\)', ' \(2\)', ' \(edu\)', ' \(edu, 6 max\)', ' \(6\)', ' \(speed\)', 'special', 'newVPP', ' no all-in', ' fast', ',', ' 50BB min', '50bb min', '\s+$']: From b0037e545ad27f1e3a26762eea88b01644aec198 Mon Sep 17 00:00:00 2001 From: sqlcoder Date: Thu, 1 Oct 2009 21:40:14 +0100 Subject: [PATCH 25/56] improve stats menu on hud --- pyfpdb/Hud.py | 48 +++++++++++++++++++++++++++--------------------- 1 file changed, 27 insertions(+), 21 deletions(-) diff --git a/pyfpdb/Hud.py b/pyfpdb/Hud.py index cc8994b5..ec2b09cb 100644 --- a/pyfpdb/Hud.py +++ b/pyfpdb/Hud.py @@ -152,38 +152,32 @@ class Hud: aggitem.set_submenu(self.aggMenu) # set agg_bb_mult to 1 to stop aggregation item = gtk.CheckMenuItem('For This Blind Level Only') - item.ms = 1 self.aggMenu.append(item) - item.connect("activate", self.set_aggregation) - setattr(self, 'showStatsMenuItem1', item) + item.connect("activate", self.set_aggregation, 1) + setattr(self, 'aggBBmultItem1', item) # item = gtk.MenuItem('For Multiple Blind Levels:') self.aggMenu.append(item) - setattr(self, 'showStatsMenuItem2', item) # item = gtk.CheckMenuItem(' 0.5 to 2.0 x Current Blinds') - item.ms = 2 self.aggMenu.append(item) - item.connect("activate", self.set_aggregation) - setattr(self, 'showStatsMenuItem3', item) + item.connect("activate", self.set_aggregation, 2) + setattr(self, 'aggBBmultItem2', item) # item = gtk.CheckMenuItem(' 0.33 to 3.0 x Current Blinds') - item.ms = 3 self.aggMenu.append(item) - item.connect("activate", self.set_aggregation) - setattr(self, 'showStatsMenuItem4', item) + item.connect("activate", self.set_aggregation, 3) + setattr(self, 'aggBBmultItem3', item) # item = gtk.CheckMenuItem(' 0.1 to 10 x Current Blinds') - item.ms = 10 self.aggMenu.append(item) - item.connect("activate", self.set_aggregation) - setattr(self, 'showStatsMenuItem5', item) + item.connect("activate", self.set_aggregation, 10) + setattr(self, 'aggBBmultItem10', item) # item = gtk.CheckMenuItem(' All Levels') - item.ms = 10000 self.aggMenu.append(item) - item.connect("activate", self.set_aggregation) - setattr(self, 'showStatsMenuItem6', item) + item.connect("activate", self.set_aggregation, 10000) + setattr(self, 'aggBBmultItemAll', item) # item = gtk.MenuItem('For Hero:') self.aggMenu.append(item) @@ -203,12 +197,24 @@ class Hud: self.aggMenu.append(item) item.connect("activate", self.set_hud_style, 'HT') setattr(self, 'HTStyleOption', item) + + # set active on current options: + if self.hud_params['agg_bb_mult'] == 1: + getattr(self, 'aggBBmultItem1').set_active(True) + elif self.hud_params['agg_bb_mult'] == 2: + getattr(self, 'aggBBmultItem2').set_active(True) + elif self.hud_params['agg_bb_mult'] == 3: + getattr(self, 'aggBBmultItem3').set_active(True) + elif self.hud_params['agg_bb_mult'] == 10: + getattr(self, 'aggBBmultItem10').set_active(True) + elif self.hud_params['agg_bb_mult'] > 9000: + getattr(self, 'aggBBmultItemAll').set_active(True) if self.hud_params['h_hud_style'] == 'A': - item.set_active(True) - if self.hud_params['h_hud_style'] == 'S': - item.set_active(True) - if self.hud_params['h_hud_style'] == 'T': - item.set_active(True) + getattr(self, 'HAStyleOption').set_active(True) + elif self.hud_params['h_hud_style'] == 'S': + getattr(self, 'HSStyleOption').set_active(True) + elif self.hud_params['h_hud_style'] == 'T': + getattr(self, 'HTStyleOption').set_active(True) eventbox.connect_object("button-press-event", self.on_button_press, menu) From 61f384a8864ec844505e1f41e6f287bb3a4d5a31 Mon Sep 17 00:00:00 2001 From: sqlcoder Date: Thu, 1 Oct 2009 23:16:20 +0100 Subject: [PATCH 26/56] improve stats menu in HUD some more --- pyfpdb/Hud.py | 17 ++++++++++++----- 1 file changed, 12 insertions(+), 5 deletions(-) diff --git a/pyfpdb/Hud.py b/pyfpdb/Hud.py index ec2b09cb..2c83ccd0 100644 --- a/pyfpdb/Hud.py +++ b/pyfpdb/Hud.py @@ -177,7 +177,7 @@ class Hud: item = gtk.CheckMenuItem(' All Levels') self.aggMenu.append(item) item.connect("activate", self.set_aggregation, 10000) - setattr(self, 'aggBBmultItemAll', item) + setattr(self, 'aggBBmultItem10000', item) # item = gtk.MenuItem('For Hero:') self.aggMenu.append(item) @@ -253,14 +253,21 @@ class Hud: print "Exception:",str(e) pass - def set_aggregation(self, widget): + def set_aggregation(self, widget, val): # try setting these to true all the time, and set the multiplier to 1 to turn agg off: self.hud_params['aggregate_ring'] = True self.hud_params['aggregate_tour'] = True + self.hud_params['h_aggregate_ring'] = True + self.hud_params['h_aggregate_tour'] = True - if self.hud_params['agg_bb_mult'] != widget.ms: - print 'set_aggregation', widget.ms - self.hud_params['agg_bb_mult'] = widget.ms + if self.hud_params['agg_bb_mult'] != val \ + and getattr(self, 'aggBBmultItem'+str(val)).get_active(): + print 'set_aggregation', val + self.hud_params['agg_bb_mult'] = val + self.hud_params['h_agg_bb_mult'] = val + for mult in ('1', '2', '3', '10', '10000'): + if mult != str(val): + getattr(self, 'aggBBmultItem'+mult).set_active(False) def set_hud_style(self, widget, val): # try setting these to true all the time, and set the multiplier to 1 to turn agg off: From 7eb368f2212b22b357a76fe48f1e9b3af15707ae Mon Sep 17 00:00:00 2001 From: Mika Bostrom Date: Sat, 3 Oct 2009 08:17:41 +0300 Subject: [PATCH 27/56] Debian package: architecture any -> all The installed files are scripts and even the bytecode versions are generated on install. There is no need to build arch-dependent packages. --- packaging/debian/control | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packaging/debian/control b/packaging/debian/control index 93660791..784c4b40 100644 --- a/packaging/debian/control +++ b/packaging/debian/control @@ -6,7 +6,7 @@ Build-Depends: debhelper, python-support Standards-Version: 3.8.0 Package: python-fpdb -Architecture: any +Architecture: all Section: games Priority: extra Depends: ${python:Depends}, python-gtk2, python-matplotlib, From 18cc51ba7aa1751a93d0bbcb2ec47267ea276def Mon Sep 17 00:00:00 2001 From: Mika Bostrom Date: Sat, 3 Oct 2009 21:05:41 +0300 Subject: [PATCH 28/56] Make hud's menu-area text configurable By default the hud positions a little box on top-left corner of each table. Make the text in this box user-modifiable without touching the source. Most likely useful for active users and those who play with smaller tables. On shrunk table the default box may cover some of the players' cards. --- pyfpdb/Configuration.py | 26 ++++++++++++++++++++++++++ pyfpdb/Hud.py | 3 ++- 2 files changed, 28 insertions(+), 1 deletion(-) diff --git a/pyfpdb/Configuration.py b/pyfpdb/Configuration.py index b8022a45..dbe973c1 100755 --- a/pyfpdb/Configuration.py +++ b/pyfpdb/Configuration.py @@ -278,6 +278,15 @@ class Import: return " interval = %s\n callFpdbHud = %s\n hhArchiveBase = %s\n saveActions = %s\n fastStoreHudCache = %s\n" \ % (self.interval, self.callFpdbHud, self.hhArchiveBase, self.saveActions, self.fastStoreHudCache) +class HudUI: + def __init__(self, node): + self.node = node + self.label = node.getAttribute('label') + + def __str__(self): + return " label = %s\n" % self.label + + class Tv: def __init__(self, node): self.combinedStealFold = node.getAttribute("combinedStealFold") @@ -389,6 +398,10 @@ class Config: imp = Import(node = imp_node) self.imp = imp + for hui_node in doc.getElementsByTagName('hud_ui'): + hui = HudUI(node = hui_node) + self.ui = hui + for tv_node in doc.getElementsByTagName("tv"): tv = Tv(node = tv_node) self.tv = tv @@ -598,6 +611,19 @@ class Config: try: tv['combinedPostflop'] = self.tv.combinedPostflop except: tv['combinedPostflop'] = True return tv + + # Allow to change the menu appearance + def get_hud_ui_parameters(self): + hui = {} + default_text = 'FPDB Menu - Right click\nLeft-Drag to Move' + try: + hui['label'] = self.ui.label + if self.ui.label == '': # Empty menu label is a big no-no + hui['label'] = default_text + except: + hui['label'] = default_text + return hui + def get_import_parameters(self): imp = {} diff --git a/pyfpdb/Hud.py b/pyfpdb/Hud.py index 2c83ccd0..ce8c7c9f 100644 --- a/pyfpdb/Hud.py +++ b/pyfpdb/Hud.py @@ -82,6 +82,7 @@ class Hud: (font, font_size) = config.get_default_font(self.table.site) self.colors = config.get_default_colors(self.table.site) + self.hud_ui = config.get_hud_ui_parameters() self.backgroundcolor = gtk.gdk.color_parse(self.colors['hudbgcolor']) self.foregroundcolor = gtk.gdk.color_parse(self.colors['hudfgcolor']) @@ -116,7 +117,7 @@ class Hud: win.set_opacity(self.colors["hudopacity"]) eventbox = gtk.EventBox() - label = gtk.Label("FPDB Menu - Right click\nLeft-Drag to Move") + label = gtk.Label(self.hud_ui['label']) win.add(eventbox) eventbox.add(label) From c77e1434365d9c742f16a4556a181f89ea72be1c Mon Sep 17 00:00:00 2001 From: Mika Bostrom Date: Sat, 3 Oct 2009 21:10:09 +0300 Subject: [PATCH 29/56] Add the default box text to example config Now that the text on HUD's box is configurable, move the default text from code to default/sample config. --- pyfpdb/HUD_config.xml.example | 3 +++ 1 file changed, 3 insertions(+) diff --git a/pyfpdb/HUD_config.xml.example b/pyfpdb/HUD_config.xml.example index adc8141c..de2f1bba 100644 --- a/pyfpdb/HUD_config.xml.example +++ b/pyfpdb/HUD_config.xml.example @@ -4,6 +4,9 @@ + + Date: Sat, 3 Oct 2009 23:11:45 +0100 Subject: [PATCH 30/56] debug session stats --- pyfpdb/Database.py | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/pyfpdb/Database.py b/pyfpdb/Database.py index b9ec62f4..c923517e 100755 --- a/pyfpdb/Database.py +++ b/pyfpdb/Database.py @@ -467,11 +467,13 @@ class Database: c.execute(self.sql.query[query], subs) colnames = [desc[0] for desc in c.description] for row in c.fetchall(): - t_dict = {} - for name, val in zip(colnames, row): - t_dict[name.lower()] = val -# print t_dict - stat_dict[t_dict['player_id']] = t_dict + playerid = row[0] + if (playerid == hero_id and h_hud_style != 'S') or (playerid != hero_id and hud_style != 'S'): + t_dict = {} + for name, val in zip(colnames, row): + t_dict[name.lower()] = val +# print t_dict + stat_dict[t_dict['player_id']] = t_dict return stat_dict @@ -501,10 +503,10 @@ class Database: row = c.fetchone() if colnames[0].lower() == 'player_id': - playerid = row[0] # Loop through stats adding them to appropriate stat_dict: while row: + playerid = row[0] if (playerid == hero_id and h_hud_style == 'S') or (playerid != hero_id and hud_style == 'S'): for name, val in zip(colnames, row): if not playerid in stat_dict: From 5e3644d8d9755eb898ad6ec83822c787eb168ce0 Mon Sep 17 00:00:00 2001 From: sqlcoder Date: Sun, 4 Oct 2009 12:26:37 +0100 Subject: [PATCH 31/56] make separate hud menus for player and opponents stats --- pyfpdb/Hud.py | 165 +++++++++++++++++++++++++++++++++++++------------- 1 file changed, 123 insertions(+), 42 deletions(-) diff --git a/pyfpdb/Hud.py b/pyfpdb/Hud.py index 2c83ccd0..ad42bb59 100644 --- a/pyfpdb/Hud.py +++ b/pyfpdb/Hud.py @@ -146,14 +146,65 @@ class Hud: menu.append(repositem) repositem.connect("activate", self.reposition_windows) - aggitem = gtk.MenuItem('Show Stats') + aggitem = gtk.MenuItem('Show Player Stats') menu.append(aggitem) self.aggMenu = gtk.Menu() aggitem.set_submenu(self.aggMenu) # set agg_bb_mult to 1 to stop aggregation item = gtk.CheckMenuItem('For This Blind Level Only') self.aggMenu.append(item) - item.connect("activate", self.set_aggregation, 1) + item.connect("activate", self.set_aggregation, ('P',1)) + setattr(self, 'h_aggBBmultItem1', item) + # + item = gtk.MenuItem('For Multiple Blind Levels:') + self.aggMenu.append(item) + # + item = gtk.CheckMenuItem(' 0.5 to 2.0 x Current Blinds') + self.aggMenu.append(item) + item.connect("activate", self.set_aggregation, ('P',2)) + setattr(self, 'h_aggBBmultItem2', item) + # + item = gtk.CheckMenuItem(' 0.33 to 3.0 x Current Blinds') + self.aggMenu.append(item) + item.connect("activate", self.set_aggregation, ('P',3)) + setattr(self, 'h_aggBBmultItem3', item) + # + item = gtk.CheckMenuItem(' 0.1 to 10 x Current Blinds') + self.aggMenu.append(item) + item.connect("activate", self.set_aggregation, ('P',10)) + setattr(self, 'h_aggBBmultItem10', item) + # + item = gtk.CheckMenuItem(' All Levels') + self.aggMenu.append(item) + item.connect("activate", self.set_aggregation, ('P',10000)) + setattr(self, 'h_aggBBmultItem10000', item) + # + item = gtk.MenuItem('Since:') + self.aggMenu.append(item) + # + item = gtk.CheckMenuItem(' All Time') + self.aggMenu.append(item) + item.connect("activate", self.set_hud_style, ('P','A')) + setattr(self, 'h_hudStyleOptionA', item) + # + item = gtk.CheckMenuItem(' Session') + self.aggMenu.append(item) + item.connect("activate", self.set_hud_style, ('P','S')) + setattr(self, 'h_hudStyleOptionS', item) + # + item = gtk.CheckMenuItem(' %s Days' % (self.hud_params['h_hud_days'])) + self.aggMenu.append(item) + item.connect("activate", self.set_hud_style, ('P','T')) + setattr(self, 'h_hudStyleOptionT', item) + + aggitem = gtk.MenuItem('Show Opponent Stats') + menu.append(aggitem) + self.aggMenu = gtk.Menu() + aggitem.set_submenu(self.aggMenu) + # set agg_bb_mult to 1 to stop aggregation + item = gtk.CheckMenuItem('For This Blind Level Only') + self.aggMenu.append(item) + item.connect("activate", self.set_aggregation, ('O',1)) setattr(self, 'aggBBmultItem1', item) # item = gtk.MenuItem('For Multiple Blind Levels:') @@ -161,44 +212,54 @@ class Hud: # item = gtk.CheckMenuItem(' 0.5 to 2.0 x Current Blinds') self.aggMenu.append(item) - item.connect("activate", self.set_aggregation, 2) + item.connect("activate", self.set_aggregation, ('O',2)) setattr(self, 'aggBBmultItem2', item) # item = gtk.CheckMenuItem(' 0.33 to 3.0 x Current Blinds') self.aggMenu.append(item) - item.connect("activate", self.set_aggregation, 3) + item.connect("activate", self.set_aggregation, ('O',3)) setattr(self, 'aggBBmultItem3', item) # item = gtk.CheckMenuItem(' 0.1 to 10 x Current Blinds') self.aggMenu.append(item) - item.connect("activate", self.set_aggregation, 10) + item.connect("activate", self.set_aggregation, ('O',10)) setattr(self, 'aggBBmultItem10', item) # item = gtk.CheckMenuItem(' All Levels') self.aggMenu.append(item) - item.connect("activate", self.set_aggregation, 10000) + item.connect("activate", self.set_aggregation, ('O',10000)) setattr(self, 'aggBBmultItem10000', item) # - item = gtk.MenuItem('For Hero:') + item = gtk.MenuItem('Since:') self.aggMenu.append(item) - setattr(self, 'showStatsMenuItem7', item) # item = gtk.CheckMenuItem(' All Time') self.aggMenu.append(item) - item.connect("activate", self.set_hud_style, 'HA') - setattr(self, 'HAStyleOption', item) + item.connect("activate", self.set_hud_style, ('O','A')) + setattr(self, 'hudStyleOptionA', item) # item = gtk.CheckMenuItem(' Session') self.aggMenu.append(item) - item.connect("activate", self.set_hud_style, 'HS') - setattr(self, 'HSStyleOption', item) + item.connect("activate", self.set_hud_style, ('O','S')) + setattr(self, 'hudStyleOptionS', item) # item = gtk.CheckMenuItem(' %s Days' % (self.hud_params['h_hud_days'])) self.aggMenu.append(item) - item.connect("activate", self.set_hud_style, 'HT') - setattr(self, 'HTStyleOption', item) + item.connect("activate", self.set_hud_style, ('O','T')) + setattr(self, 'hudStyleOptionT', item) # set active on current options: + if self.hud_params['h_agg_bb_mult'] == 1: + getattr(self, 'h_aggBBmultItem1').set_active(True) + elif self.hud_params['h_agg_bb_mult'] == 2: + getattr(self, 'h_aggBBmultItem2').set_active(True) + elif self.hud_params['h_agg_bb_mult'] == 3: + getattr(self, 'h_aggBBmultItem3').set_active(True) + elif self.hud_params['h_agg_bb_mult'] == 10: + getattr(self, 'h_aggBBmultItem10').set_active(True) + elif self.hud_params['h_agg_bb_mult'] > 9000: + getattr(self, 'h_aggBBmultItemAll').set_active(True) + # if self.hud_params['agg_bb_mult'] == 1: getattr(self, 'aggBBmultItem1').set_active(True) elif self.hud_params['agg_bb_mult'] == 2: @@ -209,12 +270,20 @@ class Hud: getattr(self, 'aggBBmultItem10').set_active(True) elif self.hud_params['agg_bb_mult'] > 9000: getattr(self, 'aggBBmultItemAll').set_active(True) + # if self.hud_params['h_hud_style'] == 'A': - getattr(self, 'HAStyleOption').set_active(True) + getattr(self, 'h_hudStyleOptionA').set_active(True) elif self.hud_params['h_hud_style'] == 'S': - getattr(self, 'HSStyleOption').set_active(True) + getattr(self, 'h_hudStyleOptionS').set_active(True) elif self.hud_params['h_hud_style'] == 'T': - getattr(self, 'HTStyleOption').set_active(True) + getattr(self, 'h_hudStyleOptionT').set_active(True) + # + if self.hud_params['hud_style'] == 'A': + getattr(self, 'hudStyleOptionA').set_active(True) + elif self.hud_params['hud_style'] == 'S': + getattr(self, 'hudStyleOptionS').set_active(True) + elif self.hud_params['hud_style'] == 'T': + getattr(self, 'hudStyleOptionT').set_active(True) eventbox.connect_object("button-press-event", self.on_button_press, menu) @@ -254,41 +323,53 @@ class Hud: pass def set_aggregation(self, widget, val): - # try setting these to true all the time, and set the multiplier to 1 to turn agg off: - self.hud_params['aggregate_ring'] = True - self.hud_params['aggregate_tour'] = True - self.hud_params['h_aggregate_ring'] = True - self.hud_params['h_aggregate_tour'] = True + (player_opp, num) = val + if player_opp == 'P': + # set these true all the time, set the multiplier to 1 to turn agg off: + self.hud_params['h_aggregate_ring'] = True + self.hud_params['h_aggregate_tour'] = True - if self.hud_params['agg_bb_mult'] != val \ - and getattr(self, 'aggBBmultItem'+str(val)).get_active(): - print 'set_aggregation', val - self.hud_params['agg_bb_mult'] = val - self.hud_params['h_agg_bb_mult'] = val - for mult in ('1', '2', '3', '10', '10000'): - if mult != str(val): - getattr(self, 'aggBBmultItem'+mult).set_active(False) + if self.hud_params['h_agg_bb_mult'] != num \ + and getattr(self, 'h_aggBBmultItem'+str(num)).get_active(): + print 'set_player_aggregation', num + self.hud_params['h_agg_bb_mult'] = num + for mult in ('1', '2', '3', '10', '10000'): + if mult != str(num): + getattr(self, 'h_aggBBmultItem'+mult).set_active(False) + else: + self.hud_params['aggregate_ring'] = True + self.hud_params['aggregate_tour'] = True + + if self.hud_params['agg_bb_mult'] != num \ + and getattr(self, 'aggBBmultItem'+str(num)).get_active(): + print 'set_opponent_aggregation', num + self.hud_params['agg_bb_mult'] = num + for mult in ('1', '2', '3', '10', '10000'): + if mult != str(num): + getattr(self, 'aggBBmultItem'+mult).set_active(False) def set_hud_style(self, widget, val): - # try setting these to true all the time, and set the multiplier to 1 to turn agg off: - if val[0] == 'H': + (player_opp, style) = val + if player_opp == 'P': param = 'h_hud_style' + prefix = 'h_' else: param = 'hud_style' + prefix = '' - if val[1] == 'A' and getattr(self, 'HAStyleOption').get_active(): + if style == 'A' and getattr(self, prefix+'hudStyleOptionA').get_active(): self.hud_params[param] = 'A' - getattr(self, 'HSStyleOption').set_active(False) - getattr(self, 'HTStyleOption').set_active(False) - elif val[1] == 'S' and getattr(self, 'HSStyleOption').get_active(): + getattr(self, prefix+'hudStyleOptionS').set_active(False) + getattr(self, prefix+'hudStyleOptionT').set_active(False) + elif style == 'S' and getattr(self, prefix+'hudStyleOptionS').get_active(): self.hud_params[param] = 'S' - getattr(self, 'HAStyleOption').set_active(False) - getattr(self, 'HTStyleOption').set_active(False) - elif val[1] == 'T' and self.HTStyleOption.get_active(): + getattr(self, prefix+'hudStyleOptionA').set_active(False) + getattr(self, prefix+'hudStyleOptionT').set_active(False) + elif style == 'T' and getattr(self, prefix+'hudStyleOptionT').get_active(): self.hud_params[param] = 'T' - getattr(self, 'HAStyleOption').set_active(False) - getattr(self, 'HSStyleOption').set_active(False) - print "setting self.hud_params[%s] = %s" % (param, val[1]) + getattr(self, prefix+'hudStyleOptionA').set_active(False) + getattr(self, prefix+'hudStyleOptionS').set_active(False) + print "setting self.hud_params[%s] = %s" % (param, style) def update_table_position(self): if os.name == 'nt': From 7900ebcebe429fe43a69c929ed6ea32222c797f8 Mon Sep 17 00:00:00 2001 From: sqlcoder Date: Sun, 4 Oct 2009 17:46:04 +0100 Subject: [PATCH 32/56] Tell user what is happening on startup --- pyfpdb/Configuration.py | 24 +++++++++++++++++++----- pyfpdb/fpdb.py | 9 ++++++++- 2 files changed, 27 insertions(+), 6 deletions(-) diff --git a/pyfpdb/Configuration.py b/pyfpdb/Configuration.py index b8022a45..a643696a 100755 --- a/pyfpdb/Configuration.py +++ b/pyfpdb/Configuration.py @@ -311,13 +311,21 @@ class Config: pass if file == None: # that didn't work either, just die - print "No HUD_config_xml found. Exiting" - sys.stderr.write("No HUD_config_xml found. Exiting") + print "No HUD_config_xml found after looking in current directory and "+self.default_config_path+"\nExiting" + sys.stderr.write("No HUD_config_xml found after looking in current directory and "+self.default_config_path+"\nExiting") + print "press enter to continue" + sys.stdin.readline() sys.exit() # Parse even if there was no real config file found and we are using the example # If using the example, we'll edit it later +# sc 2009/10/04 Example already copied to main filename, is this ok? log.info("Reading configuration file %s" % file) + if os.sep in file: + print "\nReading configuration file %s\n" % file + else: + print "\nReading configuration file %s" % file + print "in %s\n" % os.getcwd() try: doc = xml.dom.minidom.parse(file) except: @@ -405,6 +413,8 @@ class Config: db_pass = df_parms['db-password']) self.save(file=os.path.join(self.default_config_path, "HUD_config.xml")) + print "" + def set_hhArchiveBase(self, path): self.imp.node.setAttribute("hhArchiveBase", path) @@ -454,11 +464,15 @@ class Config: def find_example_config(self): if os.path.exists('HUD_config.xml.example'): # there is a HUD_config in the cwd - file = 'HUD_config.xml.example' # so we use it + file = 'HUD_config.xml' # so we use it + try: + shutil.copyfile(file+'.example', file) + except: + file = '' print "No HUD_config.xml found, using HUD_config.xml.example.\n", \ - "A HUD_config.xml will be written. You will probably have to edit it." + "A HUD_config.xml has been created. You will probably have to edit it." sys.stderr.write("No HUD_config.xml found, using HUD_config.xml.example.\n" + \ - "A HUD_config.xml will be written. You will probably have to edit it.") + "A HUD_config.xml has been created. You will probably have to edit it.") else: file = None return file diff --git a/pyfpdb/fpdb.py b/pyfpdb/fpdb.py index 4703d96d..4065c243 100755 --- a/pyfpdb/fpdb.py +++ b/pyfpdb/fpdb.py @@ -453,7 +453,14 @@ class fpdb: self.db.disconnect() self.sql = SQL.Sql(type = self.settings['db-type'], db_server = self.settings['db-server']) - self.db = Database.Database(self.config, sql = self.sql) + try: + self.db = Database.Database(self.config, sql = self.sql) + except FpdbError: + print "Failed to connect to %s database with username %s." % (self.settings['db-server'], self.settings['db-user']) + sys.stderr.write("Failed to connect to %s database with username %s." % (self.settings['db-server'], self.settings['db-user'])) + except: + print "Failed to connect to %s database with username %s." % (self.settings['db-server'], self.settings['db-user']) + sys.stderr.write("Failed to connect to %s database with username %s." % (self.settings['db-server'], self.settings['db-user'])) if self.db.fdb.wrongDbVersion: diaDbVersionWarning = gtk.Dialog(title="Strong Warning - Invalid database version", parent=None, flags=0, buttons=(gtk.STOCK_OK,gtk.RESPONSE_OK)) From 8851b141a2caea1780514ac90e3329b1490a07c1 Mon Sep 17 00:00:00 2001 From: sqlcoder Date: Mon, 5 Oct 2009 22:12:35 +0100 Subject: [PATCH 33/56] add dropdown to player name in filter --- pyfpdb/Database.py | 10 ++++++++++ pyfpdb/Filters.py | 12 +++++++++++- pyfpdb/SQL.py | 7 +++++++ 3 files changed, 28 insertions(+), 1 deletion(-) diff --git a/pyfpdb/Database.py b/pyfpdb/Database.py index c923517e..c5421684 100755 --- a/pyfpdb/Database.py +++ b/pyfpdb/Database.py @@ -537,6 +537,16 @@ class Database: else: return None + def get_player_names(self, config, site_id=None, like_player_name="%"): + """Fetch player names from players. Use site_id and like_player_name if provided""" + + if site_id == None: + site_id = -1 + c = self.get_cursor() + c.execute(self.sql.query['get_player_names'], (like_player_name, site_id, site_id)) + rows = c.fetchall() + return rows + #returns the SQL ids of the names given in an array # TODO: if someone gets industrious, they should make the parts that use the output of this function deal with a dict # { playername: id } instead of depending on it's relation to the positions list diff --git a/pyfpdb/Filters.py b/pyfpdb/Filters.py index 9ded56b4..d4563059 100644 --- a/pyfpdb/Filters.py +++ b/pyfpdb/Filters.py @@ -23,6 +23,7 @@ import os import sys from optparse import OptionParser from time import * +import gobject #import pokereval import Configuration @@ -228,7 +229,16 @@ class Filters(threading.Thread): pname.set_width_chars(20) hbox.pack_start(pname, False, True, 0) pname.connect("changed", self.__set_hero_name, site) - #TODO: Look at GtkCompletion - to fill out usernames + + # Added EntryCompletion but maybe comboBoxEntry is more flexible? (e.g. multiple choices) + completion = gtk.EntryCompletion() + pname.set_completion(completion) + liststore = gtk.ListStore(gobject.TYPE_STRING) + completion.set_model(liststore) + completion.set_text_column(0) + names = self.db.get_player_names(self.conf) # (config=self.conf, site_id=None, like_player_name="%") + for n in names: + liststore.append(n) self.__set_hero_name(pname, site) diff --git a/pyfpdb/SQL.py b/pyfpdb/SQL.py index 0c551634..1145afec 100644 --- a/pyfpdb/SQL.py +++ b/pyfpdb/SQL.py @@ -1235,6 +1235,13 @@ class Sql: and Players.siteId = Sites.id """ + self.query['get_player_names'] = """ + select p.name + from Players p + where lower(p.name) like lower(%s) + and (p.siteId = %s or %s = -1) + """ + self.query['getSiteId'] = """SELECT id from Sites where name = %s""" self.query['get_stats_from_hand'] = """ From 94af5b1ea82d707f689a70cfc5cf1b1c48d930c4 Mon Sep 17 00:00:00 2001 From: Worros Date: Tue, 6 Oct 2009 12:08:20 +0800 Subject: [PATCH 34/56] Fix order bug for seats in NEWIMPORT --- pyfpdb/Database.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/pyfpdb/Database.py b/pyfpdb/Database.py index f5e947e1..3c8c21c4 100755 --- a/pyfpdb/Database.py +++ b/pyfpdb/Database.py @@ -1419,9 +1419,8 @@ class Database: p['siteHandNo'], p['handStart'], datetime.today(), #importtime -# len(p['names']), #seats - p['maxSeats'], p['seats'], + p['maxSeats'], p['boardcard1'], p['boardcard2'], p['boardcard3'], From fdef5b12d9a2ea64b3e44617f2fb2f1112f6f3cb Mon Sep 17 00:00:00 2001 From: Worros Date: Tue, 6 Oct 2009 18:30:52 +0800 Subject: [PATCH 35/56] Add playersVpi to NEWIMPORT code Untested at the moment, moved the code from Hand.py into DerivedStats. --- pyfpdb/Database.py | 4 +-- pyfpdb/DerivedStats.py | 61 ++++++++++++++++++++++++++++++++++-------- pyfpdb/Hand.py | 58 +++++++++------------------------------ 3 files changed, 65 insertions(+), 58 deletions(-) diff --git a/pyfpdb/Database.py b/pyfpdb/Database.py index 3c8c21c4..22aeb677 100755 --- a/pyfpdb/Database.py +++ b/pyfpdb/Database.py @@ -1382,6 +1382,7 @@ class Database: importtime, seats, maxseats, + playersVpi, boardcard1, boardcard2, boardcard3, @@ -1395,9 +1396,8 @@ class Database: ) VALUES (%s, %s, %s, %s, %s, %s, %s, %s, %s, %s, - %s, %s, %s, %s, %s, %s, %s)""" + %s, %s, %s, %s, %s, %s, %s, %s)""" #--- texture, -#-- playersVpi, #-- playersAtStreet1, #-- playersAtStreet2, #-- playersAtStreet3, diff --git a/pyfpdb/DerivedStats.py b/pyfpdb/DerivedStats.py index 3de15ee5..9f900ce0 100644 --- a/pyfpdb/DerivedStats.py +++ b/pyfpdb/DerivedStats.py @@ -106,6 +106,9 @@ class DerivedStats(): print "hands =", self.hands print "handsplayers =", self.handsplayers + def getHands(self): + return self.hands + def assembleHands(self, hand): self.hands['tableName'] = hand.tablename self.hands['siteHandNo'] = hand.handid @@ -114,17 +117,53 @@ class DerivedStats(): self.hands['importTime'] = None self.hands['seats'] = self.countPlayers(hand) self.hands['maxSeats'] = hand.maxseats - self.hands['boardcard1'] = None - self.hands['boardcard2'] = None - self.hands['boardcard3'] = None - self.hands['boardcard4'] = None - self.hands['boardcard5'] = None - boardCard = 1 - for street in hand.communityStreets: - for card in hand.board[street]: - self.hands['boardcard%s' % str(boardCard)] = Card.encodeCard(card) - boardCard += 1 + # This (i think...) is correct for both stud and flop games, as hand.board['street'] disappears, and + # those values remain default in stud. + boardcards = hand.board['FLOP'] + hand.board['TURN'] + hand.board['RIVER'] + [u'0x', u'0x', u'0x', u'0x', u'0x'] + cards = [Card.encodeCard(c) for c in boardcards[0:5]] + self.hands['boardcard1'] = cards[0] + self.hands['boardcard2'] = cards[1] + self.hands['boardcard3'] = cards[2] + self.hands['boardcard4'] = cards[3] + self.hands['boardcard5'] = cards[4] + + #print "DEBUG: self.getStreetTotals = (%s, %s, %s, %s, %s)" % hand.getStreetTotals() + #FIXME: Pot size still in decimal, needs to be converted to cents + (self.hands['street1Pot'], + self.hands['street2Pot'], + self.hands['street3Pot'], + self.hands['street4Pot'], + self.hands['showdownPot']) = hand.getStreetTotals() + + + self.vpip(hand) # Gives playersVpi (num of players vpip) + # texture smallint, + # playersAtStreet1 SMALLINT NOT NULL, /* num of players seeing flop/street4 */ + # Needs to be recorded + # playersAtStreet2 SMALLINT NOT NULL, + # Needs to be recorded + # playersAtStreet3 SMALLINT NOT NULL, + # Needs to be recorded + # playersAtStreet4 SMALLINT NOT NULL, + # Needs to be recorded + # playersAtShowdown SMALLINT NOT NULL, + # Needs to be recorded + # street0Raises TINYINT NOT NULL, /* num small bets paid to see flop/street4, including blind */ + # Needs to be recorded + # street1Raises TINYINT NOT NULL, /* num small bets paid to see turn/street5 */ + # Needs to be recorded + # street2Raises TINYINT NOT NULL, /* num big bets paid to see river/street6 */ + # Needs to be recorded + # street3Raises TINYINT NOT NULL, /* num big bets paid to see sd/street7 */ + # Needs to be recorded + # street4Raises TINYINT NOT NULL, /* num big bets paid to see showdown */ + # Needs to be recorded + + # comment TEXT, + # commentTs DATETIME + + def assembleHandsPlayers(self, hand): self.vpip(self.hand) @@ -157,4 +196,4 @@ class DerivedStats(): self.handsplayers[player[1]]['street%sAggr' % i] = False def countPlayers(self, hand): - pass \ No newline at end of file + pass diff --git a/pyfpdb/Hand.py b/pyfpdb/Hand.py index 05ec3541..2527f636 100644 --- a/pyfpdb/Hand.py +++ b/pyfpdb/Hand.py @@ -194,64 +194,32 @@ dealt whether they were seen in a 'dealt to' line """ Function to insert Hand into database Should not commit, and do minimal selects. Callers may want to cache commits db: a connected fpdb_db object""" - # TODO: + + ##### + # Players, Gametypes, TourneyTypes are all shared functions that are needed for additional tables + # These functions are intended for prep insert eventually + ##### # Players - base playerid and siteid tuple sqlids = db.getSqlPlayerIDs([p[1] for p in self.players], self.siteId) #Gametypes gtid = db.getGameTypeId(self.siteId, self.gametype) + self.stats.assembleHands(self) + + ##### + # End prep functions + ##### + # HudCache data to come from DerivedStats class # HandsActions - all actions for all players for all streets - self.actions + # Hands - Summary information of hand indexed by handId - gameinfo - #This should be moved to prepInsert - hh = {} - hh['siteHandNo'] = self.handid - hh['handStart'] = self.starttime + hh = self.stats.getHands() hh['gameTypeId'] = gtid # seats TINYINT NOT NULL, - hh['tableName'] = self.tablename - hh['maxSeats'] = self.maxseats hh['seats'] = len(sqlids) - # Flop turn and river may all be empty - add (likely) too many elements and trim with range - boardcards = self.board['FLOP'] + self.board['TURN'] + self.board['RIVER'] + [u'0x', u'0x', u'0x', u'0x', u'0x'] - cards = [Card.encodeCard(c) for c in boardcards[0:5]] - hh['boardcard1'] = cards[0] - hh['boardcard2'] = cards[1] - hh['boardcard3'] = cards[2] - hh['boardcard4'] = cards[3] - hh['boardcard5'] = cards[4] - # texture smallint, - # playersVpi SMALLINT NOT NULL, /* num of players vpi */ - # Needs to be recorded - # playersAtStreet1 SMALLINT NOT NULL, /* num of players seeing flop/street4 */ - # Needs to be recorded - # playersAtStreet2 SMALLINT NOT NULL, - # Needs to be recorded - # playersAtStreet3 SMALLINT NOT NULL, - # Needs to be recorded - # playersAtStreet4 SMALLINT NOT NULL, - # Needs to be recorded - # playersAtShowdown SMALLINT NOT NULL, - # Needs to be recorded - # street0Raises TINYINT NOT NULL, /* num small bets paid to see flop/street4, including blind */ - # Needs to be recorded - # street1Raises TINYINT NOT NULL, /* num small bets paid to see turn/street5 */ - # Needs to be recorded - # street2Raises TINYINT NOT NULL, /* num big bets paid to see river/street6 */ - # Needs to be recorded - # street3Raises TINYINT NOT NULL, /* num big bets paid to see sd/street7 */ - # Needs to be recorded - # street4Raises TINYINT NOT NULL, /* num big bets paid to see showdown */ - # Needs to be recorded - - #print "DEBUG: self.getStreetTotals = (%s, %s, %s, %s, %s)" % self.getStreetTotals() - #FIXME: Pot size still in decimal, needs to be converted to cents - (hh['street1Pot'], hh['street2Pot'], hh['street3Pot'], hh['street4Pot'], hh['showdownPot']) = self.getStreetTotals() - - # comment TEXT, - # commentTs DATETIME #print hh handid = db.storeHand(hh) # HandsPlayers - ? ... Do we fix winnings? From 024618235f68ab29ca9d2e4379332bcd76260b6a Mon Sep 17 00:00:00 2001 From: Worros Date: Wed, 7 Oct 2009 14:15:12 +0800 Subject: [PATCH 36/56] Clean up variables in DerivedStats Doesn't look like they are going to be used like that --- pyfpdb/DerivedStats.py | 70 ------------------------------------------ 1 file changed, 70 deletions(-) diff --git a/pyfpdb/DerivedStats.py b/pyfpdb/DerivedStats.py index 9f900ce0..ffc673b1 100644 --- a/pyfpdb/DerivedStats.py +++ b/pyfpdb/DerivedStats.py @@ -22,76 +22,6 @@ class DerivedStats(): def __init__(self, hand): self.hand = hand - self.activeSeats = 0 - self.position = 0 - self.tourneyTypeId = 0 - - self.HDs = 0 - self.street0VPI = 0 - self.street0Aggr = 0 - self.street0_3BChance = 0 - self.street0_3BDone = 0 - self.street0_4BChance = 0 - self.street0_4BDone = 0 - - self.street1Seen = 0 - self.street2Seen = 0 - self.street3Seen = 0 - self.street4Seen = 0 - self.sawShowdown = 0 - - self.street1Aggr = 0 - self.street2Aggr = 0 - self.street3Aggr = 0 - self.street4Aggr = 0 - - self.otherRaisedStreet1 = 0 - self.otherRaisedStreet2 = 0 - self.otherRaisedStreet3 = 0 - self.otherRaisedStreet4 = 0 - self.foldToOtherRaisedStreet1 = 0 - self.foldToOtherRaisedStreet2 = 0 - self.foldToOtherRaisedStreet3 = 0 - self.foldToOtherRaisedStreet4 = 0 - self.wonWhenSeenStreet1 = 0 - self.wonAtSD = 0 - - self.stealAttemptChance = 0 - self.stealAttempted = 0 - self.foldBbToStealChance = 0 - self.foldedBbToSteal = 0 - self.foldSbToStealChance = 0 - self.foldedSbToSteal = 0 - - self.street1CBChance = 0 - self.street1CBDone = 0 - self.street2CBChance = 0 - self.street2CBDone = 0 - self.street3CBChance = 0 - self.street3CBDone = 0 - self.street4CBChance = 0 - self.street4CBDone = 0 - - self.foldToStreet1CBChance = 0 - self.foldToStreet1CBDone = 0 - self.foldToStreet2CBChance = 0 - self.foldToStreet2CBDone = 0 - self.foldToStreet3CBChance = 0 - self.foldToStreet3CBDone = 0 - self.foldToStreet4CBChance = 0 - self.foldToStreet4CBDone = 0 - - self.totalProfit = 0 - - self.street1CheckCallRaiseChance = 0 - self.street1CheckCallRaiseDone = 0 - self.street2CheckCallRaiseChance = 0 - self.street2CheckCallRaiseDone = 0 - self.street3CheckCallRaiseChance = 0 - self.street3CheckCallRaiseDone = 0 - self.street4CheckCallRaiseChance = 0 - self.street4CheckCallRaiseDone = 0 - self.hands = {} self.handsplayers = {} From 7d708a327c958fcdc6cd5511eaffc0026d6cb57b Mon Sep 17 00:00:00 2001 From: sqlcoder Date: Wed, 7 Oct 2009 23:45:59 +0100 Subject: [PATCH 37/56] try to fix aggBBmultItemAll error --- pyfpdb/Hud.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pyfpdb/Hud.py b/pyfpdb/Hud.py index ad42bb59..09f60700 100644 --- a/pyfpdb/Hud.py +++ b/pyfpdb/Hud.py @@ -258,7 +258,7 @@ class Hud: elif self.hud_params['h_agg_bb_mult'] == 10: getattr(self, 'h_aggBBmultItem10').set_active(True) elif self.hud_params['h_agg_bb_mult'] > 9000: - getattr(self, 'h_aggBBmultItemAll').set_active(True) + getattr(self, 'h_aggBBmultItem10000').set_active(True) # if self.hud_params['agg_bb_mult'] == 1: getattr(self, 'aggBBmultItem1').set_active(True) @@ -269,7 +269,7 @@ class Hud: elif self.hud_params['agg_bb_mult'] == 10: getattr(self, 'aggBBmultItem10').set_active(True) elif self.hud_params['agg_bb_mult'] > 9000: - getattr(self, 'aggBBmultItemAll').set_active(True) + getattr(self, 'aggBBmultItem10000').set_active(True) # if self.hud_params['h_hud_style'] == 'A': getattr(self, 'h_hudStyleOptionA').set_active(True) From 31f48c493279c0d8863a904c1f0e775882efcbf0 Mon Sep 17 00:00:00 2001 From: Worros Date: Thu, 8 Oct 2009 18:01:49 +0800 Subject: [PATCH 38/56] [NEWIMPORT] Calculate playersAtStreetX Untested code. Still missing playersAtShowdown, haven't looked to see if hand.actionStreets contains showdown. --- pyfpdb/DerivedStats.py | 54 ++++++++++++++++++++++++++++++++++-------- 1 file changed, 44 insertions(+), 10 deletions(-) diff --git a/pyfpdb/DerivedStats.py b/pyfpdb/DerivedStats.py index ffc673b1..a4fb630b 100644 --- a/pyfpdb/DerivedStats.py +++ b/pyfpdb/DerivedStats.py @@ -68,17 +68,10 @@ class DerivedStats(): self.vpip(hand) # Gives playersVpi (num of players vpip) + self.playersAtStreetX(hand) # Gives playersAtStreet1..4 and Showdown + # texture smallint, - # playersAtStreet1 SMALLINT NOT NULL, /* num of players seeing flop/street4 */ - # Needs to be recorded - # playersAtStreet2 SMALLINT NOT NULL, - # Needs to be recorded - # playersAtStreet3 SMALLINT NOT NULL, - # Needs to be recorded - # playersAtStreet4 SMALLINT NOT NULL, - # Needs to be recorded - # playersAtShowdown SMALLINT NOT NULL, - # Needs to be recorded + # street0Raises TINYINT NOT NULL, /* num small bets paid to see flop/street4, including blind */ # Needs to be recorded # street1Raises TINYINT NOT NULL, /* num small bets paid to see turn/street5 */ @@ -113,6 +106,47 @@ class DerivedStats(): self.handsplayers[player[1]]['vpip'] = False self.hands['playersVpi'] = len(vpipers) + def playersAtStreetX(self, hand): + """playersAtStreet1 SMALLINT NOT NULL, /* num of players seeing flop/street4/draw1 */""" + # self.actions[street] is a list of all actions in a tuple, contining the player name first + # [ (player, action, ....), (player2, action, ...) ] + # The number of unique players in the list per street gives the value for playersAtStreetXXX + + self.hands['playersAtStreet1'] = 0 + self.hands['playersAtStreet2'] = 0 + self.hands['playersAtStreet3'] = 0 + self.hands['playersAtStreet4'] = 0 + self.hands['playersAtShowdown'] = 0 + + for street in hand.actionStreets: + actors = {} + for act in a[street]: + actors[act[0]] = 1 + #print "len(actors.keys(%s)): %s" % ( street, len(actors.keys())) + if hand.gametype['base'] in ("hold"): + if street in "FLOP": self.hands['playersAtStreet1'] = len(actors.keys()) + elif street in "TURN": self.hands['playersAtStreet2'] = len(actors.keys()) + elif street in "RIVER": self.hands['playersAtStreet3'] = len(actors.keys()) + elif hand.gametype['base'] in ("stud"): + if street in "FOURTH": self.hands['playersAtStreet1'] = len(actors.keys()) + elif street in "FIFTH": self.hands['playersAtStreet2'] = len(actors.keys()) + elif street in "SIXTH": self.hands['playersAtStreet3'] = len(actors.keys()) + elif street in "SEVENTH": self.hands['playersAtStreet4'] = len(actors.keys()) + elif hand.gametype['base'] in ("draw"): + if street in "DRAWONE": self.hands['playersAtStreet1'] = len(actors.keys()) + elif street in "DRAWTWO": self.hands['playersAtStreet2'] = len(actors.keys()) + elif street in "DRAWTHREE": self.hands['playersAtStreet3'] = len(actors.keys()) + + #Need playersAtShowdown + + + def streetXRaises(self, hand): + # self.actions[street] is a list of all actions in a tuple, contining the action as the second element + # [ (player, action, ....), (player2, action, ...) ] + # No idea what this value is actually supposed to be + # In theory its "num small bets paid to see flop/street4, including blind" which makes sense for limit. Not so useful for nl + + def aggr(self, hand, i): aggrers = set() for act in hand.actions[hand.actionStreets[i]]: From cf6c3c8ad00075d166abb815d256130eaae63114 Mon Sep 17 00:00:00 2001 From: Worros Date: Thu, 8 Oct 2009 18:07:54 +0800 Subject: [PATCH 39/56] [NEWIMPOR] Fix playersVpi from last patch Oops - forgot to add the argument --- pyfpdb/Database.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pyfpdb/Database.py b/pyfpdb/Database.py index 22aeb677..c798e72d 100755 --- a/pyfpdb/Database.py +++ b/pyfpdb/Database.py @@ -1382,7 +1382,7 @@ class Database: importtime, seats, maxseats, - playersVpi, + playersVpi, boardcard1, boardcard2, boardcard3, @@ -1421,12 +1421,12 @@ class Database: datetime.today(), #importtime p['seats'], p['maxSeats'], + p['playersVpi'], p['boardcard1'], p['boardcard2'], p['boardcard3'], p['boardcard4'], p['boardcard5'], -# hudCache['playersVpi'], # hudCache['playersAtStreet1'], # hudCache['playersAtStreet2'], # hudCache['playersAtStreet3'], From 6d0ec5d8316682aea4069f7b925b0d1f791a57be Mon Sep 17 00:00:00 2001 From: Worros Date: Thu, 8 Oct 2009 18:13:13 +0800 Subject: [PATCH 40/56] [NEWIMPORT] Add playersAtStreetX to insert --- pyfpdb/Database.py | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/pyfpdb/Database.py b/pyfpdb/Database.py index c798e72d..38c475d9 100755 --- a/pyfpdb/Database.py +++ b/pyfpdb/Database.py @@ -1388,6 +1388,11 @@ class Database: boardcard3, boardcard4, boardcard5, + playersAtStreet1, + playersAtStreet2, + playersAtStreet3, + playersAtStreet4, + playersAtShowdown, street1Pot, street2Pot, street3Pot, @@ -1396,19 +1401,14 @@ class Database: ) VALUES (%s, %s, %s, %s, %s, %s, %s, %s, %s, %s, - %s, %s, %s, %s, %s, %s, %s, %s)""" + %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, + %s, %s, %s)""" #--- texture, -#-- playersAtStreet1, -#-- playersAtStreet2, -#-- playersAtStreet3, -#-- playersAtStreet4, -#-- playersAtShowdown, #-- street0Raises, #-- street1Raises, #-- street2Raises, #-- street3Raises, #-- street4Raises, -#-- seats, q = q.replace('%s', self.sql.query['placeholder']) print "DEBUG: p: %s" %p @@ -1427,11 +1427,11 @@ class Database: p['boardcard3'], p['boardcard4'], p['boardcard5'], -# hudCache['playersAtStreet1'], -# hudCache['playersAtStreet2'], -# hudCache['playersAtStreet3'], -# hudCache['playersAtStreet4'], -# hudCache['playersAtShowdown'], + p['playersAtStreet1'], + p['playersAtStreet2'], + p['playersAtStreet3'], + p['playersAtStreet4'], + p['playersAtShowdown'], # hudCache['street0Raises'], # hudCache['street1Raises'], # hudCache['street2Raises'], From ee864033ee09dfeda69c9ffe7256116f9650bca8 Mon Sep 17 00:00:00 2001 From: Eric Blade Date: Fri, 9 Oct 2009 07:31:25 -0400 Subject: [PATCH 41/56] Add exception for not being able to connect to MySQL, make use of it to pop up an error box --- pyfpdb/Exceptions.py | 3 +++ pyfpdb/fpdb.py | 9 +++++++-- pyfpdb/fpdb_db.py | 2 +- 3 files changed, 11 insertions(+), 3 deletions(-) diff --git a/pyfpdb/Exceptions.py b/pyfpdb/Exceptions.py index f3d75e89..eaf5d798 100644 --- a/pyfpdb/Exceptions.py +++ b/pyfpdb/Exceptions.py @@ -17,5 +17,8 @@ class FpdbParseError(FpdbError): class FpdbDatabaseError(FpdbError): pass +class FpdbMySQLFailedError(FpdbDatabaseError): + pass + class DuplicateError(FpdbError): pass diff --git a/pyfpdb/fpdb.py b/pyfpdb/fpdb.py index 4703d96d..5d8d7191 100755 --- a/pyfpdb/fpdb.py +++ b/pyfpdb/fpdb.py @@ -76,7 +76,7 @@ import SQL import Database import FpdbSQLQueries import Configuration -from Exceptions import * +import Exceptions VERSION = "0.11" @@ -453,7 +453,12 @@ class fpdb: self.db.disconnect() self.sql = SQL.Sql(type = self.settings['db-type'], db_server = self.settings['db-server']) - self.db = Database.Database(self.config, sql = self.sql) + try: + self.db = Database.Database(self.config, sql = self.sql) + except Exceptions.FpdbMySQLFailedError: + self.warning_box("Unable to connect to MySQL! Is the MySQL server running?!", "FPDB ERROR") + exit() + if self.db.fdb.wrongDbVersion: diaDbVersionWarning = gtk.Dialog(title="Strong Warning - Invalid database version", parent=None, flags=0, buttons=(gtk.STOCK_OK,gtk.RESPONSE_OK)) diff --git a/pyfpdb/fpdb_db.py b/pyfpdb/fpdb_db.py index 428aa173..17fecc2c 100644 --- a/pyfpdb/fpdb_db.py +++ b/pyfpdb/fpdb_db.py @@ -80,7 +80,7 @@ class fpdb_db: try: self.db = MySQLdb.connect(host = host, user = user, passwd = password, db = database, use_unicode=True) except: - raise FpdbError("MySQL connection failed") + raise FpdbMySQLFailedError("MySQL connection failed") elif backend==fpdb_db.PGSQL: import psycopg2 import psycopg2.extensions From d4cbed121ddc135538615f24b4613701855fd197 Mon Sep 17 00:00:00 2001 From: Eric Blade Date: Fri, 9 Oct 2009 07:39:05 -0400 Subject: [PATCH 42/56] fix indentation errors --- pyfpdb/DerivedStats.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pyfpdb/DerivedStats.py b/pyfpdb/DerivedStats.py index a4fb630b..7d428be9 100644 --- a/pyfpdb/DerivedStats.py +++ b/pyfpdb/DerivedStats.py @@ -107,7 +107,7 @@ class DerivedStats(): self.hands['playersVpi'] = len(vpipers) def playersAtStreetX(self, hand): - """playersAtStreet1 SMALLINT NOT NULL, /* num of players seeing flop/street4/draw1 */""" + """ playersAtStreet1 SMALLINT NOT NULL, /* num of players seeing flop/street4/draw1 */""" # self.actions[street] is a list of all actions in a tuple, contining the player name first # [ (player, action, ....), (player2, action, ...) ] # The number of unique players in the list per street gives the value for playersAtStreetXXX @@ -145,7 +145,7 @@ class DerivedStats(): # [ (player, action, ....), (player2, action, ...) ] # No idea what this value is actually supposed to be # In theory its "num small bets paid to see flop/street4, including blind" which makes sense for limit. Not so useful for nl - + pass def aggr(self, hand, i): aggrers = set() From b8be20f5513d43941d74a6616972b9ffbd24cbce Mon Sep 17 00:00:00 2001 From: sqlcoder Date: Sun, 11 Oct 2009 22:44:52 +0100 Subject: [PATCH 43/56] show nl and fl limits separately in filter --- pyfpdb/Filters.py | 65 +++++++++++++++++++++++----- pyfpdb/GuiPlayerStats.py | 44 ++++++++++++------- pyfpdb/SQL.py | 92 +++++++++++++++++++++++++++++++++++++--- 3 files changed, 171 insertions(+), 30 deletions(-) diff --git a/pyfpdb/Filters.py b/pyfpdb/Filters.py index d4563059..cb5ad6f2 100644 --- a/pyfpdb/Filters.py +++ b/pyfpdb/Filters.py @@ -54,6 +54,7 @@ class Filters(threading.Thread): ,'seatsbetween':'Between:', 'seatsand':'And:', 'seatsshow':'Show Number of _Players' ,'limitstitle':'Limits:', 'seatstitle':'Number of Players:' ,'groupstitle':'Grouping:', 'posnshow':'Show Position Stats:' + ,'limitsFL':'FL', 'limitsNL':'NL' } # For use in date ranges. @@ -98,6 +99,8 @@ class Filters(threading.Thread): self.cbLimits = {} self.cbNoLimits = None self.cbAllLimits = None + self.cbFL = None + self.cbNL = None self.fillLimitsFrame(vbox, self.display) limitsFrame.add(vbox) @@ -288,12 +291,29 @@ class Filters(threading.Thread): self.cbAllLimits.set_active(False) elif limit == "all": if self.limits[limit]: - for cb in self.cbLimits.values(): - cb.set_active(True) + #for cb in self.cbLimits.values(): + # cb.set_active(True) + if self.cbFL != None: + self.cbFL.set_active(True) + if self.cbNL != None: + self.cbNL.set_active(True) elif limit == "none": if self.limits[limit]: for cb in self.cbLimits.values(): cb.set_active(False) + self.cbNL.set_active(False) + self.cbFL.set_active(False) + elif limit == "fl": + for cb in self.cbLimits.values(): + #print "cb label: ", cb.children()[0].get_text() + if cb.get_children()[0].get_text().isdigit(): + cb.set_active(self.limits[limit]) + + elif limit == "nl": + for cb in self.cbLimits.values(): + t = cb.get_children()[0].get_text() + if "nl" in t and len(t) > 2: + cb.set_active(self.limits[limit]) def __set_seat_select(self, w, seat): #print "__set_seat_select: seat =", seat, "active =", w.get_active() @@ -352,8 +372,10 @@ class Filters(threading.Thread): vbox.pack_start(vbox1, False, False, 0) self.boxes['limits'] = vbox1 - self.cursor.execute(self.sql.query['getLimits']) + self.cursor.execute(self.sql.query['getLimits2']) + # selects limitType, bigBlind result = self.db.cursor.fetchall() + fl, nl = False, False if len(result) >= 1: hbox = gtk.HBox(True, 0) vbox1.pack_start(hbox, False, False, 0) @@ -367,17 +389,37 @@ class Filters(threading.Thread): vbox2.pack_start(hbox, False, False, 0) else: vbox3.pack_start(hbox, False, False, 0) - self.cbLimits[line[0]] = self.createLimitLine(hbox, line[0], line[0]) + if line[0] == 'fl': + self.cbLimits[line[1]] = self.createLimitLine(hbox, str(line[1]), str(line[1])) + fl = True + else: + self.cbLimits[str(line[1])+line[0]] = self.createLimitLine(hbox, str(line[1])+line[0], str(line[1])+line[0]) + nl = True if "LimitSep" in display and display["LimitSep"] == True and len(result) >= 2: + hbox = gtk.HBox(True, 0) + vbox1.pack_start(hbox, False, False, 0) + vbox2 = gtk.VBox(False, 0) + hbox.pack_start(vbox2, False, False, 0) + vbox3 = gtk.VBox(False, 0) + hbox.pack_start(vbox3, False, False, 0) + hbox = gtk.HBox(False, 0) - vbox1.pack_start(hbox, False, True, 0) + vbox2.pack_start(hbox, False, False, 0) self.cbAllLimits = self.createLimitLine(hbox, 'all', self.filterText['limitsall']) hbox = gtk.HBox(False, 0) - vbox1.pack_start(hbox, False, True, 0) + vbox2.pack_start(hbox, False, False, 0) self.cbNoLimits = self.createLimitLine(hbox, 'none', self.filterText['limitsnone']) - hbox = gtk.HBox(False, 0) - vbox1.pack_start(hbox, False, True, 0) - cb = self.createLimitLine(hbox, 'show', self.filterText['limitsshow']) + + if "LimitType" in display and display["LimitType"] == True and len(result) >= 2: + if fl: + hbox = gtk.HBox(False, 0) + vbox3.pack_start(hbox, False, False, 0) + self.cbFL = self.createLimitLine(hbox, 'fl', self.filterText['limitsFL']) + if nl: + hbox = gtk.HBox(False, 0) + vbox3.pack_start(hbox, False, False, 0) + self.cbNL = self.createLimitLine(hbox, 'nl', self.filterText['limitsNL']) + else: print "INFO: No games returned from database" @@ -439,8 +481,11 @@ class Filters(threading.Thread): self.boxes['groups'] = vbox1 hbox = gtk.HBox(False, 0) - vbox1.pack_start(hbox, False, True, 0) + vbox1.pack_start(hbox, False, False, 0) + cb = self.createLimitLine(hbox, 'show', self.filterText['limitsshow']) + hbox = gtk.HBox(False, 0) + vbox1.pack_start(hbox, False, True, 0) cb = gtk.CheckButton(self.filterText['posnshow']) cb.connect('clicked', self.__set_group_select, 'posn') hbox.pack_start(cb, False, False, 0) diff --git a/pyfpdb/GuiPlayerStats.py b/pyfpdb/GuiPlayerStats.py index add46bef..007ab4dd 100644 --- a/pyfpdb/GuiPlayerStats.py +++ b/pyfpdb/GuiPlayerStats.py @@ -54,17 +54,18 @@ class GuiPlayerStats (threading.Thread): self.filterText = {'handhead':'Hand Breakdown for all levels listed above' } - filters_display = { "Heroes" : True, - "Sites" : True, - "Games" : False, - "Limits" : True, - "LimitSep" : True, - "Seats" : True, - "SeatSep" : True, - "Dates" : True, - "Groups" : True, - "Button1" : True, - "Button2" : True + filters_display = { "Heroes" : True, + "Sites" : True, + "Games" : False, + "Limits" : True, + "LimitSep" : True, + "LimitType" : True, + "Seats" : True, + "SeatSep" : True, + "Dates" : True, + "Groups" : True, + "Button1" : True, + "Button2" : True } self.filters = Filters.Filters(self.db, self.conf, self.sql, display = filters_display) @@ -344,13 +345,26 @@ class GuiPlayerStats (threading.Thread): query = query.replace('', '') query = query.replace('', '') - if [x for x in limits if str(x).isdigit()]: - blindtest = str(tuple([x for x in limits if str(x).isdigit()])) + lims = [int(x) for x in limits if x.isdigit()] + nolims = [int(x[0:-2]) for x in limits if len(x) > 2 and x[-2:] == 'nl'] + bbtest = "and ( (gt.limitType = 'fl' and gt.bigBlind in " + # and ( (limit and bb in()) or (nolimit and bb in ()) ) + if lims: + blindtest = str(tuple(lims)) blindtest = blindtest.replace("L", "") blindtest = blindtest.replace(",)",")") - query = query.replace("", " and gt.bigBlind in " + blindtest + " ") + bbtest = bbtest + blindtest + ' ) ' else: - query = query.replace("", "") + bbtest = bbtest + '(-1) ) ' + bbtest = bbtest + " or (gt.limitType = 'nl' and gt.bigBlind in " + if nolims: + blindtest = str(tuple(nolims)) + blindtest = blindtest.replace("L", "") + blindtest = blindtest.replace(",)",")") + bbtest = bbtest + blindtest + ' ) )' + else: + bbtest = bbtest + '(-1) ) )' + query = query.replace("", bbtest) if holecards: # pinch level variables for hole card query query = query.replace("", "hp.startcards") diff --git a/pyfpdb/SQL.py b/pyfpdb/SQL.py index 1145afec..51ae1a1e 100644 --- a/pyfpdb/SQL.py +++ b/pyfpdb/SQL.py @@ -1720,6 +1720,9 @@ class Sql: self.query['getSiteId'] = """SELECT id from Sites where name = %s""" self.query['getGames'] = """SELECT DISTINCT category from Gametypes""" self.query['getLimits'] = """SELECT DISTINCT bigBlind from Gametypes ORDER by bigBlind DESC""" + self.query['getLimits2'] = """SELECT DISTINCT limitType, bigBlind + from Gametypes + ORDER by bigBlind DESC""" if db_server == 'mysql': self.query['playerDetailedStats'] = """ @@ -1775,7 +1778,7 @@ class Sql: inner join Gametypes gt on (gt.Id = h.gameTypeId) inner join Sites s on (s.Id = gt.siteId) where hp.playerId in - and hp.tourneysPlayersId IS NULL + /*and hp.tourneysPlayersId IS NULL*/ and h.seats @@ -1801,7 +1804,7 @@ class Sql: ,upper(gt.limitType) ,s.name """ - else: # assume postgresql + elif db_server == 'postgresql': self.query['playerDetailedStats'] = """ select AS hgametypeid ,gt.base @@ -1855,7 +1858,88 @@ class Sql: inner join Gametypes gt on (gt.Id = h.gameTypeId) inner join Sites s on (s.Id = gt.siteId) where hp.playerId in - and hp.tourneysPlayersId IS NULL + /*and hp.tourneysPlayersId IS NULL*/ + and h.seats + + + and to_char(h.handStart, 'YYYY-MM-DD') + group by hgameTypeId + ,hp.playerId + ,gt.base + ,gt.category + + ,plposition + ,upper(gt.limitType) + ,s.name + order by hp.playerId + ,gt.base + ,gt.category + + ,case when 'B' then 'B' + when 'S' then 'S' + when '0' then 'Y' + else 'Z'|| + end + + ,maxbigblind desc + ,upper(gt.limitType) + ,s.name + """ + elif db_server == 'sqlite': + self.query['playerDetailedStats'] = """ + select AS hgametypeid + ,gt.base + ,gt.category + ,upper(gt.limitType) AS limittype + ,s.name + ,min(gt.bigBlind) AS minbigblind + ,max(gt.bigBlind) AS maxbigblind + /*, AS gtid*/ + , AS plposition + ,count(1) AS n + ,100.0*sum(cast(hp.street0VPI as integer))/count(1) AS vpip + ,100.0*sum(cast(hp.street0Aggr as integer))/count(1) AS pfr + ,case when sum(cast(hp.street0_3Bchance as integer)) = 0 then -999 + else 100.0*sum(cast(hp.street0_3Bdone as integer))/sum(cast(hp.street0_3Bchance as integer)) + end AS pf3 + ,case when sum(cast(hp.stealattemptchance as integer)) = 0 then -999 + else 100.0*sum(cast(hp.stealattempted as integer))/sum(cast(hp.stealattemptchance as integer)) + end AS steals + ,100.0*sum(cast(hp.street1Seen as integer))/count(1) AS saw_f + ,100.0*sum(cast(hp.sawShowdown as integer))/count(1) AS sawsd + ,case when sum(cast(hp.street1Seen as integer)) = 0 then -999 + else 100.0*sum(cast(hp.sawShowdown as integer))/sum(cast(hp.street1Seen as integer)) + end AS wtsdwsf + ,case when sum(cast(hp.sawShowdown as integer)) = 0 then -999 + else 100.0*sum(cast(hp.wonAtSD as integer))/sum(cast(hp.sawShowdown as integer)) + end AS wmsd + ,case when sum(cast(hp.street1Seen as integer)) = 0 then -999 + else 100.0*sum(cast(hp.street1Aggr as integer))/sum(cast(hp.street1Seen as integer)) + end AS flafq + ,case when sum(cast(hp.street2Seen as integer)) = 0 then -999 + else 100.0*sum(cast(hp.street2Aggr as integer))/sum(cast(hp.street2Seen as integer)) + end AS tuafq + ,case when sum(cast(hp.street3Seen as integer)) = 0 then -999 + else 100.0*sum(cast(hp.street3Aggr as integer))/sum(cast(hp.street3Seen as integer)) + end AS rvafq + ,case when sum(cast(hp.street1Seen as integer))+sum(cast(hp.street2Seen as integer))+sum(cast(hp.street3Seen as integer)) = 0 then -999 + else 100.0*(sum(cast(hp.street1Aggr as integer))+sum(cast(hp.street2Aggr as integer))+sum(cast(hp.street3Aggr as integer))) + /(sum(cast(hp.street1Seen as integer))+sum(cast(hp.street2Seen as integer))+sum(cast(hp.street3Seen as integer))) + end AS pofafq + ,sum(hp.totalProfit)/100.0 AS net + ,sum(hp.rake)/100.0 AS rake + ,100.0*avg(hp.totalProfit/(gt.bigBlind+0.0)) AS bbper100 + ,avg(hp.totalProfit)/100.0 AS profitperhand + ,100.0*avg((hp.totalProfit+hp.rake)/(gt.bigBlind+0.0)) AS bb100xr + ,avg((hp.totalProfit+hp.rake)/100.0) AS profhndxr + ,avg(h.seats+0.0) AS avgseats + ,variance(hp.totalProfit/100.0) AS variance + from HandsPlayers hp + inner join Hands h on (h.id = hp.handId) + inner join Gametypes gt on (gt.Id = h.gameTypeId) + inner join Sites s on (s.Id = gt.siteId) + where hp.playerId in + /*and hp.tourneysPlayersId IS NULL*/ and h.seats @@ -1882,8 +1966,6 @@ class Sql: ,upper(gt.limitType) ,s.name """ - #elif db_server == 'sqlite': - # self.query['playerDetailedStats'] = """ """ if db_server == 'mysql': self.query['playerStats'] = """ From b14fd2553c9e19a160341aae206d5fac380f86d2 Mon Sep 17 00:00:00 2001 From: sqlcoder Date: Sun, 11 Oct 2009 23:34:05 +0100 Subject: [PATCH 44/56] add some debug for session stats - I think there is a bug in here somewhere that makes it include too many hands sometimes ... --- pyfpdb/Database.py | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/pyfpdb/Database.py b/pyfpdb/Database.py index c5421684..36e52d83 100755 --- a/pyfpdb/Database.py +++ b/pyfpdb/Database.py @@ -431,6 +431,11 @@ class Database: if hud_style == 'S' or h_hud_style == 'S': self.get_stats_from_hand_session(hand, stat_dict, hero_id, hud_style, h_hud_style) + try: + print "Session: hero_id =", hero_id, "hds =", stat_dict[hero_id]['n'] + except: + pass + if hud_style == 'S' and h_hud_style == 'S': return stat_dict @@ -452,7 +457,7 @@ class Database: #elif h_hud_style == 'H': # h_stylekey = date_nhands_ago needs array by player here ... - #if aggregate: always use aggreagte query now: use agg_bb_mult of 1 for no aggregation: + #if aggregate: always use aggregate query now: use agg_bb_mult of 1 for no aggregation: query = 'get_stats_from_hand_aggregated' subs = (hand, hero_id, stylekey, agg_bb_mult, agg_bb_mult, hero_id, h_stylekey, h_agg_bb_mult, h_agg_bb_mult) print "agg query subs:", subs @@ -474,6 +479,10 @@ class Database: t_dict[name.lower()] = val # print t_dict stat_dict[t_dict['player_id']] = t_dict + try: + print "get_stats end: hero_id =", hero_id, "hds =", stat_dict[hero_id]['n'] + except: + pass return stat_dict From 181294ddf4507f791f54431002165864bb4cfb1e Mon Sep 17 00:00:00 2001 From: sqlcoder Date: Sun, 11 Oct 2009 23:36:26 +0100 Subject: [PATCH 45/56] tidy up Filters and PlayerStats layout a bit --- pyfpdb/Filters.py | 18 +++++++++--------- pyfpdb/SQL.py | 10 +++++----- 2 files changed, 14 insertions(+), 14 deletions(-) diff --git a/pyfpdb/Filters.py b/pyfpdb/Filters.py index cb5ad6f2..2a02aedf 100644 --- a/pyfpdb/Filters.py +++ b/pyfpdb/Filters.py @@ -453,15 +453,6 @@ class Filters(threading.Thread): hbox.pack_start(lbl_to, expand=False, padding=3) hbox.pack_start(sb2, False, False, 0) - if "SeatSep" in display and display["SeatSep"] == True: - hbox = gtk.HBox(False, 0) - vbox1.pack_start(hbox, False, True, 0) - cb = gtk.CheckButton(self.filterText['seatsshow']) - cb.connect('clicked', self.__set_seat_select, 'show') - hbox.pack_start(cb, False, False, 0) - self.sbSeats['show'] = cb - self.seats['show'] = False - self.sbSeats['from'] = sb1 self.sbSeats['to'] = sb2 @@ -492,6 +483,15 @@ class Filters(threading.Thread): self.sbGroups['posn'] = cb self.groups['posn'] = False + if "SeatSep" in display and display["SeatSep"] == True: + hbox = gtk.HBox(False, 0) + vbox1.pack_start(hbox, False, True, 0) + cb = gtk.CheckButton(self.filterText['seatsshow']) + cb.connect('clicked', self.__set_seat_select, 'show') + hbox.pack_start(cb, False, False, 0) + self.sbSeats['show'] = cb + self.seats['show'] = False + def fillCardsFrame(self, vbox): hbox1 = gtk.HBox(True,0) hbox1.show() diff --git a/pyfpdb/SQL.py b/pyfpdb/SQL.py index 51ae1a1e..9279126e 100644 --- a/pyfpdb/SQL.py +++ b/pyfpdb/SQL.py @@ -1721,8 +1721,8 @@ class Sql: self.query['getGames'] = """SELECT DISTINCT category from Gametypes""" self.query['getLimits'] = """SELECT DISTINCT bigBlind from Gametypes ORDER by bigBlind DESC""" self.query['getLimits2'] = """SELECT DISTINCT limitType, bigBlind - from Gametypes - ORDER by bigBlind DESC""" + from Gametypes + ORDER by limitType DESC, bigBlind DESC""" if db_server == 'mysql': self.query['playerDetailedStats'] = """ @@ -1800,8 +1800,8 @@ class Sql: else concat('Z', ) end + ,upper(gt.limitType) desc ,maxbigblind desc - ,upper(gt.limitType) ,s.name """ elif db_server == 'postgresql': @@ -1881,8 +1881,8 @@ class Sql: else 'Z'|| end + ,upper(gt.limitType) desc ,maxbigblind desc - ,upper(gt.limitType) ,s.name """ elif db_server == 'sqlite': @@ -1962,8 +1962,8 @@ class Sql: else 'Z'|| end + ,upper(gt.limitType) desc ,maxbigblind desc - ,upper(gt.limitType) ,s.name """ From aaba84de191e8a6904d3a15e95797d3d955c2c94 Mon Sep 17 00:00:00 2001 From: sqlcoder Date: Mon, 12 Oct 2009 23:02:20 +0100 Subject: [PATCH 46/56] Add ring/tourney radio button to filter --- pyfpdb/Filters.py | 139 ++++++++++++++++++++++++++++++++------- pyfpdb/GuiPlayerStats.py | 22 ++++--- pyfpdb/SQL.py | 4 +- 3 files changed, 130 insertions(+), 35 deletions(-) diff --git a/pyfpdb/Filters.py b/pyfpdb/Filters.py index 2a02aedf..ac036cbf 100644 --- a/pyfpdb/Filters.py +++ b/pyfpdb/Filters.py @@ -54,7 +54,7 @@ class Filters(threading.Thread): ,'seatsbetween':'Between:', 'seatsand':'And:', 'seatsshow':'Show Number of _Players' ,'limitstitle':'Limits:', 'seatstitle':'Number of Players:' ,'groupstitle':'Grouping:', 'posnshow':'Show Position Stats:' - ,'limitsFL':'FL', 'limitsNL':'NL' + ,'limitsFL':'FL', 'limitsNL':'NL', 'ring':'Ring', 'tour':'Tourney' } # For use in date ranges. @@ -101,6 +101,9 @@ class Filters(threading.Thread): self.cbAllLimits = None self.cbFL = None self.cbNL = None + self.rb = {} # radio buttons for ring/tour + self.type = None # ring/tour + self.types = {} # list of all ring/tour values self.fillLimitsFrame(vbox, self.display) limitsFrame.add(vbox) @@ -193,6 +196,9 @@ class Filters(threading.Thread): ltuple.append(l) return ltuple + def getType(self): + return(self.type) + def getSeats(self): if 'from' in self.sbSeats: self.seats['from'] = self.sbSeats['from'].get_value_as_int() @@ -282,13 +288,18 @@ class Filters(threading.Thread): #print w.get_active() self.limits[limit] = w.get_active() print "self.limit[%s] set to %s" %(limit, self.limits[limit]) - if str(limit).isdigit(): + if limit.isdigit() or (len(limit) > 2 and limit[-2:] == 'nl'): if self.limits[limit]: if self.cbNoLimits != None: self.cbNoLimits.set_active(False) else: if self.cbAllLimits != None: self.cbAllLimits.set_active(False) + if not self.limits[limit]: + if limit.isdigit(): + self.cbFL.set_active(False) + else: + self.cbNL.set_active(False) elif limit == "all": if self.limits[limit]: #for cb in self.cbLimits.values(): @@ -304,16 +315,72 @@ class Filters(threading.Thread): self.cbNL.set_active(False) self.cbFL.set_active(False) elif limit == "fl": + if not self.limits[limit]: + # only toggle all fl limits off if they are all currently on + # this stops turning one off from cascading into 'fl' box off + # and then all fl limits being turned off + all_fl_on = True + for cb in self.cbLimits.values(): + t = cb.get_children()[0].get_text() + if t.isdigit(): + if not cb.get_active(): + all_fl_on = False + found = {'ring':False, 'tour':False} for cb in self.cbLimits.values(): #print "cb label: ", cb.children()[0].get_text() - if cb.get_children()[0].get_text().isdigit(): - cb.set_active(self.limits[limit]) - + t = cb.get_children()[0].get_text() + if t.isdigit(): + if self.limits[limit] or all_fl_on: + cb.set_active(self.limits[limit]) + found[self.types[t]] = True + if self.limits[limit]: + if not found[self.type]: + if self.type == 'ring': + if 'tour' in self.rb: + self.rb['tour'].set_active(True) + elif self.type == 'tour': + if 'ring' in self.rb: + self.rb['ring'].set_active(True) elif limit == "nl": + if not self.limits[limit]: + # only toggle all nl limits off if they are all currently on + # this stops turning one off from cascading into 'nl' box off + # and then all nl limits being turned off + all_nl_on = True + for cb in self.cbLimits.values(): + t = cb.get_children()[0].get_text() + if "nl" in t and len(t) > 2: + if not cb.get_active(): + all_nl_on = False + found = {'ring':False, 'tour':False} for cb in self.cbLimits.values(): t = cb.get_children()[0].get_text() if "nl" in t and len(t) > 2: - cb.set_active(self.limits[limit]) + if self.limits[limit] or all_nl_on: + cb.set_active(self.limits[limit]) + found[self.types[t]] = True + if self.limits[limit]: + if not found[self.type]: + if self.type == 'ring': + self.rb['tour'].set_active(True) + elif self.type == 'tour': + self.rb['ring'].set_active(True) + elif limit == "ring": + print "set", limit, "to", self.limits[limit] + if self.limits[limit]: + self.type = "ring" + for cb in self.cbLimits.values(): + #print "cb label: ", cb.children()[0].get_text() + if self.types[cb.get_children()[0].get_text()] == 'tour': + cb.set_active(False) + elif limit == "tour": + print "set", limit, "to", self.limits[limit] + if self.limits[limit]: + self.type = "tour" + for cb in self.cbLimits.values(): + #print "cb label: ", cb.children()[0].get_text() + if self.types[cb.get_children()[0].get_text()] == 'ring': + cb.set_active(False) def __set_seat_select(self, w, seat): #print "__set_seat_select: seat =", seat, "active =", w.get_active() @@ -358,15 +425,14 @@ class Filters(threading.Thread): print "INFO: No games returned from database" def fillLimitsFrame(self, vbox, display): - hbox = gtk.HBox(False, 0) - vbox.pack_start(hbox, False, False, 0) + top_hbox = gtk.HBox(False, 0) + vbox.pack_start(top_hbox, False, False, 0) lbl_title = gtk.Label(self.filterText['limitstitle']) lbl_title.set_alignment(xalign=0.0, yalign=0.5) - hbox.pack_start(lbl_title, expand=True, padding=3) + top_hbox.pack_start(lbl_title, expand=True, padding=3) showb = gtk.Button(label="hide", stock=None, use_underline=True) showb.set_alignment(xalign=1.0, yalign=0.5) showb.connect('clicked', self.__toggle_box, 'limits') - hbox.pack_start(showb, expand=False, padding=1) vbox1 = gtk.VBox(False, 0) vbox.pack_start(vbox1, False, False, 0) @@ -383,18 +449,23 @@ 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): hbox = gtk.HBox(False, 0) if i <= len(result)/2: vbox2.pack_start(hbox, False, False, 0) else: vbox3.pack_start(hbox, False, False, 0) - if line[0] == 'fl': - self.cbLimits[line[1]] = self.createLimitLine(hbox, str(line[1]), str(line[1])) - fl = True + if line[1] == 'fl': + name = str(line[2]) + found['fl'] = True else: - self.cbLimits[str(line[1])+line[0]] = self.createLimitLine(hbox, str(line[1])+line[0], str(line[1])+line[0]) - nl = True + name = str(line[2])+line[1] + found['nl'] = True + self.cbLimits[name] = self.createLimitLine(hbox, name, name) + self.types[name] = line[0] + found[line[0]] = True # type is ring/tour + self.type = line[0] # if only one type, set it now if "LimitSep" in display and display["LimitSep"] == True and len(result) >= 2: hbox = gtk.HBox(True, 0) vbox1.pack_start(hbox, False, False, 0) @@ -410,19 +481,37 @@ class Filters(threading.Thread): vbox2.pack_start(hbox, False, False, 0) self.cbNoLimits = self.createLimitLine(hbox, 'none', self.filterText['limitsnone']) - if "LimitType" in display and display["LimitType"] == True and len(result) >= 2: - if fl: - hbox = gtk.HBox(False, 0) - vbox3.pack_start(hbox, False, False, 0) - self.cbFL = self.createLimitLine(hbox, 'fl', self.filterText['limitsFL']) - if nl: - hbox = gtk.HBox(False, 0) - vbox3.pack_start(hbox, False, False, 0) - self.cbNL = self.createLimitLine(hbox, 'nl', self.filterText['limitsNL']) - + dest = vbox3 # for ring/tour buttons + if "LimitType" in display and display["LimitType"] == True and found['nl'] and found['fl']: + #if found['fl']: + hbox = gtk.HBox(False, 0) + vbox3.pack_start(hbox, False, False, 0) + self.cbFL = self.createLimitLine(hbox, 'fl', self.filterText['limitsFL']) + #if found['nl']: + hbox = gtk.HBox(False, 0) + vbox3.pack_start(hbox, False, False, 0) + self.cbNL = self.createLimitLine(hbox, 'nl', self.filterText['limitsNL']) + dest = vbox2 # for ring/tour buttons else: print "INFO: No games returned from database" + if "Type" in display and display["Type"] == True and found['ring'] and found['tour']: + rb1 = gtk.RadioButton(None, self.filterText['ring']) + rb1.connect('clicked', self.__set_limit_select, 'ring') + rb2 = gtk.RadioButton(rb1, self.filterText['tour']) + rb2.connect('clicked', self.__set_limit_select, 'tour') + top_hbox.pack_start(rb1, False, False, 0) # (child, expand, fill, padding) + top_hbox.pack_start(rb2, True, True, 0) # child uses expand space if fill is true + + self.rb['ring'] = rb1 + self.rb['tour'] = rb2 + #print "about to set ring to true" + rb1.set_active(True) + # set_active doesn't seem to call this for some reason so call manually: + self.__set_limit_select(rb1, 'ring') + self.type = 'ring' + top_hbox.pack_start(showb, expand=False, padding=1) + def fillSeatsFrame(self, vbox, display): hbox = gtk.HBox(False, 0) vbox.pack_start(hbox, False, False, 0) diff --git a/pyfpdb/GuiPlayerStats.py b/pyfpdb/GuiPlayerStats.py index 007ab4dd..4b82c861 100644 --- a/pyfpdb/GuiPlayerStats.py +++ b/pyfpdb/GuiPlayerStats.py @@ -60,6 +60,7 @@ class GuiPlayerStats (threading.Thread): "Limits" : True, "LimitSep" : True, "LimitType" : True, + "Type" : True, "Seats" : True, "SeatSep" : True, "Dates" : True, @@ -158,6 +159,7 @@ class GuiPlayerStats (threading.Thread): heroes = self.filters.getHeroes() siteids = self.filters.getSiteIds() limits = self.filters.getLimits() + type = self.filters.getType() seats = self.filters.getSeats() groups = self.filters.getGroups() dates = self.filters.getDates() @@ -186,16 +188,16 @@ class GuiPlayerStats (threading.Thread): print "No limits found" return - self.createStatsTable(vbox, playerids, sitenos, limits, seats, groups, dates) + self.createStatsTable(vbox, playerids, sitenos, limits, type, seats, groups, dates) - def createStatsTable(self, vbox, playerids, sitenos, limits, seats, groups, dates): + def createStatsTable(self, vbox, playerids, sitenos, limits, type, seats, groups, dates): starttime = time() # Display summary table at top of page # 3rd parameter passes extra flags, currently includes: # holecards - whether to display card breakdown (True/False) flags = [False] - self.addTable(vbox, 'playerDetailedStats', flags, playerids, sitenos, limits, seats, groups, dates) + self.addTable(vbox, 'playerDetailedStats', flags, playerids, sitenos, limits, type, seats, groups, dates) # Separator sep = gtk.HSeparator() @@ -218,13 +220,13 @@ class GuiPlayerStats (threading.Thread): # Detailed table flags = [True] - self.addTable(vbox1, 'playerDetailedStats', flags, playerids, sitenos, limits, seats, groups, dates) + self.addTable(vbox1, 'playerDetailedStats', flags, playerids, sitenos, limits, type, seats, groups, dates) self.db.rollback() print "Stats page displayed in %4.2f seconds" % (time() - starttime) #end def fillStatsFrame(self, vbox): - def addTable(self, vbox, query, flags, playerids, sitenos, limits, seats, groups, dates): + def addTable(self, vbox, query, flags, playerids, sitenos, limits, type, seats, groups, dates): row = 0 sqlrow = 0 colalias,colshow,colheading,colxalign,colformat = 0,1,2,3,4 @@ -232,7 +234,7 @@ class GuiPlayerStats (threading.Thread): else: holecards = flags[0] tmp = self.sql.query[query] - tmp = self.refineQuery(tmp, flags, playerids, sitenos, limits, seats, groups, dates) + tmp = self.refineQuery(tmp, flags, playerids, sitenos, limits, type, seats, groups, dates) self.cursor.execute(tmp) result = self.cursor.fetchall() colnames = [desc[0].lower() for desc in self.cursor.description] @@ -318,9 +320,9 @@ class GuiPlayerStats (threading.Thread): row += 1 vbox.show_all() - #end def addTable(self, query, vars, playerids, sitenos, limits, seats): + #end def addTable(self, query, vars, playerids, sitenos, limits, type, seats, groups, dates): - def refineQuery(self, query, flags, playerids, sitenos, limits, seats, groups, dates): + def refineQuery(self, query, flags, playerids, sitenos, limits, type, seats, groups, dates): if not flags: holecards = False else: holecards = flags[0] @@ -364,6 +366,10 @@ class GuiPlayerStats (threading.Thread): bbtest = bbtest + blindtest + ' ) )' else: bbtest = bbtest + '(-1) ) )' + if type == 'ring': + bbtest = bbtest + " and gt.type = 'ring' " + elif type == 'tour': + bbtest = bbtest + " and gt.type = 'tour' " query = query.replace("", bbtest) if holecards: # pinch level variables for hole card query diff --git a/pyfpdb/SQL.py b/pyfpdb/SQL.py index 9279126e..0f414e41 100644 --- a/pyfpdb/SQL.py +++ b/pyfpdb/SQL.py @@ -1720,9 +1720,9 @@ class Sql: self.query['getSiteId'] = """SELECT id from Sites where name = %s""" self.query['getGames'] = """SELECT DISTINCT category from Gametypes""" self.query['getLimits'] = """SELECT DISTINCT bigBlind from Gametypes ORDER by bigBlind DESC""" - self.query['getLimits2'] = """SELECT DISTINCT limitType, bigBlind + self.query['getLimits2'] = """SELECT DISTINCT type, limitType, bigBlind from Gametypes - ORDER by limitType DESC, bigBlind DESC""" + ORDER by type, limitType DESC, bigBlind DESC""" if db_server == 'mysql': self.query['playerDetailedStats'] = """ From 1d0177f6d47a93666f642334aa9438960c2475b8 Mon Sep 17 00:00:00 2001 From: Worros Date: Tue, 13 Oct 2009 14:04:19 +0800 Subject: [PATCH 47/56] [NEWIMPORT] Finish up Hand import Decided to leave streetXRaisesN alone for the moment --- pyfpdb/Database.py | 25 +++++++++++++------------ pyfpdb/DerivedStats.py | 28 +++++++++------------------- pyfpdb/fpdb.py | 0 3 files changed, 22 insertions(+), 31 deletions(-) mode change 100644 => 100755 pyfpdb/fpdb.py diff --git a/pyfpdb/Database.py b/pyfpdb/Database.py index e05a38b8..60ce39aa 100755 --- a/pyfpdb/Database.py +++ b/pyfpdb/Database.py @@ -1391,6 +1391,7 @@ class Database: importtime, seats, maxseats, + texture, playersVpi, boardcard1, boardcard2, @@ -1402,6 +1403,11 @@ class Database: playersAtStreet3, playersAtStreet4, playersAtShowdown, + street0Raises, + street1Raises, + street2Raises, + street3Raises, + street4Raises, street1Pot, street2Pot, street3Pot, @@ -1411,13 +1417,7 @@ class Database: VALUES (%s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, - %s, %s, %s)""" -#--- texture, -#-- street0Raises, -#-- street1Raises, -#-- street2Raises, -#-- street3Raises, -#-- street4Raises, + %s, %s, %s, %s, %s, %s, %s, %s, %s)""" q = q.replace('%s', self.sql.query['placeholder']) print "DEBUG: p: %s" %p @@ -1430,6 +1430,7 @@ class Database: datetime.today(), #importtime p['seats'], p['maxSeats'], + p['texture'], p['playersVpi'], p['boardcard1'], p['boardcard2'], @@ -1441,11 +1442,11 @@ class Database: p['playersAtStreet3'], p['playersAtStreet4'], p['playersAtShowdown'], -# hudCache['street0Raises'], -# hudCache['street1Raises'], -# hudCache['street2Raises'], -# hudCache['street3Raises'], -# hudCache['street4Raises'], + p['street0Raises'], + p['street1Raises'], + p['street2Raises'], + p['street3Raises'], + p['street4Raises'], p['street1Pot'], p['street2Pot'], p['street3Pot'], diff --git a/pyfpdb/DerivedStats.py b/pyfpdb/DerivedStats.py index 7d428be9..fa85df14 100644 --- a/pyfpdb/DerivedStats.py +++ b/pyfpdb/DerivedStats.py @@ -47,6 +47,7 @@ class DerivedStats(): self.hands['importTime'] = None self.hands['seats'] = self.countPlayers(hand) self.hands['maxSeats'] = hand.maxseats + self.hands['texture'] = None # No calculation done for this yet. # This (i think...) is correct for both stud and flop games, as hand.board['street'] disappears, and # those values remain default in stud. @@ -66,27 +67,11 @@ class DerivedStats(): self.hands['street4Pot'], self.hands['showdownPot']) = hand.getStreetTotals() - self.vpip(hand) # Gives playersVpi (num of players vpip) self.playersAtStreetX(hand) # Gives playersAtStreet1..4 and Showdown - # texture smallint, - - # street0Raises TINYINT NOT NULL, /* num small bets paid to see flop/street4, including blind */ - # Needs to be recorded - # street1Raises TINYINT NOT NULL, /* num small bets paid to see turn/street5 */ - # Needs to be recorded - # street2Raises TINYINT NOT NULL, /* num big bets paid to see river/street6 */ - # Needs to be recorded - # street3Raises TINYINT NOT NULL, /* num big bets paid to see sd/street7 */ - # Needs to be recorded - # street4Raises TINYINT NOT NULL, /* num big bets paid to see showdown */ - # Needs to be recorded - - # comment TEXT, - # commentTs DATETIME - - + # comment TEXT, + # commentTs DATETIME def assembleHandsPlayers(self, hand): self.vpip(self.hand) @@ -145,7 +130,12 @@ class DerivedStats(): # [ (player, action, ....), (player2, action, ...) ] # No idea what this value is actually supposed to be # In theory its "num small bets paid to see flop/street4, including blind" which makes sense for limit. Not so useful for nl - pass + # Leaving empty for the moment, + self.hands['street0Raises'] = 0 # /* num small bets paid to see flop/street4, including blind */ + self.hands['street1Raises'] = 0 # /* num small bets paid to see turn/street5 */ + self.hands['street2Raises'] = 0 # /* num big bets paid to see river/street6 */ + self.hands['street3Raises'] = 0 # /* num big bets paid to see sd/street7 */ + self.hands['street4Raises'] = 0 # /* num big bets paid to see showdown */ def aggr(self, hand, i): aggrers = set() diff --git a/pyfpdb/fpdb.py b/pyfpdb/fpdb.py old mode 100644 new mode 100755 From 00a85936316259b9cde846aa40fc5a0ac2ffbe5f Mon Sep 17 00:00:00 2001 From: Worros Date: Tue, 13 Oct 2009 14:12:25 +0800 Subject: [PATCH 48/56] Fix table re-create bug in fillDefaultData --- pyfpdb/Database.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pyfpdb/Database.py b/pyfpdb/Database.py index 60ce39aa..b283a716 100755 --- a/pyfpdb/Database.py +++ b/pyfpdb/Database.py @@ -1152,7 +1152,7 @@ class Database: elif self.backend == self.MYSQL_INNODB: c.execute("""insert into TourneyTypes(id, siteId, buyin, fee, maxSeats, knockout ,rebuyOrAddon, speed, headsUp, shootout, matrix) - values (1, 0, 0, 0, False, False, null, False, False, False);""") + values (DEFAULT, 1, 0, 0, 0, False, False, null, False, False, False);""") #end def fillDefaultData From f4887235a071c66c1f5f1ccc5d322dfe72afd15d Mon Sep 17 00:00:00 2001 From: Worros Date: Tue, 13 Oct 2009 15:58:05 +0800 Subject: [PATCH 49/56] [NEWIMPORT] Fix Hand import so it runs Also comment out some debug --- pyfpdb/DerivedStats.py | 16 ++++++++++------ 1 file changed, 10 insertions(+), 6 deletions(-) diff --git a/pyfpdb/DerivedStats.py b/pyfpdb/DerivedStats.py index fa85df14..0140f49f 100644 --- a/pyfpdb/DerivedStats.py +++ b/pyfpdb/DerivedStats.py @@ -68,7 +68,10 @@ class DerivedStats(): self.hands['showdownPot']) = hand.getStreetTotals() self.vpip(hand) # Gives playersVpi (num of players vpip) + #print "DEBUG: vpip: %s" %(self.hands['playersVpi']) self.playersAtStreetX(hand) # Gives playersAtStreet1..4 and Showdown + #print "DEBUG: playersAtStreet 1:'%s' 2:'%s' 3:'%s' 4:'%s'" %(self.hands['playersAtStreet1'],self.hands['playersAtStreet2'],self.hands['playersAtStreet3'],self.hands['playersAtStreet4']) + self.streetXRaises(hand) # Empty function currently # comment TEXT, # commentTs DATETIME @@ -84,11 +87,12 @@ class DerivedStats(): if act[1] in ('calls','bets', 'raises'): vpipers.add(act[0]) - for player in hand.players: - if player[1] in vpipers: - self.handsplayers[player[1]]['vpip'] = True - else: - self.handsplayers[player[1]]['vpip'] = False + #for player in hand.players: + # print "DEBUG: '%s' '%s' '%s'" %(player, player[1], vpipers) + # if player[1] in vpipers: + # self.handsplayers[player[1]]['vpip'] = True + # else: + # self.handsplayers[player[1]]['vpip'] = False self.hands['playersVpi'] = len(vpipers) def playersAtStreetX(self, hand): @@ -105,7 +109,7 @@ class DerivedStats(): for street in hand.actionStreets: actors = {} - for act in a[street]: + for act in hand.actions[street]: actors[act[0]] = 1 #print "len(actors.keys(%s)): %s" % ( street, len(actors.keys())) if hand.gametype['base'] in ("hold"): From 4d04a4b1dbe54b14ed28148916ca49d932f4ab21 Mon Sep 17 00:00:00 2001 From: Worros Date: Tue, 13 Oct 2009 17:30:49 +0800 Subject: [PATCH 50/56] [NEWIMPORT] Take a copy of generateHudCache for DerivedStats Commented out, should give a good basis for generating the stats from Hand class --- pyfpdb/DerivedStats.py | 690 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 690 insertions(+) diff --git a/pyfpdb/DerivedStats.py b/pyfpdb/DerivedStats.py index 0140f49f..315ae707 100644 --- a/pyfpdb/DerivedStats.py +++ b/pyfpdb/DerivedStats.py @@ -81,6 +81,696 @@ class DerivedStats(): for i, street in enumerate(hand.actionStreets[1:]): self.aggr(self.hand, i) + def assembleHudCache(self, hand): +# # 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 +# # sure to also change the following storage method and table_viewer.prepare_data if necessary +# #""" +# #print "generateHudCacheData, len(player_ids)=", len(player_ids) +# #setup subarrays of the result dictionary. +# street0VPI=[] +# street0Aggr=[] +# street0_3BChance=[] +# street0_3BDone=[] +# street1Seen=[] +# street2Seen=[] +# street3Seen=[] +# street4Seen=[] +# sawShowdown=[] +# street1Aggr=[] +# street2Aggr=[] +# street3Aggr=[] +# street4Aggr=[] +# otherRaisedStreet1=[] +# otherRaisedStreet2=[] +# otherRaisedStreet3=[] +# otherRaisedStreet4=[] +# foldToOtherRaisedStreet1=[] +# foldToOtherRaisedStreet2=[] +# foldToOtherRaisedStreet3=[] +# foldToOtherRaisedStreet4=[] +# wonWhenSeenStreet1=[] +# +# wonAtSD=[] +# stealAttemptChance=[] +# stealAttempted=[] +# hudDataPositions=[] +# +# street0Calls=[] +# street1Calls=[] +# street2Calls=[] +# street3Calls=[] +# street4Calls=[] +# street0Bets=[] +# street1Bets=[] +# street2Bets=[] +# street3Bets=[] +# street4Bets=[] +# #street0Raises=[] +# #street1Raises=[] +# #street2Raises=[] +# #street3Raises=[] +# #street4Raises=[] +# +# # Summary figures for hand table: +# result={} +# result['playersVpi']=0 +# result['playersAtStreet1']=0 +# result['playersAtStreet2']=0 +# result['playersAtStreet3']=0 +# result['playersAtStreet4']=0 +# result['playersAtShowdown']=0 +# result['street0Raises']=0 +# result['street1Raises']=0 +# result['street2Raises']=0 +# result['street3Raises']=0 +# result['street4Raises']=0 +# result['street1Pot']=0 +# result['street2Pot']=0 +# 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 +# firstPfRaiserId = action[0] +# for j, pid in enumerate(player_ids): +# if pid == firstPfRaiserId: +# firstPfRaiserNo = j +# break +# break +# for i, action in enumerate(actionTypeByNo[0]): +# if action[1] == "call": +# firstPfCallByNo = i +# firstPfCallerId = action[0] +# break +# firstPlayId = firstPfCallerId +# if firstPfRaiseByNo <> -1: +# if firstPfRaiseByNo < firstPfCallByNo or firstPfCallByNo == -1: +# firstPlayId = firstPfRaiserId +# +# +# cutoffId=-1 +# buttonId=-1 +# sbId=-1 +# bbId=-1 +# if base=="hold": +# for player, pos in enumerate(positions): +# if pos == 1: +# cutoffId = player_ids[player] +# if pos == 0: +# buttonId = player_ids[player] +# if pos == 'S': +# 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 +# myStreet0VPI=False +# myStreet0Aggr=False +# myStreet0_3BChance=False +# myStreet0_3BDone=False +# myStreet1Seen=False +# myStreet2Seen=False +# myStreet3Seen=False +# myStreet4Seen=False +# mySawShowdown=False +# myStreet1Aggr=False +# myStreet2Aggr=False +# myStreet3Aggr=False +# myStreet4Aggr=False +# myOtherRaisedStreet1=False +# myOtherRaisedStreet2=False +# myOtherRaisedStreet3=False +# myOtherRaisedStreet4=False +# myFoldToOtherRaisedStreet1=False +# myFoldToOtherRaisedStreet2=False +# myFoldToOtherRaisedStreet3=False +# myFoldToOtherRaisedStreet4=False +# myWonWhenSeenStreet1=0.0 +# myWonAtSD=0.0 +# myStealAttemptChance=False +# myStealAttempted=False +# myStreet0Calls=0 +# myStreet1Calls=0 +# myStreet2Calls=0 +# myStreet3Calls=0 +# myStreet4Calls=0 +# myStreet0Bets=0 +# myStreet1Bets=0 +# myStreet2Bets=0 +# myStreet3Bets=0 +# myStreet4Bets=0 +# #myStreet0Raises=0 +# #myStreet1Raises=0 +# #myStreet2Raises=0 +# #myStreet3Raises=0 +# #myStreet4Raises=0 +# +# #calculate VPIP and PFR +# street=0 +# heroPfRaiseCount=0 +# for currentAction in action_types[street][player]: # finally individual actions +# if currentAction == "bet": +# 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 +# if firstPfRaiseByNo != -1: +# for i, actionType in enumerate(actionTypeByNo[0]): +# if actionType[0] == player_ids[player]: +# if actionType[1] == "bet" and pfRaise == -1 and i > firstPfRaiseByNo: +# pfRaise = i +# if actionType[1] == "fold" and pfFold == -1: +# pfFold = i +# if pfFold == -1 or pfFold > firstPfRaiseByNo: +# 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 +# if positions[player]==1: +# if firstPfRaiserId==player_ids[player] \ +# and (firstPfCallByNo==-1 or firstPfCallByNo>firstPfRaiseByNo): +# myStealAttempted=True +# myStealAttemptChance=True +# if firstPlayId==cutoffId or firstPlayId==buttonId or firstPlayId==sbId or firstPlayId==bbId or firstPlayId==-1: +# myStealAttemptChance=True +# if positions[player]==0: +# if firstPfRaiserId==player_ids[player] \ +# and (firstPfCallByNo==-1 or firstPfCallByNo>firstPfRaiseByNo): +# myStealAttempted=True +# myStealAttemptChance=True +# if firstPlayId==buttonId or firstPlayId==sbId or firstPlayId==bbId or firstPlayId==-1: +# myStealAttemptChance=True +# if positions[player]=='S': +# if firstPfRaiserId==player_ids[player] \ +# and (firstPfCallByNo==-1 or firstPfCallByNo>firstPfRaiseByNo): +# myStealAttempted=True +# myStealAttemptChance=True +# if firstPlayId==sbId or firstPlayId==bbId or firstPlayId==-1: +# 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): +# 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 any(i for i in allIns[2][player]): +# isAllIn = True +# if (len(action_types[3][player])>0 or isAllIn): +# myStreet3Seen = True +# +# #print "base:", base +# if base=="hold": +# mySawShowdown = True +# if any(actiontype == "fold" for actiontype in action_types[3][player]): +# mySawShowdown = False +# else: +# #print "in else" +# if any(i for i in allIns[3][player]): +# isAllIn = True +# if (len(action_types[4][player])>0 or isAllIn): +# #print "in if" +# myStreet4Seen = True +# +# mySawShowdown = True +# if any(actiontype == "fold" for actiontype in action_types[4][player]): +# mySawShowdown = False +# +# if myStreet1Seen: +# result['playersAtStreet1'] += 1 +# if myStreet2Seen: +# result['playersAtStreet2'] += 1 +# if myStreet3Seen: +# result['playersAtStreet3'] += 1 +# if myStreet4Seen: +# 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 +# else: +# for countOther in xrange(len(action_types[street][otherPlayer])): +# 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 +# +# #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 +# else: +# for countOther in xrange(len(action_types[street][otherPlayer])): +# 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 +# +# #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 +# else: +# for countOther in xrange(len(action_types[street][otherPlayer])): +# 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 +# +# #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 +# else: +# for countOther in xrange(len(action_types[street][otherPlayer])): +# 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 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) +# street0_3BChance.append(myStreet0_3BChance) +# street0_3BDone.append(myStreet0_3BDone) +# street1Seen.append(myStreet1Seen) +# street2Seen.append(myStreet2Seen) +# street3Seen.append(myStreet3Seen) +# street4Seen.append(myStreet4Seen) +# sawShowdown.append(mySawShowdown) +# street1Aggr.append(myStreet1Aggr) +# street2Aggr.append(myStreet2Aggr) +# street3Aggr.append(myStreet3Aggr) +# street4Aggr.append(myStreet4Aggr) +# otherRaisedStreet1.append(myOtherRaisedStreet1) +# otherRaisedStreet2.append(myOtherRaisedStreet2) +# otherRaisedStreet3.append(myOtherRaisedStreet3) +# otherRaisedStreet4.append(myOtherRaisedStreet4) +# foldToOtherRaisedStreet1.append(myFoldToOtherRaisedStreet1) +# foldToOtherRaisedStreet2.append(myFoldToOtherRaisedStreet2) +# foldToOtherRaisedStreet3.append(myFoldToOtherRaisedStreet3) +# foldToOtherRaisedStreet4.append(myFoldToOtherRaisedStreet4) +# wonWhenSeenStreet1.append(myWonWhenSeenStreet1) +# wonAtSD.append(myWonAtSD) +# stealAttemptChance.append(myStealAttemptChance) +# stealAttempted.append(myStealAttempted) +# if base=="hold": +# pos=positions[player] +# if pos=='B': +# hudDataPositions.append('B') +# elif pos=='S': +# hudDataPositions.append('S') +# elif pos==0: +# hudDataPositions.append('D') +# elif pos==1: +# hudDataPositions.append('C') +# elif pos>=2 and pos<=4: +# hudDataPositions.append('M') +# elif pos>=5 and pos<=8: +# hudDataPositions.append('E') +# ### RHH Added this elif to handle being a dead hand before the BB (pos==9) +# elif pos==9: +# hudDataPositions.append('X') +# else: +# raise FpdbError("invalid position") +# elif base=="stud": +# #todo: stud positions and steals +# pass +# +# street0Calls.append(myStreet0Calls) +# street1Calls.append(myStreet1Calls) +# street2Calls.append(myStreet2Calls) +# street3Calls.append(myStreet3Calls) +# street4Calls.append(myStreet4Calls) +# street0Bets.append(myStreet0Bets) +# street1Bets.append(myStreet1Bets) +# street2Bets.append(myStreet2Bets) +# street3Bets.append(myStreet3Bets) +# street4Bets.append(myStreet4Bets) +# #street0Raises.append(myStreet0Raises) +# #street1Raises.append(myStreet1Raises) +# #street2Raises.append(myStreet2Raises) +# #street3Raises.append(myStreet3Raises) +# #street4Raises.append(myStreet4Raises) +# +# #add each array to the to-be-returned dictionary +# result['street0VPI']=street0VPI +# result['street0Aggr']=street0Aggr +# result['street0_3BChance']=street0_3BChance +# result['street0_3BDone']=street0_3BDone +# result['street1Seen']=street1Seen +# result['street2Seen']=street2Seen +# result['street3Seen']=street3Seen +# result['street4Seen']=street4Seen +# result['sawShowdown']=sawShowdown +# +# result['street1Aggr']=street1Aggr +# result['otherRaisedStreet1']=otherRaisedStreet1 +# result['foldToOtherRaisedStreet1']=foldToOtherRaisedStreet1 +# result['street2Aggr']=street2Aggr +# result['otherRaisedStreet2']=otherRaisedStreet2 +# result['foldToOtherRaisedStreet2']=foldToOtherRaisedStreet2 +# result['street3Aggr']=street3Aggr +# result['otherRaisedStreet3']=otherRaisedStreet3 +# result['foldToOtherRaisedStreet3']=foldToOtherRaisedStreet3 +# result['street4Aggr']=street4Aggr +# result['otherRaisedStreet4']=otherRaisedStreet4 +# result['foldToOtherRaisedStreet4']=foldToOtherRaisedStreet4 +# result['wonWhenSeenStreet1']=wonWhenSeenStreet1 +# result['wonAtSD']=wonAtSD +# result['stealAttemptChance']=stealAttemptChance +# result['stealAttempted']=stealAttempted +# result['street0Calls']=street0Calls +# result['street1Calls']=street1Calls +# result['street2Calls']=street2Calls +# result['street3Calls']=street3Calls +# result['street4Calls']=street4Calls +# result['street0Bets']=street0Bets +# result['street1Bets']=street1Bets +# result['street2Bets']=street2Bets +# result['street3Bets']=street3Bets +# result['street4Bets']=street4Bets +# #result['street0Raises']=street0Raises +# #result['street1Raises']=street1Raises +# #result['street2Raises']=street2Raises +# #result['street3Raises']=street3Raises +# #result['street4Raises']=street4Raises +# +# #now the various steal values +# foldBbToStealChance=[] +# foldedBbToSteal=[] +# foldSbToStealChance=[] +# foldedSbToSteal=[] +# for player in xrange(len(player_ids)): +# myFoldBbToStealChance=False +# 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 +# for count in xrange(len(action_types[street][player])):#individual actions +# if positions[player]=='B': +# myFoldBbToStealChance=True +# if action_types[street][player][count]=="fold": +# myFoldedBbToSteal=True +# if positions[player]=='S': +# myFoldSbToStealChance=True +# if action_types[street][player][count]=="fold": +# myFoldedSbToSteal=True +# +# +# foldBbToStealChance.append(myFoldBbToStealChance) +# foldedBbToSteal.append(myFoldedBbToSteal) +# foldSbToStealChance.append(myFoldSbToStealChance) +# foldedSbToSteal.append(myFoldedSbToSteal) +# result['foldBbToStealChance']=foldBbToStealChance +# result['foldedBbToSteal']=foldedBbToSteal +# result['foldSbToStealChance']=foldSbToStealChance +# result['foldedSbToSteal']=foldedSbToSteal +# +# #now CB +# street1CBChance=[] +# street1CBDone=[] +# didStreet1CB=[] +# 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=[] +# didStreet2CB=[] +# 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=[] +# didStreet3CB=[] +# 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=[] +# didStreet4CB=[] +# 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=[] +# foldToStreet2CBDone=[] +# foldToStreet3CBChance=[] +# 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 +# result['foldToStreet2CBDone']=foldToStreet2CBDone +# result['foldToStreet3CBChance']=foldToStreet3CBChance +# result['foldToStreet3CBDone']=foldToStreet3CBDone +# result['foldToStreet4CBChance']=foldToStreet4CBChance +# result['foldToStreet4CBDone']=foldToStreet4CBDone +# +# +# totalProfit=[] +# +# street1CheckCallRaiseChance=[] +# street1CheckCallRaiseDone=[] +# street2CheckCallRaiseChance=[] +# street2CheckCallRaiseDone=[] +# street3CheckCallRaiseChance=[] +# street3CheckCallRaiseDone=[] +# street4CheckCallRaiseChance=[] +# street4CheckCallRaiseDone=[] +# #print "b4 totprof calc, len(playerIds)=", len(player_ids) +# for pl in xrange(len(player_ids)): +# #print "pl=", pl +# myTotalProfit=winnings[pl] # still need to deduct other costs +# if antes: +# myTotalProfit=winnings[pl] - antes[pl] +# for i in xrange(len(actionTypes)): #iterate through streets +# #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 +# myStreet2CheckCallRaiseDone=False +# myStreet3CheckCallRaiseChance=False +# myStreet3CheckCallRaiseDone=False +# myStreet4CheckCallRaiseChance=False +# myStreet4CheckCallRaiseDone=False +# +# #print "myTotalProfit=", myTotalProfit +# totalProfit.append(myTotalProfit) +# #print "totalProfit[]=", totalProfit +# +# street1CheckCallRaiseChance.append(myStreet1CheckCallRaiseChance) +# street1CheckCallRaiseDone.append(myStreet1CheckCallRaiseDone) +# street2CheckCallRaiseChance.append(myStreet2CheckCallRaiseChance) +# street2CheckCallRaiseDone.append(myStreet2CheckCallRaiseDone) +# street3CheckCallRaiseChance.append(myStreet3CheckCallRaiseChance) +# 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 +# result['street2CheckCallRaiseDone']=street2CheckCallRaiseDone +# result['street3CheckCallRaiseChance']=street3CheckCallRaiseChance +# result['street3CheckCallRaiseDone']=street3CheckCallRaiseDone +# result['street4CheckCallRaiseChance']=street4CheckCallRaiseChance +# result['street4CheckCallRaiseDone']=street4CheckCallRaiseDone +# return result +# #end def generateHudCacheData + pass + def vpip(self, hand): vpipers = set() for act in hand.actions[hand.actionStreets[1]]: From 843bd754f6e9e259a81050c0da4f2704eee78d0d Mon Sep 17 00:00:00 2001 From: Worros Date: Tue, 13 Oct 2009 17:42:02 +0800 Subject: [PATCH 51/56] [NEWIMPORT] Prep insert functions Cleaned up storeHandsPlayers and added storeHudCacheNew Haven't decided on the data structures to be passed in as yet so the functions only insert the bare minimum and have a list of commented out variables --- pyfpdb/Database.py | 402 ++++++++++++++++++++++++++++++++++----------- 1 file changed, 306 insertions(+), 96 deletions(-) diff --git a/pyfpdb/Database.py b/pyfpdb/Database.py index b283a716..f0146c7f 100755 --- a/pyfpdb/Database.py +++ b/pyfpdb/Database.py @@ -1420,8 +1420,7 @@ class Database: %s, %s, %s, %s, %s, %s, %s, %s, %s)""" q = q.replace('%s', self.sql.query['placeholder']) - print "DEBUG: p: %s" %p - print "DEBUG: gtid: %s" % p['gameTypeId'] + self.cursor.execute(q, ( p['tableName'], p['gameTypeId'], @@ -1456,101 +1455,312 @@ class Database: #return getLastInsertId(backend, conn, cursor) # def storeHand - def storeHandsPlayers(self, p): - #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=[] - # - # # postgres (and others?) needs the booleans converted to ints before saving: - # # (or we could just save them as boolean ... but then we can't sum them so easily in sql ???) - # # NO - storing booleans for now so don't need this - # #hudCacheInt = {} - # #for k,v in hudCache.iteritems(): - # # if k in ('wonWhenSeenStreet1', 'wonAtSD', 'totalProfit'): - # # hudCacheInt[k] = v - # # else: - # # hudCacheInt[k] = map(lambda x: 1 if x else 0, v) - # - # try: - # inserts = [] - # for i in xrange(len(player_ids)): - # card1 = Card.cardFromValueSuit(card_values[i][0], card_suits[i][0]) - # card2 = Card.cardFromValueSuit(card_values[i][1], card_suits[i][1]) - # - # if (category=="holdem"): - # startCards = Card.twoStartCards(card_values[i][0], card_suits[i][0], card_values[i][1], card_suits[i][1]) - # card3 = None - # card4 = None - # elif (category=="omahahi" or category=="omahahilo"): - # startCards = Card.fourStartCards(card_values[i][0], card_suits[i][0], card_values[i][1], card_suits[i][1] - # ,card_values[i][2], card_suits[i][2], card_values[i][3], card_suits[i][3]) - # card3 = Card.cardFromValueSuit(card_values[i][2], card_suits[i][2]) - # card4 = Card.cardFromValueSuit(card_values[i][3], card_suits[i][3]) - # else: - # raise FpdbError("invalid category") - # - # inserts.append( ( - # 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['street0_3BChance'][i], hudCache['street0_3BDone'][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['otherRaisedStreet3'][i], hudCache['otherRaisedStreet4'][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['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['foldToStreet2CBChance'][i], hudCache['foldToStreet2CBDone'][i], - # hudCache['foldToStreet3CBChance'][i], hudCache['foldToStreet3CBDone'][i], - # hudCache['foldToStreet4CBChance'][i], hudCache['foldToStreet4CBDone'][i], - # hudCache['street1CheckCallRaiseChance'][i], hudCache['street1CheckCallRaiseDone'][i], - # hudCache['street2CheckCallRaiseChance'][i], hudCache['street2CheckCallRaiseDone'][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] - # ) ) - # c = self.get_cursor() - # c.executemany (""" - # INSERT INTO HandsPlayers - # (handId, playerId, startCash, position, tourneyTypeId, - # card1, card2, card3, card4, startCards, winnings, rake, seatNo, totalProfit, - # street0VPI, street0Aggr, street0_3BChance, street0_3BDone, - # street1Seen, street2Seen, street3Seen, street4Seen, sawShowdown, - # street1Aggr, street2Aggr, street3Aggr, street4Aggr, - # otherRaisedStreet1, otherRaisedStreet2, otherRaisedStreet3, otherRaisedStreet4, - # foldToOtherRaisedStreet1, foldToOtherRaisedStreet2, foldToOtherRaisedStreet3, foldToOtherRaisedStreet4, - # wonWhenSeenStreet1, wonAtSD, - # stealAttemptChance, stealAttempted, foldBbToStealChance, foldedBbToSteal, foldSbToStealChance, foldedSbToSteal, - # street1CBChance, street1CBDone, street2CBChance, street2CBDone, - # street3CBChance, street3CBDone, street4CBChance, street4CBDone, - # foldToStreet1CBChance, foldToStreet1CBDone, foldToStreet2CBChance, foldToStreet2CBDone, - # foldToStreet3CBChance, foldToStreet3CBDone, foldToStreet4CBChance, foldToStreet4CBDone, - # street1CheckCallRaiseChance, street1CheckCallRaiseDone, street2CheckCallRaiseChance, street2CheckCallRaiseDone, - # street3CheckCallRaiseChance, street3CheckCallRaiseDone, street4CheckCallRaiseChance, street4CheckCallRaiseDone, - # 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)""".replace('%s', self.sql.query['placeholder']) - # ,inserts ) - # result.append( self.get_last_insert_id(c) ) # wrong? not used currently - # except: - # raise FpdbError( "store_hands_players_holdem_omaha error: " + str(sys.exc_value) ) - # - # return result + def storeHandsPlayers(self, hid, pid, p): + q = """INSERT INTO HandsPlayers ( + handId, + playerId + ) + VALUES ( + %s, %s + )""" - pass +# startCash, +# position, +# tourneyTypeId, +# card1, +# card2, +# card3, +# card4, +# startCards, +# winnings, +# rake, +# seatNo, +# totalProfit, +# street0VPI, +# street0Aggr, +# street0_3BChance, +# street0_3BDone, +# street1Seen, +# street2Seen, +# street3Seen, +# street4Seen, +# sawShowdown, +# street1Aggr, +# street2Aggr, +# street3Aggr, +# street4Aggr, +# otherRaisedStreet1, +# otherRaisedStreet2, +# otherRaisedStreet3, +# otherRaisedStreet4, +# foldToOtherRaisedStreet1, +# foldToOtherRaisedStreet2, +# foldToOtherRaisedStreet3, +# foldToOtherRaisedStreet4, +# wonWhenSeenStreet1, +# wonAtSD, +# stealAttemptChance, +# stealAttempted, +# foldBbToStealChance, +# foldedBbToSteal, +# foldSbToStealChance, +# foldedSbToSteal, +# street1CBChance, +# street1CBDone, +# street2CBChance, +# street2CBDone, +# street3CBChance, +# street3CBDone, +# street4CBChance, +# street4CBDone, +# foldToStreet1CBChance, +# foldToStreet1CBDone, +# foldToStreet2CBChance, +# foldToStreet2CBDone, +# foldToStreet3CBChance, +# foldToStreet3CBDone, +# foldToStreet4CBChance, +# foldToStreet4CBDone, +# street1CheckCallRaiseChance, +# street1CheckCallRaiseDone, +# street2CheckCallRaiseChance, +# street2CheckCallRaiseDone, +# street3CheckCallRaiseChance, +# street3CheckCallRaiseDone, +# street4CheckCallRaiseChance, +# street4CheckCallRaiseDone, +# street0Calls, +# street1Calls, +# street2Calls, +# street3Calls, +# street4Calls, +# street0Bets, +# street1Bets, +# street2Bets, +# street3Bets, +# street4Bets + + q = q.replace('%s', self.sql.query['placeholder']) + + self.cursor.execute(q, ( + hid, + pid + )) +# startCash, +# position, +# tourneyTypeId, +# card1, +# card2, +# card3, +# card4, +# startCards, +# winnings, +# rake, +# seatNo, +# totalProfit, +# street0VPI, +# street0Aggr, +# street0_3BChance, +# street0_3BDone, +# street1Seen, +# street2Seen, +# street3Seen, +# street4Seen, +# sawShowdown, +# street1Aggr, +# street2Aggr, +# street3Aggr, +# street4Aggr, +# otherRaisedStreet1, +# otherRaisedStreet2, +# otherRaisedStreet3, +# otherRaisedStreet4, +# foldToOtherRaisedStreet1, +# foldToOtherRaisedStreet2, +# foldToOtherRaisedStreet3, +# foldToOtherRaisedStreet4, +# wonWhenSeenStreet1, +# wonAtSD, +# stealAttemptChance, +# stealAttempted, +# foldBbToStealChance, +# foldedBbToSteal, +# foldSbToStealChance, +# foldedSbToSteal, +# street1CBChance, +# street1CBDone, +# street2CBChance, +# street2CBDone, +# street3CBChance, +# street3CBDone, +# street4CBChance, +# street4CBDone, +# foldToStreet1CBChance, +# foldToStreet1CBDone, +# foldToStreet2CBChance, +# foldToStreet2CBDone, +# foldToStreet3CBChance, +# foldToStreet3CBDone, +# foldToStreet4CBChance, +# foldToStreet4CBDone, +# street1CheckCallRaiseChance, +# street1CheckCallRaiseDone, +# street2CheckCallRaiseChance, +# street2CheckCallRaiseDone, +# street3CheckCallRaiseChance, +# street3CheckCallRaiseDone, +# street4CheckCallRaiseChance, +# street4CheckCallRaiseDone, +# street0Calls, +# street1Calls, +# street2Calls, +# street3Calls, +# street4Calls, +# street0Bets, +# street1Bets, +# street2Bets, +# street3Bets, +# street4Bets + + def storeHudCacheNew(self, gid, pid, hc): + q = """INSERT INTO HudCache ( + gametypeId, + playerId + ) + VALUES ( + %s, %s + )""" + +# gametypeId, +# playerId, +# activeSeats, +# position, +# tourneyTypeId, +# styleKey, +# HDs, +# street0VPI, +# street0Aggr, +# street0_3BChance, +# street0_3BDone, +# street1Seen, +# street2Seen, +# street3Seen, +# street4Seen, +# sawShowdown, +# street1Aggr, +# street2Aggr, +# street3Aggr, +# street4Aggr, +# otherRaisedStreet1, +# otherRaisedStreet2, +# otherRaisedStreet3, +# otherRaisedStreet4, +# foldToOtherRaisedStreet1, +# foldToOtherRaisedStreet2, +# foldToOtherRaisedStreet3, +# foldToOtherRaisedStreet4, +# wonWhenSeenStreet1, +# wonAtSD, +# stealAttemptChance, +# stealAttempted, +# foldBbToStealChance, +# foldedBbToSteal, +# foldSbToStealChance, +# foldedSbToSteal, +# street1CBChance, +# street1CBDone, +# street2CBChance, +# street2CBDone, +# street3CBChance, +# street3CBDone, +# street4CBChance, +# street4CBDone, +# foldToStreet1CBChance, +# foldToStreet1CBDone, +# foldToStreet2CBChance, +# foldToStreet2CBDone, +# foldToStreet3CBChance, +# foldToStreet3CBDone, +# foldToStreet4CBChance, +# foldToStreet4CBDone, +# totalProfit, +# street1CheckCallRaiseChance, +# street1CheckCallRaiseDone, +# street2CheckCallRaiseChance, +# street2CheckCallRaiseDone, +# street3CheckCallRaiseChance, +# street3CheckCallRaiseDone, +# street4CheckCallRaiseChance, +# street4CheckCallRaiseDone) + + q = q.replace('%s', self.sql.query['placeholder']) + + self.cursor.execute(q, ( + gid, + pid + )) + +# gametypeId, +# playerId, +# activeSeats, +# position, +# tourneyTypeId, +# styleKey, +# HDs, +# street0VPI, +# street0Aggr, +# street0_3BChance, +# street0_3BDone, +# street1Seen, +# street2Seen, +# street3Seen, +# street4Seen, +# sawShowdown, +# street1Aggr, +# street2Aggr, +# street3Aggr, +# street4Aggr, +# otherRaisedStreet1, +# otherRaisedStreet2, +# otherRaisedStreet3, +# otherRaisedStreet4, +# foldToOtherRaisedStreet1, +# foldToOtherRaisedStreet2, +# foldToOtherRaisedStreet3, +# foldToOtherRaisedStreet4, +# wonWhenSeenStreet1, +# wonAtSD, +# stealAttemptChance, +# stealAttempted, +# foldBbToStealChance, +# foldedBbToSteal, +# foldSbToStealChance, +# foldedSbToSteal, +# street1CBChance, +# street1CBDone, +# street2CBChance, +# street2CBDone, +# street3CBChance, +# street3CBDone, +# street4CBChance, +# street4CBDone, +# foldToStreet1CBChance, +# foldToStreet1CBDone, +# foldToStreet2CBChance, +# foldToStreet2CBDone, +# foldToStreet3CBChance, +# foldToStreet3CBDone, +# foldToStreet4CBChance, +# foldToStreet4CBDone, +# totalProfit, +# street1CheckCallRaiseChance, +# street1CheckCallRaiseDone, +# street2CheckCallRaiseChance, +# street2CheckCallRaiseDone, +# street3CheckCallRaiseChance, +# street3CheckCallRaiseDone, +# street4CheckCallRaiseChance, +# street4CheckCallRaiseDone) ################################# From 785e3d63a23beb143f85a951ea8a2b0450c8f8db Mon Sep 17 00:00:00 2001 From: sqlcoder Date: Tue, 13 Oct 2009 21:52:13 +0100 Subject: [PATCH 52/56] add 'is db running' printed message when pg db connect fails --- pyfpdb/fpdb_db.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pyfpdb/fpdb_db.py b/pyfpdb/fpdb_db.py index 17fecc2c..986c747f 100644 --- a/pyfpdb/fpdb_db.py +++ b/pyfpdb/fpdb_db.py @@ -111,7 +111,7 @@ class fpdb_db: password = password, database = database) except: - msg = "PostgreSQL connection to database (%s) user (%s) failed." % (database, user) + msg = "PostgreSQL connection to database (%s) user (%s) failed. Are you sure the DB is running?" % (database, user) print msg raise FpdbError(msg) elif backend == fpdb_db.SQLITE: From 4b0a399ffd273b016f4ba36b272cb814f8dda9b1 Mon Sep 17 00:00:00 2001 From: sqlcoder Date: Tue, 13 Oct 2009 21:53:51 +0100 Subject: [PATCH 53/56] stop fpdb.py accessing fpdb_db directly --- pyfpdb/Database.py | 25 ++++++++++++++----------- pyfpdb/fpdb.py | 28 +++++++++++++++++----------- 2 files changed, 31 insertions(+), 22 deletions(-) diff --git a/pyfpdb/Database.py b/pyfpdb/Database.py index f0146c7f..4a0f2e17 100755 --- a/pyfpdb/Database.py +++ b/pyfpdb/Database.py @@ -188,14 +188,7 @@ class Database: 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.fdb.do_connect(c) - self.connection = self.fdb.db - - db_params = c.get_db_parameters() - self.import_options = c.get_import_parameters() - self.type = db_params['db-type'] - self.backend = db_params['db-backend'] - self.db_server = db_params['db-server'] + self.do_connect(c) if self.backend == self.PGSQL: from psycopg2.extensions import ISOLATION_LEVEL_AUTOCOMMIT, ISOLATION_LEVEL_READ_COMMITTED, ISOLATION_LEVEL_SERIALIZABLE @@ -206,14 +199,14 @@ class Database: # where possible avoid creating new SQL instance by using the global one passed in if sql is None: - self.sql = SQL.Sql(type = self.type, db_server = db_params['db-server']) + self.sql = SQL.Sql(type = self.type, db_server = self.db_server) else: self.sql = sql - if self.backend == self.SQLITE and db_params['db-databaseName'] == ':memory:' and self.fdb.wrongDbVersion: + if self.backend == self.SQLITE and self.database == ':memory:' and self.wrongDbVersion: log.info("sqlite/:memory: - creating") self.recreate_tables() - self.fdb.wrongDbVersion = False + self.wrongDbVersion = False self.pcache = None # PlayerId cache self.cachemiss = 0 # Delete me later - using to count player cache misses @@ -245,6 +238,16 @@ class Database: def do_connect(self, c): self.fdb.do_connect(c) + self.connection = self.fdb.db + self.wrongDbVersion = self.fdb.wrongDbVersion + + db_params = c.get_db_parameters() + self.import_options = c.get_import_parameters() + self.type = db_params['db-type'] + self.backend = db_params['db-backend'] + self.db_server = db_params['db-server'] + self.database = db_params['db-databaseName'] + self.host = db_params['db-host'] def commit(self): self.fdb.db.commit() diff --git a/pyfpdb/fpdb.py b/pyfpdb/fpdb.py index 6d58f733..18bc65d9 100755 --- a/pyfpdb/fpdb.py +++ b/pyfpdb/fpdb.py @@ -44,6 +44,7 @@ else: print "Python " + sys.version[0:3] + '...\n' +import traceback import threading import Options import string @@ -64,7 +65,6 @@ import gtk import interlocks -import fpdb_simple import GuiBulkImport import GuiPlayerStats import GuiPositionalStats @@ -76,7 +76,7 @@ import SQL import Database import FpdbSQLQueries import Configuration -import Exceptions +from Exceptions import * VERSION = "0.11" @@ -234,13 +234,13 @@ class fpdb: dia_confirm = gtk.MessageDialog(parent=None, flags=0, type=gtk.MESSAGE_WARNING, buttons=(gtk.BUTTONS_YES_NO), message_format="Confirm deleting and recreating tables") diastring = "Please confirm that you want to (re-)create the tables. If there already are tables in the database " \ - +self.db.fdb.database+" on "+self.db.fdb.host+" they will be deleted." + +self.db.database+" on "+self.db.host+" they will be deleted." dia_confirm.format_secondary_text(diastring)#todo: make above string with bold for db, host and deleted response = dia_confirm.run() dia_confirm.destroy() if response == gtk.RESPONSE_YES: - #if self.db.fdb.backend == self.fdb_lock.fdb.MYSQL_INNODB: + #if self.db.backend == self.fdb_lock.fdb.MYSQL_INNODB: # mysql requires locks on all tables or none - easier to release this lock # than lock all the other tables # ToDo: lock all other tables so that lock doesn't have to be released @@ -455,17 +455,23 @@ class fpdb: self.sql = SQL.Sql(type = self.settings['db-type'], db_server = self.settings['db-server']) try: self.db = Database.Database(self.config, sql = self.sql) - except Exceptions.FpdbMySQLFailedError: + except FpdbMySQLFailedError: self.warning_box("Unable to connect to MySQL! Is the MySQL server running?!", "FPDB ERROR") exit() except FpdbError: - print "Failed to connect to %s database with username %s." % (self.settings['db-server'], self.settings['db-user']) + #print "Failed to connect to %s database with username %s." % (self.settings['db-server'], self.settings['db-user']) + self.warning_box("Failed to connect to %s database with username %s." % (self.settings['db-server'], self.settings['db-user']), "FPDB ERROR") + err = traceback.extract_tb(sys.exc_info()[2])[-1] + 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'])) except: - print "Failed to connect to %s database with username %s." % (self.settings['db-server'], self.settings['db-user']) + #print "Failed to connect to %s database with username %s." % (self.settings['db-server'], self.settings['db-user']) + self.warning_box("Failed to connect to %s database with username %s." % (self.settings['db-server'], self.settings['db-user']), "FPDB ERROR") + err = traceback.extract_tb(sys.exc_info()[2])[-1] + 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.fdb.wrongDbVersion: + if 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.") @@ -484,14 +490,14 @@ class fpdb: diaDbVersionWarning.destroy() if self.status_bar == None: - self.status_bar = gtk.Label("Status: Connected to %s database named %s on host %s"%(self.db.get_backend_name(),self.db.fdb.database, self.db.fdb.host)) + 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.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.fdb.database, self.db.fdb.host)) + 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.connection.rollback() + self.db.rollback() self.validate_config() From 4d92e3d2a0275c8339062e9425f49dab9d605a0a Mon Sep 17 00:00:00 2001 From: sqlcoder Date: Tue, 13 Oct 2009 23:06:09 +0100 Subject: [PATCH 54/56] update graph viewer to work with enhanced filter --- pyfpdb/Filters.py | 16 +++++---- pyfpdb/GuiGraphViewer.py | 77 ++++++++++++++++++++++++++-------------- pyfpdb/SQL.py | 12 +++---- 3 files changed, 67 insertions(+), 38 deletions(-) diff --git a/pyfpdb/Filters.py b/pyfpdb/Filters.py index ac036cbf..6ad242bb 100644 --- a/pyfpdb/Filters.py +++ b/pyfpdb/Filters.py @@ -32,19 +32,20 @@ import FpdbSQLQueries class Filters(threading.Thread): def __init__(self, db, config, qdict, display = {}, debug=True): - self.debug=debug + # config and qdict are now redundant + self.debug = debug #print "start of GraphViewer constructor" - self.db=db - self.cursor=db.cursor - self.sql=qdict - self.conf = config + self.db = db + self.cursor = db.cursor + self.sql = db.sql + self.conf = db.config self.display = display self.sites = {} self.games = {} self.limits = {} self.seats = {} - self.groups = {} + self.groups = {} self.siteid = {} self.heroes = {} self.boxes = {} @@ -451,6 +452,9 @@ class Filters(threading.Thread): 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"]: + continue hbox = gtk.HBox(False, 0) if i <= len(result)/2: vbox2.pack_start(hbox, False, False, 0) diff --git a/pyfpdb/GuiGraphViewer.py b/pyfpdb/GuiGraphViewer.py index f5beadcf..f91c9870 100644 --- a/pyfpdb/GuiGraphViewer.py +++ b/pyfpdb/GuiGraphViewer.py @@ -53,20 +53,26 @@ class GuiGraphViewer (threading.Thread): self.db = Database.Database(self.conf, sql=self.sql) - filters_display = { "Heroes" : True, - "Sites" : True, - "Games" : True, - "Limits" : True, - "Seats" : False, - "Dates" : True, - "Button1" : True, - "Button2" : True + filters_display = { "Heroes" : True, + "Sites" : True, + "Games" : True, + "Limits" : True, + "LimitSep" : True, + "LimitType" : True, + "Type" : False, + "UseType" : 'ring', + "Seats" : False, + "SeatSep" : False, + "Dates" : True, + "Groups" : False, + "Button1" : True, + "Button2" : True } self.filters = Filters.Filters(self.db, self.conf, self.sql, display = filters_display) - self.filters.registerButton1Name("Refresh Graph") + self.filters.registerButton1Name("Refresh _Graph") self.filters.registerButton1Callback(self.generateGraph) - self.filters.registerButton2Name("Export to File") + self.filters.registerButton2Name("_Export to File") self.filters.registerButton2Callback(self.exportGraph) self.mainHBox = gtk.HBox(False, 0) @@ -146,10 +152,8 @@ class GuiGraphViewer (threading.Thread): raise def generateGraph(self, widget, data): - print "generateGraph: start" try: self.clearGraphData() - print "after cleardata" sitenos = [] playerids = [] @@ -158,15 +162,18 @@ class GuiGraphViewer (threading.Thread): heroes = self.filters.getHeroes() siteids = self.filters.getSiteIds() limits = self.filters.getLimits() - print "got filter data" + for i in ('show', 'none'): + if i in limits: + limits.remove(i) # Which sites are selected? for site in sites: if sites[site] == True: sitenos.append(siteids[site]) - self.db.cursor.execute(self.sql.query['getPlayerId'], (heroes[site],)) - result = self.db.cursor.fetchall() + c = self.db.get_cursor() + c.execute(self.sql.query['getPlayerId'], (heroes[site],)) + result = c.fetchall() if len(result) == 1: - playerids.append(result[0][0]) + playerids.append( int(result[0][0]) ) if not sitenos: #Should probably pop up here. @@ -182,12 +189,10 @@ class GuiGraphViewer (threading.Thread): return #Set graph properties - print "add_subplot" self.ax = self.fig.add_subplot(111) #Get graph data from DB starttime = time() - print "get line: playerids =", playerids, "sitenos =", sitenos, "limits =", limits line = self.getRingProfitGraph(playerids, sitenos, limits) print "Graph generated in: %s" %(time() - starttime) @@ -234,12 +239,31 @@ class GuiGraphViewer (threading.Thread): # [5L] into (5) not (5,) and [5L, 2829L] into (5, 2829) nametest = str(tuple(names)) sitetest = str(tuple(sites)) - limittest = str(tuple(limits)) - nametest = nametest.replace("L", "") - nametest = nametest.replace(",)",")") - sitetest = sitetest.replace(",)",")") - limittest = limittest.replace("L", "") - limittest = limittest.replace(",)",")") + #nametest = nametest.replace("L", "") + + lims = [int(x) for x in limits if x.isdigit()] + nolims = [int(x[0:-2]) for x in limits if len(x) > 2 and x[-2:] == 'nl'] + limittest = "and ( (gt.limitType = 'fl' and gt.bigBlind in " + # and ( (limit and bb in()) or (nolimit and bb in ()) ) + if lims: + blindtest = str(tuple(lims)) + blindtest = blindtest.replace("L", "") + blindtest = blindtest.replace(",)",")") + limittest = limittest + blindtest + ' ) ' + else: + limittest = limittest + '(-1) ) ' + limittest = limittest + " or (gt.limitType = 'nl' and gt.bigBlind in " + if nolims: + blindtest = str(tuple(nolims)) + blindtest = blindtest.replace("L", "") + blindtest = blindtest.replace(",)",")") + limittest = limittest + blindtest + ' ) )' + else: + limittest = limittest + '(-1) ) )' + if type == 'ring': + limittest = limittest + " and gt.type = 'ring' " + elif type == 'tour': + limittest = limittest + " and gt.type = 'tour' " #Must be a nicer way to deal with tuples of size 1 ie. (2,) - which makes sql barf tmp = tmp.replace("", nametest) @@ -247,6 +271,7 @@ class GuiGraphViewer (threading.Thread): tmp = tmp.replace("", start_date) tmp = tmp.replace("", end_date) tmp = tmp.replace("", limittest) + tmp = tmp.replace(",)", ")") #print "DEBUG: sql query:" #print tmp @@ -255,10 +280,10 @@ class GuiGraphViewer (threading.Thread): winnings = self.db.cursor.fetchall() self.db.rollback() - if(winnings == ()): + if winnings == (): return None - y=map(lambda x:float(x[3]), winnings) + y = map(lambda x:float(x[1]), winnings) line = cumsum(y) return line/100 #end of def getRingProfitGraph diff --git a/pyfpdb/SQL.py b/pyfpdb/SQL.py index 0f414e41..bb918d97 100644 --- a/pyfpdb/SQL.py +++ b/pyfpdb/SQL.py @@ -2455,16 +2455,16 @@ class Sql: # self.query['playerStatsByPosition'] = """ """ self.query['getRingProfitAllHandsPlayerIdSite'] = """ - SELECT hp.handId, hp.totalProfit, hp.totalProfit, hp.totalProfit + SELECT hp.handId, hp.totalProfit FROM HandsPlayers hp - INNER JOIN Players pl ON (hp.playerId = pl.id) - INNER JOIN Hands h ON (h.id = hp.handId) - INNER JOIN Gametypes g ON (h.gametypeId = g.id) - where pl.id in + INNER JOIN Players pl ON (pl.id = hp.playerId) + INNER JOIN Hands h ON (h.id = hp.handId) + INNER JOIN Gametypes gt ON (gt.id = h.gametypeId) + WHERE pl.id in AND pl.siteId in AND h.handStart > '' AND h.handStart < '' - AND g.bigBlind in + AND hp.tourneysPlayersId IS NULL GROUP BY h.handStart, hp.handId, hp.totalProfit ORDER BY h.handStart""" From a232a94eb1d36f59b79c8b67682b1572633661f3 Mon Sep 17 00:00:00 2001 From: Mika Bostrom Date: Wed, 14 Oct 2009 16:04:09 +0300 Subject: [PATCH 55/56] Try to make hud more configurable Modified files: * Configuration.py * HUD_config.xml.example * HUD_main.py Instead of tweaking aggregation settings directly in code, make the values configurable through HUD_config.xml; use the newly created element for this. Retain coding convention and key-value names as they are. --- pyfpdb/Configuration.py | 47 ++++++++++++++++++ pyfpdb/HUD_config.xml.example | 93 ++++++++++++++++++++++++++++++++++- pyfpdb/HUD_main.py | 2 +- 3 files changed, 139 insertions(+), 3 deletions(-) diff --git a/pyfpdb/Configuration.py b/pyfpdb/Configuration.py index 89f4fb29..7f0f937e 100755 --- a/pyfpdb/Configuration.py +++ b/pyfpdb/Configuration.py @@ -282,6 +282,19 @@ class HudUI: def __init__(self, node): self.node = node self.label = node.getAttribute('label') + # + self.aggregate_ring = fix_tf(node.getAttribute('aggregate_ring_game_stats')) + self.aggregate_tour = fix_tf(node.getAttribute('aggregate_tourney_stats')) + self.hud_style = node.getAttribute('stat_aggregation_range') + self.hud_days = node.getAttribute('aggregation_days') + self.agg_bb_mult = node.getAttribute('aggregation_level_multiplier') + # + self.h_aggregate_ring = fix_tf(node.getAttribute('aggregate_hero_ring_game_stats')) + self.h_aggregate_tour = fix_tf(node.getAttribute('aggregate_hero_tourney_stats')) + self.h_hud_style = node.getAttribute('hero_stat_aggregation_range') + self.h_hud_days = node.getAttribute('hero_aggregation_days') + self.h_agg_bb_mult = node.getAttribute('hero_aggregation_level_multiplier') + def __str__(self): return " label = %s\n" % self.label @@ -629,6 +642,7 @@ class Config: # Allow to change the menu appearance def get_hud_ui_parameters(self): hui = {} + default_text = 'FPDB Menu - Right click\nLeft-Drag to Move' try: hui['label'] = self.ui.label @@ -636,6 +650,39 @@ class Config: hui['label'] = default_text except: hui['label'] = default_text + + try: hui['aggregate_ring'] = self.ui.aggregate_ring + except: hui['aggregate_ring'] = False + + try: hui['aggregate_tour'] = self.ui.aggregate_tour + except: hui['aggregate_tour'] = True + + try: hui['hud_style'] = self.ui.hud_style + except: hui['hud_style'] = 'A' + + try: hui['hud_days'] = self.ui.hud_days + except: hui['hud_days'] = 90 + + try: hui['agg_bb_mult'] = self.ui.agg_bb_mult + except: hui['agg_bb_mult'] = 1 + + # Hero specific + + try: hui['h_aggregate_ring'] = self.ui.h_aggregate_ring + except: hui['h_aggregate_ring'] = False + + try: hui['h_aggregate_tour'] = self.ui.h_aggregate_tour + except: hui['h_aggregate_tour'] = True + + try: hui['h_hud_style'] = self.ui.h_hud_style + except: hui['h_hud_style'] = 'S' + + try: hui['h_hud_days'] = self.ui.h_hud_days + except: hui['h_hud_days'] = 30 + + try: hui['h_agg_bb_mult'] = self.ui.h_agg_bb_mult + except: hui['h_agg_bb_mult'] = 1 + return hui diff --git a/pyfpdb/HUD_config.xml.example b/pyfpdb/HUD_config.xml.example index de2f1bba..1fe19c5a 100644 --- a/pyfpdb/HUD_config.xml.example +++ b/pyfpdb/HUD_config.xml.example @@ -4,8 +4,97 @@ - + + + diff --git a/pyfpdb/HUD_main.py b/pyfpdb/HUD_main.py index 23c1ef03..95a25a29 100755 --- a/pyfpdb/HUD_main.py +++ b/pyfpdb/HUD_main.py @@ -91,7 +91,7 @@ class HUD_main(object): self.db_name = db_name self.config = Configuration.Config(file=options.config, dbname=options.dbname) self.hud_dict = {} - self.hud_params = def_hud_params + self.hud_params = self.config.get_hud_ui_parameters() # a thread to read stdin gobject.threads_init() # this is required From 54d309f797d68a6b629ecbb278431fd25e50865e Mon Sep 17 00:00:00 2001 From: Mika Bostrom Date: Wed, 14 Oct 2009 19:33:19 +0300 Subject: [PATCH 56/56] Minor fixes to hud setup code --- pyfpdb/Configuration.py | 4 ++-- pyfpdb/HUD_config.xml.example | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/pyfpdb/Configuration.py b/pyfpdb/Configuration.py index 7f0f937e..924d6584 100755 --- a/pyfpdb/Configuration.py +++ b/pyfpdb/Configuration.py @@ -660,7 +660,7 @@ class Config: try: hui['hud_style'] = self.ui.hud_style except: hui['hud_style'] = 'A' - try: hui['hud_days'] = self.ui.hud_days + try: hui['hud_days'] = int(self.ui.hud_days) except: hui['hud_days'] = 90 try: hui['agg_bb_mult'] = self.ui.agg_bb_mult @@ -677,7 +677,7 @@ class Config: try: hui['h_hud_style'] = self.ui.h_hud_style except: hui['h_hud_style'] = 'S' - try: hui['h_hud_days'] = self.ui.h_hud_days + try: hui['h_hud_days'] = int(self.ui.h_hud_days) except: hui['h_hud_days'] = 30 try: hui['h_agg_bb_mult'] = self.ui.h_agg_bb_mult diff --git a/pyfpdb/HUD_config.xml.example b/pyfpdb/HUD_config.xml.example index 1fe19c5a..bfeafd8d 100644 --- a/pyfpdb/HUD_config.xml.example +++ b/pyfpdb/HUD_config.xml.example @@ -82,7 +82,7 @@