From 28576d70f83770d72fca78db6e30e424b013aff2 Mon Sep 17 00:00:00 2001 From: Eric Blade Date: Thu, 5 Aug 2010 04:07:37 -0400 Subject: [PATCH 01/36] switch "0.00%" on ffreq1 to NA, need to update all the other percents with that sometime too --- pyfpdb/Stats.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/pyfpdb/Stats.py b/pyfpdb/Stats.py index 74558da8..5faa1f59 100755 --- a/pyfpdb/Stats.py +++ b/pyfpdb/Stats.py @@ -711,10 +711,10 @@ def ffreq1(stat_dict, player): ) except: return (stat, - '%3.1f' % (0) + '%', - 'ff1=%3.1f' % (0) + '%', - 'ff_1=%3.1f' % (0) + '%', - '(%d/%d)' % (0, 0), + 'NA', + 'ff1=NA', + 'ff_1=NA', + '(0/0)', '% fold frequency flop/4th' ) From e49beb772400d7dc8dd714320d9421531af5cace Mon Sep 17 00:00:00 2001 From: Eric Blade Date: Thu, 5 Aug 2010 12:12:18 -0400 Subject: [PATCH 02/36] Hand: extreme terminal spam when something bad happens in readBlinds, stop crashing import HHC: set obs when failing to open a file (ie, you've stored a zip file in your handhistory folder), stop crashing import --- pyfpdb/Hand.py | 8 +++++++- pyfpdb/HandHistoryConverter.py | 1 + 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/pyfpdb/Hand.py b/pyfpdb/Hand.py index ee6d0bf2..ef5cdae4 100644 --- a/pyfpdb/Hand.py +++ b/pyfpdb/Hand.py @@ -683,9 +683,15 @@ class HoldemOmahaHand(Hand): hhc.readPlayerStacks(self) hhc.compilePlayerRegexs(self) hhc.markStreets(self) + if self.cancelled: return - hhc.readBlinds(self) + + try: hhc.readBlinds(self) + except: + print "*** Parse error reading blinds (check compilePlayerRegexs as a likely culprit)", self + return + hhc.readAntes(self) hhc.readButton(self) hhc.readHeroCards(self) diff --git a/pyfpdb/HandHistoryConverter.py b/pyfpdb/HandHistoryConverter.py index 8faf5dfb..a6f19aaa 100644 --- a/pyfpdb/HandHistoryConverter.py +++ b/pyfpdb/HandHistoryConverter.py @@ -441,6 +441,7 @@ or None if we fail to get the info """ pass else: print "unable to read file with any codec in list!", self.in_path + self.obs = None elif self.filetype == "xml": doc = xml.dom.minidom.parse(filename) self.doc = doc From 16cd5e750511e7ce9c485c0b1e88eda659c3f66f Mon Sep 17 00:00:00 2001 From: Eric Blade Date: Thu, 5 Aug 2010 12:31:37 -0400 Subject: [PATCH 03/36] update Everleaf config example, add bbper100/BBper100 stats to popup default, fix my last tweak to hhc --- pyfpdb/HUD_config.xml.example | 87 +++++++++++++++++----------------- pyfpdb/HandHistoryConverter.py | 2 +- 2 files changed, 44 insertions(+), 45 deletions(-) diff --git a/pyfpdb/HUD_config.xml.example b/pyfpdb/HUD_config.xml.example index e25a1ab7..016b0a4d 100644 --- a/pyfpdb/HUD_config.xml.example +++ b/pyfpdb/HUD_config.xml.example @@ -252,49 +252,46 @@ Left-Drag to Move" - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - + + + diff --git a/pyfpdb/HandHistoryConverter.py b/pyfpdb/HandHistoryConverter.py index a6f19aaa..37ba831f 100644 --- a/pyfpdb/HandHistoryConverter.py +++ b/pyfpdb/HandHistoryConverter.py @@ -441,7 +441,7 @@ or None if we fail to get the info """ pass else: print "unable to read file with any codec in list!", self.in_path - self.obs = None + self.obs = "" elif self.filetype == "xml": doc = xml.dom.minidom.parse(filename) self.doc = doc From 2d8f9dcc78d8d271304293813e58e4791dbef18c Mon Sep 17 00:00:00 2001 From: gimick Date: Sun, 8 Aug 2010 22:48:08 +0100 Subject: [PATCH 04/36] GRAPH: Put legend in "best" position, not fixed in top left. --- pyfpdb/GuiGraphViewer.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pyfpdb/GuiGraphViewer.py b/pyfpdb/GuiGraphViewer.py index 96026864..e1a719ba 100644 --- a/pyfpdb/GuiGraphViewer.py +++ b/pyfpdb/GuiGraphViewer.py @@ -232,7 +232,7 @@ class GuiGraphViewer (threading.Thread): if sys.version[0:3] == '2.5': self.ax.legend(loc='upper left', shadow=True, prop=FontProperties(size='smaller')) else: - self.ax.legend(loc='upper left', fancybox=True, shadow=True, prop=FontProperties(size='smaller')) + self.ax.legend(loc='best', fancybox=True, shadow=True, prop=FontProperties(size='smaller')) self.graphBox.add(self.canvas) self.canvas.show() From c5bd036b6ed0e5e6ced1c9f4585590d6f0f5b712 Mon Sep 17 00:00:00 2001 From: steffen123 Date: Mon, 9 Aug 2010 23:22:58 +0200 Subject: [PATCH 05/36] add tourney viewer that displays info from TT and T, but not yet TP --- pyfpdb/Database.py | 14 +++++++ pyfpdb/GuiTourneyViewer.py | 86 ++++++++++++++++++++++++++++++++++++++ pyfpdb/SQL.py | 7 ++++ pyfpdb/fpdb.pyw | 9 ++++ 4 files changed, 116 insertions(+) create mode 100644 pyfpdb/GuiTourneyViewer.py diff --git a/pyfpdb/Database.py b/pyfpdb/Database.py index 7672d33c..90a464ba 100644 --- a/pyfpdb/Database.py +++ b/pyfpdb/Database.py @@ -2115,6 +2115,20 @@ class Database: result = c.fetchall() return result #end def getTourneyTypesIds + + def getTourneyInfo(self, siteName, tourneyNo): + c = self.get_cursor() + c.execute(self.sql.query['getTourneyInfo'], (siteName, tourneyNo)) + columnNames=c.description + #print "columnNames:",columnNames + + names=[] + for column in columnNames: + names.append(column[0]) + + data=c.fetchone() + return (names,data) + #end def getTourneyInfo #end class Database # Class used to hold all the data needed to write a hand to the db diff --git a/pyfpdb/GuiTourneyViewer.py b/pyfpdb/GuiTourneyViewer.py new file mode 100644 index 00000000..ab0bb38d --- /dev/null +++ b/pyfpdb/GuiTourneyViewer.py @@ -0,0 +1,86 @@ +#!/usr/bin/python +# -*- coding: utf-8 -*- + +#Copyright 2010 Steffen Schaumburg +#This program is free software: you can redistribute it and/or modify +#it under the terms of the GNU Affero General Public License as published by +#the Free Software Foundation, version 3 of the License. +# +#This program is distributed in the hope that it will be useful, +#but WITHOUT ANY WARRANTY; without even the implied warranty of +#MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +#GNU General Public License for more details. +# +#You should have received a copy of the GNU Affero General Public License +#along with this program. If not, see . +#In the "official" distribution you can find the license in agpl-3.0.txt. + +import threading +import pygtk +pygtk.require('2.0') +import gtk + +class GuiTourneyViewer (threading.Thread): + def __init__(self, config, db, sql, mainwin, debug=True): + self.db = db + + self.mainVBox = gtk.VBox() + self.interfaceHBox = gtk.HBox() + self.mainVBox.pack_start(self.interfaceHBox, expand=False) + + self.siteBox = gtk.combo_box_new_text() + for site in config.supported_sites: + self.siteBox.append_text(site) + self.siteBox.set_active(0) + self.interfaceHBox.add(self.siteBox) + + label=gtk.Label("Enter the tourney number you want to display:") + self.interfaceHBox.add(label) + + self.entryBox = gtk.Entry() + self.interfaceHBox.add(self.entryBox) + + self.button = gtk.Button("_Display") + self.button.connect('clicked', self.displayClicked) + self.interfaceHBox.add(self.button) + + self.table = gtk.Table(columns=10, rows=9) + self.mainVBox.add(self.table) + + self.mainVBox.show_all() + #end def __init__ + + def displayClicked(self, widget, data=None): + tourneyNo=int(self.entryBox.get_text()) + siteName=self.siteBox.get_active_text() + + self.table.destroy() + self.table=gtk.Table(columns=10, rows=9) + self.mainVBox.add(self.table) + + result=self.db.getTourneyInfo(siteName, tourneyNo) + x=0 + y=0 + for i in range(1,len(result[0])): + if y==9: + x+=2 + y=0 + + label=gtk.Label(result[0][i]) + self.table.attach(label,x,x+1,y,y+1) + + if result[1][i]==None: + label=gtk.Label("N/A") + else: + label=gtk.Label(result[1][i]) + self.table.attach(label,x+1,x+2,y,y+1) + + y+=1 + self.mainVBox.show_all() + #def displayClicked + + def get_vbox(self): + """returns the vbox of this thread""" + return self.mainVBox + #end def get_vbox +#end class GuiTourneyViewer diff --git a/pyfpdb/SQL.py b/pyfpdb/SQL.py index 9b43241b..216d91cc 100644 --- a/pyfpdb/SQL.py +++ b/pyfpdb/SQL.py @@ -3812,6 +3812,13 @@ class Sql: WHERE tt.siteId=%s AND t.siteTourneyNo=%s """ + self.query['getTourneyInfo'] = """SELECT tt.*, t.* + FROM Tourneys t + INNER JOIN TourneyTypes tt ON (t.tourneyTypeId = tt.id) + INNER JOIN Sites s ON (tt.siteId = s.id) + WHERE s.name=%s AND t.siteTourneyNo=%s + """ + self.query['insertTourney'] = """INSERT INTO Tourneys (tourneyTypeId, siteTourneyNo, entries, prizepool, startTime, endTime, tourneyName, matrixIdProcessed, diff --git a/pyfpdb/fpdb.pyw b/pyfpdb/fpdb.pyw index 70986c3e..75faebf2 100755 --- a/pyfpdb/fpdb.pyw +++ b/pyfpdb/fpdb.pyw @@ -106,6 +106,7 @@ import GuiBulkImport import ImapFetcher import GuiRingPlayerStats import GuiTourneyPlayerStats +import GuiTourneyViewer import GuiPositionalStats import GuiAutoImport import GuiGraphViewer @@ -794,6 +795,7 @@ class fpdb: + @@ -833,6 +835,7 @@ class fpdb: ('graphs', None, '_Graphs', 'G', 'Graphs', self.tabGraphViewer), ('ringplayerstats', None, 'Ring _Player Stats (tabulated view)', 'P', 'Ring Player Stats (tabulated view)', self.tab_ring_player_stats), ('tourneyplayerstats', None, '_Tourney Player Stats (tabulated view, mysql only)', 'T', 'Tourney Player Stats (tabulated view, mysql only)', self.tab_tourney_player_stats), + ('tourneyviewer', None, 'Tourney _Viewer', None, 'Tourney Viewer)', self.tab_tourney_viewer_stats), ('posnstats', None, 'P_ositional Stats (tabulated view)', 'O', 'Positional Stats (tabulated view)', self.tab_positional_stats), ('sessionstats', None, 'Session Stats', None, 'Session Stats', self.tab_session_stats), ('database', None, '_Database'), @@ -1033,6 +1036,12 @@ class fpdb: ps_tab=new_ps_thread.get_vbox() self.add_and_display_tab(ps_tab, "Tourney Player Stats") + def tab_tourney_viewer_stats(self, widget, data=None): + new_thread = GuiTourneyViewer.GuiTourneyViewer(self.config, self.db, self.sql, self.window) + self.threads.append(new_thread) + tab=new_thread.get_vbox() + self.add_and_display_tab(tab, "Tourney Viewer") + def tab_positional_stats(self, widget, data=None): new_ps_thread = GuiPositionalStats.GuiPositionalStats(self.config, self.sql) self.threads.append(new_ps_thread) From bb743b45677e74c60a70f7a49c86766278ba69e8 Mon Sep 17 00:00:00 2001 From: steffen123 Date: Mon, 9 Aug 2010 23:41:48 +0200 Subject: [PATCH 06/36] add button to display info from TP to tourneyviewer --- pyfpdb/Database.py | 14 ++++++++++- pyfpdb/GuiTourneyViewer.py | 51 ++++++++++++++++++++++++++++++++------ pyfpdb/SQL.py | 9 +++++++ 3 files changed, 66 insertions(+), 8 deletions(-) diff --git a/pyfpdb/Database.py b/pyfpdb/Database.py index 90a464ba..6b902921 100644 --- a/pyfpdb/Database.py +++ b/pyfpdb/Database.py @@ -2120,7 +2120,6 @@ class Database: c = self.get_cursor() c.execute(self.sql.query['getTourneyInfo'], (siteName, tourneyNo)) columnNames=c.description - #print "columnNames:",columnNames names=[] for column in columnNames: @@ -2129,6 +2128,19 @@ class Database: data=c.fetchone() return (names,data) #end def getTourneyInfo + + def getTourneyPlayerInfo(self, siteName, tourneyNo, playerName): + c = self.get_cursor() + c.execute(self.sql.query['getTourneyPlayerInfo'], (siteName, tourneyNo, playerName)) + columnNames=c.description + + names=[] + for column in columnNames: + names.append(column[0]) + + data=c.fetchone() + return (names,data) + #end def getTourneyPlayerInfo #end class Database # Class used to hold all the data needed to write a hand to the db diff --git a/pyfpdb/GuiTourneyViewer.py b/pyfpdb/GuiTourneyViewer.py index ab0bb38d..1499e8a6 100644 --- a/pyfpdb/GuiTourneyViewer.py +++ b/pyfpdb/GuiTourneyViewer.py @@ -37,21 +37,28 @@ class GuiTourneyViewer (threading.Thread): label=gtk.Label("Enter the tourney number you want to display:") self.interfaceHBox.add(label) - self.entryBox = gtk.Entry() - self.interfaceHBox.add(self.entryBox) + self.entryTourney = gtk.Entry() + self.interfaceHBox.add(self.entryTourney) - self.button = gtk.Button("_Display") - self.button.connect('clicked', self.displayClicked) - self.interfaceHBox.add(self.button) + self.displayButton = gtk.Button("_Display") + self.displayButton.connect('clicked', self.displayClicked) + self.interfaceHBox.add(self.displayButton) + + self.entryPlayer = gtk.Entry() + self.interfaceHBox.add(self.entryPlayer) + + self.playerButton = gtk.Button("Display _Player") + self.playerButton.connect('clicked', self.displayPlayerClicked) + self.interfaceHBox.add(self.playerButton) self.table = gtk.Table(columns=10, rows=9) self.mainVBox.add(self.table) - + self.mainVBox.show_all() #end def __init__ def displayClicked(self, widget, data=None): - tourneyNo=int(self.entryBox.get_text()) + tourneyNo=int(self.entryTourney.get_text()) siteName=self.siteBox.get_active_text() self.table.destroy() @@ -79,6 +86,36 @@ class GuiTourneyViewer (threading.Thread): self.mainVBox.show_all() #def displayClicked + def displayPlayerClicked(self, widget, data=None): + tourneyNo=int(self.entryTourney.get_text()) + siteName=self.siteBox.get_active_text() + playerName=self.entryPlayer.get_text() + + self.table.destroy() + self.table=gtk.Table(columns=4, rows=5) + self.mainVBox.add(self.table) + + result=self.db.getTourneyPlayerInfo(siteName, tourneyNo, playerName) + x=0 + y=0 + for i in range(1,len(result[0])): + if y==5: + x+=2 + y=0 + + label=gtk.Label(result[0][i]) + self.table.attach(label,x,x+1,y,y+1) + + if result[1][i]==None: + label=gtk.Label("N/A") + else: + label=gtk.Label(result[1][i]) + self.table.attach(label,x+1,x+2,y,y+1) + + y+=1 + self.mainVBox.show_all() + #def displayPlayerClicked + def get_vbox(self): """returns the vbox of this thread""" return self.mainVBox diff --git a/pyfpdb/SQL.py b/pyfpdb/SQL.py index 216d91cc..69d74fbe 100644 --- a/pyfpdb/SQL.py +++ b/pyfpdb/SQL.py @@ -3819,6 +3819,15 @@ class Sql: WHERE s.name=%s AND t.siteTourneyNo=%s """ + self.query['getTourneyPlayerInfo'] = """SELECT tp.* + FROM Tourneys t + INNER JOIN TourneyTypes tt ON (t.tourneyTypeId = tt.id) + INNER JOIN Sites s ON (tt.siteId = s.id) + INNER JOIN TourneysPlayers tp ON (tp.tourneyId = t.id) + INNER JOIN Players p ON (p.id = tp.playerId) + WHERE s.name=%s AND t.siteTourneyNo=%s AND p.name=%s + """ + self.query['insertTourney'] = """INSERT INTO Tourneys (tourneyTypeId, siteTourneyNo, entries, prizepool, startTime, endTime, tourneyName, matrixIdProcessed, From f72b45e8f03e628d43dfdee40a7514905a717049 Mon Sep 17 00:00:00 2001 From: steffen123 Date: Tue, 10 Aug 2010 00:03:24 +0200 Subject: [PATCH 07/36] PP corner case history from ferki --- .../PP_blind_is_in_forced_allin.txt | 63 +++++++++++++++++++ 1 file changed, 63 insertions(+) create mode 100644 pyfpdb/regression-test-files/cash/PartyPoker/PP_blind_is_in_forced_allin.txt diff --git a/pyfpdb/regression-test-files/cash/PartyPoker/PP_blind_is_in_forced_allin.txt b/pyfpdb/regression-test-files/cash/PartyPoker/PP_blind_is_in_forced_allin.txt new file mode 100644 index 00000000..489dbe5e --- /dev/null +++ b/pyfpdb/regression-test-files/cash/PartyPoker/PP_blind_is_in_forced_allin.txt @@ -0,0 +1,63 @@ +Game #9485557849 starts. + +#Game No : 9485557849 +***** Hand History for Game 9485557849 ***** +$0.80 USD NL Texas Hold'em - Saturday, July 31, 13:52:16 EDT 2010 +Table 20BB Min Speed #1770998 (Real Money) +Seat 1 is the button +Total number of players : 4/9 +Seat 3: FErki84 ( $1.64 USD ) +Seat 5: Vandercasses ( $0.01 USD ) +Seat 9: jeremyho888 ( $1.02 USD ) +Seat 1: sergeodem ( $1.20 USD ) +FErki84 posts small blind [$0.01 USD]. +Vandercasses posts big blind [$0.01 USD]. +** Dealing down cards ** +Dealt to FErki84 [ 8h Kc ] +jeremyho888 folds +sergeodem calls [$0.02 USD] +FErki84 calls [$0.01 USD] +** Dealing Flop ** [ Td, 7c, 9h ] +FErki84 checks +sergeodem checks +** Dealing Turn ** [ 3h ] +FErki84 checks +sergeodem checks +** Dealing River ** [ Jc ] +FErki84 bets [$0.04 USD] +sergeodem folds +FErki84 shows [ 8h, Kc ]a straight, Seven to Jack. +Vandercasses doesn't show [ Ts, Jd ]two pairs, Jacks and Tens. +FErki84 wins $0.06 USD from the side pot 1 with a straight, Seven to Jack. +FErki84 wins $0.03 USD from the main pot with a straight, Seven to Jack. +Vandercasses has left the table. + +Game #9498788316 starts. + +#Game No : 9498788316 +***** Hand History for Game 9498788316 ***** +$1.60 USD NL Texas Hold'em - Wednesday, August 04, 15:02:33 EDT 2010 +Table 20BB Min #1847547 (No DP) (Real Money) +Seat 2 is the button +Total number of players : 5/6 +Seat 5: CepguTbIu999 ( $1.60 USD ) +Seat 1: Daytona_955 ( $2.45 USD ) +Seat 4: FErki84 ( $2.18 USD ) +Seat 2: anjl2009 ( $2.80 USD ) +Seat 3: lukeman2 ( $0.01 USD ) +lukeman2 posts small blind [$0.01 USD]. +FErki84 posts big blind [$0.04 USD]. +** Dealing down cards ** +Dealt to FErki84 [ 6s 2c ] +CepguTbIu999 folds +Daytona_955 folds +anjl2009 folds +** Dealing Flop ** [ 9d, Ah, 3h ] +** Dealing Turn ** [ Js ] +** Dealing River ** [ Kc ] +lukeman2 shows [ 5h, 5s ]a pair of Fives. +FErki84 shows [ 6s, 2c ]high card Ace. +FErki84 wins $0.03 USD from the side pot 1 with high card, Ace. +lukeman2 wins $0.02 USD from the main pot with a pair of Fives. +lukeman2 has left the table. + From 8a6fe1588ce77c1642948fd34c5f178f0591c5a1 Mon Sep 17 00:00:00 2001 From: steffen123 Date: Tue, 10 Aug 2010 00:05:13 +0200 Subject: [PATCH 08/36] PP histories by email. note how it skips the lines about hero raising --- .../PartyPoker_sample_HH_by_email.txt | 41 +++++++++++++++++++ .../HH from email/PP_SNG_HH_by_email.txt | 37 +++++++++++++++++ 2 files changed, 78 insertions(+) create mode 100644 pyfpdb/regression-test-files/cash/PartyPoker/history from email/PartyPoker_sample_HH_by_email.txt create mode 100644 pyfpdb/regression-test-files/tour/PartyPoker/HH from email/PP_SNG_HH_by_email.txt diff --git a/pyfpdb/regression-test-files/cash/PartyPoker/history from email/PartyPoker_sample_HH_by_email.txt b/pyfpdb/regression-test-files/cash/PartyPoker/history from email/PartyPoker_sample_HH_by_email.txt new file mode 100644 index 00000000..2267fa45 --- /dev/null +++ b/pyfpdb/regression-test-files/cash/PartyPoker/history from email/PartyPoker_sample_HH_by_email.txt @@ -0,0 +1,41 @@ +***** Hand History For Game 9423586142 ***** +0.01/0.02 Texas Hold'em Game Table (NL) - Mon Jul 12 13:38:32 EDT 2010 +Table 20BB Min Speed #1775757 (Real Money) -- Seat 1 is the button +Total number of players : 9/9 +Seat 1: Player1 ($0.95) +Seat 2: Player2 ($0.57) +Seat 3: Player3 ($0.86) +Seat 4: Player4 ($1.71) +Seat 5: Player5 ($1.76) +Seat 6: Player6 ($0.44) +Seat 7: Player7 ($0.76) +Seat 8: Player8 ($0.68) +Seat 9: Player9 ($0.38) +Player2 posts small blind (0.01) +Player3 posts big blind (0.02) +** Dealing down cards ** +Dealt to Player5 [ Tc, 9d ] +Player5 folds +Player6 calls (0.02) +Player8 folds +Player9 folds +Player1 folds +Player2 calls (0.01) +Player3 raises 0.06 to 0.08 +Player6 calls (0.06) +Player2 folds +** Dealing Flop ** : [ 5s, 7h, 6h ] +Player3 bets (0.13) +Player6 folds +** Summary ** +Main Pot: $0.18 Rake: $0 +Board: [ 5s 7h 6h ] +Player1 balance $0.95, didn't bet (folded) +Player2 balance $0.55, lost $0.02 (folded) +Player3 balance $0.96, bet $0.21, collected $0.31, net +$0.1 +Player4 balance $1.71, sits out +Player5 balance $1.76, didn't bet (folded) +Player6 balance $0.36, lost $0.08 (folded) +Player7 balance $0.76, sits out +Player8 balance $0.68, didn't bet (folded) +Player9 balance $0.38, didn't bet (folded) diff --git a/pyfpdb/regression-test-files/tour/PartyPoker/HH from email/PP_SNG_HH_by_email.txt b/pyfpdb/regression-test-files/tour/PartyPoker/HH from email/PP_SNG_HH_by_email.txt new file mode 100644 index 00000000..e6afb2c8 --- /dev/null +++ b/pyfpdb/regression-test-files/tour/PartyPoker/HH from email/PP_SNG_HH_by_email.txt @@ -0,0 +1,37 @@ +***** Hand History For Game 9336845949 ***** +30/60 Tourney Texas Hold'em Game Table (NL) (STT Tournament #52792286) - Sun Jun 13 12:21:39 EDT 2010 +Table 174827 (Real Money) -- Seat 6 is the button +Total number of players : 6/6 +Seat 1: Player1 (1520) +Seat 2: Player2 (1540) +Seat 3: Player3 (2120) +Seat 4: Player4 (2460) +Seat 5: Player5 (2600) +Seat 6: Player6 (1760) +Player1 posts small blind (30) +Player2 posts big blind (60) +** Dealing down cards ** +Dealt to Player5 [ Jc, Js ] +Player3 folds +Player4 folds +Player6 folds +Player1 calls (210) +Player2 folds +** Dealing Flop ** : [ 4h, 7d, 5c ] +Player1 checks +Player1 calls (450) +** Dealing Turn ** : [ Kd ] +Player1 checks +Player1 calls (830) +Player1 is all-In. +** Dealing River ** : [ Jd ] +Creating Main Pot with 3100 with Player1 +** Summary ** +Main Pot: 3100 +Board: [ 4h 7d 5c Kd Jd ] +Player1 balance 0, lost 1520 [ Ks 6c ] [ a pair of kings -- Ks,Kd,Jd,7d,6c ] +Player2 balance 1480, lost 60 (folded) +Player3 balance 2120, didn't bet (folded) +Player4 balance 2460, didn't bet (folded) +Player5 balance 4180, bet 1520, collected 3100, net +1580 [ Jc Js ] [ three of a kind, jacks -- Kd,Jc,Js,Jd,7d ] +Player6 balance 1760, didn't bet (folded) From 3467f757d37a213c6e80898210ea28a93691d19f Mon Sep 17 00:00:00 2001 From: steffen123 Date: Tue, 10 Aug 2010 00:25:43 +0200 Subject: [PATCH 09/36] refactor a bit in GuiTourneyViewer to reduce code duplication --- pyfpdb/GuiTourneyViewer.py | 29 ++++++++++++++--------------- 1 file changed, 14 insertions(+), 15 deletions(-) diff --git a/pyfpdb/GuiTourneyViewer.py b/pyfpdb/GuiTourneyViewer.py index 1499e8a6..777c8e9b 100644 --- a/pyfpdb/GuiTourneyViewer.py +++ b/pyfpdb/GuiTourneyViewer.py @@ -58,14 +58,9 @@ class GuiTourneyViewer (threading.Thread): #end def __init__ def displayClicked(self, widget, data=None): - tourneyNo=int(self.entryTourney.get_text()) - siteName=self.siteBox.get_active_text() + self.prepare(10, 9) - self.table.destroy() - self.table=gtk.Table(columns=10, rows=9) - self.mainVBox.add(self.table) - - result=self.db.getTourneyInfo(siteName, tourneyNo) + result=self.db.getTourneyInfo(self.siteName, self.tourneyNo) x=0 y=0 for i in range(1,len(result[0])): @@ -87,15 +82,9 @@ class GuiTourneyViewer (threading.Thread): #def displayClicked def displayPlayerClicked(self, widget, data=None): - tourneyNo=int(self.entryTourney.get_text()) - siteName=self.siteBox.get_active_text() - playerName=self.entryPlayer.get_text() + self.prepare(4, 5) - self.table.destroy() - self.table=gtk.Table(columns=4, rows=5) - self.mainVBox.add(self.table) - - result=self.db.getTourneyPlayerInfo(siteName, tourneyNo, playerName) + result=self.db.getTourneyPlayerInfo(self.siteName, self.tourneyNo, self.playerName) x=0 y=0 for i in range(1,len(result[0])): @@ -120,4 +109,14 @@ class GuiTourneyViewer (threading.Thread): """returns the vbox of this thread""" return self.mainVBox #end def get_vbox + + def prepare(self, columns, rows): + self.tourneyNo=int(self.entryTourney.get_text()) + self.siteName=self.siteBox.get_active_text() + self.playerName=self.entryPlayer.get_text() + + self.table.destroy() + self.table=gtk.Table(columns=columns, rows=rows) + self.mainVBox.add(self.table) + #end def readInfo #end class GuiTourneyViewer From 391c42cdfff874cf9150dac24ddf305ac4c710cc Mon Sep 17 00:00:00 2001 From: steffen123 Date: Tue, 10 Aug 2010 00:35:02 +0200 Subject: [PATCH 10/36] add error handling for invalid entry into tourneNo field --- pyfpdb/GuiTourneyViewer.py | 77 +++++++++++++++++++++----------------- 1 file changed, 42 insertions(+), 35 deletions(-) diff --git a/pyfpdb/GuiTourneyViewer.py b/pyfpdb/GuiTourneyViewer.py index 777c8e9b..6881fac2 100644 --- a/pyfpdb/GuiTourneyViewer.py +++ b/pyfpdb/GuiTourneyViewer.py @@ -58,50 +58,48 @@ class GuiTourneyViewer (threading.Thread): #end def __init__ def displayClicked(self, widget, data=None): - self.prepare(10, 9) - - result=self.db.getTourneyInfo(self.siteName, self.tourneyNo) - x=0 - y=0 - for i in range(1,len(result[0])): - if y==9: - x+=2 - y=0 + if self.prepare(10, 9): + result=self.db.getTourneyInfo(self.siteName, self.tourneyNo) + x=0 + y=0 + for i in range(1,len(result[0])): + if y==9: + x+=2 + y=0 - label=gtk.Label(result[0][i]) - self.table.attach(label,x,x+1,y,y+1) + label=gtk.Label(result[0][i]) + self.table.attach(label,x,x+1,y,y+1) - if result[1][i]==None: - label=gtk.Label("N/A") - else: - label=gtk.Label(result[1][i]) - self.table.attach(label,x+1,x+2,y,y+1) + if result[1][i]==None: + label=gtk.Label("N/A") + else: + label=gtk.Label(result[1][i]) + self.table.attach(label,x+1,x+2,y,y+1) - y+=1 + y+=1 self.mainVBox.show_all() #def displayClicked def displayPlayerClicked(self, widget, data=None): - self.prepare(4, 5) - - result=self.db.getTourneyPlayerInfo(self.siteName, self.tourneyNo, self.playerName) - x=0 - y=0 - for i in range(1,len(result[0])): - if y==5: - x+=2 - y=0 + if self.prepare(4, 5): + result=self.db.getTourneyPlayerInfo(self.siteName, self.tourneyNo, self.playerName) + x=0 + y=0 + for i in range(1,len(result[0])): + if y==5: + x+=2 + y=0 - label=gtk.Label(result[0][i]) - self.table.attach(label,x,x+1,y,y+1) + label=gtk.Label(result[0][i]) + self.table.attach(label,x,x+1,y,y+1) - if result[1][i]==None: - label=gtk.Label("N/A") - else: - label=gtk.Label(result[1][i]) - self.table.attach(label,x+1,x+2,y,y+1) + if result[1][i]==None: + label=gtk.Label("N/A") + else: + label=gtk.Label(result[1][i]) + self.table.attach(label,x+1,x+2,y,y+1) - y+=1 + y+=1 self.mainVBox.show_all() #def displayPlayerClicked @@ -111,12 +109,21 @@ class GuiTourneyViewer (threading.Thread): #end def get_vbox def prepare(self, columns, rows): - self.tourneyNo=int(self.entryTourney.get_text()) + try: self.errorLabel.destroy() + except: pass + + try: + self.tourneyNo=int(self.entryTourney.get_text()) + except ValueError: + self.errorLabel=gtk.Label("invalid entry in tourney number - must enter numbers only") + self.mainVBox.add(self.errorLabel) + return False self.siteName=self.siteBox.get_active_text() self.playerName=self.entryPlayer.get_text() self.table.destroy() self.table=gtk.Table(columns=columns, rows=rows) self.mainVBox.add(self.table) + return True #end def readInfo #end class GuiTourneyViewer From 10fac81ef900d0d354bb6eeb5d5cc4c9b2306252 Mon Sep 17 00:00:00 2001 From: steffen123 Date: Tue, 10 Aug 2010 00:46:55 +0200 Subject: [PATCH 11/36] handle tourney not found --- pyfpdb/GuiTourneyViewer.py | 33 +++++++++++++++++++-------------- 1 file changed, 19 insertions(+), 14 deletions(-) diff --git a/pyfpdb/GuiTourneyViewer.py b/pyfpdb/GuiTourneyViewer.py index 6881fac2..c30cb642 100644 --- a/pyfpdb/GuiTourneyViewer.py +++ b/pyfpdb/GuiTourneyViewer.py @@ -60,23 +60,28 @@ class GuiTourneyViewer (threading.Thread): def displayClicked(self, widget, data=None): if self.prepare(10, 9): result=self.db.getTourneyInfo(self.siteName, self.tourneyNo) - x=0 - y=0 - for i in range(1,len(result[0])): - if y==9: - x+=2 - y=0 + if result[1] == None: + self.table.destroy() + self.errorLabel=gtk.Label("Tournament not found - please ensure you imported it and selected the correct site") + self.mainVBox.add(self.errorLabel) + else: + x=0 + y=0 + for i in range(1,len(result[0])): + if y==9: + x+=2 + y=0 - label=gtk.Label(result[0][i]) - self.table.attach(label,x,x+1,y,y+1) + label=gtk.Label(result[0][i]) + self.table.attach(label,x,x+1,y,y+1) - if result[1][i]==None: - label=gtk.Label("N/A") - else: - label=gtk.Label(result[1][i]) - self.table.attach(label,x+1,x+2,y,y+1) + if result[1][i]==None: + label=gtk.Label("N/A") + else: + label=gtk.Label(result[1][i]) + self.table.attach(label,x+1,x+2,y,y+1) - y+=1 + y+=1 self.mainVBox.show_all() #def displayClicked From 08451c77d5437bb0bdaace275c967cc34178de0f Mon Sep 17 00:00:00 2001 From: steffen123 Date: Tue, 10 Aug 2010 00:49:14 +0200 Subject: [PATCH 12/36] handle player not found --- pyfpdb/GuiTourneyViewer.py | 39 +++++++++++++++++++++----------------- 1 file changed, 22 insertions(+), 17 deletions(-) diff --git a/pyfpdb/GuiTourneyViewer.py b/pyfpdb/GuiTourneyViewer.py index c30cb642..70a8a7d7 100644 --- a/pyfpdb/GuiTourneyViewer.py +++ b/pyfpdb/GuiTourneyViewer.py @@ -88,23 +88,28 @@ class GuiTourneyViewer (threading.Thread): def displayPlayerClicked(self, widget, data=None): if self.prepare(4, 5): result=self.db.getTourneyPlayerInfo(self.siteName, self.tourneyNo, self.playerName) - x=0 - y=0 - for i in range(1,len(result[0])): - if y==5: - x+=2 - y=0 - - label=gtk.Label(result[0][i]) - self.table.attach(label,x,x+1,y,y+1) - - if result[1][i]==None: - label=gtk.Label("N/A") - else: - label=gtk.Label(result[1][i]) - self.table.attach(label,x+1,x+2,y,y+1) - - y+=1 + if result[1] == None: + self.table.destroy() + self.errorLabel=gtk.Label("Player or tourney not found - please ensure you imported it and selected the correct site") + self.mainVBox.add(self.errorLabel) + else: + x=0 + y=0 + for i in range(1,len(result[0])): + if y==5: + x+=2 + y=0 + + label=gtk.Label(result[0][i]) + self.table.attach(label,x,x+1,y,y+1) + + if result[1][i]==None: + label=gtk.Label("N/A") + else: + label=gtk.Label(result[1][i]) + self.table.attach(label,x+1,x+2,y,y+1) + + y+=1 self.mainVBox.show_all() #def displayPlayerClicked From 4fbb26b4fac86ea946c0d205bea133483c2d2122 Mon Sep 17 00:00:00 2001 From: steffen123 Date: Tue, 10 Aug 2010 01:00:35 +0200 Subject: [PATCH 13/36] remove some 100% duplicates --- pyfpdb/SQL.py | 4 ---- 1 file changed, 4 deletions(-) diff --git a/pyfpdb/SQL.py b/pyfpdb/SQL.py index 69d74fbe..5ffb47bc 100644 --- a/pyfpdb/SQL.py +++ b/pyfpdb/SQL.py @@ -1336,8 +1336,6 @@ class Sql: and (p.siteId = %s or %s = -1) """ - self.query['getSiteId'] = """SELECT id from Sites where name = %s""" - self.query['get_stats_from_hand'] = """ SELECT hc.playerId AS player_id, hp.seatNo AS seat, @@ -2010,8 +2008,6 @@ class Sql: self.query['getPlayerIdBySite'] = """SELECT id from Players where name = %s AND siteId = %s""" # used in *Filters: - self.query['getSiteId'] = """SELECT id from Sites where name = %s""" - self.query['getGames'] = """SELECT DISTINCT category from Gametypes""" #self.query['getLimits'] = already defined further up self.query['getLimits2'] = """SELECT DISTINCT type, limitType, bigBlind from Gametypes From c5acd04bb682c168c8cc7d701c63eb8e7af72c01 Mon Sep 17 00:00:00 2001 From: steffen123 Date: Tue, 10 Aug 2010 01:27:25 +0200 Subject: [PATCH 14/36] This makes HUD Cache work again but without tourneytypeid - one of these lines breaks it --- pyfpdb/SQL.py | 15 --------------- 1 file changed, 15 deletions(-) diff --git a/pyfpdb/SQL.py b/pyfpdb/SQL.py index 5ffb47bc..0ee2ad73 100644 --- a/pyfpdb/SQL.py +++ b/pyfpdb/SQL.py @@ -2988,7 +2988,6 @@ class Sql: ,playerId ,activeSeats ,position - ,tourneyTypeId ,styleKey ,HDs ,wonWhenSeenStreet1 @@ -3078,7 +3077,6 @@ class Sql: when hp.position = '9' then 'E' else 'E' end AS hc_position - ,t.tourneyTypeId ,date_format(h.startTime, 'd%y%m%d') ,count(1) ,sum(wonWhenSeenStreet1) @@ -3152,14 +3150,11 @@ class Sql: ,sum(hp.street4Raises) FROM HandsPlayers hp INNER JOIN Hands h ON (h.id = hp.handId) - INNER JOIN TourneysPlayers tp ON (tp.id = hp.tourneysPlayersId) - INNER JOIN Tourneys t ON (t.id = tp.tourneyId) GROUP BY h.gametypeId ,hp.playerId ,h.seats ,hc_position - ,t.tourneyTypeId ,date_format(h.startTime, 'd%y%m%d') """ elif db_server == 'postgresql': @@ -3169,7 +3164,6 @@ class Sql: ,playerId ,activeSeats ,position - ,tourneyTypeId ,styleKey ,HDs ,wonWhenSeenStreet1 @@ -3259,7 +3253,6 @@ class Sql: when hp.position = '9' then 'E' else 'E' end AS hc_position - ,t.tourneyTypeId ,'d' || to_char(h.startTime, 'YYMMDD') ,count(1) ,sum(wonWhenSeenStreet1) @@ -3333,14 +3326,11 @@ class Sql: ,sum(CAST(hp.street4Raises as integer)) FROM HandsPlayers hp INNER JOIN Hands h ON (h.id = hp.handId) - INNER JOIN TourneysPlayers tp ON (tp.id = hp.tourneysPlayersId) - INNER JOIN Tourneys t ON (t.id = tp.tourneyId) GROUP BY h.gametypeId ,hp.playerId ,h.seats ,hc_position - ,t.tourneyTypeId ,to_char(h.startTime, 'YYMMDD') """ else: # assume sqlite @@ -3350,7 +3340,6 @@ class Sql: ,playerId ,activeSeats ,position - ,tourneyTypeId ,styleKey ,HDs ,wonWhenSeenStreet1 @@ -3440,7 +3429,6 @@ class Sql: when hp.position = '9' then 'E' else 'E' end AS hc_position - ,t.tourneyTypeId ,'d' || substr(strftime('%Y%m%d', h.startTime),3,7) ,count(1) ,sum(wonWhenSeenStreet1) @@ -3514,14 +3502,11 @@ class Sql: ,sum(CAST(hp.street4Raises as integer)) FROM HandsPlayers hp INNER JOIN Hands h ON (h.id = hp.handId) - INNER JOIN TourneysPlayers tp ON (tp.id = hp.tourneysPlayersId) - INNER JOIN Tourneys t ON (t.id = tp.tourneyId) GROUP BY h.gametypeId ,hp.playerId ,h.seats ,hc_position - ,t.tourneyTypeId ,'d' || substr(strftime('%Y%m%d', h.startTime),3,7) """ From a6d7f27f5bb3722e8a375c99690c95926df02e31 Mon Sep 17 00:00:00 2001 From: gimick Date: Tue, 10 Aug 2010 00:32:53 +0100 Subject: [PATCH 15/36] FullTilt fixup currency typo --- pyfpdb/FulltiltToFpdb.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pyfpdb/FulltiltToFpdb.py b/pyfpdb/FulltiltToFpdb.py index 87aa0730..179824ac 100755 --- a/pyfpdb/FulltiltToFpdb.py +++ b/pyfpdb/FulltiltToFpdb.py @@ -184,7 +184,7 @@ class Fulltilt(HandHistoryConverter): 'Stud Hi' : ('stud','studhi'), 'Stud H/L' : ('stud','studhilo') } - currencies = { u' €':'EUR', '$':'USD', '':'T$' } + currencies = { u'€':'EUR', '$':'USD', '':'T$' } if mg['CAP']: info['limitType'] = 'cn' else: From c7e86513c760635c256ee4bc4f946f7d1a71f89b Mon Sep 17 00:00:00 2001 From: Erki Ferenc Date: Tue, 10 Aug 2010 00:36:34 +0200 Subject: [PATCH 16/36] Added validation to blind detection Included checks for any ring game hands if there's a blind could be found and if either SB or BB detection fails then determineGameType will return None. It's needed for handling some invalid ring hands (e.g. table closed messages at the end of a HH file). Signed-off-by: steffen123 --- pyfpdb/PartyPokerToFpdb.py | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/pyfpdb/PartyPokerToFpdb.py b/pyfpdb/PartyPokerToFpdb.py index a80810c7..b4b46615 100755 --- a/pyfpdb/PartyPokerToFpdb.py +++ b/pyfpdb/PartyPokerToFpdb.py @@ -219,8 +219,11 @@ class PartyPoker(HandHistoryConverter): info['type'] = 'ring' if info['type'] == 'ring': - info['sb'] = m_sb.group('RINGSB') - info['bb'] = m_bb.group('RINGBB') + if (m_sb is None) or (m_bb is None): + return None + else: + info['sb'] = m_sb.group('RINGSB') + info['bb'] = m_bb.group('RINGBB') info['currency'] = currencies[mg['CURRENCY']] else: info['sb'] = clearMoneyString(mg['SB']) From 6e654e5075a0cf8b6d6414725b50ae36fbb79e0f Mon Sep 17 00:00:00 2001 From: steffen123 Date: Tue, 10 Aug 2010 03:28:57 +0200 Subject: [PATCH 17/36] allow multiple email configs, start of nicer GUI for it --- pyfpdb/Configuration.py | 8 +++-- pyfpdb/GuiImapFetcher.py | 78 ++++++++++++++++++++++++++++++++++++++++ pyfpdb/ImapFetcher.py | 12 +++---- pyfpdb/fpdb.pyw | 17 +++++---- 4 files changed, 99 insertions(+), 16 deletions(-) create mode 100644 pyfpdb/GuiImapFetcher.py diff --git a/pyfpdb/Configuration.py b/pyfpdb/Configuration.py index 7c8f1fba..24f1dcd4 100755 --- a/pyfpdb/Configuration.py +++ b/pyfpdb/Configuration.py @@ -452,8 +452,8 @@ class Email: self.fetchType = node.getAttribute("fetchType") def __str__(self): - return " host = %s\n username = %s\n password = %s\n useSsl = %s\n folder = %s\n" \ - % (self.host, self.username, self.password, self.useSsl, self.folder) + return " siteName=%s\n fetchType=%s\n host = %s\n username = %s\n password = %s\n useSsl = %s\n folder = %s\n" \ + % (self.siteName, self.fetchType, self.host, self.username, self.password, self.useSsl, self.folder) class HudUI: def __init__(self, node): @@ -626,6 +626,7 @@ class Config: self.db_selected = None # database the user would like to use self.tv = None self.general = General() + self.emails = {} self.gui_cash_stats = GUICashStats() for gen_node in doc.getElementsByTagName("general"): @@ -687,7 +688,8 @@ class Config: for email_node in doc.getElementsByTagName("email"): email = Email(node = email_node) - self.email = email + if email.siteName!="": #FIXME: Why on earth is this needed? + self.emails[email.siteName+"_"+email.fetchType]=email for hui_node in doc.getElementsByTagName('hud_ui'): hui = HudUI(node = hui_node) diff --git a/pyfpdb/GuiImapFetcher.py b/pyfpdb/GuiImapFetcher.py new file mode 100644 index 00000000..d8e4d18e --- /dev/null +++ b/pyfpdb/GuiImapFetcher.py @@ -0,0 +1,78 @@ +#!/usr/bin/python +# -*- coding: utf-8 -*- + +#Copyright 2010 Steffen Schaumburg +#This program is free software: you can redistribute it and/or modify +#it under the terms of the GNU Affero General Public License as published by +#the Free Software Foundation, version 3 of the License. +# +#This program is distributed in the hope that it will be useful, +#but WITHOUT ANY WARRANTY; without even the implied warranty of +#MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +#GNU General Public License for more details. +# +#You should have received a copy of the GNU Affero General Public License +#along with this program. If not, see . +#In the "official" distribution you can find the license in agpl-3.0.txt. + +import threading +import pygtk +pygtk.require('2.0') +import gtk +import ImapFetcher + +class GuiImapFetcher (threading.Thread): + def __init__(self, config, db, sql, mainwin, debug=True): + self.config = config + self.db = db + self.mainVBox = gtk.VBox() + + + self.buttonsHBox = gtk.HBox() + self.mainVBox.pack_end(self.buttonsHBox, expand=False) + + label=gtk.Label("To cancel just close this tab") + self.buttonsHBox.add(label) + + self.saveButton = gtk.Button("_Save Configuration") + self.saveButton.connect('clicked', self.saveClicked) + self.buttonsHBox.add(self.saveButton) + + self.runAllButton = gtk.Button("_Run All") + self.runAllButton.connect('clicked', self.runAllClicked) + self.buttonsHBox.add(self.runAllButton) + + self.statusLabel=gtk.Label("Please edit your config if you wish and then click Run All") + self.mainVBox.pack_end(self.statusLabel, expand=False, padding=4) + + self.rowVBox = gtk.VBox() + self.mainVBox.add(self.rowVBox) + + self.displayConfig() + + self.mainVBox.show_all() + #end def __init__ + + def saveClicked(self, widget, data=None): + pass + #def saveClicked + + def runAllClicked(self, widget, data=None): + self.statusLabel.set_label("Starting import. Please wait.") #FIXME: why doesnt this one show? + for email in self.config.emails: + result=ImapFetcher.run(self.config.emails[email], self.db) + self.statusLabel.set_label("Finished import without error.") + #def runAllClicked + + def get_vbox(self): + """returns the vbox of this thread""" + return self.mainVBox + #end def get_vbox + + def displayConfig(self): + print self.config.emails + for email in self.config.emails: + print self.config.emails[email] + + #end def displayConfig +#end class GuiImapFetcher diff --git a/pyfpdb/ImapFetcher.py b/pyfpdb/ImapFetcher.py index da13698c..97dbf3de 100755 --- a/pyfpdb/ImapFetcher.py +++ b/pyfpdb/ImapFetcher.py @@ -33,16 +33,16 @@ def run(config, db): #print "start of IS.run" server=None #try: - #print "useSSL",config.email.useSsl,"host",config.email.host - if config.email.useSsl: - server = IMAP4_SSL(config.email.host) + #print "useSSL",config.useSsl,"host",config.host + if config.useSsl: + server = IMAP4_SSL(config.host) else: - server = IMAP4(config.email.host) - response = server.login(config.email.username, config.email.password) #TODO catch authentication error + server = IMAP4(config.host) + response = server.login(config.username, config.password) #TODO catch authentication error print "response to logging in:",response #print "server.list():",server.list() #prints list of folders - response = server.select(config.email.folder) + response = server.select(config.folder) #print "response to selecting INBOX:",response if response[0]!="OK": raise error #TODO: show error message diff --git a/pyfpdb/fpdb.pyw b/pyfpdb/fpdb.pyw index 75faebf2..8553ee72 100755 --- a/pyfpdb/fpdb.pyw +++ b/pyfpdb/fpdb.pyw @@ -103,7 +103,7 @@ import GuiPrefs import GuiLogView #import GuiDatabase import GuiBulkImport -import ImapFetcher +import GuiImapFetcher import GuiRingPlayerStats import GuiTourneyPlayerStats import GuiTourneyViewer @@ -786,7 +786,7 @@ class fpdb: - + @@ -828,7 +828,7 @@ class fpdb: ('import', None, '_Import'), ('sethharchive', None, '_Set HandHistory Archive Directory', None, 'Set HandHistory Archive Directory', self.select_hhArchiveBase), ('bulkimp', None, '_Bulk Import', 'B', 'Bulk Import', self.tab_bulk_import), - ('imapsummaries', None, '_Import Tourney Summaries through eMail/IMAP', 'I', 'Auto Import and HUD', self.import_imap_summaries), + ('imapimport', None, '_Import through eMail/IMAP', 'I', 'Import through eMail/IMAP', self.tab_imap_import), ('viewers', None, '_Viewers'), ('autoimp', None, '_Auto Import and HUD', 'A', 'Auto Import and HUD', self.tab_auto_import), ('hudConfigurator', None, '_HUD Configurator', 'H', 'HUD Configurator', self.diaHudConfigurator), @@ -860,10 +860,6 @@ class fpdb: return menubar #end def get_menu - def import_imap_summaries(self, widget, data=None): - result=ImapFetcher.run(self.config, self.db) - #print "import imap summaries result:", result - #end def import_imap_summaries def load_profile(self, create_db = False): """Loads profile from the provided path name.""" @@ -1024,6 +1020,13 @@ class fpdb: bulk_tab=new_import_thread.get_vbox() self.add_and_display_tab(bulk_tab, "Bulk Import") + def tab_imap_import(self, widget, data=None): + new_thread = GuiImapFetcher.GuiImapFetcher(self.config, self.db, self.sql, self.window) + self.threads.append(new_thread) + tab=new_thread.get_vbox() + self.add_and_display_tab(tab, "IMAP Import") + #end def tab_import_imap_summaries + def tab_ring_player_stats(self, widget, data=None): new_ps_thread = GuiRingPlayerStats.GuiRingPlayerStats(self.config, self.sql, self.window) self.threads.append(new_ps_thread) From 97f1f8b836f4858076141d8ea14c2ddf19b8e9be Mon Sep 17 00:00:00 2001 From: steffen123 Date: Tue, 10 Aug 2010 03:50:26 +0200 Subject: [PATCH 18/36] display existing configs in IMAP tab --- pyfpdb/GuiImapFetcher.py | 29 +++++++++++++++++++++++++---- 1 file changed, 25 insertions(+), 4 deletions(-) diff --git a/pyfpdb/GuiImapFetcher.py b/pyfpdb/GuiImapFetcher.py index d8e4d18e..4d155c6a 100644 --- a/pyfpdb/GuiImapFetcher.py +++ b/pyfpdb/GuiImapFetcher.py @@ -34,7 +34,7 @@ class GuiImapFetcher (threading.Thread): label=gtk.Label("To cancel just close this tab") self.buttonsHBox.add(label) - self.saveButton = gtk.Button("_Save Configuration") + self.saveButton = gtk.Button("_Save (doesn't work yet)") self.saveButton.connect('clicked', self.saveClicked) self.buttonsHBox.add(self.saveButton) @@ -70,9 +70,30 @@ class GuiImapFetcher (threading.Thread): #end def get_vbox def displayConfig(self): - print self.config.emails - for email in self.config.emails: - print self.config.emails[email] + box=gtk.HBox(homogeneous=True) + for text in ("Site", "Fetch Type", "Mailserver", "Username", "Password", "Mail Folder", "Use SSL"): + label=gtk.Label(text) + box.add(label) + self.rowVBox.pack_start(box, expand=False) + for email in self.config.emails: + config=self.config.emails[email] + box=gtk.HBox(homogeneous=True) + for field in (config.siteName, config.fetchType, config.host, config.username, config.password, config.folder): + entry=gtk.Entry() + entry.set_text(field) + box.add(entry) + + sslBox = gtk.combo_box_new_text() + sslBox.append_text("Yes") + sslBox.append_text("No") + sslBox.set_active(0) + box.add(sslBox) + + #TODO: useSsl + self.rowVBox.pack_start(box, expand=False) + #print + + self.rowVBox.show_all() #end def displayConfig #end class GuiImapFetcher From 59f8bb1a70ae78ac8d8fa7bf53a5463a918ca094 Mon Sep 17 00:00:00 2001 From: steffen123 Date: Tue, 10 Aug 2010 04:44:35 +0200 Subject: [PATCH 19/36] GuiImapFetcher can save config --- pyfpdb/Configuration.py | 15 +++++++++++ pyfpdb/GuiImapFetcher.py | 54 +++++++++++++++++++++++++++++----------- 2 files changed, 55 insertions(+), 14 deletions(-) diff --git a/pyfpdb/Configuration.py b/pyfpdb/Configuration.py index 24f1dcd4..f61b66a4 100755 --- a/pyfpdb/Configuration.py +++ b/pyfpdb/Configuration.py @@ -736,6 +736,12 @@ class Config: if site_node.getAttribute("site_name") == site: return site_node + def getEmailNode(self, siteName, fetchType): + for emailNode in self.doc.getElementsByTagName("email"): + if emailNode.getAttribute("siteName") == siteName and emailNode.getAttribute("fetchType") == fetchType: + return emailNode + #end def getEmailNode + def getGameNode(self,gameName): """returns DOM game node for a given game""" for gameNode in self.doc.getElementsByTagName("game"): @@ -810,6 +816,15 @@ class Config: else: return(l) + def editEmail(self, siteName, fetchType, newEmail): + emailNode = self.getEmailNode(siteName, fetchType) + emailNode.setAttribute("host", newEmail.host) + emailNode.setAttribute("username", newEmail.username) + emailNode.setAttribute("password", newEmail.password) + emailNode.setAttribute("folder", newEmail.folder) + emailNode.setAttribute("useSsl", newEmail.useSsl) + #end def editEmail + def edit_layout(self, site_name, max, width = None, height = None, fav_seat = None, locations = None): site_node = self.get_site_node(site_name) diff --git a/pyfpdb/GuiImapFetcher.py b/pyfpdb/GuiImapFetcher.py index 4d155c6a..f8077cfc 100644 --- a/pyfpdb/GuiImapFetcher.py +++ b/pyfpdb/GuiImapFetcher.py @@ -31,22 +31,20 @@ class GuiImapFetcher (threading.Thread): self.buttonsHBox = gtk.HBox() self.mainVBox.pack_end(self.buttonsHBox, expand=False) - label=gtk.Label("To cancel just close this tab") + label=gtk.Label("To cancel just close this tab.") self.buttonsHBox.add(label) - self.saveButton = gtk.Button("_Save (doesn't work yet)") + self.saveButton = gtk.Button("_Save") self.saveButton.connect('clicked', self.saveClicked) self.buttonsHBox.add(self.saveButton) - self.runAllButton = gtk.Button("_Run All") - self.runAllButton.connect('clicked', self.runAllClicked) - self.buttonsHBox.add(self.runAllButton) + self.importAllButton = gtk.Button("_Import All") + self.importAllButton.connect('clicked', self.importAllClicked) + self.buttonsHBox.add(self.importAllButton) - self.statusLabel=gtk.Label("Please edit your config if you wish and then click Run All") + self.statusLabel=gtk.Label("If you change the config you must save before importing") self.mainVBox.pack_end(self.statusLabel, expand=False, padding=4) - self.rowVBox = gtk.VBox() - self.mainVBox.add(self.rowVBox) self.displayConfig() @@ -54,15 +52,39 @@ class GuiImapFetcher (threading.Thread): #end def __init__ def saveClicked(self, widget, data=None): - pass + row = self.rowVBox.get_children() + columns=row[0].get_children() #TODO: make save capable of handling multiple email entries - not relevant yet as only one entry is useful atm. The rest of this tab works fine for multiple entries though + + siteName=columns[0].get_text() + fetchType=columns[1].get_text() + code=siteName+"_"+fetchType + + for email in self.config.emails: + toSave=self.config.emails[email] + break + toSave.siteName=siteName + toSave.fetchType=fetchType + + toSave.host=columns[2].get_text() + toSave.username=columns[3].get_text() + toSave.password=columns[4].get_text() + toSave.folder=columns[5].get_text() + + if columns[6].get_active() == 0: + toSave.useSsl="True" + else: + toSave.useSsl="False" + + self.config.editEmail(siteName, fetchType, toSave) + self.config.save() #def saveClicked - def runAllClicked(self, widget, data=None): + def importAllClicked(self, widget, data=None): self.statusLabel.set_label("Starting import. Please wait.") #FIXME: why doesnt this one show? for email in self.config.emails: result=ImapFetcher.run(self.config.emails[email], self.db) self.statusLabel.set_label("Finished import without error.") - #def runAllClicked + #def importAllClicked def get_vbox(self): """returns the vbox of this thread""" @@ -74,7 +96,10 @@ class GuiImapFetcher (threading.Thread): for text in ("Site", "Fetch Type", "Mailserver", "Username", "Password", "Mail Folder", "Use SSL"): label=gtk.Label(text) box.add(label) - self.rowVBox.pack_start(box, expand=False) + self.mainVBox.pack_start(box, expand=False) + + self.rowVBox = gtk.VBox() + self.mainVBox.add(self.rowVBox) for email in self.config.emails: config=self.config.emails[email] @@ -90,10 +115,11 @@ class GuiImapFetcher (threading.Thread): sslBox.set_active(0) box.add(sslBox) - #TODO: useSsl + #TODO: "run just this one" button + self.rowVBox.pack_start(box, expand=False) #print - self.rowVBox.show_all() + self.mainVBox.show_all() #end def displayConfig #end class GuiImapFetcher From d94254c9cde5645c614449f8e9227ff700e068f8 Mon Sep 17 00:00:00 2001 From: steffen123 Date: Tue, 10 Aug 2010 04:50:27 +0200 Subject: [PATCH 20/36] GuiImap: turn non-editable fields into labels --- pyfpdb/GuiImapFetcher.py | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/pyfpdb/GuiImapFetcher.py b/pyfpdb/GuiImapFetcher.py index f8077cfc..28f71399 100644 --- a/pyfpdb/GuiImapFetcher.py +++ b/pyfpdb/GuiImapFetcher.py @@ -104,7 +104,12 @@ class GuiImapFetcher (threading.Thread): for email in self.config.emails: config=self.config.emails[email] box=gtk.HBox(homogeneous=True) - for field in (config.siteName, config.fetchType, config.host, config.username, config.password, config.folder): + + for field in (config.siteName, config.fetchType): + label=gtk.Label(field) + box.add(label) + + for field in (config.host, config.username, config.password, config.folder): entry=gtk.Entry() entry.set_text(field) box.add(entry) From 4da521eadcdc83b81d0fd6df2e82cfb79aa59279 Mon Sep 17 00:00:00 2001 From: steffen123 Date: Tue, 10 Aug 2010 05:10:39 +0200 Subject: [PATCH 21/36] GuiImap: pass on auth failed error to GUI --- pyfpdb/GuiImapFetcher.py | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/pyfpdb/GuiImapFetcher.py b/pyfpdb/GuiImapFetcher.py index 28f71399..9ed9bdba 100644 --- a/pyfpdb/GuiImapFetcher.py +++ b/pyfpdb/GuiImapFetcher.py @@ -19,6 +19,8 @@ import threading import pygtk pygtk.require('2.0') import gtk +from imaplib import IMAP4 + import ImapFetcher class GuiImapFetcher (threading.Thread): @@ -82,8 +84,15 @@ class GuiImapFetcher (threading.Thread): def importAllClicked(self, widget, data=None): self.statusLabel.set_label("Starting import. Please wait.") #FIXME: why doesnt this one show? for email in self.config.emails: - result=ImapFetcher.run(self.config.emails[email], self.db) - self.statusLabel.set_label("Finished import without error.") + try: + print "trying to run" + result=ImapFetcher.run(self.config.emails[email], self.db) + self.statusLabel.set_label("Finished import without error.") + print "finished to run" + except IMAP4.error as strerror: + if str(strerror)=="[AUTHENTICATIONFAILED] Authentication failed.": + self.statusLabel.set_label("Login to mailserver failed: please check mailserver, username and password") + #def importAllClicked def get_vbox(self): From 9dff57238516490260f7dcef45360ee0b4fcb15a Mon Sep 17 00:00:00 2001 From: steffen123 Date: Tue, 10 Aug 2010 05:19:54 +0200 Subject: [PATCH 22/36] GuiImap: more error handling --- pyfpdb/GuiImapFetcher.py | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/pyfpdb/GuiImapFetcher.py b/pyfpdb/GuiImapFetcher.py index 9ed9bdba..1e8a8879 100644 --- a/pyfpdb/GuiImapFetcher.py +++ b/pyfpdb/GuiImapFetcher.py @@ -20,6 +20,7 @@ import pygtk pygtk.require('2.0') import gtk from imaplib import IMAP4 +from socket import gaierror import ImapFetcher @@ -85,14 +86,14 @@ class GuiImapFetcher (threading.Thread): self.statusLabel.set_label("Starting import. Please wait.") #FIXME: why doesnt this one show? for email in self.config.emails: try: - print "trying to run" result=ImapFetcher.run(self.config.emails[email], self.db) self.statusLabel.set_label("Finished import without error.") - print "finished to run" - except IMAP4.error as strerror: - if str(strerror)=="[AUTHENTICATIONFAILED] Authentication failed.": + except IMAP4.error as error: + if str(error)=="[AUTHENTICATIONFAILED] Authentication failed.": self.statusLabel.set_label("Login to mailserver failed: please check mailserver, username and password") - + except gaierror as error: + if str(error)=="[Errno -2] Name or service not known": + self.statusLabel.set_label("Could not connect to mailserver: check mailserver and use SSL settings and internet connectivity") #def importAllClicked def get_vbox(self): From ced47999bba2ad07705afc64a9597125de4a0eb7 Mon Sep 17 00:00:00 2001 From: steffen123 Date: Tue, 10 Aug 2010 06:14:15 +0200 Subject: [PATCH 23/36] GuiImap: don't show email password --- pyfpdb/GuiImapFetcher.py | 22 ++++++++++++++++++---- 1 file changed, 18 insertions(+), 4 deletions(-) diff --git a/pyfpdb/GuiImapFetcher.py b/pyfpdb/GuiImapFetcher.py index 1e8a8879..84af7d65 100644 --- a/pyfpdb/GuiImapFetcher.py +++ b/pyfpdb/GuiImapFetcher.py @@ -48,7 +48,7 @@ class GuiImapFetcher (threading.Thread): self.statusLabel=gtk.Label("If you change the config you must save before importing") self.mainVBox.pack_end(self.statusLabel, expand=False, padding=4) - + self.passwords={} self.displayConfig() self.mainVBox.show_all() @@ -70,14 +70,19 @@ class GuiImapFetcher (threading.Thread): toSave.host=columns[2].get_text() toSave.username=columns[3].get_text() - toSave.password=columns[4].get_text() + + if columns[4].get_text()=="***": + toSave.password=self.passwords[code] + else: + toSave.password=columns[4].get_text() + toSave.folder=columns[5].get_text() if columns[6].get_active() == 0: toSave.useSsl="True" else: toSave.useSsl="False" - + self.config.editEmail(siteName, fetchType, toSave) self.config.save() #def saveClicked @@ -119,11 +124,20 @@ class GuiImapFetcher (threading.Thread): label=gtk.Label(field) box.add(label) - for field in (config.host, config.username, config.password, config.folder): + for field in (config.host, config.username): entry=gtk.Entry() entry.set_text(field) box.add(entry) + entry=gtk.Entry() + self.passwords[email]=config.password + entry.set_text("***") + box.add(entry) + + entry=gtk.Entry() + entry.set_text(config.folder) + box.add(entry) + sslBox = gtk.combo_box_new_text() sslBox.append_text("Yes") sslBox.append_text("No") From f0ef6e7e8b314d9d2285e6c46a177730b5d1e180 Mon Sep 17 00:00:00 2001 From: steffen123 Date: Tue, 10 Aug 2010 20:45:40 +0200 Subject: [PATCH 24/36] add stub for query for positional stats on sqlite --- pyfpdb/SQL.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/pyfpdb/SQL.py b/pyfpdb/SQL.py index 0ee2ad73..194826bf 100644 --- a/pyfpdb/SQL.py +++ b/pyfpdb/SQL.py @@ -2777,6 +2777,8 @@ class Sql: order by stats.category, stats.limitType, stats.bigBlindDesc desc , cast(stats.PlPosition as signed) """ + elif db_server == 'sqlite': + self.query['playerStatsByPosition'] = ""#TODO else: # assume postgresql self.query['playerStatsByPosition'] = """ select /* stats from hudcache */ From d7a7cca2abd2bddfb6451e94224d4565ec51b43e Mon Sep 17 00:00:00 2001 From: steffen123 Date: Tue, 10 Aug 2010 20:50:19 +0200 Subject: [PATCH 25/36] Revert "GRAPH: Put legend in "best" position, not fixed in top left." previous consensus that I wasn't aware was to have the old setting, since "best" is only better in some cases so I'm reverting this This reverts commit 2d8f9dcc78d8d271304293813e58e4791dbef18c. --- pyfpdb/GuiGraphViewer.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pyfpdb/GuiGraphViewer.py b/pyfpdb/GuiGraphViewer.py index e1a719ba..96026864 100644 --- a/pyfpdb/GuiGraphViewer.py +++ b/pyfpdb/GuiGraphViewer.py @@ -232,7 +232,7 @@ class GuiGraphViewer (threading.Thread): if sys.version[0:3] == '2.5': self.ax.legend(loc='upper left', shadow=True, prop=FontProperties(size='smaller')) else: - self.ax.legend(loc='best', fancybox=True, shadow=True, prop=FontProperties(size='smaller')) + self.ax.legend(loc='upper left', fancybox=True, shadow=True, prop=FontProperties(size='smaller')) self.graphBox.add(self.canvas) self.canvas.show() From 87d4549b67023eff6dc292d78392341c62ca413e Mon Sep 17 00:00:00 2001 From: steffen123 Date: Tue, 10 Aug 2010 23:16:30 +0200 Subject: [PATCH 26/36] renamed PP files to match existing scheme --- .../NLHE-USD-0.01-0.02-20100712.emailedHistory.txt} | 0 .../NLHE-USD-0.01-0.02-20100731.blindIsForcedAllIn.txt} | 0 .../NLHE-USD-STT-unknownBuyIn-20100713.emailedHistory.txt} | 0 3 files changed, 0 insertions(+), 0 deletions(-) rename pyfpdb/regression-test-files/cash/PartyPoker/{history from email/PartyPoker_sample_HH_by_email.txt => Flop/NLHE-USD-0.01-0.02-20100712.emailedHistory.txt} (100%) rename pyfpdb/regression-test-files/cash/PartyPoker/{PP_blind_is_in_forced_allin.txt => Flop/NLHE-USD-0.01-0.02-20100731.blindIsForcedAllIn.txt} (100%) rename pyfpdb/regression-test-files/tour/PartyPoker/{HH from email/PP_SNG_HH_by_email.txt => Flop/NLHE-USD-STT-unknownBuyIn-20100713.emailedHistory.txt} (100%) diff --git a/pyfpdb/regression-test-files/cash/PartyPoker/history from email/PartyPoker_sample_HH_by_email.txt b/pyfpdb/regression-test-files/cash/PartyPoker/Flop/NLHE-USD-0.01-0.02-20100712.emailedHistory.txt similarity index 100% rename from pyfpdb/regression-test-files/cash/PartyPoker/history from email/PartyPoker_sample_HH_by_email.txt rename to pyfpdb/regression-test-files/cash/PartyPoker/Flop/NLHE-USD-0.01-0.02-20100712.emailedHistory.txt diff --git a/pyfpdb/regression-test-files/cash/PartyPoker/PP_blind_is_in_forced_allin.txt b/pyfpdb/regression-test-files/cash/PartyPoker/Flop/NLHE-USD-0.01-0.02-20100731.blindIsForcedAllIn.txt similarity index 100% rename from pyfpdb/regression-test-files/cash/PartyPoker/PP_blind_is_in_forced_allin.txt rename to pyfpdb/regression-test-files/cash/PartyPoker/Flop/NLHE-USD-0.01-0.02-20100731.blindIsForcedAllIn.txt diff --git a/pyfpdb/regression-test-files/tour/PartyPoker/HH from email/PP_SNG_HH_by_email.txt b/pyfpdb/regression-test-files/tour/PartyPoker/Flop/NLHE-USD-STT-unknownBuyIn-20100713.emailedHistory.txt similarity index 100% rename from pyfpdb/regression-test-files/tour/PartyPoker/HH from email/PP_SNG_HH_by_email.txt rename to pyfpdb/regression-test-files/tour/PartyPoker/Flop/NLHE-USD-STT-unknownBuyIn-20100713.emailedHistory.txt From 36b212388db1249c3bac177ba2a82af94f075192 Mon Sep 17 00:00:00 2001 From: steffen123 Date: Tue, 10 Aug 2010 23:31:53 +0200 Subject: [PATCH 27/36] make rebuildHudCache act on cash hands only --- pyfpdb/Database.py | 17 +++++++++++------ 1 file changed, 11 insertions(+), 6 deletions(-) diff --git a/pyfpdb/Database.py b/pyfpdb/Database.py index 6b902921..de60384d 100644 --- a/pyfpdb/Database.py +++ b/pyfpdb/Database.py @@ -1442,17 +1442,22 @@ class Database: h_start = self.hero_hudstart_def if v_start is None: v_start = self.villain_hudstart_def + if self.hero_ids == {}: - where = "" + where = "WHERE hp.tourneysPlayersId IS NULL" else: - where = "where ( hp.playerId not in " + str(tuple(self.hero_ids.values())) \ + where = "where ((( hp.playerId not in " + str(tuple(self.hero_ids.values())) \ + " and h.startTime > '" + v_start + "')" \ + " or ( hp.playerId in " + str(tuple(self.hero_ids.values())) \ - + " and h.startTime > '" + h_start + "')" - rebuild_sql = self.sql.query['rebuildHudCache'].replace('', where) - + + " and h.startTime > '" + h_start + "'))" \ + + " AND hp.tourneysPlayersId IS NULL)" + rebuild_sql_cash = self.sql.query['rebuildHudCache'].replace('', where) + print "rebuild_sql_cash:",rebuild_sql_cash + self.get_cursor().execute(self.sql.query['clearHudCache']) - self.get_cursor().execute(rebuild_sql) + + self.get_cursor().execute(rebuild_sql_cash) + #self.get_cursor().execute(rebuild_sql_tour) self.commit() print "Rebuild hudcache took %.1f seconds" % (time() - stime,) except: From 174aa4adfb2fa0faf1eb68c686a9f906326e183b Mon Sep 17 00:00:00 2001 From: steffen123 Date: Wed, 11 Aug 2010 00:10:10 +0200 Subject: [PATCH 28/36] hudcache is regenerated properly on mysql now --- pyfpdb/Database.py | 29 ++++++++++++++++++++++++----- pyfpdb/SQL.py | 8 ++++++++ 2 files changed, 32 insertions(+), 5 deletions(-) diff --git a/pyfpdb/Database.py b/pyfpdb/Database.py index de60384d..ed4d69c7 100644 --- a/pyfpdb/Database.py +++ b/pyfpdb/Database.py @@ -1451,13 +1451,32 @@ class Database: + " or ( hp.playerId in " + str(tuple(self.hero_ids.values())) \ + " and h.startTime > '" + h_start + "'))" \ + " AND hp.tourneysPlayersId IS NULL)" - rebuild_sql_cash = self.sql.query['rebuildHudCache'].replace('', where) - print "rebuild_sql_cash:",rebuild_sql_cash - + rebuild_sql_cash = self.sql.query['rebuildHudCache'].replace('', "") + rebuild_sql_cash = rebuild_sql_cash.replace('', "") + rebuild_sql_cash = rebuild_sql_cash.replace('', "") + rebuild_sql_cash = rebuild_sql_cash.replace('', "") + rebuild_sql_cash = rebuild_sql_cash.replace('', where) + #print "rebuild_sql_cash:",rebuild_sql_cash self.get_cursor().execute(self.sql.query['clearHudCache']) - self.get_cursor().execute(rebuild_sql_cash) - #self.get_cursor().execute(rebuild_sql_tour) + + if self.hero_ids == {}: + where = "WHERE hp.tourneysPlayersId >= 0" + else: + where = "where ((( hp.playerId not in " + str(tuple(self.hero_ids.values())) \ + + " and h.startTime > '" + v_start + "')" \ + + " or ( hp.playerId in " + str(tuple(self.hero_ids.values())) \ + + " and h.startTime > '" + h_start + "'))" \ + + " AND hp.tourneysPlayersId >= 0)" + rebuild_sql_tourney = self.sql.query['rebuildHudCache'].replace('', ",tourneyTypeId") + rebuild_sql_tourney = rebuild_sql_tourney.replace('', ",t.tourneyTypeId") + rebuild_sql_tourney = rebuild_sql_tourney.replace('', """INNER JOIN TourneysPlayers tp ON (tp.id = hp.tourneysPlayersId) + INNER JOIN Tourneys t ON (t.id = tp.tourneyId)""") + rebuild_sql_tourney = rebuild_sql_tourney.replace('', ",t.tourneyTypeId") + rebuild_sql_tourney = rebuild_sql_tourney.replace('', where) + #print "rebuild_sql_tourney:",rebuild_sql_tourney + + self.get_cursor().execute(rebuild_sql_tourney) self.commit() print "Rebuild hudcache took %.1f seconds" % (time() - stime,) except: diff --git a/pyfpdb/SQL.py b/pyfpdb/SQL.py index 194826bf..5c4b8cf3 100644 --- a/pyfpdb/SQL.py +++ b/pyfpdb/SQL.py @@ -2990,6 +2990,7 @@ class Sql: ,playerId ,activeSeats ,position + ,styleKey ,HDs ,wonWhenSeenStreet1 @@ -3079,6 +3080,7 @@ class Sql: when hp.position = '9' then 'E' else 'E' end AS hc_position + ,date_format(h.startTime, 'd%y%m%d') ,count(1) ,sum(wonWhenSeenStreet1) @@ -3152,11 +3154,13 @@ class Sql: ,sum(hp.street4Raises) FROM HandsPlayers hp INNER JOIN Hands h ON (h.id = hp.handId) + GROUP BY h.gametypeId ,hp.playerId ,h.seats ,hc_position + ,date_format(h.startTime, 'd%y%m%d') """ elif db_server == 'postgresql': @@ -3342,6 +3346,7 @@ class Sql: ,playerId ,activeSeats ,position + ,styleKey ,HDs ,wonWhenSeenStreet1 @@ -3431,6 +3436,7 @@ class Sql: when hp.position = '9' then 'E' else 'E' end AS hc_position + ,'d' || substr(strftime('%Y%m%d', h.startTime),3,7) ,count(1) ,sum(wonWhenSeenStreet1) @@ -3504,11 +3510,13 @@ class Sql: ,sum(CAST(hp.street4Raises as integer)) FROM HandsPlayers hp INNER JOIN Hands h ON (h.id = hp.handId) + GROUP BY h.gametypeId ,hp.playerId ,h.seats ,hc_position + ,'d' || substr(strftime('%Y%m%d', h.startTime),3,7) """ From b385f9f0da1b7db63327232dfa460bb9f95028f7 Mon Sep 17 00:00:00 2001 From: steffen123 Date: Wed, 11 Aug 2010 03:10:08 +0200 Subject: [PATCH 29/36] this caused it to create a new TourneyType for each Tourney Revert "remove some default values - if we don't know, don't just assume no/normal" This reverts commit 7f8243f19d58222d537433d66204069993cd434f. --- pyfpdb/Hand.py | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/pyfpdb/Hand.py b/pyfpdb/Hand.py index ef5cdae4..3ca578e0 100644 --- a/pyfpdb/Hand.py +++ b/pyfpdb/Hand.py @@ -79,13 +79,13 @@ class Hand(object): self.fee = None # the Database code is looking for this one .. ? self.level = None self.mixed = None - self.speed = None - self.isRebuy = None - self.isAddOn = None - self.isKO = None + self.speed = "Normal" + self.isRebuy = False + self.isAddOn = False + self.isKO = False self.koBounty = None - self.isMatrix = None - self.isShootout = None + self.isMatrix = False + self.isShootout = False self.added = None self.addedCurrency = None self.tourneyComment = None From 5cba225fb3a00b1ed34864f6e218d3b9a4a139ff Mon Sep 17 00:00:00 2001 From: steffen123 Date: Wed, 11 Aug 2010 04:23:16 +0200 Subject: [PATCH 30/36] improve naming of replacement clauses --- pyfpdb/Database.py | 10 +++++----- pyfpdb/SQL.py | 8 ++++---- 2 files changed, 9 insertions(+), 9 deletions(-) diff --git a/pyfpdb/Database.py b/pyfpdb/Database.py index ed4d69c7..a994b889 100644 --- a/pyfpdb/Database.py +++ b/pyfpdb/Database.py @@ -1451,8 +1451,8 @@ class Database: + " or ( hp.playerId in " + str(tuple(self.hero_ids.values())) \ + " and h.startTime > '" + h_start + "'))" \ + " AND hp.tourneysPlayersId IS NULL)" - rebuild_sql_cash = self.sql.query['rebuildHudCache'].replace('', "") - rebuild_sql_cash = rebuild_sql_cash.replace('', "") + rebuild_sql_cash = self.sql.query['rebuildHudCache'].replace('', "") + rebuild_sql_cash = rebuild_sql_cash.replace('', "") rebuild_sql_cash = rebuild_sql_cash.replace('', "") rebuild_sql_cash = rebuild_sql_cash.replace('', "") rebuild_sql_cash = rebuild_sql_cash.replace('', where) @@ -1468,13 +1468,13 @@ class Database: + " or ( hp.playerId in " + str(tuple(self.hero_ids.values())) \ + " and h.startTime > '" + h_start + "'))" \ + " AND hp.tourneysPlayersId >= 0)" - rebuild_sql_tourney = self.sql.query['rebuildHudCache'].replace('', ",tourneyTypeId") - rebuild_sql_tourney = rebuild_sql_tourney.replace('', ",t.tourneyTypeId") + rebuild_sql_tourney = self.sql.query['rebuildHudCache'].replace('', ",tourneyTypeId") + rebuild_sql_tourney = rebuild_sql_tourney.replace('', ",t.tourneyTypeId") rebuild_sql_tourney = rebuild_sql_tourney.replace('', """INNER JOIN TourneysPlayers tp ON (tp.id = hp.tourneysPlayersId) INNER JOIN Tourneys t ON (t.id = tp.tourneyId)""") rebuild_sql_tourney = rebuild_sql_tourney.replace('', ",t.tourneyTypeId") rebuild_sql_tourney = rebuild_sql_tourney.replace('', where) - #print "rebuild_sql_tourney:",rebuild_sql_tourney + print "rebuild_sql_tourney:",rebuild_sql_tourney self.get_cursor().execute(rebuild_sql_tourney) self.commit() diff --git a/pyfpdb/SQL.py b/pyfpdb/SQL.py index 5c4b8cf3..ca0c1b47 100644 --- a/pyfpdb/SQL.py +++ b/pyfpdb/SQL.py @@ -2990,7 +2990,7 @@ class Sql: ,playerId ,activeSeats ,position - + ,styleKey ,HDs ,wonWhenSeenStreet1 @@ -3080,7 +3080,7 @@ class Sql: when hp.position = '9' then 'E' else 'E' end AS hc_position - + ,date_format(h.startTime, 'd%y%m%d') ,count(1) ,sum(wonWhenSeenStreet1) @@ -3346,7 +3346,7 @@ class Sql: ,playerId ,activeSeats ,position - + ,styleKey ,HDs ,wonWhenSeenStreet1 @@ -3436,7 +3436,7 @@ class Sql: when hp.position = '9' then 'E' else 'E' end AS hc_position - + ,'d' || substr(strftime('%Y%m%d', h.startTime),3,7) ,count(1) ,sum(wonWhenSeenStreet1) From 02b5ea8d37326cba2bdb379d03b5a03afcd3afd4 Mon Sep 17 00:00:00 2001 From: steffen123 Date: Wed, 11 Aug 2010 04:25:47 +0200 Subject: [PATCH 31/36] corrected sqlite table layout. this also fixes hudcache generation for tourneys on sqlite --- pyfpdb/Database.py | 2 +- pyfpdb/SQL.py | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/pyfpdb/Database.py b/pyfpdb/Database.py index a994b889..6a520c41 100644 --- a/pyfpdb/Database.py +++ b/pyfpdb/Database.py @@ -74,7 +74,7 @@ except ImportError: use_numpy = False -DB_VERSION = 140 +DB_VERSION = 141 # Variance created as sqlite has a bunch of undefined aggregate functions. diff --git a/pyfpdb/SQL.py b/pyfpdb/SQL.py index ca0c1b47..af34c34f 100644 --- a/pyfpdb/SQL.py +++ b/pyfpdb/SQL.py @@ -918,7 +918,7 @@ class Sql: commentTs timestamp without time zone)""" elif db_server == 'sqlite': self.query['createTourneysPlayersTable'] = """CREATE TABLE TourneysPlayers ( - id INT PRIMARY KEY, + id INTEGER PRIMARY KEY, tourneyId INT, playerId INT, rank INT, @@ -963,7 +963,7 @@ class Sql: commentTs timestamp without time zone)""" elif db_server == 'sqlite': self.query['createHandsActionsTable'] = """CREATE TABLE HandsActions ( - id INT PRIMARY KEY, + id INTEGER PRIMARY KEY, handsPlayerId BIGINT, street SMALLINT, actionNo SMALLINT, From f1ac0b1dfaecac895adb474bbffffb27c602df62 Mon Sep 17 00:00:00 2001 From: steffen123 Date: Wed, 11 Aug 2010 04:39:34 +0200 Subject: [PATCH 32/36] record HC.TTid on pgsql --- pyfpdb/Database.py | 2 +- pyfpdb/SQL.py | 4 ++++ 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/pyfpdb/Database.py b/pyfpdb/Database.py index 6a520c41..f00c35f5 100644 --- a/pyfpdb/Database.py +++ b/pyfpdb/Database.py @@ -1474,7 +1474,7 @@ class Database: INNER JOIN Tourneys t ON (t.id = tp.tourneyId)""") rebuild_sql_tourney = rebuild_sql_tourney.replace('', ",t.tourneyTypeId") rebuild_sql_tourney = rebuild_sql_tourney.replace('', where) - print "rebuild_sql_tourney:",rebuild_sql_tourney + #print "rebuild_sql_tourney:",rebuild_sql_tourney self.get_cursor().execute(rebuild_sql_tourney) self.commit() diff --git a/pyfpdb/SQL.py b/pyfpdb/SQL.py index af34c34f..baf305b2 100644 --- a/pyfpdb/SQL.py +++ b/pyfpdb/SQL.py @@ -3170,6 +3170,7 @@ class Sql: ,playerId ,activeSeats ,position + ,styleKey ,HDs ,wonWhenSeenStreet1 @@ -3259,6 +3260,7 @@ class Sql: when hp.position = '9' then 'E' else 'E' end AS hc_position + ,'d' || to_char(h.startTime, 'YYMMDD') ,count(1) ,sum(wonWhenSeenStreet1) @@ -3332,11 +3334,13 @@ class Sql: ,sum(CAST(hp.street4Raises as integer)) FROM HandsPlayers hp INNER JOIN Hands h ON (h.id = hp.handId) + GROUP BY h.gametypeId ,hp.playerId ,h.seats ,hc_position + ,to_char(h.startTime, 'YYMMDD') """ else: # assume sqlite From d1c1a0a0f426481496ae9d662e2745e13d5f00d2 Mon Sep 17 00:00:00 2001 From: steffen123 Date: Wed, 11 Aug 2010 04:43:17 +0200 Subject: [PATCH 33/36] correct Backings.tourneysPlayerId to tourneysPlayersId like it's used in HP --- pyfpdb/Database.py | 6 +++--- pyfpdb/SQL.py | 6 +++--- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/pyfpdb/Database.py b/pyfpdb/Database.py index f00c35f5..92c30bea 100644 --- a/pyfpdb/Database.py +++ b/pyfpdb/Database.py @@ -74,7 +74,7 @@ except ImportError: use_numpy = False -DB_VERSION = 141 +DB_VERSION = 142 # Variance created as sqlite has a bunch of undefined aggregate functions. @@ -140,7 +140,7 @@ class Database: , {'tab':'TourneysPlayers', 'col':'playerId', 'drop':0} #, {'tab':'TourneysPlayers', 'col':'tourneyId', 'drop':0} unique indexes not dropped , {'tab':'TourneyTypes', 'col':'siteId', 'drop':0} - , {'tab':'Backings', 'col':'tourneysPlayerId', 'drop':0} + , {'tab':'Backings', 'col':'tourneysPlayersId', 'drop':0} , {'tab':'Backings', 'col':'playerId', 'drop':0} ] , [ # indexes for sqlite (list index 4) @@ -155,7 +155,7 @@ class Database: , {'tab':'Tourneys', 'col':'tourneyTypeId', 'drop':1} , {'tab':'TourneysPlayers', 'col':'playerId', 'drop':0} , {'tab':'TourneyTypes', 'col':'siteId', 'drop':0} - , {'tab':'Backings', 'col':'tourneysPlayerId', 'drop':0} + , {'tab':'Backings', 'col':'tourneysPlayersId', 'drop':0} , {'tab':'Backings', 'col':'playerId', 'drop':0} ] ] diff --git a/pyfpdb/SQL.py b/pyfpdb/SQL.py index baf305b2..111cae9f 100644 --- a/pyfpdb/SQL.py +++ b/pyfpdb/SQL.py @@ -137,21 +137,21 @@ class Sql: if db_server == 'mysql': self.query['createBackingsTable'] = """CREATE TABLE Backings ( id SMALLINT UNSIGNED AUTO_INCREMENT NOT NULL, PRIMARY KEY (id), - tourneysPlayerId BIGINT UNSIGNED NOT NULL, FOREIGN KEY (tourneysPlayerId) REFERENCES TourneysPlayers(id), + tourneysPlayersId BIGINT UNSIGNED NOT NULL, FOREIGN KEY (tourneysPlayerId) REFERENCES TourneysPlayers(id), playerId INT UNSIGNED NOT NULL, FOREIGN KEY (playerId) REFERENCES Players(id), buyInPercentage FLOAT UNSIGNED NOT NULL, payOffPercentage FLOAT UNSIGNED NOT NULL) ENGINE=INNODB""" elif db_server == 'postgresql': self.query['createBackingsTable'] = """CREATE TABLE Backings ( id BIGSERIAL, PRIMARY KEY (id), - tourneysPlayerId INT NOT NULL, FOREIGN KEY (tourneysPlayerId) REFERENCES TourneysPlayers(id), + tourneysPlayersId INT NOT NULL, FOREIGN KEY (tourneysPlayerId) REFERENCES TourneysPlayers(id), playerId INT NOT NULL, FOREIGN KEY (playerId) REFERENCES Players(id), buyInPercentage FLOAT NOT NULL, payOffPercentage FLOAT NOT NULL)""" elif db_server == 'sqlite': self.query['createBackingsTable'] = """CREATE TABLE Backings ( id INTEGER PRIMARY KEY, - tourneysPlayerId INT NOT NULL, + tourneysPlayersId INT NOT NULL, playerId INT NOT NULL, buyInPercentage REAL UNSIGNED NOT NULL, payOffPercentage REAL UNSIGNED NOT NULL)""" From 19bcc60c6ad4baacff43b508bd988205f05ff93b Mon Sep 17 00:00:00 2001 From: steffen123 Date: Wed, 11 Aug 2010 04:50:01 +0200 Subject: [PATCH 34/36] missed a spot --- pyfpdb/SQL.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pyfpdb/SQL.py b/pyfpdb/SQL.py index 111cae9f..b8ddf4f0 100644 --- a/pyfpdb/SQL.py +++ b/pyfpdb/SQL.py @@ -137,14 +137,14 @@ class Sql: if db_server == 'mysql': self.query['createBackingsTable'] = """CREATE TABLE Backings ( id SMALLINT UNSIGNED AUTO_INCREMENT NOT NULL, PRIMARY KEY (id), - tourneysPlayersId BIGINT UNSIGNED NOT NULL, FOREIGN KEY (tourneysPlayerId) REFERENCES TourneysPlayers(id), + tourneysPlayersId BIGINT UNSIGNED NOT NULL, FOREIGN KEY (tourneysPlayersId) REFERENCES TourneysPlayers(id), playerId INT UNSIGNED NOT NULL, FOREIGN KEY (playerId) REFERENCES Players(id), buyInPercentage FLOAT UNSIGNED NOT NULL, payOffPercentage FLOAT UNSIGNED NOT NULL) ENGINE=INNODB""" elif db_server == 'postgresql': self.query['createBackingsTable'] = """CREATE TABLE Backings ( id BIGSERIAL, PRIMARY KEY (id), - tourneysPlayersId INT NOT NULL, FOREIGN KEY (tourneysPlayerId) REFERENCES TourneysPlayers(id), + tourneysPlayersId INT NOT NULL, FOREIGN KEY (tourneysPlayersId) REFERENCES TourneysPlayers(id), playerId INT NOT NULL, FOREIGN KEY (playerId) REFERENCES Players(id), buyInPercentage FLOAT NOT NULL, payOffPercentage FLOAT NOT NULL)""" From f0b5b4063b77a892e1bf0523f476a7808ea2d35c Mon Sep 17 00:00:00 2001 From: steffen123 Date: Wed, 11 Aug 2010 05:53:02 +0200 Subject: [PATCH 35/36] fix session viewer in mysql --- pyfpdb/SQL.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pyfpdb/SQL.py b/pyfpdb/SQL.py index b8ddf4f0..cca8800d 100644 --- a/pyfpdb/SQL.py +++ b/pyfpdb/SQL.py @@ -2949,7 +2949,7 @@ class Sql: INNER JOIN Players p on (p.Id = hp.playerId) WHERE hp.playerId in AND date_format(h.startTime, '%Y-%m-%d') - AND gt.type is 'ring' + AND gt.type LIKE 'ring' ORDER by time""" elif db_server == 'postgresql': self.query['sessionStats'] = """ From b5e481412ed1da06417c059d02c322701ae964c2 Mon Sep 17 00:00:00 2001 From: steffen123 Date: Wed, 11 Aug 2010 06:11:11 +0200 Subject: [PATCH 36/36] fix session stats in pgsql --- pyfpdb/SQL.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pyfpdb/SQL.py b/pyfpdb/SQL.py index cca8800d..5d4a0235 100644 --- a/pyfpdb/SQL.py +++ b/pyfpdb/SQL.py @@ -2961,7 +2961,7 @@ class Sql: INNER JOIN Players p on (p.Id = hp.playerId) WHERE hp.playerId in AND h.startTime - AND gt.type is 'ring' + AND gt.type LIKE 'ring' ORDER by time""" elif db_server == 'sqlite': self.query['sessionStats'] = """