diff --git a/pyfpdb/AbsoluteToFpdb.py b/pyfpdb/AbsoluteToFpdb.py index 3fc42665..503c1f4e 100644 --- a/pyfpdb/AbsoluteToFpdb.py +++ b/pyfpdb/AbsoluteToFpdb.py @@ -1,4 +1,4 @@ -#!/usr/bin/env python +#!/usr/bin/env python # -*- coding: utf-8 -*- # # Copyright 2008, Carl Gherardi @@ -60,7 +60,7 @@ debugging: if False, pass on partially supported game types. If true, have a go logging.info("Initialising Absolute converter class") self.filetype = "text" self.codepage = "cp1252" - self.siteId = 3 # Needs to match id entry in Sites database + self.siteId = 8 # Needs to match id entry in Sites database self.debugging = debugging if autostart: self.start() @@ -79,7 +79,7 @@ debugging: if False, pass on partially supported game types. If true, have a go # TODO: Absolute posting when coming in new: %s - Posts $0.02 .. should that be a new Post line? where do we need to add support for that? *confused* self.re_PostBoth = re.compile(ur"^%s - Posts dead (?:\$| €|)(?P[0-9]*[.0-9]+)" % player_re, re.MULTILINE) self.re_Action = re.compile(ur"^%s - (?PBets |Raises |All-In |All-In\(Raise\) |Calls |Folds|Checks)?\$?(?P[0-9]*[.0-9]+)?" % player_re, re.MULTILINE) - print "^%s - (?PBets |Raises |All-In |All-In\(Raise\) |Calls |Folds|Checks)?\$?(?P[0-9]*[.0-9]+)?" % player_re +# print "^%s - (?PBets |Raises |All-In |All-In\(Raise\) |Calls |Folds|Checks)?\$?(?P[0-9]*[.0-9]+)?" % player_re self.re_ShowdownAction = re.compile(ur"^%s - Shows \[(?P.*)\]" % player_re, re.MULTILINE) self.re_CollectPot = re.compile(ur"^Seat [0-9]: %s(?: \(dealer\)| \(big blind\)| \(small blind\)|) (?:won|collected) Total \((?:\$| €|)(?P[0-9]*[.0-9]+)\)" % player_re, re.MULTILINE) #self.re_PostSB = re.compile(ur"^%s: posts small blind \[(?:\$| €|) (?P[.0-9]+)" % player_re, re.MULTILINE) @@ -248,8 +248,7 @@ or None if we fail to get the info """ else: #Not involved in hand hand.involved = False - - + def readStudPlayerCards(self, hand, street): # lol. see Plymouth.txt logging.warning("Absolute readStudPlayerCards is only a stub.") @@ -283,7 +282,7 @@ or None if we fail to get the info """ logging.debug("readShowdownActions") for shows in self.re_ShowdownAction.finditer(hand.handText): cards = shows.group('CARDS') - cards = [validCard(card) for card in cards.split(' ')] + cards = [validCard(card) for card in cards.split(' ')] logging.debug("readShowdownActions %s %s" %(cards, shows.group('PNAME'))) hand.addShownCards(cards, shows.group('PNAME')) diff --git a/pyfpdb/Configuration.py b/pyfpdb/Configuration.py index f7f31167..b90040d7 100755 --- a/pyfpdb/Configuration.py +++ b/pyfpdb/Configuration.py @@ -593,19 +593,20 @@ class Config: return paths def get_frames(self, site = "PokerStars"): + if site not in self.supported_sites: return False return self.supported_sites[site].use_frames == True def get_default_colors(self, site = "PokerStars"): colors = {} - if self.supported_sites[site].hudopacity == "": + if site not in self.supported_sites or self.supported_sites[site].hudopacity == "": colors['hudopacity'] = 0.90 else: colors['hudopacity'] = float(self.supported_sites[site].hudopacity) - if self.supported_sites[site].hudbgcolor == "": + if site not in self.supported_sites or self.supported_sites[site].hudbgcolor == "": colors['hudbgcolor'] = "#FFFFFF" else: colors['hudbgcolor'] = self.supported_sites[site].hudbgcolor - if self.supported_sites[site].hudfgcolor == "": + if site not in self.supported_sites or self.supported_sites[site].hudfgcolor == "": colors['hudfgcolor'] = "#000000" else: colors['hudfgcolor'] = self.supported_sites[site].hudfgcolor @@ -613,6 +614,8 @@ class Config: def get_default_font(self, site = 'PokerStars'): (font, font_size) = ("Sans", "8") + if site not in self.supported_sites: + return ("Sans", "8") if self.supported_sites[site].font == "": font = "Sans" else: diff --git a/pyfpdb/Database.py b/pyfpdb/Database.py index 4c44f5de..e83daac0 100755 --- a/pyfpdb/Database.py +++ b/pyfpdb/Database.py @@ -98,7 +98,7 @@ class Database: foreignKeys = [ [ ] # no db with index 0 , [ ] # no db with index 1 - , [ # foreign keys for mysql + , [ # foreign keys for mysql (index 2) {'fktab':'Hands', 'fkcol':'gametypeId', 'rtab':'Gametypes', 'rcol':'id', 'drop':1} , {'fktab':'HandsPlayers', 'fkcol':'handId', 'rtab':'Hands', 'rcol':'id', 'drop':1} , {'fktab':'HandsPlayers', 'fkcol':'playerId', 'rtab':'Players', 'rcol':'id', 'drop':1} @@ -107,7 +107,7 @@ class Database: , {'fktab':'HudCache', 'fkcol':'playerId', 'rtab':'Players', 'rcol':'id', 'drop':0} , {'fktab':'HudCache', 'fkcol':'tourneyTypeId', 'rtab':'TourneyTypes', 'rcol':'id', 'drop':1} ] - , [ # foreign keys for postgres + , [ # foreign keys for postgres (index 3) {'fktab':'Hands', 'fkcol':'gametypeId', 'rtab':'Gametypes', 'rcol':'id', 'drop':1} , {'fktab':'HandsPlayers', 'fkcol':'handId', 'rtab':'Hands', 'rcol':'id', 'drop':1} , {'fktab':'HandsPlayers', 'fkcol':'playerId', 'rtab':'Players', 'rcol':'id', 'drop':1} @@ -116,6 +116,8 @@ class Database: , {'fktab':'HudCache', 'fkcol':'playerId', 'rtab':'Players', 'rcol':'id', 'drop':0} , {'fktab':'HudCache', 'fkcol':'tourneyTypeId', 'rtab':'TourneyTypes', 'rcol':'id', 'drop':1} ] + , [ # no foreign keys in sqlite (index 4) + ] ] @@ -233,9 +235,15 @@ class Database: self.fdb.reconnect(due_to_error=False) def get_backend_name(self): - """Reconnects the DB""" - return self.fdb.get_backend_name() - + """Returns the name of the currently used backend""" + if self.backend==2: + return "MySQL InnoDB" + elif self.backend==3: + return "PostgreSQL" + elif self.backend==4: + return "SQLite" + else: + raise fpdb_simple.FpdbError("invalid backend") def get_table_name(self, hand_id): c = self.connection.cursor() @@ -465,11 +473,39 @@ class Database: result = c.fetchall() return result - def get_last_insert_id(self): + def get_last_insert_id(self, cursor=None): + ret = None try: - ret = self.fdb.getLastInsertId() + if self.backend == self.MYSQL_INNODB: + ret = self.connection.insert_id() + if ret < 1 or ret > 999999999: + print "getLastInsertId(): problem fetching insert_id? ret=", ret + ret = -1 + elif self.backend == self.PGSQL: + # some options: + # currval(hands_id_seq) - use name of implicit seq here + # lastval() - still needs sequences set up? + # insert ... returning is useful syntax (but postgres specific?) + # see rules (fancy trigger type things) + c = self.get_cursor() + ret = c.execute ("SELECT lastval()") + row = c.fetchone() + if not row: + print "getLastInsertId(%s): problem fetching lastval? row=" % seq, row + ret = -1 + else: + ret = row[0] + elif self.backend == self.SQLITE: + ret = cursor.lastrowid + else: + print "getLastInsertId(): unknown backend ", self.backend + ret = -1 except: - print "get_last_insert_id error:", str(sys.exc_value) + ret = -1 + err = traceback.extract_tb(sys.exc_info()[2]) + print "***get_last_insert_id error: " + str(sys.exc_info()[1]) + print "\n".join( [e[0]+':'+str(e[1])+" "+e[2] for e in err] ) + raise return ret @@ -847,6 +883,7 @@ class Database: self.commit() except: + err = traceback.extract_tb(sys.exc_info()[2])[-1] print "***Error dropping tables: "+err[2]+"("+str(err[1])+"): "+str(sys.exc_info()[1]) self.rollback() raise @@ -939,12 +976,14 @@ class Database: try: stime = time() - self.connection.cursor().execute(self.sql.query['clearHudCache']) - self.connection.cursor().execute(self.sql.query['rebuildHudCache']) + self.get_cursor().execute(self.sql.query['clearHudCache']) + self.get_cursor().execute(self.sql.query['rebuildHudCache']) self.commit() print "Rebuild hudcache took %.1f seconds" % (time() - stime,) except: + err = traceback.extract_tb(sys.exc_info()[2])[-1] print "Error rebuilding hudcache:", str(sys.exc_value) + print err #end def rebuild_hudcache @@ -1001,15 +1040,26 @@ class Database: def insertPlayer(self, name, site_id): result = None c = self.get_cursor() - c.execute ("SELECT id FROM Players WHERE name=%s", (name,)) - tmp=c.fetchall() - if (len(tmp)==0): #new player - c.execute ("INSERT INTO Players (name, siteId) VALUES (%s, %s)", (name, site_id)) - #Get last id might be faster here. - c.execute ("SELECT id FROM Players WHERE name=%s", (name,)) - tmp=c.fetchall() - return tmp[0][0] + q = "SELECT name, id FROM Players WHERE siteid=%s and name=%s" + q = q.replace('%s', self.sql.query['placeholder']) + print "DEBUG: name: %s site: %s" %(name, site_id) + + c.execute (q, (site_id, name)) + + tmp = c.fetchone() + if (tmp == None): #new player + c.execute ("INSERT INTO Players (name, siteId) VALUES (%s, %s)".replace('%s',self.sql.query['placeholder']) + ,(name, site_id)) + #Get last id might be faster here. + #c.execute ("SELECT id FROM Players WHERE name=%s", (name,)) + tmp = [self.get_last_insert_id(c)] + return tmp[0] + + def insertGameTypes(self, row): + c = self.get_cursor() + c.execute( self.sql.query['insertGameTypes'], row ) + return [self.get_last_insert_id(c)] def store_the_hand(self, h): """Take a HandToWrite object and store it in the db""" @@ -1069,6 +1119,76 @@ class Database: return result #end def store_the_hand + def storeHand(self, p): + #stores into table hands: + self.cursor.execute ("""INSERT INTO Hands ( + tablename, + sitehandno, + gametypeid, + handstart, + importtime, + seats, + maxseats, + boardcard1, + boardcard2, + boardcard3, + boardcard4, + boardcard5, +-- texture, + playersVpi, + playersAtStreet1, + playersAtStreet2, + playersAtStreet3, + playersAtStreet4, + playersAtShowdown, + street0Raises, + street1Raises, + street2Raises, + street3Raises, + street4Raises, +-- street1Pot, +-- street2Pot, +-- street3Pot, +-- street4Pot, +-- showdownPot + ) + VALUES + (%s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, + %s, %s, %s, %s, %s, %s, %s)""", + ( + p['tablename'], + p['sitehandno'], + p['gametypeid'], + p['handStart'], + datetime.datetime.today(), + len(p['names']), + p['maxSeats'], + p['boardcard1'], + p['boardcard2'], + p['boardcard3'], + p['boardcard4'], + p['boardcard5'], + hudCache['playersVpi'], + hudCache['playersAtStreet1'], + hudCache['playersAtStreet2'], + hudCache['playersAtStreet3'], + hudCache['playersAtStreet4'], + hudCache['playersAtShowdown'], + hudCache['street0Raises'], + hudCache['street1Raises'], + hudCache['street2Raises'], + hudCache['street3Raises'], + hudCache['street4Raises'], + hudCache['street1Pot'], + hudCache['street2Pot'], + hudCache['street3Pot'], + hudCache['street4Pot'], + hudCache['showdownPot'] + ) + ) + #return getLastInsertId(backend, conn, cursor) + # def storeHand + def storeHands(self, backend, site_hand_no, gametype_id ,hand_start_time, names, tableName, maxSeats, hudCache ,board_values, board_suits): @@ -1076,30 +1196,31 @@ class Database: cards = [Card.cardFromValueSuit(v,s) for v,s in zip(board_values,board_suits)] #stores into table hands: try: - self.get_cursor().execute ("""INSERT INTO Hands - (siteHandNo, gametypeId, handStart, seats, tableName, importTime, maxSeats - ,boardcard1,boardcard2,boardcard3,boardcard4,boardcard5 - ,playersVpi, playersAtStreet1, playersAtStreet2 - ,playersAtStreet3, playersAtStreet4, playersAtShowdown - ,street0Raises, street1Raises, street2Raises - ,street3Raises, street4Raises, street1Pot - ,street2Pot, street3Pot, street4Pot - ,showdownPot - ) - VALUES - (%s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, - %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s) - """ - , (site_hand_no, gametype_id, hand_start_time, len(names), tableName, datetime.today(), maxSeats - ,cards[0], cards[1], cards[2], cards[3], cards[4] - ,hudCache['playersVpi'], hudCache['playersAtStreet1'], hudCache['playersAtStreet2'] - ,hudCache['playersAtStreet3'], hudCache['playersAtStreet4'], hudCache['playersAtShowdown'] - ,hudCache['street0Raises'], hudCache['street1Raises'], hudCache['street2Raises'] - ,hudCache['street3Raises'], hudCache['street4Raises'], hudCache['street1Pot'] - ,hudCache['street2Pot'], hudCache['street3Pot'], hudCache['street4Pot'] - ,hudCache['showdownPot'] - )) - ret = self.get_last_insert_id() + c = self.get_cursor() + c.execute ("""INSERT INTO Hands + (siteHandNo, gametypeId, handStart, seats, tableName, importTime, maxSeats + ,boardcard1,boardcard2,boardcard3,boardcard4,boardcard5 + ,playersVpi, playersAtStreet1, playersAtStreet2 + ,playersAtStreet3, playersAtStreet4, playersAtShowdown + ,street0Raises, street1Raises, street2Raises + ,street3Raises, street4Raises, street1Pot + ,street2Pot, street3Pot, street4Pot + ,showdownPot + ) + VALUES + (%s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, + %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s) + """.replace('%s', self.sql.query['placeholder']) + , (site_hand_no, gametype_id, hand_start_time, len(names), tableName, datetime.today(), maxSeats + ,cards[0], cards[1], cards[2], cards[3], cards[4] + ,hudCache['playersVpi'], hudCache['playersAtStreet1'], hudCache['playersAtStreet2'] + ,hudCache['playersAtStreet3'], hudCache['playersAtStreet4'], hudCache['playersAtShowdown'] + ,hudCache['street0Raises'], hudCache['street1Raises'], hudCache['street2Raises'] + ,hudCache['street3Raises'], hudCache['street4Raises'], hudCache['street1Pot'] + ,hudCache['street2Pot'], hudCache['street3Pot'], hudCache['street4Pot'] + ,hudCache['showdownPot'] + )) + ret = self.get_last_insert_id(c) except: ret = -1 raise fpdb_simple.FpdbError( "storeHands error: " + str(sys.exc_value) ) @@ -1168,7 +1289,8 @@ class Database: hudCache['street0Calls'][i], hudCache['street1Calls'][i], hudCache['street2Calls'][i], hudCache['street3Calls'][i], hudCache['street4Calls'][i], hudCache['street0Bets'][i], hudCache['street1Bets'][i], hudCache['street2Bets'][i], hudCache['street3Bets'][i], hudCache['street4Bets'][i] ) ) - self.get_cursor().executemany (""" + c = self.get_cursor() + c.executemany (""" INSERT INTO HandsPlayers (handId, playerId, startCash, position, tourneyTypeId, card1, card2, card3, card4, startCards, winnings, rake, seatNo, totalProfit, @@ -1191,13 +1313,9 @@ class Database: VALUES (%s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, - %s, %s, %s, %s, %s, %s, %s, %s, %s, %s)""" + %s, %s, %s, %s, %s, %s, %s, %s, %s, %s)""".replace('%s', self.sql.query['placeholder']) ,inserts ) - result.append( self.get_last_insert_id() ) - - #cursor.execute("SELECT id FROM HandsPlayers WHERE handId=%s AND playerId+0=%s", (hands_id, player_ids[i])) - #result.append(cursor.fetchall()[0][0]) - result.append( self.get_last_insert_id() ) + result.append( self.get_last_insert_id(c) ) # wrong? not used currently except: raise fpdb_simple.FpdbError( "store_hands_players_holdem_omaha error: " + str(sys.exc_value) ) @@ -1220,13 +1338,14 @@ class Database: card6 = Card.cardFromValueSuit(card_values[i][5], card_suits[i][5]) card7 = Card.cardFromValueSuit(card_values[i][6], card_suits[i][6]) - self.get_cursor().execute ("""INSERT INTO HandsPlayers + c = self.get_cursor() + c.execute ("""INSERT INTO HandsPlayers (handId, playerId, startCash, ante, tourneyTypeId, card1, card2, card3, card4, card5, card6, card7, winnings, rake, seatNo) - VALUES (%s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s)""", + VALUES (%s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s)""".replace('%s', self.sql.query['placeholder']), (hands_id, player_ids[i], start_cashes[i], antes[i], 1, card1, card2, card3, card4, @@ -1234,7 +1353,7 @@ class Database: card7, winnings[i], rakes[i], seatNos[i])) #cursor.execute("SELECT id FROM HandsPlayers WHERE handId=%s AND playerId+0=%s", (hands_id, player_ids[i])) #result.append(cursor.fetchall()[0][0]) - result.append( self.get_last_insert_id() ) + result.append( self.get_last_insert_id(c) ) except: raise fpdb_simple.FpdbError( "store_hands_players_stud error: " + str(sys.exc_value) ) @@ -1297,7 +1416,8 @@ class Database: hudCache['street3Bets'][i], hudCache['street4Bets'][i] ) ) - self.get_cursor().executemany (""" + c = self.get_cursor() + c.executemany (""" INSERT INTO HandsPlayers (handId, playerId, startCash, position, tourneyTypeId, card1, card2, card3, card4, startCards, winnings, rake, tourneysPlayersId, seatNo, totalProfit, @@ -1321,10 +1441,10 @@ class Database: (%s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, - %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s)""" + %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s)""".replace('%s', self.sql.query['placeholder']) ,inserts ) - result.append( self.get_last_insert_id() ) + result.append( self.get_last_insert_id(c) ) #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: @@ -1340,14 +1460,15 @@ class Database: try: result=[] for i in xrange(len(player_ids)): - self.get_cursor().execute ("""INSERT INTO HandsPlayers + c = self.get_cursor() + c.execute ("""INSERT INTO HandsPlayers (handId, playerId, startCash, ante, card1Value, card1Suit, card2Value, card2Suit, card3Value, card3Suit, card4Value, card4Suit, card5Value, card5Suit, card6Value, card6Suit, card7Value, card7Suit, winnings, rake, tourneysPlayersId, seatNo) VALUES (%s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, - %s, %s, %s, %s, %s, %s)""", + %s, %s, %s, %s, %s, %s)""".replace('%s', self.sql.query['placeholder']), (hands_id, player_ids[i], start_cashes[i], antes[i], card_values[i][0], card_suits[i][0], card_values[i][1], card_suits[i][1], card_values[i][2], card_suits[i][2], card_values[i][3], card_suits[i][3], @@ -1355,7 +1476,7 @@ class Database: card_values[i][6], card_suits[i][6], winnings[i], rakes[i], tourneys_players_ids[i], seatNos[i])) #cursor.execute("SELECT id FROM HandsPlayers WHERE handId=%s AND playerId+0=%s", (hands_id, player_ids[i])) #result.append(cursor.fetchall()[0][0]) - result.append( self.get_last_insert_id() ) + result.append( self.get_last_insert_id(c) ) except: raise fpdb_simple.FpdbError( "store_hands_players_stud_tourney error: " + str(sys.exc_value) ) @@ -1493,24 +1614,28 @@ class Database: AND position=%s AND tourneyTypeId+0=%s AND styleKey=%s - """, (row[6], row[7], row[8], row[9], row[10], - row[11], row[12], row[13], row[14], row[15], - row[16], row[17], row[18], row[19], row[20], - row[21], row[22], row[23], row[24], row[25], - row[26], row[27], row[28], row[29], row[30], - row[31], row[32], row[33], row[34], row[35], - row[36], row[37], row[38], row[39], row[40], - row[41], row[42], row[43], row[44], row[45], - row[46], row[47], row[48], row[49], row[50], - row[51], row[52], row[53], row[54], row[55], - row[56], row[57], row[58], row[59], row[60], - row[1], row[2], row[3], str(row[4]), row[5], styleKey)) + """.replace('%s', self.sql.query['placeholder']) + ,(row[6], row[7], row[8], row[9], row[10], + row[11], row[12], row[13], row[14], row[15], + row[16], row[17], row[18], row[19], row[20], + row[21], row[22], row[23], row[24], row[25], + row[26], row[27], row[28], row[29], row[30], + row[31], row[32], row[33], row[34], row[35], + row[36], row[37], row[38], row[39], row[40], + row[41], row[42], row[43], row[44], row[45], + row[46], row[47], row[48], row[49], row[50], + row[51], row[52], row[53], row[54], row[55], + row[56], row[57], row[58], row[59], row[60], + row[1], row[2], row[3], str(row[4]), row[5], styleKey)) # Test statusmessage to see if update worked, do insert if not - #print "storehud2, upd num =", num + #print "storehud2, upd num =", num.rowcount + # num is a cursor in sqlite if ( (backend == self.PGSQL and cursor.statusmessage != "UPDATE 1") - or (backend == self.MYSQL_INNODB and num == 0) ): + or (backend == self.MYSQL_INNODB and num == 0) + or (backend == self.SQLITE and num.rowcount == 0) + ): #print "playerid before insert:",row[2]," num = ", num - cursor.execute("""INSERT INTO HudCache + num = cursor.execute("""INSERT INTO HudCache (gametypeId, playerId, activeSeats, position, tourneyTypeId, styleKey, HDs, street0VPI, street0Aggr, street0_3BChance, street0_3BDone, street1Seen, street2Seen, street3Seen, street4Seen, sawShowdown, @@ -1534,14 +1659,14 @@ class Database: %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, - %s, %s, %s, %s, %s)""" + %s, %s, %s, %s, %s)""".replace('%s', self.sql.query['placeholder']) , (row[1], row[2], row[3], row[4], row[5], styleKey, row[6], row[7], row[8], row[9], row[10] ,row[11], row[12], row[13], row[14], row[15], row[16], row[17], row[18], row[19], row[20] ,row[21], row[22], row[23], row[24], row[25], row[26], row[27], row[28], row[29], row[30] ,row[31], row[32], row[33], row[34], row[35], row[36], row[37], row[38], row[39], row[40] ,row[41], row[42], row[43], row[44], row[45], row[46], row[47], row[48], row[49], row[50] ,row[51], row[52], row[53], row[54], row[55], row[56], row[57], row[58], row[59], row[60]) ) - #print "hopefully inserted hud data line: ", cursor.statusmessage + #print "hopefully inserted hud data line: ", cursor.rowcount # message seems to be "INSERT 0 1" else: #print "updated(2) hud data line" @@ -1557,7 +1682,8 @@ 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", (siteTourneyNo, tourneyTypeId)) + 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 @@ -1566,7 +1692,8 @@ class Database: 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)""", (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 @@ -1586,7 +1713,8 @@ 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", (tourney_id, player_ids[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() #print "tried SELECTing tourneys_players.id:",tmp @@ -1594,10 +1722,10 @@ class Database: len(tmp) except TypeError: cursor.execute("""INSERT INTO TourneysPlayers - (tourneyId, playerId, payinAmount, rank, winnings) VALUES (%s, %s, %s, %s, %s)""", + (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", + 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 "created new tourneys_players.id:",tmp diff --git a/pyfpdb/GuiAutoImport.py b/pyfpdb/GuiAutoImport.py index e86bab67..b1815e95 100755 --- a/pyfpdb/GuiAutoImport.py +++ b/pyfpdb/GuiAutoImport.py @@ -17,6 +17,7 @@ import threading import subprocess +import traceback import pygtk pygtk.require('2.0') diff --git a/pyfpdb/GuiBulkImport.py b/pyfpdb/GuiBulkImport.py index a0df4504..269efe13 100755 --- a/pyfpdb/GuiBulkImport.py +++ b/pyfpdb/GuiBulkImport.py @@ -74,7 +74,10 @@ class GuiBulkImport(): cb_hmodel = self.cb_drophudcache.get_model() cb_hindex = self.cb_drophudcache.get_active() - self.lab_info.set_text("Importing") # doesn't display :-( + self.lab_info.set_markup('Importing ...') # uses pango markup! + while gtk.events_pending(): # see http://faq.pygtk.org/index.py?req=index for more hints (3.7) + gtk.main_iteration(False) + if cb_index: self.importer.setDropIndexes(cb_model[cb_index][0]) else: diff --git a/pyfpdb/GuiGraphViewer.py b/pyfpdb/GuiGraphViewer.py index 5fad35ba..645896b4 100644 --- a/pyfpdb/GuiGraphViewer.py +++ b/pyfpdb/GuiGraphViewer.py @@ -20,6 +20,7 @@ import pygtk pygtk.require('2.0') import gtk import os +import traceback from time import * #import pokereval @@ -72,20 +73,19 @@ class GuiGraphViewer (threading.Thread): self.mainHBox.show() self.leftPanelBox = self.filters.get_vbox() - self.graphBox = gtk.VBox(False, 0) - self.graphBox.show() self.hpane = gtk.HPaned() self.hpane.pack1(self.leftPanelBox) + self.mainHBox.add(self.hpane) + # hierarchy: self.mainHBox / self.hpane / self.graphBox / self.canvas / self.fig / self.ax + + self.graphBox = gtk.VBox(False, 0) + self.graphBox.show() self.hpane.pack2(self.graphBox) self.hpane.show() - self.mainHBox.add(self.hpane) - self.fig = None #self.exportButton.set_sensitive(False) - - self.fig = Figure(figsize=(5,4), dpi=100) self.canvas = None @@ -125,79 +125,103 @@ class GuiGraphViewer (threading.Thread): #end def get_vbox def clearGraphData(self): - self.fig.clear() - if self.canvas is not None: - self.canvas.destroy() - self.canvas = FigureCanvas(self.fig) # a gtk.DrawingArea + try: + try: + if self.canvas: + self.graphBox.remove(self.canvas) + except: + pass + + if self.fig != None: + self.fig.clear() + self.fig = Figure(figsize=(5,4), dpi=100) + if self.canvas is not None: + self.canvas.destroy() + + self.canvas = FigureCanvas(self.fig) # a gtk.DrawingArea + except: + err = traceback.extract_tb(sys.exc_info()[2])[-1] + print "***Error: "+err[2]+"("+str(err[1])+"): "+str(sys.exc_info()[1]) + raise def generateGraph(self, widget, data): - self.clearGraphData() + print "generateGraph: start" + try: + self.clearGraphData() + print "after cleardata" - sitenos = [] - playerids = [] + sitenos = [] + playerids = [] - sites = self.filters.getSites() - heroes = self.filters.getHeroes() - siteids = self.filters.getSiteIds() - limits = self.filters.getLimits() - # Which sites are selected? - for site in sites: - if sites[site] == True: - sitenos.append(siteids[site]) - self.db.cursor.execute(self.sql.query['getPlayerId'], (heroes[site],)) - result = self.db.cursor.fetchall() - if len(result) == 1: - playerids.append(result[0][0]) + sites = self.filters.getSites() + heroes = self.filters.getHeroes() + siteids = self.filters.getSiteIds() + limits = self.filters.getLimits() + print "got filter data" + # Which sites are selected? + for site in sites: + if sites[site] == True: + sitenos.append(siteids[site]) + self.db.cursor.execute(self.sql.query['getPlayerId'], (heroes[site],)) + result = self.db.cursor.fetchall() + if len(result) == 1: + playerids.append(result[0][0]) - if not sitenos: - #Should probably pop up here. - print "No sites selected - defaulting to PokerStars" - return + if not sitenos: + #Should probably pop up here. + print "No sites selected - defaulting to PokerStars" + return - if not playerids: - print "No player ids found" - return + if not playerids: + print "No player ids found" + return - if not limits: - print "No limits found" - return + if not limits: + print "No limits found" + return - #Set graph properties - self.ax = self.fig.add_subplot(111) + #Set graph properties + print "add_subplot" + self.ax = self.fig.add_subplot(111) - #Get graph data from DB - starttime = time() - line = self.getRingProfitGraph(playerids, sitenos, limits) - print "Graph generated in: %s" %(time() - starttime) + #Get graph data from DB + starttime = time() + print "get line: playerids =", playerids, "sitenos =", sitenos, "limits =", limits + line = self.getRingProfitGraph(playerids, sitenos, limits) + print "Graph generated in: %s" %(time() - starttime) - self.ax.set_title("Profit graph for ring games") + self.ax.set_title("Profit graph for ring games") - #Set axis labels and grid overlay properites - self.ax.set_xlabel("Hands", fontsize = 12) - self.ax.set_ylabel("$", fontsize = 12) - self.ax.grid(color='g', linestyle=':', linewidth=0.2) - if line == None or line == []: + #Set axis labels and grid overlay properites + self.ax.set_xlabel("Hands", fontsize = 12) + self.ax.set_ylabel("$", fontsize = 12) + self.ax.grid(color='g', linestyle=':', linewidth=0.2) + if line == None or line == []: - #TODO: Do something useful like alert user - print "No hands returned by graph query" - else: -# text = "All Hands, " + sitename + str(name) + "\nProfit: $" + str(line[-1]) + "\nTotal Hands: " + str(len(line)) - text = "All Hands, " + "\nProfit: $" + str(line[-1]) + "\nTotal Hands: " + str(len(line)) + #TODO: Do something useful like alert user + print "No hands returned by graph query" + else: + # text = "All Hands, " + sitename + str(name) + "\nProfit: $" + str(line[-1]) + "\nTotal Hands: " + str(len(line)) + text = "All Hands, " + "\nProfit: $" + str(line[-1]) + "\nTotal Hands: " + str(len(line)) - self.ax.annotate(text, - xy=(10, -10), - xycoords='axes points', - horizontalalignment='left', verticalalignment='top', - fontsize=10) + self.ax.annotate(text, + xy=(10, -10), + xycoords='axes points', + horizontalalignment='left', verticalalignment='top', + fontsize=10) - #Draw plot - self.ax.plot(line,) + #Draw plot + self.ax.plot(line,) + + self.graphBox.add(self.canvas) + self.canvas.show() + self.canvas.draw() + #self.exportButton.set_sensitive(True) + except: + err = traceback.extract_tb(sys.exc_info()[2])[-1] + print "***Error: "+err[2]+"("+str(err[1])+"): "+str(sys.exc_info()[1]) - self.graphBox.add(self.canvas) - self.canvas.show() - self.canvas.draw() - #self.exportButton.set_sensitive(True) #end of def showClicked def getRingProfitGraph(self, names, sites, limits): diff --git a/pyfpdb/GuiPlayerStats.py b/pyfpdb/GuiPlayerStats.py index ffcab178..add46bef 100644 --- a/pyfpdb/GuiPlayerStats.py +++ b/pyfpdb/GuiPlayerStats.py @@ -132,7 +132,7 @@ class GuiPlayerStats (threading.Thread): self.stats_vbox = gtk.VBox(False, 0) self.stats_vbox.show() self.stats_frame.add(self.stats_vbox) - self.fillStatsFrame(self.stats_vbox) + # self.fillStatsFrame(self.stats_vbox) self.main_hbox.pack_start(self.filters.get_vbox()) self.main_hbox.pack_start(self.stats_frame, expand=True, fill=True) @@ -167,7 +167,9 @@ class GuiPlayerStats (threading.Thread): for site in sites: if sites[site] == True: sitenos.append(siteids[site]) - self.cursor.execute(self.sql.query['getPlayerId'], (heroes[site],)) + # Nasty hack to deal with multiple sites + same player name -Eric + que = self.sql.query['getPlayerId'] + " AND siteId=%d" % siteids[site] + self.cursor.execute(que, (heroes[site],)) result = self.db.cursor.fetchall() if len(result) == 1: playerids.append(result[0][0]) diff --git a/pyfpdb/GuiTableViewer.py b/pyfpdb/GuiTableViewer.py index 35dbb797..8d25366a 100644 --- a/pyfpdb/GuiTableViewer.py +++ b/pyfpdb/GuiTableViewer.py @@ -22,288 +22,270 @@ import gtk import os import fpdb_simple -try: - import MySQLdb -except: - diaSQLLibMissing = gtk.Dialog(title="Fatal Error - SQL interface library missing", parent=None, flags=0, buttons=(gtk.STOCK_QUIT,gtk.RESPONSE_OK)) - - label = gtk.Label("Please note that the table viewer only works with MySQL, if you use PostgreSQL this error is expected.") - diaSQLLibMissing.vbox.add(label) - label.show() - - label = gtk.Label("Since the HUD now runs on all supported plattforms I do not see any point in table viewer anymore, if you disagree please send a message to steffen@sycamoretest.info") - diaSQLLibMissing.vbox.add(label) - label.show() - - response = diaSQLLibMissing.run() - #sys.exit(1) - + import fpdb_import import fpdb_db + class GuiTableViewer (threading.Thread): - def hudDivide (self, a, b): - if b==0: - return "n/a" - else: - return str(int((a/float(b))*100))+"%" - #end def hudDivide - - def browse_clicked(self, widget, data): - """runs when user clicks browse on tv tab""" - #print "start of table_viewer.browser_clicked" - current_path=self.filename_tbuffer.get_text(self.filename_tbuffer.get_start_iter(), self.filename_tbuffer.get_end_iter()) - - dia_chooser = gtk.FileChooserDialog(title="Please choose the file for which you want to open the Table Viewer", - action=gtk.FILE_CHOOSER_ACTION_OPEN, - buttons=(gtk.STOCK_CANCEL,gtk.RESPONSE_CANCEL,gtk.STOCK_OPEN,gtk.RESPONSE_OK)) - #dia_chooser.set_current_folder(pathname) - dia_chooser.set_filename(current_path) - #dia_chooser.set_select_multiple(select_multiple) #not in tv, but want this in bulk import - - response = dia_chooser.run() - if response == gtk.RESPONSE_OK: - #print dia_chooser.get_filename(), 'selected' - self.filename_tbuffer.set_text(dia_chooser.get_filename()) - elif response == gtk.RESPONSE_CANCEL: - print 'Closed, no files selected' - dia_chooser.destroy() - #end def table_viewer.browse_clicked - - def prepare_data(self): - """prepares the data for display by refresh_clicked, returns a 2D array""" - #print "start of prepare_data" - arr=[] - #first prepare the header row - if (self.category=="holdem" or self.category=="omahahi" or self.category=="omahahilo"): - tmp=("Name", "HDs", "VPIP", "PFR", "PF3B", "ST") - - tmp+=("FS", "FB") - - tmp+=("CB", ) - - tmp+=("2B", "3B") - - tmp+=("AF", "FF", "AT", "FT", "AR", "FR") - - tmp+=("WtSD", "W$wsF", "W$SD") - else: - raise fpdb_simple.FpdbError("reimplement stud") - arr.append(tmp) - - #then the data rows - for player in range(len(self.player_names)): - tmp=[] - tmp.append(self.player_names[player][0]) - - seatCount=len(self.player_names) - if seatCount>=8: - minSeats,maxSeats=7,10 - elif seatCount==7: - minSeats,maxSeats=6,10 - elif seatCount==6 or seatCount==5: - minSeats,maxSeats=seatCount-1,seatCount+1 - elif seatCount==4: - minSeats,maxSeats=4,5 - elif seatCount==2 or seatCount==3: - minSeats,maxSeats=seatCount,seatCount - else: - fpdb_simple.FpdbError("invalid seatCount") - - self.cursor.execute("SELECT * FROM HudCache WHERE gametypeId=%s AND playerId=%s AND activeSeats>=%s AND activeSeats<=%s", (self.gametype_id, self.player_ids[player][0], minSeats, maxSeats)) - rows=self.cursor.fetchall() - - row=[] - for field_no in range(len(rows[0])): - row.append(rows[0][field_no]) - - for row_no in range(len(rows)): - if row_no==0: - pass - else: - for field_no in range(len(rows[row_no])): - if field_no<=3: - pass - else: - #print "in prep data, row_no:",row_no,"field_no:",field_no - row[field_no]+=rows[row_no][field_no] - - tmp.append(str(row[6]))#Hands - tmp.append(self.hudDivide(row[7],row[6])) #VPIP - tmp.append(self.hudDivide(row[8],row[6])) #PFR - tmp.append(self.hudDivide(row[10],row[9])+" ("+str(row[9])+")") #PF3B - - tmp.append(self.hudDivide(row[31],row[30])+" ("+str(row[30])+")") #ST - - tmp.append(self.hudDivide(row[35],row[34])+" ("+str(row[34])+")") #FS - tmp.append(self.hudDivide(row[33],row[32])+" ("+str(row[32])+")") #FB - - tmp.append(self.hudDivide(row[37],row[36])+" ("+str(row[36])+")") #CB - - tmp.append(self.hudDivide(row[39],row[38])+" ("+str(row[38])+")") #2B - tmp.append(self.hudDivide(row[41],row[40])+" ("+str(row[40])+")") #3B - - tmp.append(self.hudDivide(row[16],row[11])+" ("+str(row[11])+")") #AF - tmp.append(self.hudDivide(row[24],row[20])+" ("+str(row[20])+")") #FF - tmp.append(self.hudDivide(row[17],row[12])+" ("+str(row[12])+")") #AT - tmp.append(self.hudDivide(row[25],row[21])+" ("+str(row[21])+")") #FT - tmp.append(self.hudDivide(row[18],row[13])+" ("+str(row[13])+")") #AR - tmp.append(self.hudDivide(row[26],row[22])+" ("+str(row[22])+")") #FR - - tmp.append(self.hudDivide(row[15],row[11])) #WtSD - tmp.append(self.hudDivide(row[28],row[11])) #W$wSF - tmp.append(self.hudDivide(row[29],row[15])+" ("+str(row[15])+")") #W$@SD - - arr.append(tmp) - return arr - #end def table_viewer.prepare_data - - def refresh_clicked(self, widget, data): - """runs when user clicks refresh""" - #print "start of table_viewer.refresh_clicked" - arr=self.prepare_data() - - try: self.data_table.destroy() - except AttributeError: pass - self.data_table=gtk.Table(rows=len(arr), columns=len(arr[0]), homogeneous=False) - self.main_vbox.pack_start(self.data_table) - self.data_table.show() - - for row in range(len(arr)): - for column in range (len(arr[row])): - eventBox=gtk.EventBox() - new_label=gtk.Label(arr[row][column]) - if row%2==0: # - bg_col="white" - if column==0 or (column>=5 and column<=10): - bg_col="lightgrey" - else: - bg_col="lightgrey" - if column==0 or (column>=5 and column<=10): - bg_col="grey" - #style = eventBox.get_style() - #style.font.height=8 - #eventBox.set_style(style) - - eventBox.modify_bg(gtk.STATE_NORMAL, gtk.gdk.color_parse(bg_col)) - eventBox.add(new_label) - self.data_table.attach(child=eventBox, left_attach=column, right_attach=column+1, top_attach=row, bottom_attach=row+1) - eventBox.show() - new_label.show() - #end def table_viewer.refresh_clicked - - def read_names_clicked(self, widget, data): - """runs when user clicks read names""" - #print "start of table_viewer.read_names_clicked" - self.db.reconnect() - self.cursor=self.db.cursor - #self.hands_id=self.last_read_hand_id - - self.db.cursor.execute("SELECT gametypeId FROM Hands WHERE id=%s", (self.hands_id, )) - self.gametype_id=self.db.cursor.fetchone()[0] - self.cursor.execute("SELECT category FROM Gametypes WHERE id=%s", (self.gametype_id, )) - self.category=self.db.cursor.fetchone()[0] - #print "self.gametype_id", self.gametype_id," category:", self.category, " self.hands_id:", self.hands_id - - self.db.cursor.execute("""SELECT DISTINCT Players.id FROM HandsPlayers - INNER JOIN Players ON HandsPlayers.playerId=Players.id - WHERE handId=%s""", (self.hands_id, )) - self.player_ids=self.db.cursor.fetchall() - #print "self.player_ids:",self.player_ids - - self.db.cursor.execute("""SELECT DISTINCT Players.name FROM HandsPlayers - INNER JOIN Players ON HandsPlayers.playerId=Players.id - WHERE handId=%s""", (self.hands_id, )) - self.player_names=self.db.cursor.fetchall() - #print "self.player_names:",self.player_names - #end def table_viewer.read_names_clicked - - def import_clicked(self, widget, data): - """runs when user clicks import""" - #print "start of table_viewer.import_clicked" - self.inputFile=self.filename_tbuffer.get_text(self.filename_tbuffer.get_start_iter(), self.filename_tbuffer.get_end_iter()) - - self.server=self.db.host - self.database=self.db.database - self.user=self.db.user - self.password=self.db.password - - self.importer = fpdb_import.Importer(self, self.settings) - self.importer.setMinPrint(0) - self.importer.setQuiet(False) - self.importer.setFailOnError(False) - self.importer.setHandCount(0) - - self.importer.addImportFile(self.inputFile) - self.importer.runImport() - self.hands_id=self.importer.handsId - #end def table_viewer.import_clicked - - def all_clicked(self, widget, data): - """runs when user clicks all""" - #print "start of table_viewer.all_clicked" - self.import_clicked(widget, data) - self.read_names_clicked(widget, data) - self.refresh_clicked(widget, data) - #end def table_viewer.all_clicked - - def get_vbox(self): - """returns the vbox of this thread""" - return self.main_vbox - #end def get_vbox - - def __init__(self, db, settings, debug=True): - """Constructor for table_viewer""" - self.debug=debug - #print "start of table_viewer constructor" - self.db=db - self.cursor=db.cursor - self.settings=settings + def hudDivide (self, a, b): + if b==0: + return "n/a" + else: + return str(int((a/float(b))*100))+"%" + #end def hudDivide + + def browse_clicked(self, widget, data): + """runs when user clicks browse on tv tab""" + #print "start of table_viewer.browser_clicked" + current_path=self.filename_tbuffer.get_text(self.filename_tbuffer.get_start_iter(), self.filename_tbuffer.get_end_iter()) - self.main_vbox = gtk.VBox(False, 0) - self.main_vbox.show() - - self.settings_hbox = gtk.HBox(False, 0) - self.main_vbox.pack_end(self.settings_hbox, False, True, 0) - self.settings_hbox.show() - - self.filename_label = gtk.Label("Path of history file") - self.settings_hbox.pack_start(self.filename_label, False, False) - self.filename_label.show() - - self.filename_tbuffer=gtk.TextBuffer() - self.filename_tbuffer.set_text(self.settings['hud-defaultPath']) - self.filename_tview=gtk.TextView(self.filename_tbuffer) - self.settings_hbox.pack_start(self.filename_tview, True, True, padding=5) - self.filename_tview.show() - - self.browse_button=gtk.Button("Browse...") - self.browse_button.connect("clicked", self.browse_clicked, "Browse clicked") - self.settings_hbox.pack_start(self.browse_button, False, False) - self.browse_button.show() - - - self.button_hbox = gtk.HBox(False, 0) - self.main_vbox.pack_end(self.button_hbox, False, True, 0) - self.button_hbox.show() - - #self.import_button = gtk.Button("Import") - #self.import_button.connect("clicked", self.import_clicked, "Import clicked") - #self.button_hbox.add(self.import_button) - #self.import_button.show() + dia_chooser = gtk.FileChooserDialog(title="Please choose the file for which you want to open the Table Viewer", + action=gtk.FILE_CHOOSER_ACTION_OPEN, + buttons=(gtk.STOCK_CANCEL,gtk.RESPONSE_CANCEL,gtk.STOCK_OPEN,gtk.RESPONSE_OK)) + #dia_chooser.set_current_folder(pathname) + dia_chooser.set_filename(current_path) + #dia_chooser.set_select_multiple(select_multiple) #not in tv, but want this in bulk import - #self.read_names_button = gtk.Button("Read Names") - #self.read_names_button.connect("clicked", self.read_names_clicked, "Read clicked") - #self.button_hbox.add(self.read_names_button) - #self.read_names_button.show() - - #self.refresh_button = gtk.Button("Show/Refresh data") - #self.refresh_button.connect("clicked", self.refresh_clicked, "Refresh clicked") - #self.button_hbox.add(self.refresh_button) - #self.refresh_button.show() - - self.all_button = gtk.Button("Import&Read&Refresh") - self.all_button.connect("clicked", self.all_clicked, "All clicked") - self.button_hbox.add(self.all_button) - self.all_button.show() - #end of table_viewer.__init__ + response = dia_chooser.run() + if response == gtk.RESPONSE_OK: + #print dia_chooser.get_filename(), 'selected' + self.filename_tbuffer.set_text(dia_chooser.get_filename()) + elif response == gtk.RESPONSE_CANCEL: + print 'Closed, no files selected' + dia_chooser.destroy() + #end def table_viewer.browse_clicked + + def prepare_data(self): + """prepares the data for display by refresh_clicked, returns a 2D array""" + #print "start of prepare_data" + arr=[] + #first prepare the header row + if (self.category=="holdem" or self.category=="omahahi" or self.category=="omahahilo"): + tmp=("Name", "HDs", "VPIP", "PFR", "PF3B", "ST") + + tmp+=("FS", "FB") + + tmp+=("CB", ) + + tmp+=("2B", "3B") + + tmp+=("AF", "FF", "AT", "FT", "AR", "FR") + + tmp+=("WtSD", "W$wsF", "W$SD") + else: + raise fpdb_simple.FpdbError("reimplement stud") + arr.append(tmp) + + #then the data rows + for player in range(len(self.player_names)): + tmp=[] + tmp.append(self.player_names[player][0]) + + seatCount=len(self.player_names) + if seatCount>=8: + minSeats,maxSeats=7,10 + elif seatCount==7: + minSeats,maxSeats=6,10 + elif seatCount==6 or seatCount==5: + minSeats,maxSeats=seatCount-1,seatCount+1 + elif seatCount==4: + minSeats,maxSeats=4,5 + elif seatCount==2 or seatCount==3: + minSeats,maxSeats=seatCount,seatCount + else: + fpdb_simple.FpdbError("invalid seatCount") + + self.cursor.execute("SELECT * FROM HudCache WHERE gametypeId=%s AND playerId=%s AND activeSeats>=%s AND activeSeats<=%s", (self.gametype_id, self.player_ids[player][0], minSeats, maxSeats)) + rows=self.cursor.fetchall() + + row=[] + for field_no in range(len(rows[0])): + row.append(rows[0][field_no]) + + for row_no in range(len(rows)): + if row_no==0: + pass + else: + for field_no in range(len(rows[row_no])): + if field_no<=3: + pass + else: + #print "in prep data, row_no:",row_no,"field_no:",field_no + row[field_no]+=rows[row_no][field_no] + + tmp.append(str(row[6]))#Hands + tmp.append(self.hudDivide(row[7],row[6])) #VPIP + tmp.append(self.hudDivide(row[8],row[6])) #PFR + tmp.append(self.hudDivide(row[10],row[9])+" ("+str(row[9])+")") #PF3B + + tmp.append(self.hudDivide(row[31],row[30])+" ("+str(row[30])+")") #ST + + tmp.append(self.hudDivide(row[35],row[34])+" ("+str(row[34])+")") #FS + tmp.append(self.hudDivide(row[33],row[32])+" ("+str(row[32])+")") #FB + + tmp.append(self.hudDivide(row[37],row[36])+" ("+str(row[36])+")") #CB + + tmp.append(self.hudDivide(row[39],row[38])+" ("+str(row[38])+")") #2B + tmp.append(self.hudDivide(row[41],row[40])+" ("+str(row[40])+")") #3B + + tmp.append(self.hudDivide(row[16],row[11])+" ("+str(row[11])+")") #AF + tmp.append(self.hudDivide(row[24],row[20])+" ("+str(row[20])+")") #FF + tmp.append(self.hudDivide(row[17],row[12])+" ("+str(row[12])+")") #AT + tmp.append(self.hudDivide(row[25],row[21])+" ("+str(row[21])+")") #FT + tmp.append(self.hudDivide(row[18],row[13])+" ("+str(row[13])+")") #AR + tmp.append(self.hudDivide(row[26],row[22])+" ("+str(row[22])+")") #FR + + tmp.append(self.hudDivide(row[15],row[11])) #WtSD + tmp.append(self.hudDivide(row[28],row[11])) #W$wSF + tmp.append(self.hudDivide(row[29],row[15])+" ("+str(row[15])+")") #W$@SD + + arr.append(tmp) + return arr + #end def table_viewer.prepare_data + + def refresh_clicked(self, widget, data): + """runs when user clicks refresh""" + #print "start of table_viewer.refresh_clicked" + arr=self.prepare_data() + + try: self.data_table.destroy() + except AttributeError: pass + self.data_table=gtk.Table(rows=len(arr), columns=len(arr[0]), homogeneous=False) + self.main_vbox.pack_start(self.data_table) + self.data_table.show() + + for row in range(len(arr)): + for column in range (len(arr[row])): + eventBox=gtk.EventBox() + new_label=gtk.Label(arr[row][column]) + if row%2==0: # + bg_col="white" + if column==0 or (column>=5 and column<=10): + bg_col="lightgrey" + else: + bg_col="lightgrey" + if column==0 or (column>=5 and column<=10): + bg_col="grey" + #style = eventBox.get_style() + #style.font.height=8 + #eventBox.set_style(style) + + eventBox.modify_bg(gtk.STATE_NORMAL, gtk.gdk.color_parse(bg_col)) + eventBox.add(new_label) + self.data_table.attach(child=eventBox, left_attach=column, right_attach=column+1, top_attach=row, bottom_attach=row+1) + eventBox.show() + new_label.show() + #end def table_viewer.refresh_clicked + + def read_names_clicked(self, widget, data): + """runs when user clicks read names""" + #print "start of table_viewer.read_names_clicked" + self.db.reconnect() + self.cursor=self.db.get_cursor() + #self.hands_id=self.last_read_hand_id + + self.cursor.execute("SELECT gametypeId FROM Hands WHERE id=%s", (self.hands_id, )) + self.gametype_id=self.cursor.fetchone()[0] + self.cursor.execute("SELECT category FROM Gametypes WHERE id=%s", (self.gametype_id, )) + self.category=self.cursor.fetchone()[0] + #print "self.gametype_id", self.gametype_id," category:", self.category, " self.hands_id:", self.hands_id + + self.cursor.execute("""SELECT DISTINCT Players.id FROM HandsPlayers + INNER JOIN Players ON HandsPlayers.playerId=Players.id + WHERE handId=%s""", (self.hands_id, )) + self.player_ids=self.cursor.fetchall() + #print "self.player_ids:",self.player_ids + + self.cursor.execute("""SELECT DISTINCT Players.name FROM HandsPlayers + INNER JOIN Players ON HandsPlayers.playerId=Players.id + WHERE handId=%s""", (self.hands_id, )) + self.player_names=self.cursor.fetchall() + #print "self.player_names:",self.player_names + #end def table_viewer.read_names_clicked + + def import_clicked(self, widget, data): + """runs when user clicks import""" + #print "start of table_viewer.import_clicked" + self.inputFile=self.filename_tbuffer.get_text(self.filename_tbuffer.get_start_iter(), self.filename_tbuffer.get_end_iter()) + + self.importer = fpdb_import.Importer(self, self.settings, self.config) + self.importer.setMinPrint(0) + self.importer.setQuiet(False) + self.importer.setFailOnError(False) + self.importer.setHandCount(0) + + self.importer.addImportFile(self.inputFile) + self.importer.runImport() + self.hands_id=self.importer.handsId + #end def table_viewer.import_clicked + + def all_clicked(self, widget, data): + """runs when user clicks all""" + #print "start of table_viewer.all_clicked" + self.import_clicked(widget, data) + self.read_names_clicked(widget, data) + self.refresh_clicked(widget, data) + #end def table_viewer.all_clicked + + def get_vbox(self): + """returns the vbox of this thread""" + return self.main_vbox + #end def get_vbox + + def __init__(self, db, settings, config=None, debug=True): + """Constructor for table_viewer""" + self.debug=debug + #print "start of table_viewer constructor" + self.db = db + self.cursor = db.get_cursor() + self.settings = settings + self.config = config + + self.main_vbox = gtk.VBox(False, 0) + self.main_vbox.show() + + self.settings_hbox = gtk.HBox(False, 0) + self.main_vbox.pack_end(self.settings_hbox, False, True, 0) + self.settings_hbox.show() + + self.filename_label = gtk.Label("Path of history file") + self.settings_hbox.pack_start(self.filename_label, False, False) + self.filename_label.show() + + self.filename_tbuffer=gtk.TextBuffer() + self.filename_tbuffer.set_text(self.settings['hud-defaultPath']) + self.filename_tview=gtk.TextView(self.filename_tbuffer) + self.settings_hbox.pack_start(self.filename_tview, True, True, padding=5) + self.filename_tview.show() + + self.browse_button=gtk.Button("Browse...") + self.browse_button.connect("clicked", self.browse_clicked, "Browse clicked") + self.settings_hbox.pack_start(self.browse_button, False, False) + self.browse_button.show() + + + self.button_hbox = gtk.HBox(False, 0) + self.main_vbox.pack_end(self.button_hbox, False, True, 0) + self.button_hbox.show() + + #self.import_button = gtk.Button("Import") + #self.import_button.connect("clicked", self.import_clicked, "Import clicked") + #self.button_hbox.add(self.import_button) + #self.import_button.show() + + #self.read_names_button = gtk.Button("Read Names") + #self.read_names_button.connect("clicked", self.read_names_clicked, "Read clicked") + #self.button_hbox.add(self.read_names_button) + #self.read_names_button.show() + + #self.refresh_button = gtk.Button("Show/Refresh data") + #self.refresh_button.connect("clicked", self.refresh_clicked, "Refresh clicked") + #self.button_hbox.add(self.refresh_button) + #self.refresh_button.show() + + self.all_button = gtk.Button("Import&Read&Refresh") + self.all_button.connect("clicked", self.all_clicked, "All clicked") + self.button_hbox.add(self.all_button) + self.all_button.show() + #end of table_viewer.__init__ diff --git a/pyfpdb/HUD_config.xml.example b/pyfpdb/HUD_config.xml.example index 43cf4bcd..bd8cb7df 100644 --- a/pyfpdb/HUD_config.xml.example +++ b/pyfpdb/HUD_config.xml.example @@ -432,7 +432,8 @@ - + + diff --git a/pyfpdb/HUD_main.py b/pyfpdb/HUD_main.py index b240b64c..ac8332f3 100755 --- a/pyfpdb/HUD_main.py +++ b/pyfpdb/HUD_main.py @@ -37,7 +37,7 @@ import traceback if not options.errorsToConsole: print "Note: error output is being diverted to fpdb-error-log.txt and HUD-error.txt. Any major error will be reported there _only_." - errorFile = open('fpdb-error-log.txt', 'w', 0) + errorFile = open('HUD-error.txt', 'w', 0) sys.stderr = errorFile import thread diff --git a/pyfpdb/Hud.py b/pyfpdb/Hud.py index 04b67c7a..8a7aa740 100644 --- a/pyfpdb/Hud.py +++ b/pyfpdb/Hud.py @@ -60,6 +60,8 @@ class Hud: def __init__(self, parent, table, max, poker_game, config, db_connection): # __init__ is (now) intended to be called from the stdin thread, so it # cannot touch the gui + if parent == None: # running from cli .. + self.parent = self self.parent = parent self.table = table self.config = config @@ -125,7 +127,8 @@ class Hud: self.menu = gtk.Menu() self.item1 = gtk.MenuItem('Kill this HUD') self.menu.append(self.item1) - self.item1.connect("activate", self.parent.kill_hud, self.table_name) + if self.parent != None: + self.item1.connect("activate", self.parent.kill_hud, self.table_name) self.item1.show() self.item2 = gtk.MenuItem('Save Layout') @@ -233,7 +236,7 @@ class Hud: # Need range here, not xrange -> need the actual list adj = range(0, self.max + 1) # default seat adjustments = no adjustment # does the user have a fav_seat? - if int(config.supported_sites[self.table.site].layout[self.max].fav_seat) > 0: + if self.table.site != None and int(config.supported_sites[self.table.site].layout[self.max].fav_seat) > 0: try: fav_seat = config.supported_sites[self.table.site].layout[self.max].fav_seat actual_seat = self.get_actual_seat(config.supported_sites[self.table.site].screen_name) @@ -600,15 +603,17 @@ if __name__== "__main__": c = Configuration.Config() #tables = Tables.discover(c) - t = Tables.discover_table_by_name(c, "Motorway") + t = Tables.discover_table_by_name(c, "Patriot Dr") if t is None: print "Table not found." db = Database.Database(c, 'fpdb', 'holdem') + + stat_dict = db.get_stats_from_hand(1) # for t in tables: - win = Hud(t, 10, 'holdem', c, db) - win.create(1, c) + win = Hud(None, t, 10, 'holdem', c, db) # parent, table, max, poker_game, config, db_connection + win.create(1, c, stat_dict, None) # hand, config, stat_dict, cards): # t.get_details() - win.update(8300, db, c) + win.update(8300, c) # self, hand, config): gtk.main() diff --git a/pyfpdb/SQL.py b/pyfpdb/SQL.py index 972bf615..18eaad5c 100644 --- a/pyfpdb/SQL.py +++ b/pyfpdb/SQL.py @@ -410,16 +410,37 @@ class Sql: elif db_server == 'sqlite': self.query['createHandsTable'] = """CREATE TABLE Hands ( id INTEGER PRIMARY KEY, - tableName TEXT(20), - siteHandNo INTEGER, - gametypeId INTEGER, - handStart REAL, - importTime REAL, - seats INTEGER, - maxSeats INTEGER, + tableName TEXT(20) NOT NULL, + siteHandNo INT NOT NULL, + gametypeId INT NOT NULL, + handStart REAL NOT NULL, + importTime REAL NOT NULL, + seats INT NOT NULL, + maxSeats INT NOT NULL, + boardcard1 INT, /* 0=none, 1-13=2-Ah 14-26=2-Ad 27-39=2-Ac 40-52=2-As */ + boardcard2 INT, + boardcard3 INT, + boardcard4 INT, + boardcard5 INT, + texture INT, + playersVpi INT NOT NULL, /* num of players vpi */ + playersAtStreet1 INT NOT NULL, /* num of players seeing flop/street4 */ + playersAtStreet2 INT NOT NULL, + playersAtStreet3 INT NOT NULL, + playersAtStreet4 INT NOT NULL, + playersAtShowdown INT NOT NULL, + street0Raises INT NOT NULL, /* num small bets paid to see flop/street4, including blind */ + street1Raises INT NOT NULL, /* num small bets paid to see turn/street5 */ + street2Raises INT NOT NULL, /* num big bets paid to see river/street6 */ + street3Raises INT NOT NULL, /* num big bets paid to see sd/street7 */ + street4Raises INT NOT NULL, /* num big bets paid to see showdown */ + street1Pot INT, /* pot size at flop/street4 */ + street2Pot INT, /* pot size at turn/street5 */ + street3Pot INT, /* pot size at river/street6 */ + street4Pot INT, /* pot size at sd/street7 */ + showdownPot INT, /* pot size at sd/street7 */ comment TEXT, - commentTs REAL, - FOREIGN KEY(gametypeId) REFERENCES Gametypes(id) ON DELETE CASCADE)""" + commentTs REAL)""" ################################ @@ -919,78 +940,78 @@ class Sql: styleKey CHAR(7) NOT NULL, /* 1st char is style (A/T/H/S), other 6 are the key */ HDs INT NOT NULL, - wonWhenSeenStreet1 FLOAT NOT NULL, + wonWhenSeenStreet1 FLOAT, wonWhenSeenStreet2 FLOAT, wonWhenSeenStreet3 FLOAT, wonWhenSeenStreet4 FLOAT, - wonAtSD FLOAT NOT NULL, + wonAtSD FLOAT, - street0VPI INT NOT NULL, - street0Aggr INT NOT NULL, - street0_3BChance INT NOT NULL, - street0_3BDone INT NOT NULL, + street0VPI INT, + street0Aggr INT, + street0_3BChance INT, + street0_3BDone INT, street0_4BChance INT, street0_4BDone INT, other3BStreet0 INT, other4BStreet0 INT, - street1Seen INT NOT NULL, - street2Seen INT NOT NULL, - street3Seen INT NOT NULL, - street4Seen INT NOT NULL, - sawShowdown INT NOT NULL, + street1Seen INT, + street2Seen INT, + street3Seen INT, + street4Seen INT, + sawShowdown INT, - street1Aggr INT NOT NULL, - street2Aggr INT NOT NULL, - street3Aggr INT NOT NULL, - street4Aggr INT NOT NULL, + street1Aggr INT, + street2Aggr INT, + street3Aggr INT, + street4Aggr INT, otherRaisedStreet0 INT, - otherRaisedStreet1 INT NOT NULL, - otherRaisedStreet2 INT NOT NULL, - otherRaisedStreet3 INT NOT NULL, - otherRaisedStreet4 INT NOT NULL, + otherRaisedStreet1 INT, + otherRaisedStreet2 INT, + otherRaisedStreet3 INT, + otherRaisedStreet4 INT, foldToOtherRaisedStreet0 INT, - foldToOtherRaisedStreet1 INT NOT NULL, - foldToOtherRaisedStreet2 INT NOT NULL, - foldToOtherRaisedStreet3 INT NOT NULL, - foldToOtherRaisedStreet4 INT NOT NULL, + foldToOtherRaisedStreet1 INT, + foldToOtherRaisedStreet2 INT, + foldToOtherRaisedStreet3 INT, + foldToOtherRaisedStreet4 INT, - stealAttemptChance INT NOT NULL, - stealAttempted INT NOT NULL, - foldBbToStealChance INT NOT NULL, - foldedBbToSteal INT NOT NULL, - foldSbToStealChance INT NOT NULL, - foldedSbToSteal INT NOT NULL, + stealAttemptChance INT, + stealAttempted INT, + foldBbToStealChance INT, + foldedBbToSteal INT, + foldSbToStealChance INT, + foldedSbToSteal INT, - street1CBChance INT NOT NULL, - street1CBDone INT NOT NULL, - street2CBChance INT NOT NULL, - street2CBDone INT NOT NULL, - street3CBChance INT NOT NULL, - street3CBDone INT NOT NULL, - street4CBChance INT NOT NULL, - street4CBDone INT NOT NULL, + street1CBChance INT, + street1CBDone INT, + street2CBChance INT, + street2CBDone INT, + street3CBChance INT, + street3CBDone INT, + street4CBChance INT, + street4CBDone INT, - foldToStreet1CBChance INT NOT NULL, - foldToStreet1CBDone INT NOT NULL, - foldToStreet2CBChance INT NOT NULL, - foldToStreet2CBDone INT NOT NULL, - foldToStreet3CBChance INT NOT NULL, - foldToStreet3CBDone INT NOT NULL, - foldToStreet4CBChance INT NOT NULL, - foldToStreet4CBDone INT NOT NULL, + foldToStreet1CBChance INT, + foldToStreet1CBDone INT, + foldToStreet2CBChance INT, + foldToStreet2CBDone INT, + foldToStreet3CBChance INT, + foldToStreet3CBDone INT, + foldToStreet4CBChance INT, + foldToStreet4CBDone INT, - totalProfit INT NOT NULL, + totalProfit INT, - street1CheckCallRaiseChance INT NOT NULL, - street1CheckCallRaiseDone INT NOT NULL, - street2CheckCallRaiseChance INT NOT NULL, - street2CheckCallRaiseDone INT NOT NULL, - street3CheckCallRaiseChance INT NOT NULL, - street3CheckCallRaiseDone INT NOT NULL, - street4CheckCallRaiseChance INT NOT NULL, - street4CheckCallRaiseDone INT NOT NULL, + street1CheckCallRaiseChance INT, + street1CheckCallRaiseDone INT, + street2CheckCallRaiseChance INT, + street2CheckCallRaiseDone INT, + street3CheckCallRaiseChance INT, + street3CheckCallRaiseDone INT, + street4CheckCallRaiseChance INT, + street4CheckCallRaiseDone INT, street0Calls INT, street1Calls INT, @@ -1020,16 +1041,16 @@ class Sql: styleKey CHAR(7) NOT NULL, /* 1st char is style (A/T/H/S), other 6 are the key */ HDs INT, - wonWhenSeenStreet1 FLOAT NOT NULL, + wonWhenSeenStreet1 FLOAT, wonWhenSeenStreet2 FLOAT, wonWhenSeenStreet3 FLOAT, wonWhenSeenStreet4 FLOAT, - wonAtSD FLOAT NOT NULL, + wonAtSD FLOAT, - street0VPI INT NOT NULL, + street0VPI INT, street0Aggr INT, - street0_3BChance INT NOT NULL, - street0_3BDone INT NOT NULL, + street0_3BChance INT, + street0_3BDone INT, street0_4BChance INT, street0_4BDone INT, other3BStreet0 INT, @@ -1119,16 +1140,16 @@ class Sql: styleKey TEXT NOT NULL, /* 1st char is style (A/T/H/S), other 6 are the key */ HDs INT, - wonWhenSeenStreet1 REAL NOT NULL, + wonWhenSeenStreet1 REAL, wonWhenSeenStreet2 REAL, wonWhenSeenStreet3 REAL, wonWhenSeenStreet4 REAL, - wonAtSD REAL NOT NULL, + wonAtSD REAL, - street0VPI INT NOT NULL, + street0VPI INT, street0Aggr INT, - street0_3BChance INT NOT NULL, - street0_3BDone INT NOT NULL, + street0_3BChance INT, + street0_3BDone INT, street0_4BChance INT, street0_4BDone INT, other3BStreet0 INT, @@ -1646,6 +1667,11 @@ class Sql: select coalesce(max(id),0) from Hands where handStart < now() at time zone 'UTC' - interval '1 day'""" + elif db_server == 'sqlite': + self.query['get_hand_1day_ago'] = """ + select coalesce(max(id),0) + from Hands + where handStart < strftime('%J', 'now') - 1""" # not used yet ... # gets a date, would need to use handsplayers (not hudcache) to get exact hand Id @@ -2084,7 +2110,7 @@ class Sql: when stats.PlPosition = 1 then 'CO' when stats.PlPosition = 2 then 'MP' when stats.PlPosition = 5 then 'EP' - else '??' + else 'xx' end AS PlPosition ,stats.n ,stats.vpip @@ -2218,7 +2244,7 @@ class Sql: when stats.PlPosition = 1 then 'CO' when stats.PlPosition = 2 then 'MP' when stats.PlPosition = 5 then 'EP' - else '??' + else 'xx' end AS PlPosition ,stats.n ,stats.vpip @@ -2515,7 +2541,7 @@ class Sql: ,hp.tourneyTypeId ,date_format(h.handStart, 'd%y%m%d') """ - else: # assume postgres + elif db_server == 'postgresql': self.query['rebuildHudCache'] = """ INSERT INTO HudCache (gametypeId @@ -2663,6 +2689,154 @@ class Sql: ,hp.tourneyTypeId ,to_char(h.handStart, 'YYMMDD') """ + else: # assume sqlite + self.query['rebuildHudCache'] = """ + INSERT INTO HudCache + (gametypeId + ,playerId + ,activeSeats + ,position + ,tourneyTypeId + ,styleKey + ,HDs + ,wonWhenSeenStreet1 + ,wonAtSD + ,street0VPI + ,street0Aggr + ,street0_3BChance + ,street0_3BDone + ,street1Seen + ,street2Seen + ,street3Seen + ,street4Seen + ,sawShowdown + ,street1Aggr + ,street2Aggr + ,street3Aggr + ,street4Aggr + ,otherRaisedStreet1 + ,otherRaisedStreet2 + ,otherRaisedStreet3 + ,otherRaisedStreet4 + ,foldToOtherRaisedStreet1 + ,foldToOtherRaisedStreet2 + ,foldToOtherRaisedStreet3 + ,foldToOtherRaisedStreet4 + ,stealAttemptChance + ,stealAttempted + ,foldBbToStealChance + ,foldedBbToSteal + ,foldSbToStealChance + ,foldedSbToSteal + ,street1CBChance + ,street1CBDone + ,street2CBChance + ,street2CBDone + ,street3CBChance + ,street3CBDone + ,street4CBChance + ,street4CBDone + ,foldToStreet1CBChance + ,foldToStreet1CBDone + ,foldToStreet2CBChance + ,foldToStreet2CBDone + ,foldToStreet3CBChance + ,foldToStreet3CBDone + ,foldToStreet4CBChance + ,foldToStreet4CBDone + ,totalProfit + ,street1CheckCallRaiseChance + ,street1CheckCallRaiseDone + ,street2CheckCallRaiseChance + ,street2CheckCallRaiseDone + ,street3CheckCallRaiseChance + ,street3CheckCallRaiseDone + ,street4CheckCallRaiseChance + ,street4CheckCallRaiseDone + ) + SELECT h.gametypeId + ,hp.playerId + ,h.seats + ,case when hp.position = 'B' then 'B' + when hp.position = 'S' then 'S' + when hp.position = '0' then 'D' + when hp.position = '1' then 'C' + when hp.position = '2' then 'M' + when hp.position = '3' then 'M' + when hp.position = '4' then 'M' + when hp.position = '5' then 'E' + when hp.position = '6' then 'E' + when hp.position = '7' then 'E' + when hp.position = '8' then 'E' + when hp.position = '9' then 'E' + else 'E' + end AS hc_position + ,hp.tourneyTypeId + ,'d' || substr(strftime('%Y%m%d', h.handStart),3,7) + ,count(1) + ,sum(wonWhenSeenStreet1) + ,sum(wonAtSD) + ,sum(CAST(street0VPI as integer)) + ,sum(CAST(street0Aggr as integer)) + ,sum(CAST(street0_3BChance as integer)) + ,sum(CAST(street0_3BDone as integer)) + ,sum(CAST(street1Seen as integer)) + ,sum(CAST(street2Seen as integer)) + ,sum(CAST(street3Seen as integer)) + ,sum(CAST(street4Seen as integer)) + ,sum(CAST(sawShowdown as integer)) + ,sum(CAST(street1Aggr as integer)) + ,sum(CAST(street2Aggr as integer)) + ,sum(CAST(street3Aggr as integer)) + ,sum(CAST(street4Aggr as integer)) + ,sum(CAST(otherRaisedStreet1 as integer)) + ,sum(CAST(otherRaisedStreet2 as integer)) + ,sum(CAST(otherRaisedStreet3 as integer)) + ,sum(CAST(otherRaisedStreet4 as integer)) + ,sum(CAST(foldToOtherRaisedStreet1 as integer)) + ,sum(CAST(foldToOtherRaisedStreet2 as integer)) + ,sum(CAST(foldToOtherRaisedStreet3 as integer)) + ,sum(CAST(foldToOtherRaisedStreet4 as integer)) + ,sum(CAST(stealAttemptChance as integer)) + ,sum(CAST(stealAttempted as integer)) + ,sum(CAST(foldBbToStealChance as integer)) + ,sum(CAST(foldedBbToSteal as integer)) + ,sum(CAST(foldSbToStealChance as integer)) + ,sum(CAST(foldedSbToSteal as integer)) + ,sum(CAST(street1CBChance as integer)) + ,sum(CAST(street1CBDone as integer)) + ,sum(CAST(street2CBChance as integer)) + ,sum(CAST(street2CBDone as integer)) + ,sum(CAST(street3CBChance as integer)) + ,sum(CAST(street3CBDone as integer)) + ,sum(CAST(street4CBChance as integer)) + ,sum(CAST(street4CBDone as integer)) + ,sum(CAST(foldToStreet1CBChance as integer)) + ,sum(CAST(foldToStreet1CBDone as integer)) + ,sum(CAST(foldToStreet2CBChance as integer)) + ,sum(CAST(foldToStreet2CBDone as integer)) + ,sum(CAST(foldToStreet3CBChance as integer)) + ,sum(CAST(foldToStreet3CBDone as integer)) + ,sum(CAST(foldToStreet4CBChance as integer)) + ,sum(CAST(foldToStreet4CBDone as integer)) + ,sum(CAST(totalProfit as integer)) + ,sum(CAST(street1CheckCallRaiseChance as integer)) + ,sum(CAST(street1CheckCallRaiseDone as integer)) + ,sum(CAST(street2CheckCallRaiseChance as integer)) + ,sum(CAST(street2CheckCallRaiseDone as integer)) + ,sum(CAST(street3CheckCallRaiseChance as integer)) + ,sum(CAST(street3CheckCallRaiseDone as integer)) + ,sum(CAST(street4CheckCallRaiseChance as integer)) + ,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 + ,hc_position + ,hp.tourneyTypeId + ,'d' || substr(strftime('%Y%m%d', h.handStart),3,7) +""" if db_server == 'mysql': self.query['analyze'] = """ @@ -2681,6 +2855,44 @@ class Sql: else: # assume postgres self.query['lockForInsert'] = "" + self.query['getGametypeFL'] = """SELECT id + FROM Gametypes + WHERE siteId=%s + AND type=%s + AND category=%s + AND limitType=%s + AND smallBet=%s + AND bigBet=%s + """ + + self.query['getGametypeNL'] = """SELECT id + FROM Gametypes + WHERE siteId=%s + AND type=%s + AND category=%s + AND limitType=%s + AND smallBlind=%s + AND bigBlind=%s + """ + + self.query['insertGameTypes'] = """INSERT INTO Gametypes + (siteId, type, base, category, limitType + ,hiLo, smallBlind, bigBlind, smallBet, bigBet) + VALUES (%s, %s, %s, %s, %s, %s, %s, %s, %s, %s)""" + + self.query['isAlreadyInDB'] = """SELECT id FROM Hands + WHERE gametypeId=%s AND siteHandNo=%s + """ + + if db_server == 'mysql': + self.query['placeholder'] = u'%s' + elif db_server == 'postgresql': + self.query['placeholder'] = u'%s' + elif db_server == 'sqlite': + self.query['placeholder'] = u'?' + + + # If using sqlite, use the ? placeholder instead of %s if db_server == 'sqlite': for k,q in self.query.iteritems(): self.query[k] = re.sub('%s','?',q) diff --git a/pyfpdb/Tables.py b/pyfpdb/Tables.py index d4b879b2..97a897ca 100755 --- a/pyfpdb/Tables.py +++ b/pyfpdb/Tables.py @@ -234,7 +234,7 @@ def discover_nt_by_name(c, tablename): #print "Tables.py: tablename =", tablename, "title =", titles[hwnd] try: # this can blow up in XP on some windows, eg firefox displaying http://docs.python.org/tutorial/classes.html - if not tablename in titles[hwnd]: continue + if not tablename.lower() in titles[hwnd].lower(): continue except: continue if 'History for table:' in titles[hwnd]: continue # Everleaf Network HH viewer window @@ -302,7 +302,9 @@ def decode_windows(c, title, hwnd): return info def win_enum_handler(hwnd, titles): - titles[hwnd] = win32gui.GetWindowText(hwnd) + str = win32gui.GetWindowText(hwnd) + if str != "": + titles[hwnd] = win32gui.GetWindowText(hwnd) ################################################################### # Utility routines used by all the discoverers. diff --git a/pyfpdb/fpdb.py b/pyfpdb/fpdb.py index 37907397..23bb4495 100755 --- a/pyfpdb/fpdb.py +++ b/pyfpdb/fpdb.py @@ -531,7 +531,7 @@ This program is licensed under the AGPL3, see docs"""+os.sep+"agpl-3.0.txt") def tab_table_viewer(self, widget, data=None): """opens a table viewer tab""" #print "start of tab_table_viewer" - new_tv_thread=GuiTableViewer.GuiTableViewer(self.db.fdb, self.settings) + new_tv_thread = GuiTableViewer.GuiTableViewer(self.db, self.settings, self.config) self.threads.append(new_tv_thread) tv_tab=new_tv_thread.get_vbox() self.add_and_display_tab(tv_tab, "Table Viewer") diff --git a/pyfpdb/fpdb_db.py b/pyfpdb/fpdb_db.py index f0e0de12..edd12b3b 100644 --- a/pyfpdb/fpdb_db.py +++ b/pyfpdb/fpdb_db.py @@ -64,7 +64,7 @@ class fpdb_db: if backend==fpdb_db.MYSQL_INNODB: import MySQLdb try: - self.db = MySQLdb.connect(host = host, user = user, passwd = password, db = database, use_unicode=True, charset="utf8") + self.db = MySQLdb.connect(host = host, user = user, passwd = password, db = database, use_unicode=True) except: raise fpdb_simple.FpdbError("MySQL connection failed") elif backend==fpdb_db.PGSQL: @@ -155,105 +155,4 @@ class fpdb_db: return (self.host, self.database, self.user, self.password) #end def get_db_info - def getLastInsertId(self, cursor=None): - try: - if self.backend == self.MYSQL_INNODB: - ret = self.db.insert_id() - if ret < 1 or ret > 999999999: - print "getLastInsertId(): problem fetching insert_id? ret=", ret - ret = -1 - elif self.backend == self.PGSQL: - # some options: - # currval(hands_id_seq) - use name of implicit seq here - # lastval() - still needs sequences set up? - # insert ... returning is useful syntax (but postgres specific?) - # see rules (fancy trigger type things) - c = self.db.cursor() - ret = c.execute ("SELECT lastval()") - row = c.fetchone() - if not row: - print "getLastInsertId(%s): problem fetching lastval? row=" % seq, row - ret = -1 - else: - ret = row[0] - elif self.backend == fpdb_db.SQLITE: - ret = cursor.lastrowid - else: - print "getLastInsertId(): unknown backend ", self.backend - ret = -1 - except: - ret = -1 - print "getLastInsertId error:", str(sys.exc_value), " ret =", ret - raise fpdb_simple.FpdbError( "getLastInsertId error: " + str(sys.exc_value) ) - - return ret - - def storeHand(self, p): - #stores into table hands: - self.cursor.execute ("""INSERT INTO Hands ( - tablename, - sitehandno, - gametypeid, - handstart, - importtime, - seats, - maxseats, - boardcard1, - boardcard2, - boardcard3, - boardcard4, - boardcard5, --- texture, - playersVpi, - playersAtStreet1, - playersAtStreet2, - playersAtStreet3, - playersAtStreet4, - playersAtShowdown, - street0Raises, - street1Raises, - street2Raises, - street3Raises, - street4Raises, --- street1Pot, --- street2Pot, --- street3Pot, --- street4Pot, --- showdownPot - ) - VALUES - (%s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, - %s, %s, %s, %s, %s, %s, %s)""", - ( - p['tablename'], - p['sitehandno'], - p['gametypeid'], - p['handStart'], - datetime.datetime.today(), - len(p['names']), - p['maxSeats'], - p['boardcard1'], - p['boardcard2'], - p['boardcard3'], - p['boardcard4'], - p['boardcard5'], - hudCache['playersVpi'], - hudCache['playersAtStreet1'], - hudCache['playersAtStreet2'], - hudCache['playersAtStreet3'], - hudCache['playersAtStreet4'], - hudCache['playersAtShowdown'], - hudCache['street0Raises'], - hudCache['street1Raises'], - hudCache['street2Raises'], - hudCache['street3Raises'], - hudCache['street4Raises'], - hudCache['street1Pot'], - hudCache['street2Pot'], - hudCache['street3Pot'], - hudCache['street4Pot'], - hudCache['showdownPot'] - ) - ) - #return getLastInsertId(backend, conn, cursor) #end class fpdb_db diff --git a/pyfpdb/fpdb_import.py b/pyfpdb/fpdb_import.py index 159de588..6b4994b6 100644 --- a/pyfpdb/fpdb_import.py +++ b/pyfpdb/fpdb_import.py @@ -85,6 +85,8 @@ class Importer: #self.settings.setdefault("forceThreads", 2) # NOT USED NOW self.settings.setdefault("writeQSize", 1000) # no need to change self.settings.setdefault("writeQMaxWait", 10) # not used + self.settings.setdefault("dropIndexes", "don't drop") + self.settings.setdefault("dropHudCache", "don't drop") self.writeq = None self.database = Database.Database(self.config, sql = self.sql) @@ -380,7 +382,7 @@ class Importer: # Load filter, process file, pass returned filename to import_fpdb_file - if self.writeq != None: + if self.settings['threads'] > 0 and self.writeq != None: print "\nConverting " + file + " (" + str(q.qsize()) + ")" else: print "\nConverting " + file diff --git a/pyfpdb/fpdb_parse_logic.py b/pyfpdb/fpdb_parse_logic.py index 0314b83e..696f42d2 100644 --- a/pyfpdb/fpdb_parse_logic.py +++ b/pyfpdb/fpdb_parse_logic.py @@ -79,7 +79,7 @@ def mainParser(settings, siteID, category, hand, config, db = None, writeq = Non rebuyOrAddon = -1 tourneyTypeId = 1 - fpdb_simple.isAlreadyInDB(db.get_cursor(), gametypeID, siteHandNo) + fpdb_simple.isAlreadyInDB(db, gametypeID, siteHandNo) hand = fpdb_simple.filterCrap(hand, isTourney) @@ -93,7 +93,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.get_cursor(), names, siteID) # inserts players as needed + playerIDs = fpdb_simple.recognisePlayerIDs(db, names, siteID) # inserts players as needed tmp = fpdb_simple.parseCashesAndSeatNos(seatLines) startCashes = tmp['startCashes'] seatNos = tmp['seatNos'] @@ -141,7 +141,7 @@ def mainParser(settings, siteID, category, hand, config, db = None, writeq = Non fpdb_simple.checkPositions(positions) c = db.get_cursor() - c.execute("SELECT limitType FROM Gametypes WHERE id=%s",(gametypeID, )) + c.execute("SELECT limitType FROM Gametypes WHERE id=%s" % (db.sql.query['placeholder'],), (gametypeID, )) limit_type = c.fetchone()[0] fpdb_simple.convert3B4B(category, limit_type, actionTypes, actionAmounts) diff --git a/pyfpdb/fpdb_simple.py b/pyfpdb/fpdb_simple.py index d91becb8..3f75d8d3 100644 --- a/pyfpdb/fpdb_simple.py +++ b/pyfpdb/fpdb_simple.py @@ -400,10 +400,11 @@ def isActionLine(line): #end def isActionLine #returns whether this is a duplicate -def isAlreadyInDB(cursor, gametypeID, siteHandNo): +def isAlreadyInDB(db, gametypeID, siteHandNo): #print "isAlreadyInDB gtid,shand:",gametypeID, siteHandNo - cursor.execute ("SELECT id FROM Hands WHERE gametypeId=%s AND siteHandNo=%s", (gametypeID, siteHandNo)) - result=cursor.fetchall() + c = db.get_cursor() + c.execute( db.sql.query['isAlreadyInDB'], (gametypeID, siteHandNo)) + result = c.fetchall() if (len(result)>=1): raise DuplicateError ("dupl") #end isAlreadyInDB @@ -898,9 +899,11 @@ def recogniseGametypeID(backend, db, cursor, topline, smallBlindLine, site_id, c #print "recogniseGametypeID small_bet/blind:",small_bet,"big bet/blind:", big_bet,"limit type:",limit_type if (limit_type=="fl"): - cursor.execute ("SELECT id FROM Gametypes WHERE siteId=%s AND type=%s AND category=%s AND limitType=%s AND smallBet=%s AND bigBet=%s", (site_id, type, category, limit_type, small_bet, big_bet)) + cursor.execute ( db.sql.query['getGametypeFL'] + , (site_id, type, category, limit_type, small_bet, big_bet)) else: - cursor.execute ("SELECT id FROM Gametypes WHERE siteId=%s AND type=%s AND category=%s AND limitType=%s AND smallBlind=%s AND bigBlind=%s", (site_id, type, category, limit_type, small_bet, big_bet)) + cursor.execute ( db.sql.query['getGametypeNL'] + , (site_id, type, category, limit_type, small_bet, big_bet)) result=cursor.fetchone() #print "recgt1 result=",result #ret=result[0] @@ -935,25 +938,16 @@ def recogniseGametypeID(backend, db, cursor, topline, smallBlindLine, site_id, c small_blind=float2int(smallBlindLine[pos:]) else: small_blind=0 - cursor.execute( """INSERT INTO Gametypes(siteId, type, base, category, limitType - ,hiLo, smallBlind, bigBlind, smallBet, bigBet) - VALUES (%s, %s, %s, %s, %s, %s, %s, %s, %s, %s)""" - , (site_id, type, base, category, limit_type, hiLo - ,small_blind, big_blind, small_bet, big_bet) ) + result = db.insertGameTypes( (site_id, type, base, category, limit_type, hiLo + ,small_blind, big_blind, small_bet, big_bet) ) #cursor.execute ("SELECT id FROM Gametypes WHERE siteId=%s AND type=%s AND category=%s #AND limitType=%s AND smallBet=%s AND bigBet=%s", (site_id, type, category, limit_type, small_bet, big_bet)) else: - cursor.execute( """INSERT INTO Gametypes(siteId, type, base, category, limitType - ,hiLo, smallBlind, bigBlind, smallBet, bigBet) - VALUES (%s, %s, %s, %s, %s, %s, %s, %s, %s, %s)""" - , (site_id, type, base, category, limit_type - ,hiLo, small_bet, big_bet, 0, 0))#remember, for these bet means blind + result = db.insertGameTypes( (site_id, type, base, category, limit_type, hiLo + ,small_bet, big_bet, 0, 0) )#remember, for these bet means blind #cursor.execute ("SELECT id FROM Gametypes WHERE siteId=%s AND type=%s AND category=%s #AND limitType=%s AND smallBlind=%s AND bigBlind=%s", (site_id, type, category, limit_type, small_bet, big_bet)) - #result=(db.insert_id(),) - result=(db.get_last_insert_id(),) - return result[0] #end def recogniseGametypeID @@ -990,17 +984,21 @@ def recogniseTourneyTypeId(cursor, siteId, buyin, fee, knockout, rebuyOrAddon): # result.append(tmp[0][0]) # return result -def recognisePlayerIDs(cursor, names, site_id): - q = "SELECT name,id FROM Players WHERE name=%s" % " OR name=".join(["%s" for n in names]) - cursor.execute(q, names) # get all playerids by the names passed in - ids = dict(cursor.fetchall()) # convert to dict +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 - cursor.executemany("INSERT INTO Players (name, siteId) VALUES (%s, "+str(site_id)+")", [(n,) for n in notfound]) - q2 = "SELECT name,id FROM Players WHERE name=%s" % " OR name=".join(["%s" for n in notfound]) - cursor.execute(q2, notfound) # get their new ids - tmp = cursor.fetchall() + 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