From 23f56ea2ae26f7226218dda47fef9a261f165c23 Mon Sep 17 00:00:00 2001 From: sqlcoder Date: Wed, 23 Sep 2009 23:03:34 +0100 Subject: [PATCH 01/20] 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 02/20] 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 03/20] 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 04/20] 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 05/20] 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 06/20] 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 07/20] 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 08/20] 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 09/20] 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 10/20] 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 11/20] 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 12/20] 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 13/20] 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 14/20] 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 15/20] 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 16/20] 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 17/20] 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 18/20] 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 19/20] 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 20/20] 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