From 47dad738dde87a779f2f9399f657d5190a831b8d Mon Sep 17 00:00:00 2001 From: sqlcoder Date: Tue, 5 May 2009 23:57:20 +0100 Subject: [PATCH 1/5] work around unicode problem with windows and postgres - use old version of recognisePlayerIDs --- pyfpdb/fpdb_simple.py | 59 +++++++++++++++++++++++-------------------- 1 file changed, 31 insertions(+), 28 deletions(-) diff --git a/pyfpdb/fpdb_simple.py b/pyfpdb/fpdb_simple.py index 4413d461..f0d3d633 100644 --- a/pyfpdb/fpdb_simple.py +++ b/pyfpdb/fpdb_simple.py @@ -1310,35 +1310,38 @@ def recogniseTourneyTypeId(cursor, siteId, buyin, fee, knockout, rebuyOrAddon): # { playername: id } instead of depending on it's relation to the positions list # then this can be reduced in complexity a bit -#def recognisePlayerIDs(cursor, names, site_id): -# result = [] -# for i in xrange(len(names)): -# cursor.execute ("SELECT id FROM Players WHERE name=%s", (names[i],)) -# tmp=cursor.fetchall() -# if (len(tmp)==0): #new player -# cursor.execute ("INSERT INTO Players (name, siteId) VALUES (%s, %s)", (names[i], site_id)) -# #print "Number of players rows inserted: %d" % cursor.rowcount -# cursor.execute ("SELECT id FROM Players WHERE name=%s", (names[i],)) -# tmp=cursor.fetchall() -# #print "recognisePlayerIDs, names[i]:",names[i],"tmp:",tmp -# result.append(tmp[0][0]) -# return result - def recognisePlayerIDs(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 - 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 = dict(cursor.fetchall()) - for n in tmp: # put them all into the same dict - ids[n] = tmp[n] - # return them in the SAME ORDER that they came in in the names argument, rather than the order they came out of the DB - return [ids[n] for n in names] + result = [] + for i in xrange(len(names)): + cursor.execute ("SELECT id FROM Players WHERE name=%s", (names[i],)) + tmp=cursor.fetchall() + if (len(tmp)==0): #new player + cursor.execute ("INSERT INTO Players (name, siteId) VALUES (%s, %s)", (names[i], site_id)) + #print "Number of players rows inserted: %d" % cursor.rowcount + cursor.execute ("SELECT id FROM Players WHERE name=%s", (names[i],)) + tmp=cursor.fetchall() + #print "recognisePlayerIDs, names[i]:",names[i],"tmp:",tmp + result.append(tmp[0][0]) + return result + +# This version breaks for me using postgres on windows with a unicode problem. The names don't come out in unicode +# for some reason so the id isn't found even though it's just been created. Currently investigating the unicode issue but +# not really understanding it yet .... - sqlcoder +#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 +# 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 = dict(cursor.fetchall()) +# for n in tmp: # put them all into the same dict +# ids[n] = tmp[n] +# # return them in the SAME ORDER that they came in in the names argument, rather than the order they came out of the DB +# return [ids[n] for n in names] #end def recognisePlayerIDs From 9fe2fc902dd90af057d9c0cbfb285b866ae370a1 Mon Sep 17 00:00:00 2001 From: sqlcoder Date: Thu, 7 May 2009 21:17:14 +0100 Subject: [PATCH 2/5] make psycopg2 return unicode strings and go back to new recognisePlayerIDs() very similar to @885f0a023 --- pyfpdb/fpdb_simple.py | 59 ++++++++++++++++++++----------------------- 1 file changed, 28 insertions(+), 31 deletions(-) diff --git a/pyfpdb/fpdb_simple.py b/pyfpdb/fpdb_simple.py index f0d3d633..988b5dbb 100644 --- a/pyfpdb/fpdb_simple.py +++ b/pyfpdb/fpdb_simple.py @@ -1310,38 +1310,35 @@ def recogniseTourneyTypeId(cursor, siteId, buyin, fee, knockout, rebuyOrAddon): # { playername: id } instead of depending on it's relation to the positions list # then this can be reduced in complexity a bit -def recognisePlayerIDs(cursor, names, site_id): - result = [] - for i in xrange(len(names)): - cursor.execute ("SELECT id FROM Players WHERE name=%s", (names[i],)) - tmp=cursor.fetchall() - if (len(tmp)==0): #new player - cursor.execute ("INSERT INTO Players (name, siteId) VALUES (%s, %s)", (names[i], site_id)) - #print "Number of players rows inserted: %d" % cursor.rowcount - cursor.execute ("SELECT id FROM Players WHERE name=%s", (names[i],)) - tmp=cursor.fetchall() - #print "recognisePlayerIDs, names[i]:",names[i],"tmp:",tmp - result.append(tmp[0][0]) - return result - -# This version breaks for me using postgres on windows with a unicode problem. The names don't come out in unicode -# for some reason so the id isn't found even though it's just been created. Currently investigating the unicode issue but -# not really understanding it yet .... - sqlcoder #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 -# 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 = dict(cursor.fetchall()) -# for n in tmp: # put them all into the same dict -# ids[n] = tmp[n] -# # return them in the SAME ORDER that they came in in the names argument, rather than the order they came out of the DB -# return [ids[n] for n in names] +# result = [] +# for i in xrange(len(names)): +# cursor.execute ("SELECT id FROM Players WHERE name=%s", (names[i],)) +# tmp=cursor.fetchall() +# if (len(tmp)==0): #new player +# cursor.execute ("INSERT INTO Players (name, siteId) VALUES (%s, %s)", (names[i], site_id)) +# #print "Number of players rows inserted: %d" % cursor.rowcount +# cursor.execute ("SELECT id FROM Players WHERE name=%s", (names[i],)) +# tmp=cursor.fetchall() +# #print "recognisePlayerIDs, names[i]:",names[i],"tmp:",tmp +# result.append(tmp[0][0]) +# return result + +def recognisePlayerIDs(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 + 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() + for n,id in tmp: # put them all into the same dict + ids[n] = id + # return them in the SAME ORDER that they came in in the names argument, rather than the order they came out of the DB + return [ids[n] for n in names] #end def recognisePlayerIDs From 4ffc028bbce3206610a81c41a0437a46d67feef4 Mon Sep 17 00:00:00 2001 From: sqlcoder Date: Thu, 7 May 2009 21:24:06 +0100 Subject: [PATCH 3/5] oops, missed out the key change in previous commit --- pyfpdb/fpdb_db.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/pyfpdb/fpdb_db.py b/pyfpdb/fpdb_db.py index eba87f52..fda04e19 100644 --- a/pyfpdb/fpdb_db.py +++ b/pyfpdb/fpdb_db.py @@ -62,6 +62,8 @@ class fpdb_db: self.db=MySQLdb.connect(host = host, user = user, passwd = password, db = database, use_unicode=True) elif backend==self.PGSQL: import psycopg2 + import psycopg2.extensions + psycopg2.extensions.register_type(psycopg2.extensions.UNICODE) # If DB connection is made over TCP, then the variables # host, user and password are required print "host=%s user=%s pass=%s." % (host, user, password) From 527232595bd044ddd09c56ee78d7dcc66ddcbcd9 Mon Sep 17 00:00:00 2001 From: sqlcoder Date: Thu, 7 May 2009 21:24:53 +0100 Subject: [PATCH 4/5] change import time calc --- pyfpdb/GuiBulkImport.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/pyfpdb/GuiBulkImport.py b/pyfpdb/GuiBulkImport.py index 8a047769..77dee9b7 100755 --- a/pyfpdb/GuiBulkImport.py +++ b/pyfpdb/GuiBulkImport.py @@ -72,6 +72,9 @@ class GuiBulkImport(): self.importer.setCallHud(False) starttime = time() (stored, dups, partial, errs, ttime) = self.importer.runImport() + ttime = time() - starttime + if ttime == 0: + ttime = 1 print 'GuiBulkImport.import_dir done: Stored: %d \tDuplicates: %d \tPartial: %d \tErrors: %d in %s seconds - %d/sec'\ % (stored, dups, partial, errs, ttime, stored / ttime) self.importer.clearFileList() From b7ee4255587c84d997deacce36a57d7d26a35cb2 Mon Sep 17 00:00:00 2001 From: sqlcoder Date: Fri, 8 May 2009 22:41:09 +0100 Subject: [PATCH 5/5] add seats to filters and stats queries --- pyfpdb/Filters.py | 86 +++++++++++++++++++++++++++------ pyfpdb/FpdbSQLQueries.py | 36 ++++++++++---- pyfpdb/GuiPlayerStats.py | 51 +++++++++++++------- pyfpdb/GuiPositionalStats.py | 93 ++++++++++++++++++++++++------------ 4 files changed, 193 insertions(+), 73 deletions(-) diff --git a/pyfpdb/Filters.py b/pyfpdb/Filters.py index ef7c8d29..9a8e788f 100644 --- a/pyfpdb/Filters.py +++ b/pyfpdb/Filters.py @@ -42,9 +42,15 @@ class Filters(threading.Thread): self.sites = {} self.games = {} self.limits = {} + self.seats = {} self.siteid = {} self.heroes = {} + # text used on screen stored here so that it can be configured + self.filterText = {'limitsall':'All', 'limitsnone':'None', 'limitsshow':'Show Limits' + ,'seatsbetween':'Between:', 'seatsand':'And:', 'seatsand':'Show Seats' + } + # For use in date ranges. self.start_date = gtk.Entry(max=12) self.end_date = gtk.Entry(max=12) @@ -89,6 +95,16 @@ class Filters(threading.Thread): self.fillLimitsFrame(vbox, display) limitsFrame.add(vbox) + # Seats + seatsFrame = gtk.Frame("Seats:") + seatsFrame.set_label_align(0.0, 0.0) + seatsFrame.show() + vbox = gtk.VBox(False, 0) + self.sbSeats = {} + + self.fillSeatsFrame(vbox) + seatsFrame.add(vbox) + dateFrame = gtk.Frame("Date:") dateFrame.set_label_align(0.0, 0.0) dateFrame.show() @@ -97,9 +113,9 @@ class Filters(threading.Thread): self.fillDateFrame(vbox) dateFrame.add(vbox) - self.Button1=gtk.Button("Unamed 1") + self.Button1=gtk.Button("Unnamed 1") - self.Button2=gtk.Button("Unamed 2") + self.Button2=gtk.Button("Unnamed 2") #self.exportButton.connect("clicked", self.exportGraph, "show clicked") self.Button2.set_sensitive(False) @@ -107,6 +123,7 @@ class Filters(threading.Thread): self.mainVBox.add(sitesFrame) self.mainVBox.add(gamesFrame) self.mainVBox.add(limitsFrame) + self.mainVBox.add(seatsFrame) self.mainVBox.add(dateFrame) self.mainVBox.add(self.Button1) self.mainVBox.add(self.Button2) @@ -114,19 +131,21 @@ class Filters(threading.Thread): self.mainVBox.show_all() # Should do this cleaner - if display["Heroes"] == False: + if "Heroes" not in display or display["Heroes"] == False: playerFrame.hide() - if display["Sites"] == False: + if "Sites" not in display or display["Sites"] == False: sitesFrame.hide() - if display["Games"] == False: + if "Games" not in display or display["Games"] == False: gamesFrame.hide() - if display["Limits"] == False: + if "Limits" not in display or display["Limits"] == False: limitsFrame.hide() - if display["Dates"] == False: + if "Seats" not in display or display["Seats"] == False: + seatsFrame.hide() + if "Dates" not in display or display["Dates"] == False: dateFrame.hide() - if display["Button1"] == False: + if "Button1" not in display or display["Button1"] == False: self.Button1.hide() - if display["Button2"] == False: + if "Button2" not in display or display["Button2"] == False: self.Button2.hide() def get_vbox(self): @@ -150,6 +169,11 @@ class Filters(threading.Thread): ltuple.append(l) return ltuple + def getSeats(self): + self.seats['from'] = self.sbSeats['from'].get_value_as_int() + self.seats['to'] = self.sbSeats['to'].get_value_as_int() + return self.seats + def getDates(self): return self.__get_dates() @@ -196,8 +220,8 @@ class Filters(threading.Thread): cb.connect('clicked', self.__set_game_select, game) hbox.pack_start(cb, False, False, 0) - def createLimitLine(self, hbox, limit): - cb = gtk.CheckButton(str(limit)) + def createLimitLine(self, hbox, limit, ltext): + cb = gtk.CheckButton(str(ltext)) cb.connect('clicked', self.__set_limit_select, limit) hbox.pack_start(cb, False, False, 0) if limit != "None": @@ -234,6 +258,11 @@ class Filters(threading.Thread): for cb in self.cbLimits.values(): cb.set_active(False) + def __set_seat_select(self, w, seat): + #print "__set_seat_select: seat =", seat, "active =", w.get_active() + self.seats[seat] = w.get_active() + print "self.seats[%s] set to %s" %(seat, self.seats[seat]) + def fillPlayerFrame(self, vbox): for site in self.conf.get_supported_sites(): pathHBox = gtk.HBox(False, 0) @@ -282,20 +311,47 @@ class Filters(threading.Thread): vbox1.pack_start(hbox, False, False, 0) else: vbox2.pack_start(hbox, False, False, 0) - self.cbLimits[line[0]] = self.createLimitLine(hbox, line[0]) + self.cbLimits[line[0]] = self.createLimitLine(hbox, line[0], line[0]) if "LimitSep" in display and display["LimitSep"] == True and len(result) >= 2: hbox = gtk.HBox(False, 0) vbox.pack_start(hbox, False, True, 0) - self.cbAllLimits = self.createLimitLine(hbox, "All") + self.cbAllLimits = self.createLimitLine(hbox, 'all', self.filterText['limitsall']) hbox = gtk.HBox(False, 0) vbox.pack_start(hbox, False, True, 0) - self.cbNoLimits = self.createLimitLine(hbox, "None") + self.cbNoLimits = self.createLimitLine(hbox, 'none', self.filterText['limitsnone']) hbox = gtk.HBox(False, 0) vbox.pack_start(hbox, False, True, 0) - cb = self.createLimitLine(hbox, "Separate levels") + cb = self.createLimitLine(hbox, 'show', self.filterText['limitsshow']) else: print "INFO: No games returned from database" + def fillSeatsFrame(self, vbox): + hbox = gtk.HBox(False, 0) + vbox.pack_start(hbox, False, True, 0) + + lbl_from = gtk.Label(self.filterText['seatsbetween']) + lbl_to = gtk.Label(self.filterText['seatsand']) + adj1 = gtk.Adjustment(value=2, lower=2, upper=10, step_incr=1, page_incr=1, page_size=0) + sb1 = gtk.SpinButton(adjustment=adj1, climb_rate=0.0, digits=0) + adj2 = gtk.Adjustment(value=10, lower=2, upper=10, step_incr=1, page_incr=1, page_size=0) + sb2 = gtk.SpinButton(adjustment=adj2, climb_rate=0.0, digits=0) + cb = gtk.CheckButton(self.filterText['seatsand']) + cb.connect('clicked', self.__set_seat_select, 'show') + + hbox.pack_start(lbl_from, expand=False, padding=3) + hbox.pack_start(sb1, False, False, 0) + hbox.pack_start(lbl_to, expand=False, padding=3) + hbox.pack_start(sb2, False, False, 0) + + hbox = gtk.HBox(False, 0) + vbox.pack_start(hbox, False, True, 0) + hbox.pack_start(cb, False, False, 0) + + self.sbSeats['from'] = sb1 + self.sbSeats['to'] = sb2 + self.sbSeats['show'] = cb + self.seats['show'] = False + def fillCardsFrame(self, vbox): hbox1 = gtk.HBox(True,0) hbox1.show() diff --git a/pyfpdb/FpdbSQLQueries.py b/pyfpdb/FpdbSQLQueries.py index ba2d7230..5bb3f7c4 100644 --- a/pyfpdb/FpdbSQLQueries.py +++ b/pyfpdb/FpdbSQLQueries.py @@ -632,7 +632,7 @@ class FpdbSQLQueries: SELECT concat(upper(stats.limitType), ' ' ,concat(upper(substring(stats.category,1,1)),substring(stats.category,2) ), ' ' - ,stats.name, ' $' + ,stats.name, ' ' ,cast(stats.bigBlindDesc as char) ) AS Game ,stats.n @@ -654,6 +654,7 @@ class FpdbSQLQueries: ,case when hprof2.variance = -999 then '-' else format(hprof2.variance, 2) end AS Variance + ,stats.AvgSeats FROM (select /* stats from hudcache */ gt.base @@ -696,11 +697,13 @@ class FpdbSQLQueries: ,format((sum(totalProfit/(gt.bigBlind+0.0))) / (sum(HDs)/100.0),2) AS BBper100 ,format( (sum(totalProfit)/100.0) / sum(HDs), 4) AS Profitperhand + ,format( avg(activeSeats), 1) AS AvgSeats from Gametypes gt inner join Sites s on s.Id = gt.siteId inner join HudCache hc on hc.gameTypeId = gt.Id where hc.playerId in and + and hc.activeSeats group by gt.base ,gt.category ,upper(gt.limitType) @@ -728,12 +731,12 @@ class FpdbSQLQueries: group by hprof.gtId ) hprof2 on hprof2.gtId = stats.gtId - order by stats.category, stats.limittype, stats.bigBlindDesc""" + order by stats.category, stats.limittype, stats.bigBlindDesc """ elif(self.dbname == 'PostgreSQL'): self.query['playerStats'] = """ SELECT upper(stats.limitType) || ' ' || initcap(stats.category) || ' ' - || stats.name || ' $' + || stats.name || ' ' || stats.bigBlindDesc AS Game ,stats.n ,stats.vpip @@ -754,6 +757,7 @@ class FpdbSQLQueries: ,case when hprof2.variance = -999 then '-' else to_char(hprof2.variance, '0D00') end AS Variance + ,AvgSeats FROM (select gt.base ,gt.category @@ -762,7 +766,7 @@ class FpdbSQLQueries: , AS bigBlindDesc , AS gtId ,sum(HDs) as n - ,to_char(100.0*sum(street0VPI)/sum(HDs),'90D0') AS vpip + ,to_char(100.0*sum(street0VPI)/sum(HDs),'990D0') AS vpip ,to_char(100.0*sum(street0Aggr)/sum(HDs),'90D0') AS pfr ,case when sum(street0_3b4bchance) = 0 then '0' else to_char(100.0*sum(street0_3b4bdone)/sum(street0_3b4bchance),'90D0') @@ -795,11 +799,13 @@ class FpdbSQLQueries: ,to_char((sum(totalProfit/(gt.bigBlind+0.0))) / (sum(HDs)/100.0), '990D00') AS BBper100 ,to_char(sum(totalProfit/100.0) / (sum(HDs)+0.0), '990D0000') AS Profitperhand + ,to_char(avg(activeSeats),'90D0') AS AvgSeats from Gametypes gt inner join Sites s on s.Id = gt.siteId inner join HudCache hc on hc.gameTypeId = gt.Id where hc.playerId in and + and hc.activeSeats group by gt.base ,gt.category ,upper(gt.limitType) @@ -827,7 +833,7 @@ class FpdbSQLQueries: group by hprof.gtId ) hprof2 on hprof2.gtId = stats.gtId - order by stats.base, stats.limittype, stats.bigBlindDesc""" + order by stats.base, stats.limittype, stats.bigBlindDesc """ elif(self.dbname == 'SQLite'): self.query['playerStats'] = """ """ @@ -836,7 +842,7 @@ class FpdbSQLQueries: SELECT concat(upper(stats.limitType), ' ' ,concat(upper(substring(stats.category,1,1)),substring(stats.category,2) ), ' ' - ,stats.name, ' $' + ,stats.name, ' ' ,cast(stats.bigBlindDesc as char) ) AS Game ,case when stats.PlPosition = -2 then 'BB' @@ -866,6 +872,7 @@ class FpdbSQLQueries: ,case when hprof2.variance = -999 then '-' else format(hprof2.variance, 2) end AS Variance + ,stats.AvgSeats FROM (select /* stats from hudcache */ gt.base @@ -916,17 +923,20 @@ class FpdbSQLQueries: ,format((sum(totalProfit/(gt.bigBlind+0.0))) / (sum(HDs)/100.0),2) AS BBper100 ,format( (sum(totalProfit)/100.0) / sum(HDs), 4) AS Profitperhand + ,format( avg(activeSeats), 1) AS AvgSeats from Gametypes gt inner join Sites s on s.Id = gt.siteId inner join HudCache hc on hc.gameTypeId = gt.Id where hc.playerId in and + and hc.activeSeats group by gt.base ,gt.category ,upper(gt.limitType) ,s.name ,gtId + ,PlPosition ) stats inner join @@ -957,14 +967,15 @@ class FpdbSQLQueries: ) hprof2 on ( hprof2.gtId = stats.gtId and hprof2.PlPosition = stats.PlPosition) - order by stats.category, stats.limitType, stats.bigBlindDesc, cast(stats.PlPosition as signed) + order by stats.category, stats.limitType, stats.bigBlindDesc + , cast(stats.PlPosition as signed) """ elif(self.dbname == 'PostgreSQL'): self.query['playerStatsByPosition'] = """ select /* stats from hudcache */ upper(stats.limitType) || ' ' || upper(substr(stats.category,1,1)) || substr(stats.category,2) || ' ' - || stats.name || ' $' + || stats.name || ' ' || stats.bigBlindDesc AS Game ,case when stats.PlPosition = -2 then 'BB' when stats.PlPosition = -1 then 'SB' @@ -993,6 +1004,7 @@ class FpdbSQLQueries: ,case when hprof2.variance = -999 then '-' else to_char(hprof2.variance, '0D00') end AS Variance + ,stats.AvgSeats FROM (select /* stats from hudcache */ gt.base @@ -1010,7 +1022,7 @@ class FpdbSQLQueries: else 9 end AS PlPosition ,sum(HDs) AS n - ,to_char(round(100.0*sum(street0VPI)/sum(HDs)),'90D0') AS vpip + ,to_char(round(100.0*sum(street0VPI)/sum(HDs)),'990D0') AS vpip ,to_char(round(100.0*sum(street0Aggr)/sum(HDs)),'90D0') AS pfr ,case when sum(street0_3b4bchance) = 0 then '0' else to_char(100.0*sum(street0_3b4bdone)/sum(street0_3b4bchance),'90D0') @@ -1046,17 +1058,20 @@ class FpdbSQLQueries: ,case when sum(HDs) = 0 then '0' else to_char( (sum(totalProfit)/100.0) / sum(HDs), '90D0000') end AS Profitperhand + ,to_char(avg(activeSeats),'90D0') AS AvgSeats from Gametypes gt inner join Sites s on (s.Id = gt.siteId) inner join HudCache hc on (hc.gameTypeId = gt.Id) where hc.playerId in and + and hc.activeSeats group by gt.base ,gt.category ,upper(gt.limitType) ,s.name ,gtId + ,PlPosition ) stats inner join @@ -1087,7 +1102,8 @@ class FpdbSQLQueries: ) hprof2 on ( hprof2.gtId = stats.gtId and hprof2.PlPosition = stats.PlPosition) - order by stats.category, stats.limitType, stats.bigBlindDesc, cast(stats.PlPosition as smallint) + order by stats.category, stats.limitType, stats.bigBlindDesc + , cast(stats.PlPosition as smallint) """ elif(self.dbname == 'SQLite'): self.query['playerStatsByPosition'] = """ """ diff --git a/pyfpdb/GuiPlayerStats.py b/pyfpdb/GuiPlayerStats.py index dfc5d1c3..432cd283 100644 --- a/pyfpdb/GuiPlayerStats.py +++ b/pyfpdb/GuiPlayerStats.py @@ -92,6 +92,7 @@ class GuiPlayerStats (threading.Thread): heroes = self.filters.getHeroes() siteids = self.filters.getSiteIds() limits = self.filters.getLimits() + seats = self.filters.getSeats() sitenos = [] playerids = [] @@ -115,11 +116,11 @@ class GuiPlayerStats (threading.Thread): print "No limits found" return - self.createStatsTable(vbox, playerids, sitenos, limits) + self.createStatsTable(vbox, playerids, sitenos, limits, seats) - def createStatsTable(self, vbox, playerids, sitenos, limits): + def createStatsTable(self, vbox, playerids, sitenos, limits, seats): tmp = self.sql.query['playerStats'] - tmp = self.refineQuery(tmp, playerids, sitenos, limits) + tmp = self.refineQuery(tmp, playerids, sitenos, limits, seats) self.cursor.execute(tmp) result = self.cursor.fetchall() cols = 18 @@ -163,7 +164,7 @@ class GuiPlayerStats (threading.Thread): self.db.db.commit() #end def fillStatsFrame(self, vbox): - def refineQuery(self, query, playerids, sitenos, limits): + def refineQuery(self, query, playerids, sitenos, limits, seats): if playerids: nametest = str(tuple(playerids)) nametest = nametest.replace("L", "") @@ -172,6 +173,19 @@ class GuiPlayerStats (threading.Thread): else: query = query.replace("", "1 = 2") + if seats: + query = query.replace('', 'between ' + str(seats['from']) + ' and ' + str(seats['to'])) + if 'show' in seats and seats['show']: + query = query.replace('', ',hc.activeSeats') + query = query.replace('', ',stats.AvgSeats') + else: + query = query.replace('', '') + query = query.replace('', '') + else: + query = query.replace('', 'between 0 and 100') + query = query.replace('', '') + query = query.replace('', '') + if [x for x in limits if str(x).isdigit()]: blindtest = str(tuple([x for x in limits if str(x).isdigit()])) blindtest = blindtest.replace("L", "") @@ -180,7 +194,7 @@ class GuiPlayerStats (threading.Thread): else: query = query.replace("", "gt.bigBlind = -1 ") - groupLevels = "Separate" not in str(limits) + groupLevels = "show" not in str(limits) if groupLevels: if self.db.backend == self.MYSQL_INNODB: bigblindselect = """concat(trim(leading ' ' from @@ -207,25 +221,28 @@ class GuiPlayerStats (threading.Thread): then to_char(max(gt.bigBlind)/100.0,'90D00') else to_char(max(gt.bigBlind)/100.0,'999990') end) """ + bigblindselect = "cast('' as char)" # avoid odd effects when some posns and/or seats + # are missing from some limits (dunno why cast is + # needed but it says "unknown type" otherwise?! query = query.replace("", bigblindselect) query = query.replace("", "") query = query.replace("", "-1") query = query.replace("", "-1") else: if self.db.backend == self.MYSQL_INNODB: - bigblindselect = """trim(leading ' ' from - case when gt.bigBlind < 100 - then format(gt.bigBlind/100.0, 2) - else format(gt.bigBlind/100.0, 0) - end - ) """ + bigblindselect = """concat('$', trim(leading ' ' from + case when gt.bigBlind < 100 + then format(gt.bigBlind/100.0, 2) + else format(gt.bigBlind/100.0, 0) + end + ) ) """ else: - bigblindselect = """trim(leading ' ' from - case when gt.bigBlind < 100 - then to_char(gt.bigBlind/100.0,'90D00') - else to_char(gt.bigBlind/100.0,'999990') - end - ) """ + bigblindselect = """'$' || trim(leading ' ' from + case when gt.bigBlind < 100 + then to_char(gt.bigBlind/100.0,'90D00') + else to_char(gt.bigBlind/100.0,'999990') + end + ) """ query = query.replace("", bigblindselect) query = query.replace("", ",gt.bigBlind") query = query.replace("", "hc.gametypeId") diff --git a/pyfpdb/GuiPositionalStats.py b/pyfpdb/GuiPositionalStats.py index 8ed12172..4498b214 100644 --- a/pyfpdb/GuiPositionalStats.py +++ b/pyfpdb/GuiPositionalStats.py @@ -51,6 +51,7 @@ class GuiPositionalStats (threading.Thread): "Games" : False, "Limits" : True, "LimitSep" : True, + "Seats" : True, "Dates" : False, "Button1" : True, "Button2" : False @@ -79,12 +80,14 @@ class GuiPositionalStats (threading.Thread): # To miss columns out remove them from both tuples (the 1st 2 elements should always be included). # To change the heading just edit the second list element as required # If the first list element does not match a query column that pair is ignored - self.posncols = ( "game", "plposition", "vpip", "pfr", "pf3", "steals" + self.posncols = ( "game", "avgseats", "plposition", "vpip", "pfr", "pf3", "steals" , "saw_f", "sawsd", "wtsdwsf", "wmsd", "flafq", "tuafq", "rvafq" - , "pofafq", "net", "bbper100", "profitperhand", "variance", "n" ) - self.posnheads = ( "Game", "Posn", "VPIP", "PFR", "PF3", "Steals" + , "pofafq", "net", "bbper100", "profitperhand", "variance", "n" + ) + self.posnheads = ( "Game", "Seats", "Posn", "VPIP", "PFR", "PF3", "Steals" , "Saw_F", "SawSD", "WtSDwsF", "W$SD", "FlAFq", "TuAFq", "RvAFq" - , "PoFAFq", "Net($)", "BB/100", "$/hand", "Variance", "Hds" ) + , "PoFAFq", "Net($)", "BB/100", "$/hand", "Variance", "Hds" + ) self.fillStatsFrame(self.stats_frame) statsFrame.add(self.stats_frame) @@ -112,6 +115,7 @@ class GuiPositionalStats (threading.Thread): heroes = self.filters.getHeroes() siteids = self.filters.getSiteIds() limits = self.filters.getLimits() + seats = self.filters.getSeats() sitenos = [] playerids = [] @@ -135,11 +139,11 @@ class GuiPositionalStats (threading.Thread): print "No limits found" return - self.createStatsTable(vbox, playerids, sitenos, limits) + self.createStatsTable(vbox, playerids, sitenos, limits, seats) - def createStatsTable(self, vbox, playerids, sitenos, limits): + def createStatsTable(self, vbox, playerids, sitenos, limits, seats): tmp = self.sql.query['playerStatsByPosition'] - tmp = self.refineQuery(tmp, playerids, sitenos, limits) + tmp = self.refineQuery(tmp, playerids, sitenos, limits, seats) self.cursor.execute(tmp) result = self.cursor.fetchall() self.stats_table = gtk.Table(1, 1, False) # gtk table expands as required @@ -158,14 +162,14 @@ class GuiPositionalStats (threading.Thread): self.stats_table.attach(l, col, col+1, row, row+1, yoptions=gtk.SHRINK) col +=1 - last_game = "" - sqlrow = 0 + last_game,last_seats,sqlrow = "","",0 while sqlrow < rows: if(row%2 == 0): bgcolor = "white" else: bgcolor = "lightgrey" rowprinted=0 + avgcol = colnames.index('avgseats') for col,colname in enumerate(self.posncols): if colname in colnames: sqlcol = colnames.index(colname) @@ -174,9 +178,17 @@ class GuiPositionalStats (threading.Thread): eb = gtk.EventBox() eb.modify_bg(gtk.STATE_NORMAL, gtk.gdk.color_parse(bgcolor)) # print blank row between levels: - if result[sqlrow][sqlcol] and (sqlrow == 0 or result[sqlrow][0] == last_game): - l = gtk.Label(result[sqlrow][sqlcol]) - rowprinted=1 + if result[sqlrow][sqlcol]: + if sqlrow == 0: + l = gtk.Label(result[sqlrow][sqlcol]) + rowprinted=1 + elif result[sqlrow][0] != last_game: + l = gtk.Label(' ') + elif 'show' in seats and seats['show'] and result[sqlrow][avgcol] != last_seats: + l = gtk.Label(' ') + else: + l = gtk.Label(result[sqlrow][sqlcol]) + rowprinted=1 else: l = gtk.Label(' ') if col == 0: @@ -190,13 +202,14 @@ class GuiPositionalStats (threading.Thread): l.show() eb.show() last_game = result[sqlrow][0] + last_seats = result[sqlrow][avgcol] if rowprinted: sqlrow = sqlrow+1 row = row + 1 # show totals at bottom tmp = self.sql.query['playerStats'] - tmp = self.refineQuery(tmp, playerids, sitenos, limits) + tmp = self.refineQuery(tmp, playerids, sitenos, limits, seats) self.cursor.execute(tmp) result = self.cursor.fetchall() @@ -251,7 +264,7 @@ class GuiPositionalStats (threading.Thread): self.db.db.rollback() #end def fillStatsFrame(self, vbox): - def refineQuery(self, query, playerids, sitenos, limits): + def refineQuery(self, query, playerids, sitenos, limits, seats): if playerids: nametest = str(tuple(playerids)) nametest = nametest.replace("L", "") @@ -260,6 +273,19 @@ class GuiPositionalStats (threading.Thread): else: query = query.replace("", "1 = 2") + if seats: + query = query.replace('', 'between ' + str(seats['from']) + ' and ' + str(seats['to'])) + if 'show' in seats and seats['show']: + query = query.replace('', ',hc.activeSeats') + query = query.replace('', ',stats.AvgSeats') + else: + query = query.replace('', '') + query = query.replace('', '') + else: + query = query.replace('', 'between 0 and 100') + query = query.replace('', '') + query = query.replace('', '') + if [x for x in limits if str(x).isdigit()]: blindtest = str(tuple([x for x in limits if str(x).isdigit()])) blindtest = blindtest.replace("L", "") @@ -268,15 +294,16 @@ class GuiPositionalStats (threading.Thread): else: query = query.replace("", "gt.bigBlind = -1 ") - groupLevels = "Separate" not in str(limits) + groupLevels = "show" not in str(limits) if groupLevels: if self.db.backend == self.MYSQL_INNODB: - bigblindselect = """concat(trim(leading ' ' from + bigblindselect = """concat('$' + ,trim(leading ' ' from case when min(gt.bigBlind) < 100 then format(min(gt.bigBlind)/100.0, 2) else format(min(gt.bigBlind)/100.0, 0) end) - ,' - ' + ,' - $' ,trim(leading ' ' from case when max(gt.bigBlind) < 100 then format(max(gt.bigBlind)/100.0, 2) @@ -284,36 +311,40 @@ class GuiPositionalStats (threading.Thread): end) ) """ else: - bigblindselect = """trim(leading ' ' from + bigblindselect = """'$' || + trim(leading ' ' from case when min(gt.bigBlind) < 100 then to_char(min(gt.bigBlind)/100.0,'90D00') else to_char(min(gt.bigBlind)/100.0,'999990') end) - || ' - ' || + || ' - $' || trim(leading ' ' from case when max(gt.bigBlind) < 100 then to_char(max(gt.bigBlind)/100.0,'90D00') else to_char(max(gt.bigBlind)/100.0,'999990') end) """ + bigblindselect = "cast('' as char)" # avoid odd effects when some posns and/or seats + # are missing from some limits (dunno why cast is + # needed but it says "unknown type" otherwise?! query = query.replace("", bigblindselect) query = query.replace("", "") query = query.replace("", "-1") query = query.replace("", "-1") else: if self.db.backend == self.MYSQL_INNODB: - bigblindselect = """trim(leading ' ' from - case when gt.bigBlind < 100 - then format(gt.bigBlind/100.0, 2) - else format(gt.bigBlind/100.0, 0) - end - ) """ + bigblindselect = """concat('$', trim(leading ' ' from + case when gt.bigBlind < 100 + then format(gt.bigBlind/100.0, 2) + else format(gt.bigBlind/100.0, 0) + end + ) )""" else: - bigblindselect = """trim(leading ' ' from - case when gt.bigBlind < 100 - then to_char(gt.bigBlind/100.0,'90D00') - else to_char(gt.bigBlind/100.0,'999990') - end - ) """ + bigblindselect = """'$' || trim(leading ' ' from + case when gt.bigBlind < 100 + then to_char(gt.bigBlind/100.0,'90D00') + else to_char(gt.bigBlind/100.0,'999990') + end + ) """ query = query.replace("", bigblindselect) query = query.replace("", ",gt.bigBlind") query = query.replace("", "hc.gametypeId")