Merge branch 'master' of git://git.assembla.com/fpdboz.git
This commit is contained in:
commit
2e4c792bbe
83
pyfpdb/Card.py
Executable file
83
pyfpdb/Card.py
Executable file
|
@ -0,0 +1,83 @@
|
|||
#!/usr/bin/python
|
||||
|
||||
#Copyright 2008 Carl Gherardi
|
||||
#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 <http://www.gnu.org/licenses/>.
|
||||
#In the "official" distribution you can find the license in
|
||||
#agpl-3.0.txt in the docs folder of the package.
|
||||
|
||||
|
||||
|
||||
|
||||
def twoStartCards(value1, suit1, value2, suit2):
|
||||
""" Function to convert 2 value,suit pairs into a Holdem style starting hand e.g. AQo
|
||||
Hand is stored as an int 13 * x + y where (x+2) represents rank of 1st card and
|
||||
(y+2) represents rank of second card (2=2 .. 14=Ace)
|
||||
If x > y then pair is suited, if x < y then unsuited"""
|
||||
if value1 < 2 or value2 < 2:
|
||||
return(0)
|
||||
if (suit1 == suit2 and value1 < value2) or (suit1 != suit2 and value2 > value1):
|
||||
return(13 * (value2-2) + (value1-1))
|
||||
else:
|
||||
return(13 * (value1-2) + (value2-1))
|
||||
|
||||
def twoStartCardString(card):
|
||||
""" Function to convert an int representing 2 holdem hole cards (as created by twoStartCards)
|
||||
into a string like AQo """
|
||||
if card <= 0:
|
||||
return 'xx'
|
||||
else:
|
||||
card -= 1
|
||||
s = ('2', '3', '4', '5', '6', '7', '8', '9', 'T', 'J', 'Q', 'K', 'A')
|
||||
x = card/13
|
||||
y = card - 13*x
|
||||
if x == y: return(s[x] + s[y])
|
||||
elif x > y: return(s[x] + s[y] + 's')
|
||||
else: return(s[y] + s[x] + 'o')
|
||||
|
||||
def fourStartCards(value1, suit1, value2, suit2, value3, suit3, value4, suit4):
|
||||
""" Function to convert 4 value,suit pairs into a Omaha style starting hand,
|
||||
haven't decided how to encode this yet """
|
||||
# This doesn't actually do anything yet - CG
|
||||
|
||||
# What combinations do we need to store? just cards: AA23? some suits as well e.g. when
|
||||
# double suited ATcKTd? Lots more possible combos than holdem :-( 270K vs 1326? not sure
|
||||
# Probably need to use this field as a key into some other table - sc
|
||||
|
||||
#AAKKds
|
||||
#AAKKs
|
||||
#AAKKr
|
||||
# Is probably what we are looking for
|
||||
return(0)
|
||||
|
||||
def cardFromValueSuit(value, suit):
|
||||
""" 0=none, 1-13=2-Ah 14-26=2-Ad 27-39=2-Ac 40-52=2-As """
|
||||
if suit == 'h': return(value-1)
|
||||
elif suit == 'd': return(value+12)
|
||||
elif suit == 'c': return(value+25)
|
||||
elif suit == 's': return(value+38)
|
||||
else: return(0)
|
||||
|
||||
def valueSuitFromCard(card):
|
||||
""" Function to convert a card stored in the database (int 0-52) into value
|
||||
and suit like 9s, 4c etc """
|
||||
if card < 0 or card > 52:
|
||||
return('')
|
||||
else:
|
||||
return( ['', '2h', '3h', '4h', '5h', '6h', '7h', '8h', '9h', 'Th', 'Jh', 'Qh', 'Kh', 'Ah'
|
||||
, '2d', '3d', '4d', '5d', '6d', '7d', '8d', '9d', 'Td', 'Jd', 'Qd', 'Kd', 'Ad'
|
||||
, '2c', '3c', '4c', '5c', '6c', '7c', '8c', '9c', 'Tc', 'Jc', 'Qc', 'Kc', 'Ac'
|
||||
, '2s', '3s', '4s', '5s', '6s', '7s', '8s', '9s', 'Ts', 'Js', 'Qs', 'Ks', 'As'
|
||||
][card] )
|
||||
|
||||
|
||||
|
|
@ -197,6 +197,15 @@ class Aux_window:
|
|||
temp = temp + "%s" % self.layout[layout]
|
||||
return temp
|
||||
|
||||
class HHC:
|
||||
def __init__(self, node):
|
||||
self.site = node.getAttribute("site")
|
||||
self.converter = node.getAttribute("converter")
|
||||
|
||||
def __str__(self):
|
||||
return "%s:\t%s" % (self.site, self.converter)
|
||||
|
||||
|
||||
class Popup:
|
||||
def __init__(self, node):
|
||||
self.name = node.getAttribute("pu_name")
|
||||
|
@ -277,6 +286,7 @@ class Config:
|
|||
self.supported_games = {}
|
||||
self.supported_databases = {}
|
||||
self.aux_windows = {}
|
||||
self.hhcs = {}
|
||||
self.popup_windows = {}
|
||||
|
||||
# s_sites = doc.getElementsByTagName("supported_sites")
|
||||
|
@ -299,6 +309,11 @@ class Config:
|
|||
aw = Aux_window(node = aw_node)
|
||||
self.aux_windows[aw.name] = aw
|
||||
|
||||
# s_dbs = doc.getElementsByTagName("mucked_windows")
|
||||
for hhc_node in doc.getElementsByTagName("hhc"):
|
||||
hhc = HHC(node = hhc_node)
|
||||
self.hhcs[hhc.site] = hhc
|
||||
|
||||
# s_dbs = doc.getElementsByTagName("popup_windows")
|
||||
for pu_node in doc.getElementsByTagName("pu"):
|
||||
pu = Popup(node = pu_node)
|
||||
|
@ -703,6 +718,11 @@ if __name__== "__main__":
|
|||
for w in c.aux_windows.keys():
|
||||
print c.aux_windows[w]
|
||||
print "----------- END AUX WINDOW FORMATS -----------"
|
||||
|
||||
print "\n----------- HAND HISTORY CONVERTERS -----------"
|
||||
for w in c.hhcs.keys():
|
||||
print c.hhcs[w]
|
||||
print "----------- END HAND HISTORY CONVERTERS -----------"
|
||||
|
||||
print "\n----------- POPUP WINDOW FORMATS -----------"
|
||||
for w in c.popup_windows.keys():
|
||||
|
|
|
@ -26,12 +26,14 @@ Create and manage the database objects.
|
|||
# Standard Library modules
|
||||
import sys
|
||||
import traceback
|
||||
from datetime import datetime, date, time, timedelta
|
||||
|
||||
# pyGTK modules
|
||||
|
||||
# FreePokerTools modules
|
||||
import Configuration
|
||||
import SQL
|
||||
import Card
|
||||
|
||||
class Database:
|
||||
def __init__(self, c, db_name, game):
|
||||
|
@ -76,9 +78,40 @@ class Database:
|
|||
print "press enter to continue"
|
||||
sys.exit()
|
||||
|
||||
self.db_server = c.supported_databases[db_name].db_server
|
||||
self.type = c.supported_databases[db_name].db_type
|
||||
self.sql = SQL.Sql(game = game, type = self.type)
|
||||
self.sql = SQL.Sql(game = game, type = self.type, db_server = self.db_server)
|
||||
self.connection.rollback()
|
||||
|
||||
# To add to config:
|
||||
self.hud_style = 'T' # A=All-time
|
||||
# S=Session
|
||||
# T=timed (last n days)
|
||||
# Future values may also include:
|
||||
# H=Hands (last n hands)
|
||||
self.hud_hands = 1000 # Max number of hands from each player to use for hud stats
|
||||
self.hud_days = 90 # Max number of days from each player to use for hud stats
|
||||
self.hud_session_gap = 30 # Gap (minutes) between hands that indicates a change of session
|
||||
# (hands every 2 mins for 1 hour = one session, if followed
|
||||
# by a 40 minute gap and then more hands on same table that is
|
||||
# a new session)
|
||||
cur = self.connection.cursor()
|
||||
|
||||
self.hand_1day_ago = 0
|
||||
cur.execute(self.sql.query['get_hand_1day_ago'])
|
||||
row = cur.fetchone()
|
||||
if row and row[0]:
|
||||
self.hand_1day_ago = row[0]
|
||||
#print "hand 1day ago =", self.hand_1day_ago
|
||||
|
||||
d = timedelta(days=self.hud_days)
|
||||
now = datetime.utcnow() - d
|
||||
self.date_ndays_ago = "d%02d%02d%02d" % (now.year-2000, now.month, now.day)
|
||||
|
||||
self.hand_nhands_ago = 0 # todo
|
||||
#cur.execute(self.sql.query['get_table_name'], (hand_id, ))
|
||||
#row = cur.fetchone()
|
||||
|
||||
def close_connection(self):
|
||||
self.connection.close()
|
||||
|
||||
|
@ -120,20 +153,26 @@ class Database:
|
|||
"""Get and return the cards for each player in the hand."""
|
||||
cards = {} # dict of cards, the key is the seat number example: {1: 'AcQd9hTs5d'}
|
||||
c = self.connection.cursor()
|
||||
c.execute(self.sql.query['get_cards'], hand)
|
||||
c.execute(self.sql.query['get_cards'], [hand])
|
||||
colnames = [desc[0] for desc in c.description]
|
||||
cardnames = ['card1', 'card2', 'card3', 'card4', 'card5', 'card6', 'card7']
|
||||
for row in c.fetchall():
|
||||
s_dict = {}
|
||||
for name, val in zip(colnames, row):
|
||||
s_dict[name] = val
|
||||
cards[s_dict['seat_number']] = (self.convert_cards(s_dict))
|
||||
cs = ['', '', '', '', '', '', '']
|
||||
seat = -1
|
||||
for col,name in enumerate(colnames):
|
||||
if name in cardnames:
|
||||
cs[cardnames.index(name)] = Card.valueSuitFromCard(row[col])
|
||||
elif name == 'seat_number':
|
||||
seat = row[col]
|
||||
if seat != -1:
|
||||
cards[seat] = ''.join(cs)
|
||||
return cards
|
||||
|
||||
def get_common_cards(self, hand):
|
||||
"""Get and return the community cards for the specified hand."""
|
||||
cards = {}
|
||||
c = self.connection.cursor()
|
||||
c.execute(self.sql.query['get_common_cards'], hand)
|
||||
c.execute(self.sql.query['get_common_cards'], [hand])
|
||||
colnames = [desc[0] for desc in c.description]
|
||||
for row in c.fetchall():
|
||||
s_dict = {}
|
||||
|
@ -184,24 +223,79 @@ class Database:
|
|||
return winners
|
||||
|
||||
def get_stats_from_hand(self, hand, aggregate = False):
|
||||
if self.hud_style == 'S':
|
||||
return( self.get_stats_from_hand_session(hand) )
|
||||
else: # self.hud_style == A
|
||||
if aggregate:
|
||||
query = 'get_stats_from_hand_aggregated'
|
||||
else:
|
||||
query = 'get_stats_from_hand'
|
||||
|
||||
if self.hud_style == 'T':
|
||||
stylekey = self.date_ndays_ago
|
||||
else: # assume A (all-time)
|
||||
stylekey = '0000000' # all stylekey values should be higher than this
|
||||
|
||||
subs = (hand, hand, stylekey)
|
||||
#print "get stats: hud style =", self.hud_style, "subs =", subs
|
||||
c = self.connection.cursor()
|
||||
|
||||
if aggregate:
|
||||
query = 'get_stats_from_hand_aggregated'
|
||||
subs = (hand, hand, hand)
|
||||
else:
|
||||
query = 'get_stats_from_hand'
|
||||
subs = (hand, hand)
|
||||
|
||||
# now get the stats
|
||||
# now get the stats
|
||||
c.execute(self.sql.query[query], subs)
|
||||
colnames = [desc[0] for desc in c.description]
|
||||
stat_dict = {}
|
||||
for row in c.fetchall():
|
||||
t_dict = {}
|
||||
for name, val in zip(colnames, row):
|
||||
t_dict[name] = val
|
||||
t_dict[name.lower()] = val
|
||||
# print t_dict
|
||||
stat_dict[t_dict['player_id']] = t_dict
|
||||
|
||||
return stat_dict
|
||||
|
||||
# uses query on handsplayers instead of hudcache to get stats on just this session
|
||||
def get_stats_from_hand_session(self, hand):
|
||||
|
||||
if self.hud_style == 'S':
|
||||
query = self.sql.query['get_stats_from_hand_session']
|
||||
if self.db_server == 'mysql':
|
||||
query = query.replace("<signed>", 'signed ')
|
||||
else:
|
||||
query = query.replace("<signed>", '')
|
||||
else: # self.hud_style == A
|
||||
return None
|
||||
|
||||
subs = (self.hand_1day_ago, hand)
|
||||
c = self.connection.cursor()
|
||||
|
||||
# now get the stats
|
||||
#print "sess_stats: subs =", subs, "subs[0] =", subs[0]
|
||||
c.execute(query, subs)
|
||||
colnames = [desc[0] for desc in c.description]
|
||||
n,stat_dict = 0,{}
|
||||
row = c.fetchone()
|
||||
while row:
|
||||
if colnames[0].lower() == 'player_id':
|
||||
playerid = row[0]
|
||||
else:
|
||||
print "ERROR: query %s result does not have player_id as first column" % (query,)
|
||||
break
|
||||
|
||||
for name, val in zip(colnames, row):
|
||||
if not playerid in stat_dict:
|
||||
stat_dict[playerid] = {}
|
||||
stat_dict[playerid][name.lower()] = val
|
||||
elif not name.lower() in stat_dict[playerid]:
|
||||
stat_dict[playerid][name.lower()] = val
|
||||
elif name.lower() not in ('hand_id', 'player_id', 'seat', 'screen_name', 'seats'):
|
||||
stat_dict[playerid][name.lower()] += val
|
||||
n += 1
|
||||
if n >= 4000: break # todo: don't think this is needed so set nice and high
|
||||
# for now - comment out or remove?
|
||||
row = c.fetchone()
|
||||
#print " %d rows fetched, len(stat_dict) = %d" % (n, len(stat_dict))
|
||||
|
||||
#print "session stat_dict =", stat_dict
|
||||
return stat_dict
|
||||
|
||||
def get_player_id(self, config, site, player_name):
|
||||
|
@ -209,7 +303,10 @@ class Database:
|
|||
c = self.connection.cursor()
|
||||
c.execute(self.sql.query['get_player_id'], {'player': player_name, 'site': site})
|
||||
row = c.fetchone()
|
||||
return row[0]
|
||||
if row:
|
||||
return row[0]
|
||||
else:
|
||||
return None
|
||||
|
||||
if __name__=="__main__":
|
||||
c = Configuration.Config()
|
||||
|
@ -225,16 +322,17 @@ if __name__=="__main__":
|
|||
print "last hand = ", h
|
||||
|
||||
hero = db_connection.get_player_id(c, 'PokerStars', 'nutOmatic')
|
||||
print "nutOmatic is id_player = %d" % hero
|
||||
if hero:
|
||||
print "nutOmatic is id_player = %d" % hero
|
||||
|
||||
stat_dict = db_connection.get_stats_from_hand(h)
|
||||
for p in stat_dict.keys():
|
||||
print p, " ", stat_dict[p]
|
||||
|
||||
print "nutOmatics stats:"
|
||||
stat_dict = db_connection.get_stats_from_hand(h, hero)
|
||||
for p in stat_dict.keys():
|
||||
print p, " ", stat_dict[p]
|
||||
#print "nutOmatics stats:"
|
||||
#stat_dict = db_connection.get_stats_from_hand(h, hero)
|
||||
#for p in stat_dict.keys():
|
||||
# print p, " ", stat_dict[p]
|
||||
|
||||
print "cards =", db_connection.get_cards(73525)
|
||||
db_connection.close_connection
|
||||
|
|
|
@ -26,8 +26,10 @@ class DerivedStats():
|
|||
self.HDs = 0
|
||||
self.street0VPI = 0
|
||||
self.street0Aggr = 0
|
||||
self.street0_3B4BChance = 0
|
||||
self.street0_3B4BDone = 0
|
||||
self.street0_3BChance = 0
|
||||
self.street0_3BDone = 0
|
||||
self.street0_4BChance = 0
|
||||
self.street0_4BDone = 0
|
||||
|
||||
self.street1Seen = 0
|
||||
self.street2Seen = 0
|
||||
|
|
540
pyfpdb/Filters.py
Normal file
540
pyfpdb/Filters.py
Normal file
|
@ -0,0 +1,540 @@
|
|||
#!/usr/bin/python
|
||||
|
||||
#Copyright 2008 Steffen Jobbagy-Felso
|
||||
#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 <http://www.gnu.org/licenses/>.
|
||||
#In the "official" distribution you can find the license in
|
||||
#agpl-3.0.txt in the docs folder of the package.
|
||||
|
||||
import threading
|
||||
import pygtk
|
||||
pygtk.require('2.0')
|
||||
import gtk
|
||||
import os
|
||||
import sys
|
||||
from optparse import OptionParser
|
||||
from time import *
|
||||
#import pokereval
|
||||
|
||||
import Configuration
|
||||
import fpdb_db
|
||||
import FpdbSQLQueries
|
||||
|
||||
class Filters(threading.Thread):
|
||||
def __init__(self, db, settings, config, qdict, display = {},debug=True):
|
||||
self.debug=debug
|
||||
#print "start of GraphViewer constructor"
|
||||
self.db=db
|
||||
self.cursor=db.cursor
|
||||
self.settings=settings
|
||||
self.sql=qdict
|
||||
self.conf = config
|
||||
self.display = display
|
||||
|
||||
self.sites = {}
|
||||
self.games = {}
|
||||
self.limits = {}
|
||||
self.seats = {}
|
||||
self.siteid = {}
|
||||
self.heroes = {}
|
||||
self.boxes = {}
|
||||
|
||||
# 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:', 'seatsshow':'Show Number of _Players'
|
||||
,'limitstitle':'Limits:', 'seatstitle':'Number of Players:'
|
||||
}
|
||||
|
||||
# For use in date ranges.
|
||||
self.start_date = gtk.Entry(max=12)
|
||||
self.end_date = gtk.Entry(max=12)
|
||||
self.start_date.set_property('editable', False)
|
||||
self.end_date.set_property('editable', False)
|
||||
|
||||
# Outer Packing box
|
||||
self.mainVBox = gtk.VBox(False, 0)
|
||||
|
||||
playerFrame = gtk.Frame("Hero:")
|
||||
playerFrame.set_label_align(0.0, 0.0)
|
||||
vbox = gtk.VBox(False, 0)
|
||||
|
||||
self.fillPlayerFrame(vbox)
|
||||
playerFrame.add(vbox)
|
||||
self.boxes['player'] = vbox
|
||||
|
||||
sitesFrame = gtk.Frame("Sites:")
|
||||
sitesFrame.set_label_align(0.0, 0.0)
|
||||
vbox = gtk.VBox(False, 0)
|
||||
|
||||
self.fillSitesFrame(vbox)
|
||||
sitesFrame.add(vbox)
|
||||
self.boxes['sites'] = vbox
|
||||
|
||||
# Game types
|
||||
gamesFrame = gtk.Frame("Games:")
|
||||
gamesFrame.set_label_align(0.0, 0.0)
|
||||
gamesFrame.show()
|
||||
vbox = gtk.VBox(False, 0)
|
||||
|
||||
self.fillGamesFrame(vbox)
|
||||
gamesFrame.add(vbox)
|
||||
self.boxes['games'] = vbox
|
||||
|
||||
# Limits
|
||||
limitsFrame = gtk.Frame()
|
||||
limitsFrame.show()
|
||||
vbox = gtk.VBox(False, 0)
|
||||
self.cbLimits = {}
|
||||
self.cbNoLimits = None
|
||||
self.cbAllLimits = None
|
||||
|
||||
self.fillLimitsFrame(vbox, self.display)
|
||||
limitsFrame.add(vbox)
|
||||
|
||||
# Seats
|
||||
seatsFrame = gtk.Frame()
|
||||
seatsFrame.show()
|
||||
vbox = gtk.VBox(False, 0)
|
||||
self.sbSeats = {}
|
||||
|
||||
self.fillSeatsFrame(vbox, self.display)
|
||||
seatsFrame.add(vbox)
|
||||
|
||||
# Date
|
||||
dateFrame = gtk.Frame("Date:")
|
||||
dateFrame.set_label_align(0.0, 0.0)
|
||||
dateFrame.show()
|
||||
vbox = gtk.VBox(False, 0)
|
||||
|
||||
self.fillDateFrame(vbox)
|
||||
dateFrame.add(vbox)
|
||||
self.boxes['date'] = vbox
|
||||
|
||||
# Buttons
|
||||
self.Button1=gtk.Button("Unnamed 1")
|
||||
self.Button1.set_sensitive(False)
|
||||
|
||||
self.Button2=gtk.Button("Unnamed 2")
|
||||
self.Button2.set_sensitive(False)
|
||||
|
||||
self.mainVBox.add(playerFrame)
|
||||
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)
|
||||
|
||||
self.mainVBox.show_all()
|
||||
|
||||
# Should do this cleaner
|
||||
if "Heroes" not in self.display or self.display["Heroes"] == False:
|
||||
playerFrame.hide()
|
||||
if "Sites" not in self.display or self.display["Sites"] == False:
|
||||
sitesFrame.hide()
|
||||
if "Games" not in self.display or self.display["Games"] == False:
|
||||
gamesFrame.hide()
|
||||
if "Limits" not in self.display or self.display["Limits"] == False:
|
||||
limitsFrame.hide()
|
||||
if "Seats" not in self.display or self.display["Seats"] == False:
|
||||
seatsFrame.hide()
|
||||
if "Dates" not in self.display or self.display["Dates"] == False:
|
||||
dateFrame.hide()
|
||||
if "Button1" not in self.display or self.display["Button1"] == False:
|
||||
self.Button1.hide()
|
||||
if "Button2" not in self.display or self.display["Button2"] == False:
|
||||
self.Button2.hide()
|
||||
|
||||
def get_vbox(self):
|
||||
"""returns the vbox of this thread"""
|
||||
return self.mainVBox
|
||||
#end def get_vbox
|
||||
|
||||
def getSites(self):
|
||||
return self.sites
|
||||
|
||||
def getSiteIds(self):
|
||||
return self.siteid
|
||||
|
||||
def getHeroes(self):
|
||||
return self.heroes
|
||||
|
||||
def getLimits(self):
|
||||
ltuple = []
|
||||
for l in self.limits:
|
||||
if self.limits[l] == True:
|
||||
ltuple.append(l)
|
||||
return ltuple
|
||||
|
||||
def getSeats(self):
|
||||
if 'from' in self.sbSeats:
|
||||
self.seats['from'] = self.sbSeats['from'].get_value_as_int()
|
||||
if 'to' in self.sbSeats:
|
||||
self.seats['to'] = self.sbSeats['to'].get_value_as_int()
|
||||
return self.seats
|
||||
|
||||
def getDates(self):
|
||||
return self.__get_dates()
|
||||
|
||||
def registerButton1Name(self, title):
|
||||
self.Button1.set_label(title)
|
||||
|
||||
def registerButton1Callback(self, callback):
|
||||
self.Button1.connect("clicked", callback, "clicked")
|
||||
self.Button1.set_sensitive(True)
|
||||
|
||||
def registerButton2Name(self, title):
|
||||
self.Button2.set_label(title)
|
||||
|
||||
def registerButton2Callback(self, callback):
|
||||
self.Button2.connect("clicked", callback, "clicked")
|
||||
self.Button2.set_sensitive(True)
|
||||
|
||||
def cardCallback(self, widget, data=None):
|
||||
print "DEBUG: %s was toggled %s" % (data, ("OFF", "ON")[widget.get_active()])
|
||||
|
||||
def createPlayerLine(self, hbox, site, player):
|
||||
label = gtk.Label(site +" id:")
|
||||
hbox.pack_start(label, False, False, 0)
|
||||
|
||||
pname = gtk.Entry()
|
||||
pname.set_text(player)
|
||||
pname.set_width_chars(20)
|
||||
hbox.pack_start(pname, False, True, 0)
|
||||
pname.connect("changed", self.__set_hero_name, site)
|
||||
#TODO: Look at GtkCompletion - to fill out usernames
|
||||
|
||||
self.__set_hero_name(pname, site)
|
||||
|
||||
def __set_hero_name(self, w, site):
|
||||
self.heroes[site] = w.get_text()
|
||||
# print "DEBUG: settings heroes[%s]: %s"%(site, self.heroes[site])
|
||||
|
||||
def createSiteLine(self, hbox, site):
|
||||
cb = gtk.CheckButton(site)
|
||||
cb.connect('clicked', self.__set_site_select, site)
|
||||
cb.set_active(True)
|
||||
hbox.pack_start(cb, False, False, 0)
|
||||
|
||||
def createGameLine(self, hbox, game):
|
||||
cb = gtk.CheckButton(game)
|
||||
cb.connect('clicked', self.__set_game_select, game)
|
||||
hbox.pack_start(cb, False, False, 0)
|
||||
|
||||
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":
|
||||
cb.set_active(True)
|
||||
return(cb)
|
||||
|
||||
def __set_site_select(self, w, site):
|
||||
#print w.get_active()
|
||||
self.sites[site] = w.get_active()
|
||||
print "self.sites[%s] set to %s" %(site, self.sites[site])
|
||||
|
||||
def __set_game_select(self, w, game):
|
||||
#print w.get_active()
|
||||
self.games[game] = w.get_active()
|
||||
print "self.games[%s] set to %s" %(game, self.games[game])
|
||||
|
||||
def __set_limit_select(self, w, limit):
|
||||
#print w.get_active()
|
||||
self.limits[limit] = w.get_active()
|
||||
print "self.limit[%s] set to %s" %(limit, self.limits[limit])
|
||||
if str(limit).isdigit():
|
||||
if self.limits[limit]:
|
||||
if self.cbNoLimits != None:
|
||||
self.cbNoLimits.set_active(False)
|
||||
else:
|
||||
if self.cbAllLimits != None:
|
||||
self.cbAllLimits.set_active(False)
|
||||
elif limit == "all":
|
||||
if self.limits[limit]:
|
||||
for cb in self.cbLimits.values():
|
||||
cb.set_active(True)
|
||||
elif limit == "none":
|
||||
if self.limits[limit]:
|
||||
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)
|
||||
vbox.pack_start(pathHBox, False, True, 0)
|
||||
|
||||
player = self.conf.supported_sites[site].screen_name
|
||||
self.createPlayerLine(pathHBox, site, player)
|
||||
|
||||
def fillSitesFrame(self, vbox):
|
||||
for site in self.conf.get_supported_sites():
|
||||
hbox = gtk.HBox(False, 0)
|
||||
vbox.pack_start(hbox, False, True, 0)
|
||||
self.createSiteLine(hbox, site)
|
||||
#Get db site id for filtering later
|
||||
self.cursor.execute(self.sql.query['getSiteId'], (site,))
|
||||
result = self.db.cursor.fetchall()
|
||||
if len(result) == 1:
|
||||
self.siteid[site] = result[0][0]
|
||||
else:
|
||||
print "Either 0 or more than one site matched - EEK"
|
||||
|
||||
def fillGamesFrame(self, vbox):
|
||||
self.cursor.execute(self.sql.query['getGames'])
|
||||
result = self.db.cursor.fetchall()
|
||||
if len(result) >= 1:
|
||||
for line in result:
|
||||
hbox = gtk.HBox(False, 0)
|
||||
vbox.pack_start(hbox, False, True, 0)
|
||||
self.createGameLine(hbox, line[0])
|
||||
else:
|
||||
print "INFO: No games returned from database"
|
||||
|
||||
def fillLimitsFrame(self, vbox, display):
|
||||
hbox = gtk.HBox(False, 0)
|
||||
vbox.pack_start(hbox, False, False, 0)
|
||||
lbl_title = gtk.Label(self.filterText['limitstitle'])
|
||||
lbl_title.set_alignment(xalign=0.0, yalign=0.5)
|
||||
hbox.pack_start(lbl_title, expand=True, padding=3)
|
||||
showb = gtk.Button(label="hide", stock=None, use_underline=True)
|
||||
showb.set_alignment(xalign=1.0, yalign=0.5)
|
||||
showb.connect('clicked', self.__toggle_box, 'limits')
|
||||
hbox.pack_start(showb, expand=False, padding=1)
|
||||
|
||||
vbox1 = gtk.VBox(False, 0)
|
||||
vbox.pack_start(vbox1, False, False, 0)
|
||||
self.boxes['limits'] = vbox1
|
||||
|
||||
self.cursor.execute(self.sql.query['getLimits'])
|
||||
result = self.db.cursor.fetchall()
|
||||
if len(result) >= 1:
|
||||
hbox = gtk.HBox(True, 0)
|
||||
vbox1.pack_start(hbox, False, False, 0)
|
||||
vbox2 = gtk.VBox(False, 0)
|
||||
hbox.pack_start(vbox2, False, False, 0)
|
||||
vbox3 = gtk.VBox(False, 0)
|
||||
hbox.pack_start(vbox3, False, False, 0)
|
||||
for i, line in enumerate(result):
|
||||
hbox = gtk.HBox(False, 0)
|
||||
if i <= len(result)/2:
|
||||
vbox2.pack_start(hbox, False, False, 0)
|
||||
else:
|
||||
vbox3.pack_start(hbox, False, False, 0)
|
||||
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)
|
||||
vbox1.pack_start(hbox, False, True, 0)
|
||||
self.cbAllLimits = self.createLimitLine(hbox, 'all', self.filterText['limitsall'])
|
||||
hbox = gtk.HBox(False, 0)
|
||||
vbox1.pack_start(hbox, False, True, 0)
|
||||
self.cbNoLimits = self.createLimitLine(hbox, 'none', self.filterText['limitsnone'])
|
||||
hbox = gtk.HBox(False, 0)
|
||||
vbox1.pack_start(hbox, False, True, 0)
|
||||
cb = self.createLimitLine(hbox, 'show', self.filterText['limitsshow'])
|
||||
else:
|
||||
print "INFO: No games returned from database"
|
||||
|
||||
def fillSeatsFrame(self, vbox, display):
|
||||
hbox = gtk.HBox(False, 0)
|
||||
vbox.pack_start(hbox, False, False, 0)
|
||||
lbl_title = gtk.Label(self.filterText['seatstitle'])
|
||||
lbl_title.set_alignment(xalign=0.0, yalign=0.5)
|
||||
hbox.pack_start(lbl_title, expand=True, padding=3)
|
||||
showb = gtk.Button(label="hide", stock=None, use_underline=True)
|
||||
showb.set_alignment(xalign=1.0, yalign=0.5)
|
||||
showb.connect('clicked', self.__toggle_box, 'seats')
|
||||
hbox.pack_start(showb, expand=False, padding=1)
|
||||
|
||||
vbox1 = gtk.VBox(False, 0)
|
||||
vbox.pack_start(vbox1, False, False, 0)
|
||||
self.boxes['seats'] = vbox1
|
||||
|
||||
hbox = gtk.HBox(False, 0)
|
||||
vbox1.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)
|
||||
|
||||
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)
|
||||
|
||||
if "SeatSep" in display and display["SeatSep"] == True:
|
||||
hbox = gtk.HBox(False, 0)
|
||||
vbox1.pack_start(hbox, False, True, 0)
|
||||
cb = gtk.CheckButton(self.filterText['seatsshow'])
|
||||
cb.connect('clicked', self.__set_seat_select, 'show')
|
||||
hbox.pack_start(cb, False, False, 0)
|
||||
self.sbSeats['show'] = cb
|
||||
self.seats['show'] = False
|
||||
|
||||
|
||||
self.sbSeats['from'] = sb1
|
||||
self.sbSeats['to'] = sb2
|
||||
|
||||
def fillCardsFrame(self, vbox):
|
||||
hbox1 = gtk.HBox(True,0)
|
||||
hbox1.show()
|
||||
vbox.pack_start(hbox1, True, True, 0)
|
||||
|
||||
cards = [ "A", "K","Q","J","T","9","8","7","6","5","4","3","2" ]
|
||||
|
||||
for j in range(0, len(cards)):
|
||||
hbox1 = gtk.HBox(True,0)
|
||||
hbox1.show()
|
||||
vbox.pack_start(hbox1, True, True, 0)
|
||||
for i in range(0, len(cards)):
|
||||
if i < (j + 1):
|
||||
suit = "o"
|
||||
else:
|
||||
suit = "s"
|
||||
button = gtk.ToggleButton("%s%s%s" %(cards[i], cards[j], suit))
|
||||
button.connect("toggled", self.cardCallback, "%s%s%s" %(cards[i], cards[j], suit))
|
||||
hbox1.pack_start(button, True, True, 0)
|
||||
button.show()
|
||||
|
||||
def fillDateFrame(self, vbox):
|
||||
# Hat tip to Mika Bostrom - calendar code comes from PokerStats
|
||||
hbox = gtk.HBox()
|
||||
vbox.pack_start(hbox, False, True, 0)
|
||||
|
||||
lbl_start = gtk.Label('From:')
|
||||
|
||||
btn_start = gtk.Button()
|
||||
btn_start.set_image(gtk.image_new_from_stock(gtk.STOCK_INDEX, gtk.ICON_SIZE_BUTTON))
|
||||
btn_start.connect('clicked', self.__calendar_dialog, self.start_date)
|
||||
|
||||
hbox.pack_start(lbl_start, expand=False, padding=3)
|
||||
hbox.pack_start(btn_start, expand=False, padding=3)
|
||||
hbox.pack_start(self.start_date, expand=False, padding=2)
|
||||
|
||||
#New row for end date
|
||||
hbox = gtk.HBox()
|
||||
vbox.pack_start(hbox, False, True, 0)
|
||||
|
||||
lbl_end = gtk.Label(' To:')
|
||||
btn_end = gtk.Button()
|
||||
btn_end.set_image(gtk.image_new_from_stock(gtk.STOCK_INDEX, gtk.ICON_SIZE_BUTTON))
|
||||
btn_end.connect('clicked', self.__calendar_dialog, self.end_date)
|
||||
|
||||
btn_clear = gtk.Button(label=' Clear Dates ')
|
||||
btn_clear.connect('clicked', self.__clear_dates)
|
||||
|
||||
hbox.pack_start(lbl_end, expand=False, padding=3)
|
||||
hbox.pack_start(btn_end, expand=False, padding=3)
|
||||
hbox.pack_start(self.end_date, expand=False, padding=2)
|
||||
|
||||
hbox.pack_start(btn_clear, expand=False, padding=15)
|
||||
|
||||
def __toggle_box(self, widget, entry):
|
||||
if "Limits" not in self.display or self.display["Limits"] == False:
|
||||
self.boxes[entry].hide()
|
||||
elif self.boxes[entry].props.visible:
|
||||
self.boxes[entry].hide()
|
||||
widget.set_label("show")
|
||||
else:
|
||||
self.boxes[entry].show()
|
||||
widget.set_label("hide")
|
||||
|
||||
def __calendar_dialog(self, widget, entry):
|
||||
d = gtk.Window(gtk.WINDOW_TOPLEVEL)
|
||||
d.set_title('Pick a date')
|
||||
|
||||
vb = gtk.VBox()
|
||||
cal = gtk.Calendar()
|
||||
vb.pack_start(cal, expand=False, padding=0)
|
||||
|
||||
btn = gtk.Button('Done')
|
||||
btn.connect('clicked', self.__get_date, cal, entry, d)
|
||||
|
||||
vb.pack_start(btn, expand=False, padding=4)
|
||||
|
||||
d.add(vb)
|
||||
d.set_position(gtk.WIN_POS_MOUSE)
|
||||
d.show_all()
|
||||
|
||||
def __clear_dates(self, w):
|
||||
self.start_date.set_text('')
|
||||
self.end_date.set_text('')
|
||||
|
||||
def __get_dates(self):
|
||||
t1 = self.start_date.get_text()
|
||||
t2 = self.end_date.get_text()
|
||||
|
||||
if t1 == '':
|
||||
t1 = '1970-01-01'
|
||||
if t2 == '':
|
||||
t2 = '2020-12-12'
|
||||
|
||||
return (t1, t2)
|
||||
|
||||
def __get_date(self, widget, calendar, entry, win):
|
||||
# year and day are correct, month is 0..11
|
||||
(year, month, day) = calendar.get_date()
|
||||
month += 1
|
||||
ds = '%04d-%02d-%02d' % (year, month, day)
|
||||
entry.set_text(ds)
|
||||
win.destroy()
|
||||
|
||||
def main(argv=None):
|
||||
"""main can also be called in the python interpreter, by supplying the command line as the argument."""
|
||||
if argv is None:
|
||||
argv = sys.argv[1:]
|
||||
|
||||
def destroy(*args): # call back for terminating the main eventloop
|
||||
gtk.main_quit()
|
||||
|
||||
parser = OptionParser()
|
||||
(options, sys.argv) = parser.parse_args(args = argv)
|
||||
|
||||
config = Configuration.Config()
|
||||
db = None
|
||||
|
||||
settings = {}
|
||||
|
||||
settings.update(config.get_db_parameters())
|
||||
settings.update(config.get_tv_parameters())
|
||||
settings.update(config.get_import_parameters())
|
||||
settings.update(config.get_default_paths())
|
||||
|
||||
db = fpdb_db.fpdb_db()
|
||||
db.connect(settings['db-backend'],
|
||||
settings['db-host'],
|
||||
settings['db-databaseName'],
|
||||
settings['db-user'],
|
||||
settings['db-password'])
|
||||
|
||||
qdict = FpdbSQLQueries.FpdbSQLQueries(db.get_backend_name())
|
||||
|
||||
i = Filters(db, settings, config, qdict)
|
||||
main_window = gtk.Window()
|
||||
main_window.connect('destroy', destroy)
|
||||
main_window.add(i.get_vbox())
|
||||
main_window.show()
|
||||
gtk.main()
|
||||
|
||||
if __name__ == '__main__':
|
||||
sys.exit(main())
|
||||
|
||||
|
File diff suppressed because it is too large
Load Diff
|
@ -57,28 +57,55 @@ class GuiAutoImport (threading.Thread):
|
|||
self.database=settings['db-databaseName']
|
||||
|
||||
self.mainVBox=gtk.VBox(False,1)
|
||||
self.mainVBox.show()
|
||||
|
||||
self.settingsHBox = gtk.HBox(False, 0)
|
||||
self.mainVBox.pack_start(self.settingsHBox, False, True, 0)
|
||||
self.settingsHBox.show()
|
||||
hbox = gtk.HBox(True, 0) # contains 2 equal vboxes
|
||||
self.mainVBox.pack_start(hbox, False, False, 0)
|
||||
|
||||
vbox1 = gtk.VBox(True, 0)
|
||||
hbox.pack_start(vbox1, True, True, 0)
|
||||
vbox2 = gtk.VBox(True, 0)
|
||||
hbox.pack_start(vbox2, True, True, 0)
|
||||
|
||||
self.intervalLabel = gtk.Label("Interval (ie. break) between imports in seconds:")
|
||||
self.settingsHBox.pack_start(self.intervalLabel)
|
||||
self.intervalLabel.show()
|
||||
self.intervalLabel = gtk.Label("Time between imports in seconds:")
|
||||
self.intervalLabel.set_alignment(xalign=1.0, yalign=0.5)
|
||||
vbox1.pack_start(self.intervalLabel, True, True, 0)
|
||||
|
||||
self.intervalEntry=gtk.Entry()
|
||||
hbox = gtk.HBox(False, 0)
|
||||
vbox2.pack_start(hbox, True, True, 0)
|
||||
self.intervalEntry = gtk.Entry()
|
||||
self.intervalEntry.set_text(str(self.config.get_import_parameters().get("interval")))
|
||||
self.settingsHBox.pack_start(self.intervalEntry)
|
||||
self.intervalEntry.show()
|
||||
hbox.pack_start(self.intervalEntry, False, False, 0)
|
||||
lbl1 = gtk.Label()
|
||||
hbox.pack_start(lbl1, expand=True, fill=True)
|
||||
|
||||
self.addSites(self.mainVBox)
|
||||
lbl = gtk.Label('')
|
||||
vbox1.pack_start(lbl, expand=True, fill=True)
|
||||
lbl = gtk.Label('')
|
||||
vbox2.pack_start(lbl, expand=True, fill=True)
|
||||
|
||||
self.addSites(vbox1, vbox2)
|
||||
|
||||
hbox = gtk.HBox(False, 0)
|
||||
self.mainVBox.pack_start(hbox, expand=True, padding=3)
|
||||
|
||||
hbox = gtk.HBox(False, 0)
|
||||
self.mainVBox.pack_start(hbox, expand=False, padding=3)
|
||||
|
||||
lbl1 = gtk.Label()
|
||||
hbox.pack_start(lbl1, expand=True, fill=False)
|
||||
|
||||
self.doAutoImportBool = False
|
||||
self.startButton=gtk.ToggleButton("Start Autoimport")
|
||||
self.startButton = gtk.ToggleButton(" _Start Autoimport ")
|
||||
self.startButton.connect("clicked", self.startClicked, "start clicked")
|
||||
self.mainVBox.add(self.startButton)
|
||||
self.startButton.show()
|
||||
hbox.pack_start(self.startButton, expand=False, fill=False)
|
||||
|
||||
lbl2 = gtk.Label()
|
||||
hbox.pack_start(lbl2, expand=True, fill=False)
|
||||
|
||||
hbox = gtk.HBox(False, 0)
|
||||
hbox.show()
|
||||
self.mainVBox.pack_start(hbox, expand=True, padding=3)
|
||||
self.mainVBox.show_all()
|
||||
|
||||
|
||||
#end of GuiAutoImport.__init__
|
||||
|
@ -127,7 +154,7 @@ class GuiAutoImport (threading.Thread):
|
|||
# to watch.
|
||||
if widget.get_active(): # toggled on
|
||||
self.doAutoImportBool = True
|
||||
widget.set_label(u'Stop Autoimport')
|
||||
widget.set_label(u' _Stop Autoimport ')
|
||||
if self.pipe_to_hud is None:
|
||||
if os.name == 'nt':
|
||||
command = "python HUD_main.py" + " %s" % (self.database)
|
||||
|
@ -163,7 +190,7 @@ class GuiAutoImport (threading.Thread):
|
|||
#print >>self.pipe_to_hud.stdin, "\n"
|
||||
self.pipe_to_hud.communicate('\n') # waits for process to terminate
|
||||
self.pipe_to_hud = None
|
||||
self.startButton.set_label(u'Start Autoimport')
|
||||
self.startButton.set_label(u' _Start Autoimport ')
|
||||
|
||||
|
||||
|
||||
|
@ -177,40 +204,41 @@ class GuiAutoImport (threading.Thread):
|
|||
#Create the site line given required info and setup callbacks
|
||||
#enabling and disabling sites from this interface not possible
|
||||
#expects a box to layout the line horizontally
|
||||
def createSiteLine(self, hbox, site, iconpath, hhpath, filter_name, active = True):
|
||||
def createSiteLine(self, hbox1, hbox2, site, iconpath, hhpath, filter_name, active = True):
|
||||
label = gtk.Label(site + " auto-import:")
|
||||
hbox.pack_start(label, False, False, 0)
|
||||
hbox1.pack_start(label, False, False, 3)
|
||||
label.show()
|
||||
|
||||
dirPath=gtk.Entry()
|
||||
dirPath.set_text(hhpath)
|
||||
hbox.pack_start(dirPath, False, True, 0)
|
||||
hbox1.pack_start(dirPath, True, True, 3)
|
||||
dirPath.show()
|
||||
|
||||
browseButton=gtk.Button("Browse...")
|
||||
browseButton.connect("clicked", self.browseClicked, [site] + [dirPath])
|
||||
hbox.pack_start(browseButton, False, False, 0)
|
||||
hbox2.pack_start(browseButton, False, False, 3)
|
||||
browseButton.show()
|
||||
|
||||
label = gtk.Label(site + " filter:")
|
||||
hbox.pack_start(label, False, False, 0)
|
||||
label = gtk.Label(' ' + site + " filter:")
|
||||
hbox2.pack_start(label, False, False, 3)
|
||||
label.show()
|
||||
|
||||
filter=gtk.Entry()
|
||||
filter.set_text(filter_name)
|
||||
hbox.pack_start(filter, False, True, 0)
|
||||
hbox2.pack_start(filter, True, True, 3)
|
||||
filter.show()
|
||||
|
||||
def addSites(self, vbox):
|
||||
def addSites(self, vbox1, vbox2):
|
||||
the_sites = self.config.get_supported_sites()
|
||||
for site in the_sites:
|
||||
pathHBox = gtk.HBox(False, 0)
|
||||
vbox.pack_start(pathHBox, False, True, 0)
|
||||
pathHBox.show()
|
||||
pathHBox1 = gtk.HBox(False, 0)
|
||||
vbox1.pack_start(pathHBox1, False, True, 0)
|
||||
pathHBox2 = gtk.HBox(False, 0)
|
||||
vbox2.pack_start(pathHBox2, False, True, 0)
|
||||
|
||||
params = self.config.get_site_parameters(site)
|
||||
paths = self.config.get_default_paths(site)
|
||||
self.createSiteLine(pathHBox, site, False, paths['hud-defaultPath'], params['converter'], params['enabled'])
|
||||
self.createSiteLine(pathHBox1, pathHBox2, site, False, paths['hud-defaultPath'], params['converter'], params['enabled'])
|
||||
self.input_settings[site] = [paths['hud-defaultPath']] + [params['converter']]
|
||||
|
||||
if __name__== "__main__":
|
||||
|
|
|
@ -30,7 +30,6 @@ import gtk
|
|||
# fpdb/FreePokerTools modules
|
||||
import fpdb_simple
|
||||
import fpdb_import
|
||||
import fpdb_db
|
||||
import Configuration
|
||||
|
||||
class GuiBulkImport():
|
||||
|
@ -66,13 +65,16 @@ class GuiBulkImport():
|
|||
self.importer.setDropIndexes(cb_model[cb_index][0])
|
||||
else:
|
||||
self.importer.setDropIndexes("auto")
|
||||
hhc=self.cbfilter.get_model()[self.cbfilter.get_active()][0]
|
||||
sitename = self.cbfilter.get_model()[self.cbfilter.get_active()][0]
|
||||
self.lab_info.set_text("Importing")
|
||||
|
||||
self.importer.addBulkImportImportFileOrDir(self.inputFile,filter=hhc)
|
||||
self.importer.addBulkImportImportFileOrDir(self.inputFile, site = sitename)
|
||||
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()
|
||||
|
@ -83,8 +85,7 @@ class GuiBulkImport():
|
|||
"""returns the vbox of this thread"""
|
||||
return self.vbox
|
||||
|
||||
def __init__(self, db, settings, config):
|
||||
self.db = db # this is an instance of fpdb_db
|
||||
def __init__(self, settings, config):
|
||||
self.settings = settings
|
||||
self.config = config
|
||||
self.importer = fpdb_import.Importer(self, self.settings,
|
||||
|
@ -175,11 +176,9 @@ class GuiBulkImport():
|
|||
|
||||
# ComboBox - filter
|
||||
self.cbfilter = gtk.combo_box_new_text()
|
||||
self.cbfilter.append_text("passthrough")
|
||||
self.cbfilter.append_text("BetfairToFpdb")
|
||||
self.cbfilter.append_text("EverleafToFpdb")
|
||||
self.cbfilter.append_text("FulltiltToFpdb")
|
||||
self.cbfilter.append_text("PokerStarsToFpdb")
|
||||
for w in self.config.hhcs:
|
||||
print w
|
||||
self.cbfilter.append_text(w)
|
||||
self.cbfilter.set_active(0)
|
||||
self.table.attach(self.cbfilter, 3, 4, 2, 3, xpadding = 10, ypadding = 0, yoptions=gtk.SHRINK)
|
||||
self.cbfilter.show()
|
||||
|
@ -220,8 +219,8 @@ def main(argv=None):
|
|||
help="Input file in quiet mode")
|
||||
parser.add_option("-q", "--quiet", action="store_false", dest="gui", default=True,
|
||||
help="don't start gui; deprecated (just give a filename with -f).")
|
||||
parser.add_option("-c", "--convert", dest="filtername", default="passthrough", metavar="FILTER",
|
||||
help="Conversion filter (*passthrough, FullTiltToFpdb, PokerStarsToFpdb, EverleafToFpdb)")
|
||||
parser.add_option("-c", "--convert", dest="filtername", default="PokerStars", metavar="FILTER",
|
||||
help="Conversion filter (*Full Tilt Poker, PokerStars, Everleaf)")
|
||||
parser.add_option("-x", "--failOnError", action="store_true", default=False,
|
||||
help="If this option is passed it quits when it encounters any error")
|
||||
parser.add_option("-m", "--minPrint", "--status", dest="minPrint", default="0", type="int",
|
||||
|
@ -229,7 +228,6 @@ def main(argv=None):
|
|||
(options, sys.argv) = parser.parse_args(args = argv)
|
||||
|
||||
config = Configuration.Config()
|
||||
db = None
|
||||
|
||||
settings = {}
|
||||
settings['minPrint'] = options.minPrint
|
||||
|
@ -245,7 +243,7 @@ def main(argv=None):
|
|||
print '-q is deprecated. Just use "-f filename" instead'
|
||||
# This is because -q on its own causes an error, so -f is necessary and sufficient for cmd line use
|
||||
if not options.filename:
|
||||
i = GuiBulkImport(db, settings, config)
|
||||
i = GuiBulkImport(settings, config)
|
||||
main_window = gtk.Window()
|
||||
main_window.connect('destroy', destroy)
|
||||
main_window.add(i.vbox)
|
||||
|
@ -256,7 +254,7 @@ def main(argv=None):
|
|||
importer = fpdb_import.Importer(False,settings, config)
|
||||
importer.setDropIndexes("auto")
|
||||
importer.setFailOnError(options.failOnError)
|
||||
importer.addBulkImportImportFileOrDir(os.path.expanduser(options.filename), filter=options.filtername)
|
||||
importer.addBulkImportImportFileOrDir(os.path.expanduser(options.filename), site=options.filtername)
|
||||
importer.setCallHud(False)
|
||||
importer.runImport()
|
||||
importer.clearFileList()
|
||||
|
|
|
@ -39,269 +39,9 @@ except:
|
|||
|
||||
import fpdb_import
|
||||
import fpdb_db
|
||||
import Filters
|
||||
|
||||
class GuiGraphViewer (threading.Thread):
|
||||
def get_vbox(self):
|
||||
"""returns the vbox of this thread"""
|
||||
return self.mainHBox
|
||||
#end def get_vbox
|
||||
|
||||
def clearGraphData(self):
|
||||
self.fig.clf()
|
||||
if self.canvas is not None:
|
||||
self.canvas.destroy()
|
||||
|
||||
self.canvas = FigureCanvas(self.fig) # a gtk.DrawingArea
|
||||
|
||||
def generateGraph(self, widget, data):
|
||||
self.clearGraphData()
|
||||
|
||||
sitenos = []
|
||||
playerids = []
|
||||
|
||||
# Which sites are selected?
|
||||
for site in self.sites:
|
||||
if self.sites[site] == True:
|
||||
sitenos.append(self.siteid[site])
|
||||
self.cursor.execute(self.sql.query['getPlayerId'], (self.heroes[site],))
|
||||
result = self.db.cursor.fetchall()
|
||||
if len(result) == 1:
|
||||
playerids.append(result[0][0])
|
||||
|
||||
if not sitenos:
|
||||
#Should probably pop up here.
|
||||
print "No sites selected - defaulting to PokerStars"
|
||||
sitenos = [2]
|
||||
|
||||
|
||||
if not playerids:
|
||||
print "No player ids found"
|
||||
return
|
||||
|
||||
|
||||
#Set graph properties
|
||||
self.ax = self.fig.add_subplot(111)
|
||||
|
||||
#Get graph data from DB
|
||||
starttime = time()
|
||||
line = self.getRingProfitGraph(playerids, sitenos)
|
||||
print "Graph generated in: %s" %(time() - starttime)
|
||||
|
||||
self.ax.set_title("Profit graph for ring games")
|
||||
|
||||
#Set axis labels and grid overlay properites
|
||||
self.ax.set_xlabel("Hands", fontsize = 12)
|
||||
self.ax.set_ylabel("$", fontsize = 12)
|
||||
self.ax.grid(color='g', linestyle=':', linewidth=0.2)
|
||||
if(line == None):
|
||||
#TODO: Do something useful like alert user
|
||||
print "No hands returned by graph query"
|
||||
else:
|
||||
# text = "All Hands, " + sitename + str(name) + "\nProfit: $" + str(line[-1]) + "\nTotal Hands: " + str(len(line))
|
||||
text = "All Hands, " + "\nProfit: $" + str(line[-1]) + "\nTotal Hands: " + str(len(line))
|
||||
|
||||
self.ax.annotate(text,
|
||||
xy=(10, -10),
|
||||
xycoords='axes points',
|
||||
horizontalalignment='left', verticalalignment='top',
|
||||
fontsize=10)
|
||||
|
||||
#Draw plot
|
||||
self.ax.plot(line,)
|
||||
|
||||
self.graphBox.add(self.canvas)
|
||||
self.canvas.show()
|
||||
self.exportButton.set_sensitive(True)
|
||||
#end of def showClicked
|
||||
|
||||
def getRingProfitGraph(self, names, sites):
|
||||
tmp = self.sql.query['getRingProfitAllHandsPlayerIdSite']
|
||||
# print "DEBUG: getRingProfitGraph"
|
||||
start_date, end_date = self.__get_dates()
|
||||
|
||||
if start_date == '':
|
||||
start_date = '1970-01-01'
|
||||
if end_date == '':
|
||||
end_date = '2020-12-12'
|
||||
|
||||
#Buggered if I can find a way to do this 'nicely' take a list of intergers and longs
|
||||
# and turn it into a tuple readale by sql.
|
||||
# [5L] into (5) not (5,) and [5L, 2829L] into (5, 2829)
|
||||
nametest = str(tuple(names))
|
||||
sitetest = str(tuple(sites))
|
||||
nametest = nametest.replace("L", "")
|
||||
nametest = nametest.replace(",)",")")
|
||||
sitetest = sitetest.replace(",)",")")
|
||||
|
||||
#Must be a nicer way to deal with tuples of size 1 ie. (2,) - which makes sql barf
|
||||
tmp = tmp.replace("<player_test>", nametest)
|
||||
tmp = tmp.replace("<site_test>", sitetest)
|
||||
tmp = tmp.replace("<startdate_test>", start_date)
|
||||
tmp = tmp.replace("<enddate_test>", end_date)
|
||||
|
||||
# print "DEBUG: sql query:"
|
||||
# print tmp
|
||||
self.cursor.execute(tmp)
|
||||
#returns (HandId,Winnings,Costs,Profit)
|
||||
winnings = self.db.cursor.fetchall()
|
||||
|
||||
if(winnings == ()):
|
||||
return None
|
||||
|
||||
y=map(lambda x:float(x[3]), winnings)
|
||||
line = cumsum(y)
|
||||
return line/100
|
||||
#end of def getRingProfitGraph
|
||||
|
||||
def createPlayerLine(self, hbox, site, player):
|
||||
label = gtk.Label(site +" id:")
|
||||
hbox.pack_start(label, False, False, 0)
|
||||
label.show()
|
||||
|
||||
pname = gtk.Entry()
|
||||
pname.set_text(player)
|
||||
pname.set_width_chars(20)
|
||||
hbox.pack_start(pname, False, True, 0)
|
||||
pname.connect("changed", self.__set_hero_name, site)
|
||||
#TODO: Look at GtkCompletion - to fill out usernames
|
||||
pname.show()
|
||||
|
||||
self.__set_hero_name(pname, site)
|
||||
|
||||
def __set_hero_name(self, w, site):
|
||||
self.heroes[site] = w.get_text()
|
||||
# print "DEBUG: settings heroes[%s]: %s"%(site, self.heroes[site])
|
||||
|
||||
def createSiteLine(self, hbox, site):
|
||||
cb = gtk.CheckButton(site)
|
||||
cb.connect('clicked', self.__set_site_select, site)
|
||||
hbox.pack_start(cb, False, False, 0)
|
||||
cb.show()
|
||||
|
||||
def __set_site_select(self, w, site):
|
||||
# This doesn't behave as intended - self.site only allows 1 site for the moment.
|
||||
print w.get_active()
|
||||
self.sites[site] = w.get_active()
|
||||
print "self.sites[%s] set to %s" %(site, self.sites[site])
|
||||
|
||||
def fillPlayerFrame(self, vbox):
|
||||
for site in self.conf.supported_sites.keys():
|
||||
pathHBox = gtk.HBox(False, 0)
|
||||
vbox.pack_start(pathHBox, False, True, 0)
|
||||
pathHBox.show()
|
||||
|
||||
player = self.conf.supported_sites[site].screen_name
|
||||
self.createPlayerLine(pathHBox, site, player)
|
||||
|
||||
def fillSitesFrame(self, vbox):
|
||||
for site in self.conf.supported_sites.keys():
|
||||
hbox = gtk.HBox(False, 0)
|
||||
vbox.pack_start(hbox, False, True, 0)
|
||||
hbox.show()
|
||||
self.createSiteLine(hbox, site)
|
||||
#Get db site id for filtering later
|
||||
self.cursor.execute(self.sql.query['getSiteId'], (site,))
|
||||
result = self.db.cursor.fetchall()
|
||||
if len(result) == 1:
|
||||
self.siteid[site] = result[0][0]
|
||||
else:
|
||||
print "Either 0 or more than one site matched - EEK"
|
||||
|
||||
def fillDateFrame(self, vbox):
|
||||
# Hat tip to Mika Bostrom - calendar code comes from PokerStats
|
||||
hbox = gtk.HBox()
|
||||
vbox.pack_start(hbox, False, True, 0)
|
||||
hbox.show()
|
||||
|
||||
lbl_start = gtk.Label('From:')
|
||||
lbl_start.show()
|
||||
|
||||
btn_start = gtk.Button()
|
||||
btn_start.set_image(gtk.image_new_from_stock(gtk.STOCK_INDEX, gtk.ICON_SIZE_BUTTON))
|
||||
btn_start.connect('clicked', self.__calendar_dialog, self.start_date)
|
||||
btn_start.show()
|
||||
|
||||
hbox.pack_start(lbl_start, expand=False, padding=3)
|
||||
hbox.pack_start(btn_start, expand=False, padding=3)
|
||||
hbox.pack_start(self.start_date, expand=False, padding=2)
|
||||
self.start_date.show()
|
||||
|
||||
#New row for end date
|
||||
hbox = gtk.HBox()
|
||||
vbox.pack_start(hbox, False, True, 0)
|
||||
hbox.show()
|
||||
|
||||
lbl_end = gtk.Label(' To:')
|
||||
lbl_end.show()
|
||||
btn_end = gtk.Button()
|
||||
btn_end.set_image(gtk.image_new_from_stock(gtk.STOCK_INDEX, gtk.ICON_SIZE_BUTTON))
|
||||
btn_end.connect('clicked', self.__calendar_dialog, self.end_date)
|
||||
btn_end.show()
|
||||
|
||||
btn_clear = gtk.Button(label=' Clear Dates ')
|
||||
btn_clear.connect('clicked', self.__clear_dates)
|
||||
btn_clear.show()
|
||||
|
||||
hbox.pack_start(lbl_end, expand=False, padding=3)
|
||||
hbox.pack_start(btn_end, expand=False, padding=3)
|
||||
hbox.pack_start(self.end_date, expand=False, padding=2)
|
||||
self.end_date.show()
|
||||
|
||||
hbox.pack_start(btn_clear, expand=False, padding=15)
|
||||
|
||||
def __calendar_dialog(self, widget, entry):
|
||||
d = gtk.Window(gtk.WINDOW_TOPLEVEL)
|
||||
d.set_title('Pick a date')
|
||||
|
||||
vb = gtk.VBox()
|
||||
cal = gtk.Calendar()
|
||||
vb.pack_start(cal, expand=False, padding=0)
|
||||
|
||||
btn = gtk.Button('Done')
|
||||
btn.connect('clicked', self.__get_date, cal, entry, d)
|
||||
|
||||
vb.pack_start(btn, expand=False, padding=4)
|
||||
|
||||
d.add(vb)
|
||||
d.set_position(gtk.WIN_POS_MOUSE)
|
||||
d.show_all()
|
||||
|
||||
def __clear_dates(self, w):
|
||||
self.start_date.set_text('')
|
||||
self.end_date.set_text('')
|
||||
|
||||
def __get_dates(self):
|
||||
t1 = self.start_date.get_text()
|
||||
t2 = self.end_date.get_text()
|
||||
return (t1, t2)
|
||||
|
||||
def __get_date(self, widget, calendar, entry, win):
|
||||
# year and day are correct, month is 0..11
|
||||
(year, month, day) = calendar.get_date()
|
||||
month += 1
|
||||
ds = '%04d-%02d-%02d' % (year, month, day)
|
||||
entry.set_text(ds)
|
||||
win.destroy()
|
||||
|
||||
def exportGraph (self, widget, data):
|
||||
if self.fig is None:
|
||||
return # Might want to disable export button until something has been generated.
|
||||
dia_chooser = gtk.FileChooserDialog(title="Please choose the directory you wish to export to:",
|
||||
action=gtk.FILE_CHOOSER_ACTION_OPEN,
|
||||
buttons=(gtk.STOCK_CANCEL,gtk.RESPONSE_CANCEL,gtk.STOCK_OPEN,gtk.RESPONSE_OK))
|
||||
#TODO: Suggest path and filename to start with
|
||||
|
||||
response = dia_chooser.run()
|
||||
if response == gtk.RESPONSE_OK:
|
||||
self.exportDir = dia_chooser.get_filename()
|
||||
print "DEBUG: self.exportDir = %s" %(self.exportDir)
|
||||
elif response == gtk.RESPONSE_CANCEL:
|
||||
print 'Closed, no graph exported'
|
||||
dia_chooser.destroy()
|
||||
#TODO: Check to see if file exists
|
||||
#NOTE: Dangerous - will happily overwrite any file we have write access too
|
||||
#TODO: This asks for a directory but will take a filename and overwrite it.
|
||||
self.fig.savefig(self.exportDir, format="png")
|
||||
|
||||
def __init__(self, db, settings, querylist, config, debug=True):
|
||||
"""Constructor for GraphViewer"""
|
||||
|
@ -313,21 +53,28 @@ class GuiGraphViewer (threading.Thread):
|
|||
self.sql=querylist
|
||||
self.conf = config
|
||||
|
||||
self.sites = {}
|
||||
self.siteid = {}
|
||||
self.heroes = {}
|
||||
filters_display = { "Heroes" : True,
|
||||
"Sites" : True,
|
||||
"Games" : True,
|
||||
"Limits" : True,
|
||||
"Seats" : False,
|
||||
"Dates" : True,
|
||||
"Button1" : True,
|
||||
"Button2" : True
|
||||
}
|
||||
|
||||
self.filters = Filters.Filters(db, settings, config, querylist, display = filters_display)
|
||||
self.filters.registerButton1Name("Refresh Graph")
|
||||
self.filters.registerButton1Callback(self.generateGraph)
|
||||
self.filters.registerButton2Name("Export to File")
|
||||
self.filters.registerButton2Callback(self.exportGraph)
|
||||
|
||||
# For use in date ranges.
|
||||
self.start_date = gtk.Entry(max=12)
|
||||
self.end_date = gtk.Entry(max=12)
|
||||
self.start_date.set_property('editable', False)
|
||||
self.end_date.set_property('editable', False)
|
||||
|
||||
self.mainHBox = gtk.HBox(False, 0)
|
||||
self.mainHBox.show()
|
||||
|
||||
self.leftPanelBox = gtk.VBox(False, 0)
|
||||
self.leftPanelBox = self.filters.get_vbox()
|
||||
self.graphBox = gtk.VBox(False, 0)
|
||||
self.graphBox.show()
|
||||
|
||||
self.hpane = gtk.HPaned()
|
||||
self.hpane.pack1(self.leftPanelBox)
|
||||
|
@ -336,55 +83,15 @@ class GuiGraphViewer (threading.Thread):
|
|||
|
||||
self.mainHBox.add(self.hpane)
|
||||
|
||||
playerFrame = gtk.Frame("Hero:")
|
||||
playerFrame.set_label_align(0.0, 0.0)
|
||||
playerFrame.show()
|
||||
vbox = gtk.VBox(False, 0)
|
||||
vbox.show()
|
||||
|
||||
self.fillPlayerFrame(vbox)
|
||||
playerFrame.add(vbox)
|
||||
|
||||
sitesFrame = gtk.Frame("Sites:")
|
||||
sitesFrame.set_label_align(0.0, 0.0)
|
||||
sitesFrame.show()
|
||||
vbox = gtk.VBox(False, 0)
|
||||
vbox.show()
|
||||
|
||||
self.fillSitesFrame(vbox)
|
||||
sitesFrame.add(vbox)
|
||||
|
||||
dateFrame = gtk.Frame("Date:")
|
||||
dateFrame.set_label_align(0.0, 0.0)
|
||||
dateFrame.show()
|
||||
vbox = gtk.VBox(False, 0)
|
||||
vbox.show()
|
||||
|
||||
self.fillDateFrame(vbox)
|
||||
dateFrame.add(vbox)
|
||||
|
||||
graphButton=gtk.Button("Generate Graph")
|
||||
graphButton.connect("clicked", self.generateGraph, "cliced data")
|
||||
graphButton.show()
|
||||
|
||||
self.fig = None
|
||||
self.exportButton=gtk.Button("Export to File")
|
||||
self.exportButton.connect("clicked", self.exportGraph, "show clicked")
|
||||
self.exportButton.set_sensitive(False)
|
||||
self.exportButton.show()
|
||||
|
||||
self.leftPanelBox.add(playerFrame)
|
||||
self.leftPanelBox.add(sitesFrame)
|
||||
self.leftPanelBox.add(dateFrame)
|
||||
self.leftPanelBox.add(graphButton)
|
||||
self.leftPanelBox.add(self.exportButton)
|
||||
|
||||
self.leftPanelBox.show()
|
||||
self.graphBox.show()
|
||||
#self.exportButton.set_sensitive(False)
|
||||
|
||||
self.fig = Figure(figsize=(5,4), dpi=100)
|
||||
self.canvas = None
|
||||
|
||||
|
||||
self.db.db.rollback()
|
||||
|
||||
#################################
|
||||
#
|
||||
# self.db.cursor.execute("""select UNIX_TIMESTAMP(handStart) as time, id from Hands ORDER BY time""")
|
||||
|
@ -412,3 +119,144 @@ class GuiGraphViewer (threading.Thread):
|
|||
# print "Total: ", total
|
||||
#################################
|
||||
|
||||
|
||||
def get_vbox(self):
|
||||
"""returns the vbox of this thread"""
|
||||
return self.mainHBox
|
||||
#end def get_vbox
|
||||
|
||||
def clearGraphData(self):
|
||||
self.fig.clf()
|
||||
if self.canvas is not None:
|
||||
self.canvas.destroy()
|
||||
|
||||
self.canvas = FigureCanvas(self.fig) # a gtk.DrawingArea
|
||||
|
||||
def generateGraph(self, widget, data):
|
||||
self.clearGraphData()
|
||||
|
||||
sitenos = []
|
||||
playerids = []
|
||||
|
||||
sites = self.filters.getSites()
|
||||
heroes = self.filters.getHeroes()
|
||||
siteids = self.filters.getSiteIds()
|
||||
limits = self.filters.getLimits()
|
||||
# Which sites are selected?
|
||||
for site in sites:
|
||||
if sites[site] == True:
|
||||
sitenos.append(siteids[site])
|
||||
self.cursor.execute(self.sql.query['getPlayerId'], (heroes[site],))
|
||||
result = self.db.cursor.fetchall()
|
||||
if len(result) == 1:
|
||||
playerids.append(result[0][0])
|
||||
|
||||
if not sitenos:
|
||||
#Should probably pop up here.
|
||||
print "No sites selected - defaulting to PokerStars"
|
||||
sitenos = [2]
|
||||
|
||||
if not playerids:
|
||||
print "No player ids found"
|
||||
return
|
||||
|
||||
if not limits:
|
||||
print "No limits found"
|
||||
return
|
||||
|
||||
#Set graph properties
|
||||
self.ax = self.fig.add_subplot(111)
|
||||
|
||||
#Get graph data from DB
|
||||
starttime = time()
|
||||
line = self.getRingProfitGraph(playerids, sitenos, limits)
|
||||
print "Graph generated in: %s" %(time() - starttime)
|
||||
|
||||
self.ax.set_title("Profit graph for ring games")
|
||||
|
||||
#Set axis labels and grid overlay properites
|
||||
self.ax.set_xlabel("Hands", fontsize = 12)
|
||||
self.ax.set_ylabel("$", fontsize = 12)
|
||||
self.ax.grid(color='g', linestyle=':', linewidth=0.2)
|
||||
if line == None or line == []:
|
||||
|
||||
#TODO: Do something useful like alert user
|
||||
print "No hands returned by graph query"
|
||||
else:
|
||||
# text = "All Hands, " + sitename + str(name) + "\nProfit: $" + str(line[-1]) + "\nTotal Hands: " + str(len(line))
|
||||
text = "All Hands, " + "\nProfit: $" + str(line[-1]) + "\nTotal Hands: " + str(len(line))
|
||||
|
||||
self.ax.annotate(text,
|
||||
xy=(10, -10),
|
||||
xycoords='axes points',
|
||||
horizontalalignment='left', verticalalignment='top',
|
||||
fontsize=10)
|
||||
|
||||
#Draw plot
|
||||
self.ax.plot(line,)
|
||||
|
||||
self.graphBox.add(self.canvas)
|
||||
self.canvas.show()
|
||||
#self.exportButton.set_sensitive(True)
|
||||
#end of def showClicked
|
||||
|
||||
def getRingProfitGraph(self, names, sites, limits):
|
||||
tmp = self.sql.query['getRingProfitAllHandsPlayerIdSite']
|
||||
# print "DEBUG: getRingProfitGraph"
|
||||
start_date, end_date = self.filters.getDates()
|
||||
|
||||
#Buggered if I can find a way to do this 'nicely' take a list of intergers and longs
|
||||
# and turn it into a tuple readale by sql.
|
||||
# [5L] into (5) not (5,) and [5L, 2829L] into (5, 2829)
|
||||
nametest = str(tuple(names))
|
||||
sitetest = str(tuple(sites))
|
||||
limittest = str(tuple(limits))
|
||||
nametest = nametest.replace("L", "")
|
||||
nametest = nametest.replace(",)",")")
|
||||
sitetest = sitetest.replace(",)",")")
|
||||
limittest = limittest.replace("L", "")
|
||||
limittest = limittest.replace(",)",")")
|
||||
|
||||
#Must be a nicer way to deal with tuples of size 1 ie. (2,) - which makes sql barf
|
||||
tmp = tmp.replace("<player_test>", nametest)
|
||||
tmp = tmp.replace("<site_test>", sitetest)
|
||||
tmp = tmp.replace("<startdate_test>", start_date)
|
||||
tmp = tmp.replace("<enddate_test>", end_date)
|
||||
tmp = tmp.replace("<limit_test>", limittest)
|
||||
|
||||
#print "DEBUG: sql query:"
|
||||
#print tmp
|
||||
self.cursor.execute(tmp)
|
||||
#returns (HandId,Winnings,Costs,Profit)
|
||||
winnings = self.db.cursor.fetchall()
|
||||
self.db.db.rollback()
|
||||
|
||||
if(winnings == ()):
|
||||
return None
|
||||
|
||||
y=map(lambda x:float(x[3]), winnings)
|
||||
line = cumsum(y)
|
||||
return line/100
|
||||
#end of def getRingProfitGraph
|
||||
|
||||
def exportGraph (self, widget, data):
|
||||
if self.fig is None:
|
||||
return # Might want to disable export button until something has been generated.
|
||||
dia_chooser = gtk.FileChooserDialog(title="Please choose the directory you wish to export to:",
|
||||
action=gtk.FILE_CHOOSER_ACTION_OPEN,
|
||||
buttons=(gtk.STOCK_CANCEL,gtk.RESPONSE_CANCEL,gtk.STOCK_OPEN,gtk.RESPONSE_OK))
|
||||
#TODO: Suggest path and filename to start with
|
||||
|
||||
response = dia_chooser.run()
|
||||
if response == gtk.RESPONSE_OK:
|
||||
self.exportDir = dia_chooser.get_filename()
|
||||
print "DEBUG: self.exportDir = %s" %(self.exportDir)
|
||||
elif response == gtk.RESPONSE_CANCEL:
|
||||
print 'Closed, no graph exported'
|
||||
dia_chooser.destroy()
|
||||
#TODO: Check to see if file exists
|
||||
#NOTE: Dangerous - will happily overwrite any file we have write access too
|
||||
#TODO: This asks for a directory but will take a filename and overwrite it.
|
||||
self.fig.savefig(self.exportDir, format="png")
|
||||
|
||||
|
||||
|
|
|
@ -20,158 +20,421 @@ import pygtk
|
|||
pygtk.require('2.0')
|
||||
import gtk
|
||||
import os
|
||||
|
||||
from time import time, strftime
|
||||
|
||||
import Card
|
||||
import fpdb_import
|
||||
import fpdb_db
|
||||
import Filters
|
||||
import FpdbSQLQueries
|
||||
|
||||
class GuiPlayerStats (threading.Thread):
|
||||
def get_vbox(self):
|
||||
"""returns the vbox of this thread"""
|
||||
return self.main_hbox
|
||||
|
||||
def toggleCallback(self, widget, data=None):
|
||||
# print "%s was toggled %s" % (data, ("OFF", "ON")[widget.get_active()])
|
||||
self.activesite = data
|
||||
print "DEBUG: activesite set to %s" %(self.activesite)
|
||||
|
||||
def refreshStats(self, widget, data):
|
||||
try: self.stats_table.destroy()
|
||||
except AttributeError: pass
|
||||
self.fillStatsFrame(self.stats_frame)
|
||||
|
||||
def fillStatsFrame(self, vbox):
|
||||
# Get currently active site and grab playerid
|
||||
tmp = self.sql.query['playerStats']
|
||||
|
||||
result = self.cursor.execute(self.sql.query['getPlayerId'], (self.heroes[self.activesite],))
|
||||
result = self.cursor.fetchall()
|
||||
if not result == ():
|
||||
pid = result[0][0]
|
||||
pid = result[0][0]
|
||||
tmp = tmp.replace("<player_test>", "(" + str(pid) + ")")
|
||||
self.cursor.execute(tmp)
|
||||
result = self.cursor.fetchall()
|
||||
cols = 16
|
||||
rows = len(result)+1 # +1 for title row
|
||||
self.stats_table = gtk.Table(rows, cols, False)
|
||||
self.stats_table.set_col_spacings(4)
|
||||
self.stats_table.show()
|
||||
vbox.add(self.stats_table)
|
||||
|
||||
# Create header row
|
||||
titles = ("Game", "Hands", "VPIP", "PFR", "Saw_F", "SawSD", "WtSDwsF", "W$SD", "FlAFq", "TuAFq", "RvAFq", "PoFAFq", "Net($)", "BB/100", "$/hand", "Variance")
|
||||
|
||||
col = 0
|
||||
row = 0
|
||||
for t in titles:
|
||||
l = gtk.Label(titles[col])
|
||||
l.show()
|
||||
self.stats_table.attach(l, col, col+1, row, row+1, yoptions=gtk.SHRINK)
|
||||
col +=1
|
||||
|
||||
for row in range(rows-1):
|
||||
if(row%2 == 0):
|
||||
bgcolor = "white"
|
||||
else:
|
||||
bgcolor = "lightgrey"
|
||||
for col in range(cols):
|
||||
eb = gtk.EventBox()
|
||||
eb.modify_bg(gtk.STATE_NORMAL, gtk.gdk.color_parse(bgcolor))
|
||||
if result[row][col]:
|
||||
l = gtk.Label(result[row][col])
|
||||
else:
|
||||
l = gtk.Label(' ')
|
||||
if col == 0:
|
||||
l.set_alignment(xalign=0.0, yalign=0.5)
|
||||
else:
|
||||
l.set_alignment(xalign=1.0, yalign=0.5)
|
||||
eb.add(l)
|
||||
self.stats_table.attach(eb, col, col+1, row+1, row+2, yoptions=gtk.SHRINK)
|
||||
l.show()
|
||||
eb.show()
|
||||
self.fdb.db.commit()
|
||||
#end def fillStatsFrame(self, vbox):
|
||||
|
||||
def fillPlayerFrame(self, vbox):
|
||||
for site in self.conf.supported_sites.keys():
|
||||
hbox = gtk.HBox(False, 0)
|
||||
vbox.pack_start(hbox, False, True, 0)
|
||||
hbox.show()
|
||||
|
||||
player = self.conf.supported_sites[site].screen_name
|
||||
self.createPlayerLine(hbox, site, player)
|
||||
hbox = gtk.HBox(False, 0)
|
||||
button = gtk.Button("Refresh")
|
||||
button.connect("clicked", self.refreshStats, False)
|
||||
button.show()
|
||||
hbox.add(button)
|
||||
vbox.pack_start(hbox, False, True, 0)
|
||||
hbox.show()
|
||||
|
||||
def createPlayerLine(self, hbox, site, player):
|
||||
if(self.buttongroup == None):
|
||||
button = gtk.RadioButton(None, site + " id:")
|
||||
button.set_active(True)
|
||||
self.buttongroup = button
|
||||
self.activesite = site
|
||||
else:
|
||||
button = gtk.RadioButton(self.buttongroup, site + " id:")
|
||||
hbox.pack_start(button, True, True, 0)
|
||||
button.connect("toggled", self.toggleCallback, site)
|
||||
button.show()
|
||||
|
||||
pname = gtk.Entry()
|
||||
pname.set_text(player)
|
||||
pname.set_width_chars(20)
|
||||
hbox.pack_start(pname, False, True, 0)
|
||||
pname.connect("changed", self.__set_hero_name, site)
|
||||
#TODO: Look at GtkCompletion - to fill out usernames
|
||||
pname.show()
|
||||
self.__set_hero_name(pname, site)
|
||||
|
||||
def __set_hero_name(self, w, site):
|
||||
self.heroes[site] = w.get_text()
|
||||
|
||||
def __init__(self, db, config, querylist, debug=True):
|
||||
def __init__(self, config, querylist, mainwin, debug=True):
|
||||
self.debug=debug
|
||||
self.conf=config
|
||||
self.main_window=mainwin
|
||||
self.MYSQL_INNODB = 2
|
||||
self.PGSQL = 3
|
||||
self.SQLITE = 4
|
||||
|
||||
# create new db connection to avoid conflicts with other threads
|
||||
self.fdb = fpdb_db.fpdb_db()
|
||||
self.fdb.do_connect(self.conf)
|
||||
self.cursor=self.fdb.cursor
|
||||
|
||||
self.db = fpdb_db.fpdb_db()
|
||||
self.db.do_connect(self.conf)
|
||||
self.cursor=self.db.cursor
|
||||
self.sql = querylist
|
||||
|
||||
self.activesite = None
|
||||
self.buttongroup = None
|
||||
settings = {}
|
||||
settings.update(config.get_db_parameters())
|
||||
settings.update(config.get_tv_parameters())
|
||||
settings.update(config.get_import_parameters())
|
||||
settings.update(config.get_default_paths())
|
||||
|
||||
# text used on screen stored here so that it can be configured
|
||||
self.filterText = {'handhead':'Hand Breakdown for all levels listed above'
|
||||
}
|
||||
|
||||
filters_display = { "Heroes" : True,
|
||||
"Sites" : True,
|
||||
"Games" : False,
|
||||
"Limits" : True,
|
||||
"LimitSep" : True,
|
||||
"Seats" : True,
|
||||
"SeatSep" : True,
|
||||
"Dates" : False,
|
||||
"Groups" : True,
|
||||
"Button1" : True,
|
||||
"Button2" : True
|
||||
}
|
||||
|
||||
self.filters = Filters.Filters(self.db, settings, config, querylist, display = filters_display)
|
||||
self.filters.registerButton1Name("_Filters")
|
||||
self.filters.registerButton1Callback(self.showDetailFilter)
|
||||
self.filters.registerButton2Name("_Refresh")
|
||||
self.filters.registerButton2Callback(self.refreshStats)
|
||||
|
||||
# ToDo: store in config
|
||||
# ToDo: create popup to adjust column config
|
||||
# columns to display, keys match column name returned by sql, values in tuple are:
|
||||
# is column displayed, column heading, xalignment, formatting
|
||||
self.columns = [ ("game", True, "Game", 0.0, "%s")
|
||||
, ("hand", False, "Hand", 0.0, "%s") # true not allowed for this line
|
||||
, ("n", True, "Hds", 1.0, "%d")
|
||||
, ("avgseats", True, "Seats", 1.0, "%3.1f")
|
||||
, ("vpip", True, "VPIP", 1.0, "%3.1f")
|
||||
, ("pfr", True, "PFR", 1.0, "%3.1f")
|
||||
, ("pf3", True, "PF3", 1.0, "%3.1f")
|
||||
, ("steals", True, "Steals", 1.0, "%3.1f")
|
||||
, ("saw_f", True, "Saw_F", 1.0, "%3.1f")
|
||||
, ("sawsd", True, "SawSD", 1.0, "%3.1f")
|
||||
, ("wtsdwsf", True, "WtSDwsF", 1.0, "%3.1f")
|
||||
, ("wmsd", True, "W$SD", 1.0, "%3.1f")
|
||||
, ("flafq", True, "FlAFq", 1.0, "%3.1f")
|
||||
, ("tuafq", True, "TuAFq", 1.0, "%3.1f")
|
||||
, ("rvafq", True, "RvAFq", 1.0, "%3.1f")
|
||||
, ("pofafq", False, "PoFAFq", 1.0, "%3.1f")
|
||||
, ("net", True, "Net($)", 1.0, "%6.2f")
|
||||
, ("bbper100", True, "BB/100", 1.0, "%4.2f")
|
||||
, ("rake", True, "Rake($)", 1.0, "%6.2f")
|
||||
, ("variance", True, "Variance", 1.0, "%5.2f")
|
||||
]
|
||||
|
||||
# Detail filters: This holds the data used in the popup window, extra values are
|
||||
# added at the end of these lists during processing
|
||||
# sql test, screen description, min, max
|
||||
self.handtests = [ # already in filter class : ['h.seats', 'Number of Players', 2, 10]
|
||||
['h.maxSeats', 'Size of Table', 2, 10]
|
||||
,['h.playersVpi', 'Players who VPI', 0, 10]
|
||||
,['h.playersAtStreet1', 'Players at Flop', 0, 10]
|
||||
,['h.playersAtStreet2', 'Players at Turn', 0, 10]
|
||||
,['h.playersAtStreet3', 'Players at River', 0, 10]
|
||||
,['h.playersAtStreet4', 'Players at Street7', 0, 10]
|
||||
,['h.playersAtShowdown', 'Players at Showdown', 0, 10]
|
||||
,['h.street0Raises', 'Bets to See Flop', 0, 5]
|
||||
,['h.street1Raises', 'Bets to See Turn', 0, 5]
|
||||
,['h.street2Raises', 'Bets to See River', 0, 5]
|
||||
,['h.street3Raises', 'Bets to See Street7', 0, 5]
|
||||
,['h.street4Raises', 'Bets to See Showdown', 0, 5]
|
||||
]
|
||||
|
||||
self.heroes = {}
|
||||
self.stat_table = None
|
||||
self.stats_frame = None
|
||||
self.stats_vbox = None
|
||||
self.detailFilters = [] # the data used to enhance the sql select
|
||||
|
||||
self.main_hbox = gtk.HBox(False, 0)
|
||||
self.main_hbox.show()
|
||||
|
||||
playerFrame = gtk.Frame("Hero:")
|
||||
playerFrame.set_label_align(0.0, 0.0)
|
||||
playerFrame.show()
|
||||
vbox = gtk.VBox(False, 0)
|
||||
vbox.show()
|
||||
|
||||
self.fillPlayerFrame(vbox)
|
||||
playerFrame.add(vbox)
|
||||
|
||||
statsFrame = gtk.Frame("Stats:")
|
||||
statsFrame.set_label_align(0.0, 0.0)
|
||||
statsFrame.show()
|
||||
self.stats_frame = gtk.VBox(False, 0)
|
||||
self.stats_frame = gtk.Frame()
|
||||
self.stats_frame.show()
|
||||
|
||||
self.fillStatsFrame(self.stats_frame)
|
||||
statsFrame.add(self.stats_frame)
|
||||
self.stats_vbox = gtk.VBox(False, 0)
|
||||
self.stats_vbox.show()
|
||||
self.stats_frame.add(self.stats_vbox)
|
||||
self.fillStatsFrame(self.stats_vbox)
|
||||
|
||||
self.main_hbox.pack_start(self.filters.get_vbox())
|
||||
self.main_hbox.pack_start(self.stats_frame, expand=True, fill=True)
|
||||
|
||||
# make sure Hand column is not displayed
|
||||
[x for x in self.columns if x[0] == 'hand'][0][1] == False
|
||||
|
||||
def get_vbox(self):
|
||||
"""returns the vbox of this thread"""
|
||||
return self.main_hbox
|
||||
|
||||
def refreshStats(self, widget, data):
|
||||
try: self.stats_vbox.destroy()
|
||||
except AttributeError: pass
|
||||
self.stats_vbox = gtk.VBox(False, 0)
|
||||
self.stats_vbox.show()
|
||||
self.stats_frame.add(self.stats_vbox)
|
||||
self.fillStatsFrame(self.stats_vbox)
|
||||
|
||||
def fillStatsFrame(self, vbox):
|
||||
sites = self.filters.getSites()
|
||||
heroes = self.filters.getHeroes()
|
||||
siteids = self.filters.getSiteIds()
|
||||
limits = self.filters.getLimits()
|
||||
seats = self.filters.getSeats()
|
||||
sitenos = []
|
||||
playerids = []
|
||||
|
||||
# Which sites are selected?
|
||||
for site in sites:
|
||||
if sites[site] == True:
|
||||
sitenos.append(siteids[site])
|
||||
self.cursor.execute(self.sql.query['getPlayerId'], (heroes[site],))
|
||||
result = self.db.cursor.fetchall()
|
||||
if len(result) == 1:
|
||||
playerids.append(result[0][0])
|
||||
|
||||
if not sitenos:
|
||||
#Should probably pop up here.
|
||||
print "No sites selected - defaulting to PokerStars"
|
||||
sitenos = [2]
|
||||
if not playerids:
|
||||
print "No player ids found"
|
||||
return
|
||||
if not limits:
|
||||
print "No limits found"
|
||||
return
|
||||
|
||||
self.createStatsTable(vbox, playerids, sitenos, limits, seats)
|
||||
|
||||
def createStatsTable(self, vbox, playerids, sitenos, limits, seats):
|
||||
starttime = time()
|
||||
|
||||
# Display summary table at top of page
|
||||
# 3rd parameter passes extra flags, currently includes:
|
||||
# holecards - whether to display card breakdown (True/False)
|
||||
flags = [False]
|
||||
self.addTable(vbox, 'playerDetailedStats', flags, playerids, sitenos, limits, seats)
|
||||
|
||||
# Separator
|
||||
sep = gtk.HSeparator()
|
||||
vbox.pack_start(sep, expand=False, padding=3)
|
||||
sep.show_now()
|
||||
vbox.show_now()
|
||||
heading = gtk.Label(self.filterText['handhead'])
|
||||
heading.show()
|
||||
vbox.pack_start(heading, expand=False, padding=3)
|
||||
|
||||
# Scrolled window for detailed table (display by hand)
|
||||
swin = gtk.ScrolledWindow(hadjustment=None, vadjustment=None)
|
||||
swin.set_policy(gtk.POLICY_AUTOMATIC, gtk.POLICY_AUTOMATIC)
|
||||
swin.show()
|
||||
vbox.pack_start(swin, expand=True, padding=3)
|
||||
|
||||
vbox1 = gtk.VBox(False, 0)
|
||||
vbox1.show()
|
||||
swin.add_with_viewport(vbox1)
|
||||
|
||||
# Detailed table
|
||||
flags = [True]
|
||||
self.addTable(vbox1, 'playerDetailedStats', flags, playerids, sitenos, limits, seats)
|
||||
|
||||
self.db.db.commit()
|
||||
print "Stats page displayed in %4.2f seconds" % (time() - starttime)
|
||||
#end def fillStatsFrame(self, vbox):
|
||||
|
||||
def addTable(self, vbox, query, flags, playerids, sitenos, limits, seats):
|
||||
row = 0
|
||||
sqlrow = 0
|
||||
colalias,colshow,colheading,colxalign,colformat = 0,1,2,3,4
|
||||
if not flags: holecards = False
|
||||
else: holecards = flags[0]
|
||||
|
||||
|
||||
self.stats_table = gtk.Table(1, 1, False)
|
||||
self.stats_table.set_col_spacings(4)
|
||||
self.stats_table.show()
|
||||
|
||||
tmp = self.sql.query[query]
|
||||
tmp = self.refineQuery(tmp, flags, playerids, sitenos, limits, seats)
|
||||
self.cursor.execute(tmp)
|
||||
result = self.cursor.fetchall()
|
||||
colnames = [desc[0].lower() for desc in self.cursor.description]
|
||||
|
||||
# pre-fetch some constant values:
|
||||
cols_to_show = [x for x in self.columns if x[colshow]]
|
||||
hgametypeid_idx = colnames.index('hgametypeid')
|
||||
|
||||
liststore = gtk.ListStore(*([str] * len(cols_to_show)))
|
||||
view = gtk.TreeView(model=liststore)
|
||||
view.set_grid_lines(gtk.TREE_VIEW_GRID_LINES_BOTH)
|
||||
vbox.pack_start(view, expand=False, padding=3)
|
||||
textcell = gtk.CellRendererText()
|
||||
numcell = gtk.CellRendererText()
|
||||
numcell.set_property('xalign', 1.0)
|
||||
listcols = []
|
||||
|
||||
# Create header row eg column: ("game", True, "Game", 0.0, "%s")
|
||||
for col, column in enumerate(cols_to_show):
|
||||
if column[colalias] == 'game' and holecards:
|
||||
s = [x for x in self.columns if x[colalias] == 'hand'][0][colheading]
|
||||
else:
|
||||
s = column[colheading]
|
||||
listcols.append(gtk.TreeViewColumn(s))
|
||||
view.append_column(listcols[col])
|
||||
if column[colformat] == '%s':
|
||||
if col == 1 and holecards:
|
||||
listcols[col].pack_start(textcell, expand=True)
|
||||
else:
|
||||
listcols[col].pack_start(textcell, expand=True)
|
||||
listcols[col].add_attribute(textcell, 'text', col)
|
||||
listcols[col].set_expand(True)
|
||||
else:
|
||||
listcols[col].pack_start(numcell, expand=True)
|
||||
listcols[col].add_attribute(numcell, 'text', col)
|
||||
listcols[col].set_alignment(1.0)
|
||||
listcols[col].set_expand(True)
|
||||
|
||||
rows = len(result) # +1 for title row
|
||||
|
||||
while sqlrow < rows:
|
||||
treerow = []
|
||||
if(row%2 == 0):
|
||||
bgcolor = "white"
|
||||
else:
|
||||
bgcolor = "lightgrey"
|
||||
for col,column in enumerate(cols_to_show):
|
||||
if column[colalias] in colnames:
|
||||
value = result[sqlrow][colnames.index(column[colalias])]
|
||||
else:
|
||||
if column[colalias] == 'game':
|
||||
if holecards:
|
||||
value = Card.twoStartCardString( result[sqlrow][hgametypeid_idx] )
|
||||
else:
|
||||
minbb = result[sqlrow][colnames.index('minbigblind')]
|
||||
maxbb = result[sqlrow][colnames.index('maxbigblind')]
|
||||
value = result[sqlrow][colnames.index('limittype')] + ' ' \
|
||||
+ result[sqlrow][colnames.index('category')].title() + ' ' \
|
||||
+ result[sqlrow][colnames.index('name')] + ' $'
|
||||
if 100 * int(minbb/100.0) != minbb:
|
||||
value += '%.2f' % (minbb/100.0)
|
||||
else:
|
||||
value += '%.0f' % (minbb/100.0)
|
||||
if minbb != maxbb:
|
||||
if 100 * int(maxbb/100.0) != maxbb:
|
||||
value += ' - $' + '%.2f' % (maxbb/100.0)
|
||||
else:
|
||||
value += ' - $' + '%.0f' % (maxbb/100.0)
|
||||
else:
|
||||
continue
|
||||
if value and value != -999:
|
||||
treerow.append(column[colformat] % value)
|
||||
else:
|
||||
treerow.append(' ')
|
||||
iter = liststore.append(treerow)
|
||||
sqlrow += 1
|
||||
row += 1
|
||||
vbox.show_all()
|
||||
|
||||
#end def addTable(self, query, vars, playerids, sitenos, limits, seats):
|
||||
|
||||
def refineQuery(self, query, flags, playerids, sitenos, limits, seats):
|
||||
if not flags: holecards = False
|
||||
else: holecards = flags[0]
|
||||
|
||||
if playerids:
|
||||
nametest = str(tuple(playerids))
|
||||
nametest = nametest.replace("L", "")
|
||||
nametest = nametest.replace(",)",")")
|
||||
query = query.replace("<player_test>", nametest)
|
||||
else:
|
||||
query = query.replace("<player_test>", "1 = 2")
|
||||
|
||||
if seats:
|
||||
query = query.replace('<seats_test>', 'between ' + str(seats['from']) + ' and ' + str(seats['to']))
|
||||
if 'show' in seats and seats['show']:
|
||||
query = query.replace('<groupbyseats>', ',h.seats')
|
||||
query = query.replace('<orderbyseats>', ',h.seats')
|
||||
else:
|
||||
query = query.replace('<groupbyseats>', '')
|
||||
query = query.replace('<orderbyseats>', '')
|
||||
else:
|
||||
query = query.replace('<seats_test>', 'between 0 and 100')
|
||||
query = query.replace('<groupbyseats>', '')
|
||||
query = query.replace('<orderbyseats>', '')
|
||||
|
||||
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", "")
|
||||
blindtest = blindtest.replace(",)",")")
|
||||
query = query.replace("<gtbigBlind_test>", " and gt.bigBlind in " + blindtest + " ")
|
||||
else:
|
||||
query = query.replace("<gtbigBlind_test>", "")
|
||||
|
||||
if holecards: # pinch level variables for hole card query
|
||||
query = query.replace("<hgameTypeId>", "hp.startcards")
|
||||
query = query.replace("<orderbyhgameTypeId>", ",hgameTypeId desc")
|
||||
else:
|
||||
query = query.replace("<orderbyhgameTypeId>", "")
|
||||
groupLevels = "show" not in str(limits)
|
||||
if groupLevels:
|
||||
query = query.replace("<hgameTypeId>", "-1")
|
||||
else:
|
||||
query = query.replace("<hgameTypeId>", "h.gameTypeId")
|
||||
|
||||
# process self.detailFilters (a list of tuples)
|
||||
flagtest = ''
|
||||
#self.detailFilters = [('h.seats', 5, 6)] # for debug
|
||||
if self.detailFilters:
|
||||
for f in self.detailFilters:
|
||||
if len(f) == 3:
|
||||
# X between Y and Z
|
||||
flagtest += ' and %s between %s and %s ' % (f[0], str(f[1]), str(f[2]))
|
||||
query = query.replace("<flagtest>", flagtest)
|
||||
|
||||
# allow for differences in sql cast() function:
|
||||
if self.db.backend == self.MYSQL_INNODB:
|
||||
query = query.replace("<signed>", 'signed ')
|
||||
else:
|
||||
query = query.replace("<signed>", '')
|
||||
|
||||
#print "query =\n", query
|
||||
return(query)
|
||||
#end def refineQuery(self, query, playerids, sitenos, limits):
|
||||
|
||||
def showDetailFilter(self, widget, data):
|
||||
detailDialog = gtk.Dialog(title="Detailed Filters", parent=self.main_window
|
||||
,flags=gtk.DIALOG_MODAL | gtk.DIALOG_DESTROY_WITH_PARENT
|
||||
,buttons=(gtk.STOCK_CANCEL, gtk.RESPONSE_REJECT,
|
||||
gtk.STOCK_OK, gtk.RESPONSE_ACCEPT))
|
||||
|
||||
handbox = gtk.VBox(True, 0)
|
||||
detailDialog.vbox.pack_start(handbox, False, False, 0)
|
||||
handbox.show()
|
||||
|
||||
label = gtk.Label("Hand Filters:")
|
||||
handbox.add(label)
|
||||
label.show()
|
||||
|
||||
betweenFilters = []
|
||||
for htest in self.handtests:
|
||||
hbox = gtk.HBox(False, 0)
|
||||
handbox.pack_start(hbox, False, False, 0)
|
||||
hbox.show()
|
||||
|
||||
cb = gtk.CheckButton()
|
||||
lbl_from = gtk.Label(htest[1])
|
||||
lbl_from.set_alignment(xalign=0.0, yalign=0.5)
|
||||
lbl_tween = gtk.Label('between')
|
||||
lbl_to = gtk.Label('and')
|
||||
adj1 = gtk.Adjustment(value=htest[2], lower=0, 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=htest[3], lower=2, upper=10, step_incr=1, page_incr=1, page_size=0)
|
||||
sb2 = gtk.SpinButton(adjustment=adj2, climb_rate=0.0, digits=0)
|
||||
|
||||
for df in [x for x in self.detailFilters if x[0] == htest[0]]:
|
||||
cb.set_active(True)
|
||||
|
||||
hbox.pack_start(cb, expand=False, padding=3)
|
||||
hbox.pack_start(lbl_from, expand=True, padding=3)
|
||||
hbox.pack_start(lbl_tween, 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)
|
||||
|
||||
cb.show()
|
||||
lbl_from.show()
|
||||
lbl_tween.show()
|
||||
sb1.show()
|
||||
lbl_to.show()
|
||||
sb2.show()
|
||||
|
||||
htest[4:7] = [cb,sb1,sb2]
|
||||
|
||||
response = detailDialog.run()
|
||||
|
||||
if response == gtk.RESPONSE_ACCEPT:
|
||||
self.detailFilters = []
|
||||
for ht in self.handtests:
|
||||
if ht[4].get_active():
|
||||
self.detailFilters.append( (ht[0], ht[5].get_value_as_int(), ht[6].get_value_as_int()) )
|
||||
ht[2],ht[3] = ht[5].get_value_as_int(), ht[6].get_value_as_int()
|
||||
print "detailFilters =", self.detailFilters
|
||||
self.refreshStats(None, None)
|
||||
|
||||
detailDialog.destroy()
|
||||
|
||||
self.main_hbox.pack_start(playerFrame)
|
||||
self.main_hbox.pack_start(statsFrame)
|
||||
|
||||
|
|
|
@ -23,9 +23,80 @@ import os
|
|||
|
||||
import fpdb_import
|
||||
import fpdb_db
|
||||
import Filters
|
||||
import FpdbSQLQueries
|
||||
|
||||
class GuiPositionalStats (threading.Thread):
|
||||
def __init__(self, config, querylist, debug=True):
|
||||
self.debug=debug
|
||||
self.conf=config
|
||||
self.MYSQL_INNODB = 2
|
||||
self.PGSQL = 3
|
||||
self.SQLITE = 4
|
||||
|
||||
# create new db connection to avoid conflicts with other threads
|
||||
self.db = fpdb_db.fpdb_db()
|
||||
self.db.do_connect(self.conf)
|
||||
self.cursor=self.db.cursor
|
||||
self.sql = querylist
|
||||
|
||||
settings = {}
|
||||
settings.update(config.get_db_parameters())
|
||||
settings.update(config.get_tv_parameters())
|
||||
settings.update(config.get_import_parameters())
|
||||
settings.update(config.get_default_paths())
|
||||
|
||||
filters_display = { "Heroes" : True,
|
||||
"Sites" : True,
|
||||
"Games" : False,
|
||||
"Limits" : True,
|
||||
"LimitSep" : True,
|
||||
"Seats" : True,
|
||||
"SeatSep" : True,
|
||||
"Dates" : True,
|
||||
"Button1" : True,
|
||||
"Button2" : False
|
||||
}
|
||||
|
||||
self.filters = Filters.Filters(self.db, settings, config, querylist, display = filters_display)
|
||||
self.filters.registerButton1Name("Refresh")
|
||||
self.filters.registerButton1Callback(self.refreshStats)
|
||||
|
||||
self.stat_table = None
|
||||
self.stats_frame = None
|
||||
|
||||
self.main_hbox = gtk.HBox(False, 0)
|
||||
self.main_hbox.show()
|
||||
|
||||
statsFrame = gtk.Frame("Stats:")
|
||||
statsFrame.set_label_align(0.0, 0.0)
|
||||
statsFrame.show()
|
||||
self.stats_frame = gtk.VBox(False, 0)
|
||||
self.stats_frame.show()
|
||||
|
||||
# This could be stored in config eventually, or maybe configured in this window somehow.
|
||||
# Each posncols element is the name of a column returned by the sql
|
||||
# query (in lower case) and each posnheads element is the text to use as
|
||||
# the heading in the GUI. Both sequences should be the same length.
|
||||
# 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", "avgseats", "plposition", "vpip", "pfr", "pf3", "steals"
|
||||
, "saw_f", "sawsd", "wtsdwsf", "wmsd", "flafq", "tuafq", "rvafq"
|
||||
, "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"
|
||||
)
|
||||
|
||||
self.fillStatsFrame(self.stats_frame)
|
||||
statsFrame.add(self.stats_frame)
|
||||
|
||||
self.main_hbox.pack_start(self.filters.get_vbox())
|
||||
self.main_hbox.pack_start(statsFrame)
|
||||
|
||||
|
||||
def get_vbox(self):
|
||||
"""returns the vbox of this thread"""
|
||||
return self.main_hbox
|
||||
|
@ -35,177 +106,255 @@ class GuiPositionalStats (threading.Thread):
|
|||
self.activesite = data
|
||||
print "DEBUG: activesite set to %s" %(self.activesite)
|
||||
|
||||
def cardCallback(self, widget, data=None):
|
||||
print "DEBUG: %s was toggled %s" % (data, ("OFF", "ON")[widget.get_active()])
|
||||
|
||||
def refreshStats(self, widget, data):
|
||||
try: self.stats_table.destroy()
|
||||
except AttributeError: pass
|
||||
self.fillStatsFrame(self.stats_frame)
|
||||
|
||||
def fillStatsFrame(self, vbox):
|
||||
# Get currently active site and grab playerid
|
||||
print "DEBUG: attempting to fill stats frame"
|
||||
sites = self.filters.getSites()
|
||||
heroes = self.filters.getHeroes()
|
||||
siteids = self.filters.getSiteIds()
|
||||
limits = self.filters.getLimits()
|
||||
seats = self.filters.getSeats()
|
||||
dates = self.filters.getDates()
|
||||
sitenos = []
|
||||
playerids = []
|
||||
|
||||
# Which sites are selected?
|
||||
for site in sites:
|
||||
if sites[site] == True:
|
||||
sitenos.append(siteids[site])
|
||||
self.cursor.execute(self.sql.query['getPlayerId'], (heroes[site],))
|
||||
result = self.db.cursor.fetchall()
|
||||
if len(result) == 1:
|
||||
playerids.append(result[0][0])
|
||||
|
||||
if not sitenos:
|
||||
#Should probably pop up here.
|
||||
print "No sites selected - defaulting to PokerStars"
|
||||
sitenos = [2]
|
||||
if not playerids:
|
||||
print "No player ids found"
|
||||
return
|
||||
if not limits:
|
||||
print "No limits found"
|
||||
return
|
||||
|
||||
self.createStatsTable(vbox, playerids, sitenos, limits, seats, dates)
|
||||
|
||||
def createStatsTable(self, vbox, playerids, sitenos, limits, seats, dates):
|
||||
self.stats_table = gtk.Table(1, 1, False) # gtk table expands as required
|
||||
self.stats_table.set_col_spacings(4)
|
||||
self.stats_table.show()
|
||||
vbox.add(self.stats_table)
|
||||
|
||||
row = 0
|
||||
col = 0
|
||||
for t in self.posnheads:
|
||||
l = gtk.Label(self.posnheads[col])
|
||||
l.show()
|
||||
self.stats_table.attach(l, col, col+1, row, row+1, yoptions=gtk.SHRINK)
|
||||
col +=1
|
||||
|
||||
tmp = self.sql.query['playerStatsByPosition']
|
||||
|
||||
result = self.cursor.execute(self.sql.query['getPlayerId'], (self.heroes[self.activesite],))
|
||||
tmp = self.refineQuery(tmp, playerids, sitenos, limits, seats, dates)
|
||||
self.cursor.execute(tmp)
|
||||
result = self.cursor.fetchall()
|
||||
if not result == ():
|
||||
pid = result[0][0]
|
||||
pid = result[0][0]
|
||||
tmp = tmp.replace("<player_test>", "(" + str(pid) + ")")
|
||||
self.cursor.execute(tmp)
|
||||
result = self.cursor.fetchall()
|
||||
cols = 16
|
||||
rows = len(result)+1 # +1 for title row
|
||||
self.stats_table = gtk.Table(rows, cols, False)
|
||||
self.stats_table.set_col_spacings(4)
|
||||
self.stats_table.show()
|
||||
vbox.add(self.stats_table)
|
||||
|
||||
# Create header row
|
||||
titles = ("Game", "Position", "#", "VPIP", "PFR", "Saw_F", "SawSD", "WtSDwsF", "W$SD", "FlAFq", "TuAFq", "RvAFq", "PoFAFq", "Net($)", "BB/100", "$/hand", "Variance")
|
||||
rows = len(result)
|
||||
colnames = [desc[0].lower() for desc in self.cursor.description]
|
||||
|
||||
col = 0
|
||||
row = 0
|
||||
for t in titles:
|
||||
l = gtk.Label(titles[col])
|
||||
l.show()
|
||||
self.stats_table.attach(l, col, col+1, row, row+1, yoptions=gtk.SHRINK)
|
||||
col +=1
|
||||
|
||||
for row in range(rows-1):
|
||||
if(row%2 == 0):
|
||||
bgcolor = "white"
|
||||
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)
|
||||
else:
|
||||
continue
|
||||
eb = gtk.EventBox()
|
||||
eb.modify_bg(gtk.STATE_NORMAL, gtk.gdk.color_parse(bgcolor))
|
||||
# print blank row between levels:
|
||||
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:
|
||||
bgcolor = "lightgrey"
|
||||
for col in range(cols):
|
||||
eb = gtk.EventBox()
|
||||
eb.modify_bg(gtk.STATE_NORMAL, gtk.gdk.color_parse(bgcolor))
|
||||
if result[row][col]:
|
||||
l = gtk.Label(result[row][col])
|
||||
else:
|
||||
l = gtk.Label(' ')
|
||||
if col == 0:
|
||||
l.set_alignment(xalign=0.0, yalign=0.5)
|
||||
else:
|
||||
l.set_alignment(xalign=1.0, yalign=0.5)
|
||||
eb.add(l)
|
||||
self.stats_table.attach(eb, col, col+1, row+1, row+2, yoptions=gtk.SHRINK)
|
||||
l.show()
|
||||
eb.show()
|
||||
self.fdb.db.commit()
|
||||
l = gtk.Label(result[sqlrow][sqlcol])
|
||||
rowprinted=1
|
||||
else:
|
||||
l = gtk.Label(' ')
|
||||
if col == 0:
|
||||
l.set_alignment(xalign=0.0, yalign=0.5)
|
||||
elif col == 1:
|
||||
l.set_alignment(xalign=0.5, yalign=0.5)
|
||||
else:
|
||||
l.set_alignment(xalign=1.0, yalign=0.5)
|
||||
eb.add(l)
|
||||
self.stats_table.attach(eb, col, col+1, row+1, row+2, yoptions=gtk.SHRINK)
|
||||
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, seats, dates)
|
||||
self.cursor.execute(tmp)
|
||||
result = self.cursor.fetchall()
|
||||
rows = len(result)
|
||||
colnames = [desc[0].lower() for desc in self.cursor.description]
|
||||
|
||||
# blank row between main stats and totals:
|
||||
col = 0
|
||||
if(row%2 == 0):
|
||||
bgcolor = "white"
|
||||
else:
|
||||
bgcolor = "lightgrey"
|
||||
eb = gtk.EventBox()
|
||||
eb.modify_bg(gtk.STATE_NORMAL, gtk.gdk.color_parse(bgcolor))
|
||||
l = gtk.Label(' ')
|
||||
eb.add(l)
|
||||
self.stats_table.attach(eb, col, col+1, row+1, row+2, yoptions=gtk.SHRINK)
|
||||
l.show()
|
||||
eb.show()
|
||||
row = row + 1
|
||||
|
||||
for sqlrow in range(rows):
|
||||
if(row%2 == 0):
|
||||
bgcolor = "white"
|
||||
else:
|
||||
bgcolor = "lightgrey"
|
||||
for col,colname in enumerate(self.posncols):
|
||||
if colname in colnames:
|
||||
sqlcol = colnames.index(colname)
|
||||
elif colname != "plposition":
|
||||
continue
|
||||
eb = gtk.EventBox()
|
||||
eb.modify_bg(gtk.STATE_NORMAL, gtk.gdk.color_parse(bgcolor))
|
||||
if colname == 'plposition':
|
||||
l = gtk.Label('Totals')
|
||||
elif result[sqlrow][sqlcol]:
|
||||
l = gtk.Label(result[sqlrow][sqlcol])
|
||||
else:
|
||||
l = gtk.Label(' ')
|
||||
if col == 0:
|
||||
l.set_alignment(xalign=0.0, yalign=0.5)
|
||||
elif col == 1:
|
||||
l.set_alignment(xalign=0.5, yalign=0.5)
|
||||
else:
|
||||
l.set_alignment(xalign=1.0, yalign=0.5)
|
||||
eb.add(l)
|
||||
self.stats_table.attach(eb, col, col+1, row+1, row+2, yoptions=gtk.SHRINK)
|
||||
l.show()
|
||||
eb.show()
|
||||
row = row + 1
|
||||
|
||||
self.db.db.rollback()
|
||||
#end def fillStatsFrame(self, vbox):
|
||||
|
||||
def fillPlayerFrame(self, vbox):
|
||||
for site in self.conf.supported_sites.keys():
|
||||
hbox = gtk.HBox(False, 0)
|
||||
vbox.pack_start(hbox, False, True, 0)
|
||||
hbox.show()
|
||||
|
||||
player = self.conf.supported_sites[site].screen_name
|
||||
self.createPlayerLine(hbox, site, player)
|
||||
hbox = gtk.HBox(False, 0)
|
||||
button = gtk.Button("Refresh")
|
||||
button.connect("clicked", self.refreshStats, False)
|
||||
button.show()
|
||||
hbox.add(button)
|
||||
vbox.pack_start(hbox, False, True, 0)
|
||||
hbox.show()
|
||||
|
||||
def fillCardsFrame(self, vbox):
|
||||
hbox1 = gtk.HBox(True,0)
|
||||
hbox1.show()
|
||||
vbox.pack_start(hbox1, True, True, 0)
|
||||
|
||||
cards = [ "A", "K","Q","J","T","9","8","7","6","5","4","3","2" ]
|
||||
|
||||
for j in range(0, len(cards)):
|
||||
hbox1 = gtk.HBox(True,0)
|
||||
hbox1.show()
|
||||
vbox.pack_start(hbox1, True, True, 0)
|
||||
for i in range(0, len(cards)):
|
||||
if i < (j + 1):
|
||||
suit = "o"
|
||||
else:
|
||||
suit = "s"
|
||||
button = gtk.ToggleButton("%s%s%s" %(cards[i], cards[j], suit))
|
||||
button.connect("toggled", self.cardCallback, "%s%s%s" %(cards[i], cards[j], suit))
|
||||
hbox1.pack_start(button, True, True, 0)
|
||||
button.show()
|
||||
|
||||
def createPlayerLine(self, hbox, site, player):
|
||||
if(self.buttongroup == None):
|
||||
button = gtk.RadioButton(None, site + " id:")
|
||||
button.set_active(True)
|
||||
self.buttongroup = button
|
||||
self.activesite = site
|
||||
def refineQuery(self, query, playerids, sitenos, limits, seats, dates):
|
||||
if playerids:
|
||||
nametest = str(tuple(playerids))
|
||||
nametest = nametest.replace("L", "")
|
||||
nametest = nametest.replace(",)",")")
|
||||
query = query.replace("<player_test>", nametest)
|
||||
else:
|
||||
button = gtk.RadioButton(self.buttongroup, site + " id:")
|
||||
hbox.pack_start(button, True, True, 0)
|
||||
button.connect("toggled", self.toggleCallback, site)
|
||||
button.show()
|
||||
query = query.replace("<player_test>", "1 = 2")
|
||||
|
||||
pname = gtk.Entry()
|
||||
pname.set_text(player)
|
||||
pname.set_width_chars(20)
|
||||
hbox.pack_start(pname, False, True, 0)
|
||||
pname.connect("changed", self.__set_hero_name, site)
|
||||
#TODO: Look at GtkCompletion - to fill out usernames
|
||||
pname.show()
|
||||
self.__set_hero_name(pname, site)
|
||||
if seats:
|
||||
query = query.replace('<seats_test>', 'between ' + str(seats['from']) + ' and ' + str(seats['to']))
|
||||
if 'show' in seats and seats['show']:
|
||||
query = query.replace('<groupbyseats>', ',hc.activeSeats')
|
||||
query = query.replace('<orderbyseats>', ',stats.AvgSeats')
|
||||
else:
|
||||
query = query.replace('<groupbyseats>', '')
|
||||
query = query.replace('<orderbyseats>', '')
|
||||
else:
|
||||
query = query.replace('<seats_test>', 'between 0 and 100')
|
||||
query = query.replace('<groupbyseats>', '')
|
||||
query = query.replace('<orderbyseats>', '')
|
||||
|
||||
def __set_hero_name(self, w, site):
|
||||
self.heroes[site] = w.get_text()
|
||||
|
||||
def __init__(self, db, config, querylist, debug=True):
|
||||
self.debug=debug
|
||||
self.conf=config
|
||||
|
||||
# create new db connection to avoid conflicts with other threads
|
||||
self.fdb = fpdb_db.fpdb_db()
|
||||
self.fdb.do_connect(self.conf)
|
||||
self.cursor=self.fdb.cursor
|
||||
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", "")
|
||||
blindtest = blindtest.replace(",)",")")
|
||||
query = query.replace("<gtbigBlind_test>", "gt.bigBlind in " + blindtest)
|
||||
else:
|
||||
query = query.replace("<gtbigBlind_test>", "gt.bigBlind = -1 ")
|
||||
|
||||
self.sql = querylist
|
||||
groupLevels = "show" not in str(limits)
|
||||
if groupLevels:
|
||||
if self.db.backend == self.MYSQL_INNODB:
|
||||
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)
|
||||
else format(max(gt.bigBlind)/100.0, 0)
|
||||
end)
|
||||
) """
|
||||
else:
|
||||
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("<selectgt.bigBlind>", bigblindselect)
|
||||
query = query.replace("<groupbygt.bigBlind>", "")
|
||||
query = query.replace("<hcgametypeId>", "-1")
|
||||
query = query.replace("<hgameTypeId>", "-1")
|
||||
else:
|
||||
if self.db.backend == self.MYSQL_INNODB:
|
||||
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
|
||||
) """
|
||||
query = query.replace("<selectgt.bigBlind>", bigblindselect)
|
||||
query = query.replace("<groupbygt.bigBlind>", ",gt.bigBlind")
|
||||
query = query.replace("<hcgametypeId>", "hc.gametypeId")
|
||||
query = query.replace("<hgameTypeId>", "h.gameTypeId")
|
||||
|
||||
self.activesite = None
|
||||
self.buttongroup = None
|
||||
|
||||
self.heroes = {}
|
||||
self.stat_table = None
|
||||
self.stats_frame = None
|
||||
|
||||
self.main_hbox = gtk.HBox(False, 0)
|
||||
self.main_hbox.show()
|
||||
|
||||
playerFrame = gtk.Frame("Hero:")
|
||||
playerFrame.set_label_align(0.0, 0.0)
|
||||
playerFrame.show()
|
||||
vbox = gtk.VBox(False, 0)
|
||||
vbox.show()
|
||||
|
||||
self.fillPlayerFrame(vbox)
|
||||
playerFrame.add(vbox)
|
||||
|
||||
cardsFrame = gtk.Frame("Cards:")
|
||||
cardsFrame.set_label_align(0.0, 0.0)
|
||||
cardsFrame.show()
|
||||
vbox = gtk.VBox(False, 0)
|
||||
vbox.show()
|
||||
|
||||
self.fillCardsFrame(vbox)
|
||||
cardsFrame.add(vbox)
|
||||
|
||||
statsFrame = gtk.Frame("Stats:")
|
||||
statsFrame.set_label_align(0.0, 0.0)
|
||||
statsFrame.show()
|
||||
self.stats_frame = gtk.VBox(False, 0)
|
||||
self.stats_frame.show()
|
||||
|
||||
self.fillStatsFrame(self.stats_frame)
|
||||
statsFrame.add(self.stats_frame)
|
||||
|
||||
self.main_hbox.pack_start(playerFrame)
|
||||
self.main_hbox.pack_start(statsFrame)
|
||||
# Filter on dates
|
||||
query = query.replace("<datestest>", " between '" + dates[0] + "' and '" + dates[1] + "'")
|
||||
|
||||
#print "query =\n", query
|
||||
return(query)
|
||||
#end def refineQuery(self, query, playerids, sitenos, limits):
|
||||
|
|
310
pyfpdb/GuiSessionViewer.py
Normal file
310
pyfpdb/GuiSessionViewer.py
Normal file
|
@ -0,0 +1,310 @@
|
|||
#!/usr/bin/python
|
||||
|
||||
#Copyright 2008 Steffen Jobbagy-Felso
|
||||
#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 <http://www.gnu.org/licenses/>.
|
||||
#In the "official" distribution you can find the license in
|
||||
#agpl-3.0.txt in the docs folder of the package.
|
||||
|
||||
import threading
|
||||
import pygtk
|
||||
pygtk.require('2.0')
|
||||
import gtk
|
||||
import os
|
||||
from time import time, strftime, localtime
|
||||
from numpy import diff, nonzero
|
||||
|
||||
import Card
|
||||
import fpdb_import
|
||||
import fpdb_db
|
||||
import Filters
|
||||
import FpdbSQLQueries
|
||||
|
||||
class GuiSessionViewer (threading.Thread):
|
||||
def __init__(self, config, querylist, debug=True):
|
||||
self.debug=debug
|
||||
self.conf=config
|
||||
self.MYSQL_INNODB = 2
|
||||
self.PGSQL = 3
|
||||
self.SQLITE = 4
|
||||
|
||||
# create new db connection to avoid conflicts with other threads
|
||||
self.db = fpdb_db.fpdb_db()
|
||||
self.db.do_connect(self.conf)
|
||||
self.cursor=self.db.cursor
|
||||
self.sql = querylist
|
||||
|
||||
settings = {}
|
||||
settings.update(config.get_db_parameters())
|
||||
settings.update(config.get_tv_parameters())
|
||||
settings.update(config.get_import_parameters())
|
||||
settings.update(config.get_default_paths())
|
||||
|
||||
# text used on screen stored here so that it can be configured
|
||||
self.filterText = {'handhead':'Hand Breakdown for all levels listed above'
|
||||
}
|
||||
|
||||
filters_display = { "Heroes" : True,
|
||||
"Sites" : True,
|
||||
"Games" : False,
|
||||
"Limits" : True,
|
||||
"LimitSep" : True,
|
||||
"Seats" : True,
|
||||
"SeatSep" : True,
|
||||
"Dates" : False,
|
||||
"Groups" : True,
|
||||
"Button1" : True,
|
||||
"Button2" : True
|
||||
}
|
||||
|
||||
self.filters = Filters.Filters(self.db, settings, config, querylist, display = filters_display)
|
||||
self.filters.registerButton2Name("_Refresh")
|
||||
self.filters.registerButton2Callback(self.refreshStats)
|
||||
|
||||
# ToDo: store in config
|
||||
# ToDo: create popup to adjust column config
|
||||
# columns to display, keys match column name returned by sql, values in tuple are:
|
||||
# is column displayed, column heading, xalignment, formatting
|
||||
self.columns = [ ("game", True, "Game", 0.0, "%s")
|
||||
, ("hand", False, "Hand", 0.0, "%s") # true not allowed for this line
|
||||
, ("n", True, "Hds", 1.0, "%d")
|
||||
, ("avgseats", True, "Seats", 1.0, "%3.1f")
|
||||
, ("vpip", True, "VPIP", 1.0, "%3.1f")
|
||||
, ("pfr", True, "PFR", 1.0, "%3.1f")
|
||||
, ("pf3", True, "PF3", 1.0, "%3.1f")
|
||||
, ("steals", True, "Steals", 1.0, "%3.1f")
|
||||
, ("saw_f", True, "Saw_F", 1.0, "%3.1f")
|
||||
, ("sawsd", True, "SawSD", 1.0, "%3.1f")
|
||||
, ("wtsdwsf", True, "WtSDwsF", 1.0, "%3.1f")
|
||||
, ("wmsd", True, "W$SD", 1.0, "%3.1f")
|
||||
, ("flafq", True, "FlAFq", 1.0, "%3.1f")
|
||||
, ("tuafq", True, "TuAFq", 1.0, "%3.1f")
|
||||
, ("rvafq", True, "RvAFq", 1.0, "%3.1f")
|
||||
, ("pofafq", False, "PoFAFq", 1.0, "%3.1f")
|
||||
, ("net", True, "Net($)", 1.0, "%6.2f")
|
||||
, ("bbper100", True, "BB/100", 1.0, "%4.2f")
|
||||
, ("rake", True, "Rake($)", 1.0, "%6.2f")
|
||||
, ("variance", True, "Variance", 1.0, "%5.2f")
|
||||
]
|
||||
|
||||
self.stats_frame = None
|
||||
self.stats_vbox = None
|
||||
self.detailFilters = [] # the data used to enhance the sql select
|
||||
|
||||
self.main_hbox = gtk.HBox(False, 0)
|
||||
self.main_hbox.show()
|
||||
|
||||
self.stats_frame = gtk.Frame()
|
||||
self.stats_frame.show()
|
||||
|
||||
self.stats_vbox = gtk.VBox(False, 0)
|
||||
self.stats_vbox.show()
|
||||
self.stats_frame.add(self.stats_vbox)
|
||||
self.fillStatsFrame(self.stats_vbox)
|
||||
|
||||
self.main_hbox.pack_start(self.filters.get_vbox())
|
||||
self.main_hbox.pack_start(self.stats_frame, expand=True, fill=True)
|
||||
|
||||
################################
|
||||
|
||||
|
||||
# make sure Hand column is not displayed
|
||||
[x for x in self.columns if x[0] == 'hand'][0][1] == False
|
||||
|
||||
def get_vbox(self):
|
||||
"""returns the vbox of this thread"""
|
||||
return self.main_hbox
|
||||
|
||||
def refreshStats(self, widget, data):
|
||||
try: self.stats_vbox.destroy()
|
||||
except AttributeError: pass
|
||||
self.stats_vbox = gtk.VBox(False, 0)
|
||||
self.stats_vbox.show()
|
||||
self.stats_frame.add(self.stats_vbox)
|
||||
self.fillStatsFrame(self.stats_vbox)
|
||||
|
||||
def fillStatsFrame(self, vbox):
|
||||
sites = self.filters.getSites()
|
||||
heroes = self.filters.getHeroes()
|
||||
siteids = self.filters.getSiteIds()
|
||||
limits = self.filters.getLimits()
|
||||
seats = self.filters.getSeats()
|
||||
sitenos = []
|
||||
playerids = []
|
||||
|
||||
# Which sites are selected?
|
||||
for site in sites:
|
||||
if sites[site] == True:
|
||||
sitenos.append(siteids[site])
|
||||
self.cursor.execute(self.sql.query['getPlayerId'], (heroes[site],))
|
||||
result = self.db.cursor.fetchall()
|
||||
if len(result) == 1:
|
||||
playerids.append(result[0][0])
|
||||
|
||||
if not sitenos:
|
||||
#Should probably pop up here.
|
||||
print "No sites selected - defaulting to PokerStars"
|
||||
sitenos = [2]
|
||||
if not playerids:
|
||||
print "No player ids found"
|
||||
return
|
||||
if not limits:
|
||||
print "No limits found"
|
||||
return
|
||||
|
||||
self.createStatsTable(vbox, playerids, sitenos, limits, seats)
|
||||
|
||||
def createStatsTable(self, vbox, playerids, sitenos, limits, seats):
|
||||
starttime = time()
|
||||
|
||||
# Display summary table at top of page
|
||||
# 3rd parameter passes extra flags, currently includes:
|
||||
# holecards - whether to display card breakdown (True/False)
|
||||
flags = [False]
|
||||
self.addTable(vbox, 'playerDetailedStats', flags, playerids, sitenos, limits, seats)
|
||||
|
||||
# Separator
|
||||
sep = gtk.HSeparator()
|
||||
vbox.pack_start(sep, expand=False, padding=3)
|
||||
sep.show_now()
|
||||
vbox.show_now()
|
||||
heading = gtk.Label(self.filterText['handhead'])
|
||||
heading.show()
|
||||
vbox.pack_start(heading, expand=False, padding=3)
|
||||
|
||||
# Scrolled window for detailed table (display by hand)
|
||||
swin = gtk.ScrolledWindow(hadjustment=None, vadjustment=None)
|
||||
swin.set_policy(gtk.POLICY_AUTOMATIC, gtk.POLICY_AUTOMATIC)
|
||||
swin.show()
|
||||
vbox.pack_start(swin, expand=True, padding=3)
|
||||
|
||||
vbox1 = gtk.VBox(False, 0)
|
||||
vbox1.show()
|
||||
swin.add_with_viewport(vbox1)
|
||||
|
||||
# Detailed table
|
||||
flags = [True]
|
||||
self.addTable(vbox1, 'playerDetailedStats', flags, playerids, sitenos, limits, seats)
|
||||
|
||||
self.db.db.commit()
|
||||
print "Stats page displayed in %4.2f seconds" % (time() - starttime)
|
||||
#end def fillStatsFrame(self, vbox):
|
||||
|
||||
def addTable(self, vbox, query, flags, playerids, sitenos, limits, seats):
|
||||
row = 0
|
||||
sqlrow = 0
|
||||
colalias,colshow,colheading,colxalign,colformat = 0,1,2,3,4
|
||||
if not flags: holecards = False
|
||||
else: holecards = flags[0]
|
||||
|
||||
|
||||
self.stats_table = gtk.Table(1, 1, False)
|
||||
self.stats_table.set_col_spacings(4)
|
||||
self.stats_table.show()
|
||||
|
||||
self.db.cursor.execute("""select UNIX_TIMESTAMP(handStart) as time, id from Hands ORDER BY time""")
|
||||
THRESHOLD = 1800
|
||||
hands = self.db.cursor.fetchall()
|
||||
|
||||
times = map(lambda x:long(x[0]), hands)
|
||||
handids = map(lambda x:int(x[1]), hands)
|
||||
print "DEBUG: len(times) %s" %(len(times))
|
||||
diffs = diff(times)
|
||||
print "DEBUG: len(diffs) %s" %(len(diffs))
|
||||
index = nonzero(diff(times) > THRESHOLD)
|
||||
print "DEBUG: len(index[0]) %s" %(len(index[0]))
|
||||
print "DEBUG: index %s" %(index)
|
||||
print "DEBUG: index[0][0] %s" %(index[0][0])
|
||||
|
||||
total = 0
|
||||
|
||||
last_idx = 0
|
||||
for i in range(len(index[0])):
|
||||
print "Hands in session %4s: %4s Start: %s End: %s Total: %s" %(i, index[0][i] - last_idx, strftime("%d/%m/%Y %H:%M", localtime(times[last_idx])), strftime("%d/%m/%Y %H:%M", localtime(times[index[0][i]])), times[index[0][i]] - times[last_idx])
|
||||
total = total + (index[0][i] - last_idx)
|
||||
last_idx = index[0][i] + 1
|
||||
|
||||
print "Total: ", total
|
||||
#
|
||||
# colnames = [desc[0].lower() for desc in self.cursor.description]
|
||||
#
|
||||
# # pre-fetch some constant values:
|
||||
# cols_to_show = [x for x in self.columns if x[colshow]]
|
||||
# hgametypeid_idx = colnames.index('hgametypeid')
|
||||
#
|
||||
# liststore = gtk.ListStore(*([str] * len(cols_to_show)))
|
||||
# view = gtk.TreeView(model=liststore)
|
||||
# view.set_grid_lines(gtk.TREE_VIEW_GRID_LINES_BOTH)
|
||||
# vbox.pack_start(view, expand=False, padding=3)
|
||||
# textcell = gtk.CellRendererText()
|
||||
# numcell = gtk.CellRendererText()
|
||||
# numcell.set_property('xalign', 1.0)
|
||||
# listcols = []
|
||||
#
|
||||
# # Create header row eg column: ("game", True, "Game", 0.0, "%s")
|
||||
# for col, column in enumerate(cols_to_show):
|
||||
# if column[colalias] == 'game' and holecards:
|
||||
# s = [x for x in self.columns if x[colalias] == 'hand'][0][colheading]
|
||||
# else:
|
||||
# s = column[colheading]
|
||||
# listcols.append(gtk.TreeViewColumn(s))
|
||||
# view.append_column(listcols[col])
|
||||
# if column[colformat] == '%s':
|
||||
# if col == 1 and holecards:
|
||||
# listcols[col].pack_start(textcell, expand=True)
|
||||
# else:
|
||||
# listcols[col].pack_start(textcell, expand=False)
|
||||
# listcols[col].add_attribute(textcell, 'text', col)
|
||||
# else:
|
||||
# listcols[col].pack_start(numcell, expand=False)
|
||||
# listcols[col].add_attribute(numcell, 'text', col)
|
||||
#
|
||||
# rows = len(result) # +1 for title row
|
||||
#
|
||||
# while sqlrow < rows:
|
||||
# treerow = []
|
||||
# if(row%2 == 0):
|
||||
# bgcolor = "white"
|
||||
# else:
|
||||
# bgcolor = "lightgrey"
|
||||
# for col,column in enumerate(cols_to_show):
|
||||
# if column[colalias] in colnames:
|
||||
# value = result[sqlrow][colnames.index(column[colalias])]
|
||||
# else:
|
||||
# if column[colalias] == 'game':
|
||||
# if holecards:
|
||||
# value = Card.twoStartCardString( result[sqlrow][hgametypeid_idx] )
|
||||
# else:
|
||||
# minbb = result[sqlrow][colnames.index('minbigblind')]
|
||||
# maxbb = result[sqlrow][colnames.index('maxbigblind')]
|
||||
# value = result[sqlrow][colnames.index('limittype')] + ' ' \
|
||||
# + result[sqlrow][colnames.index('category')].title() + ' ' \
|
||||
# + result[sqlrow][colnames.index('name')] + ' $'
|
||||
# if 100 * int(minbb/100.0) != minbb:
|
||||
# value += '%.2f' % (minbb/100.0)
|
||||
# else:
|
||||
# value += '%.0f' % (minbb/100.0)
|
||||
# if minbb != maxbb:
|
||||
# if 100 * int(maxbb/100.0) != maxbb:
|
||||
# value += ' - $' + '%.2f' % (maxbb/100.0)
|
||||
# else:
|
||||
# value += ' - $' + '%.0f' % (maxbb/100.0)
|
||||
# else:
|
||||
# continue
|
||||
# if value and value != -999:
|
||||
# treerow.append(column[colformat] % value)
|
||||
# else:
|
||||
# treerow.append(' ')
|
||||
# iter = liststore.append(treerow)
|
||||
# sqlrow += 1
|
||||
# row += 1
|
||||
vbox.show_all()
|
|
@ -76,7 +76,7 @@ class GuiTableViewer (threading.Thread):
|
|||
arr=[]
|
||||
#first prepare the header row
|
||||
if (self.category=="holdem" or self.category=="omahahi" or self.category=="omahahilo"):
|
||||
tmp=("Name", "HDs", "VPIP", "PFR", "PF3B4B", "ST")
|
||||
tmp=("Name", "HDs", "VPIP", "PFR", "PF3B", "ST")
|
||||
|
||||
tmp+=("FS", "FB")
|
||||
|
||||
|
@ -131,7 +131,7 @@ class GuiTableViewer (threading.Thread):
|
|||
tmp.append(str(row[6]))#Hands
|
||||
tmp.append(self.hudDivide(row[7],row[6])) #VPIP
|
||||
tmp.append(self.hudDivide(row[8],row[6])) #PFR
|
||||
tmp.append(self.hudDivide(row[10],row[9])+" ("+str(row[9])+")") #PF3B4B
|
||||
tmp.append(self.hudDivide(row[10],row[9])+" ("+str(row[9])+")") #PF3B
|
||||
|
||||
tmp.append(self.hudDivide(row[31],row[30])+" ("+str(row[30])+")") #ST
|
||||
|
||||
|
|
|
@ -1,8 +1,25 @@
|
|||
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
|
||||
|
||||
<FreePokerToolsConfig xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="FreePokerToolsConfig.xsd">
|
||||
|
||||
<import callFpdbHud = "True" interval = "10" fastStoreHudCache="False" hhArchiveBase="~/.fpdb/HandHistories/" saveActions="True"></import>
|
||||
|
||||
<supported_sites>
|
||||
<site enabled="True" site_name="PokerStars" table_finder="PokerStars.exe" screen_name="DO NOT NEED THIS YET" site_path="~/.wine/drive_c/Program Files/PokerStars/" HH_path="~/.wine/drive_c/Program Files/PokerStars/HandHistory/abc/" decoder="pokerstars_decode_table" converter="passthrough" supported_games="holdem,razz,omahahi,omahahilo,studhi,studhilo">
|
||||
|
||||
<site enabled="True"
|
||||
site_name="PokerStars"
|
||||
table_finder="PokerStars.exe"
|
||||
screen_name="YOUR SCREEN NAME HERE"
|
||||
site_path="C:/Program Files/PokerStars/"
|
||||
HH_path="C:/Program Files/PokerStars/HandHistory/YOUR SCREEN NAME HERE/"
|
||||
decoder="pokerstars_decode_table"
|
||||
converter="PokerStarsToFpdb"
|
||||
bgcolor="#000000"
|
||||
fgcolor="#FFFFFF"
|
||||
hudopacity="1.0"
|
||||
font="Sans"
|
||||
font_size="8"
|
||||
supported_games="holdem,razz,omahahi,omahahilo,studhi,studhilo">
|
||||
<layout max="8" width="792" height="546" fav_seat="0">
|
||||
<location seat="1" x="684" y="61"> </location>
|
||||
<location seat="2" x="689" y="239"> </location>
|
||||
|
@ -49,7 +66,21 @@
|
|||
<location seat="2" x="10" y="288"> </location>
|
||||
</layout>
|
||||
</site>
|
||||
<site enabled="True" site_name="Full Tilt Poker" table_finder="FullTiltPoker.exe" screen_name="DO NOT NEED THIS YET" site_path="~/.wine/drive_c/Program Files/Full Tilt Poker/" HH_path="~/.wine/drive_c/Program Files/Full Tilt Poker/HandHistory/abc/" decoder="fulltilt_decode_table" converter="passthrough" supported_games="holdem,razz,omahahi,omahahilo,studhi,studhilo">
|
||||
|
||||
<site enabled="True"
|
||||
site_name="Full Tilt Poker"
|
||||
table_finder="FullTiltPoker"
|
||||
screen_name="YOUR SCREEN NAME HERE"
|
||||
site_path="C:/Program Files/Full Tilt Poker/"
|
||||
HH_path="C:/Program Files/Full Tilt Poker/HandHistory/YOUR SCREEN NAME HERE/"
|
||||
decoder="fulltilt_decode_table"
|
||||
converter="FulltiltToFpdb"
|
||||
bgcolor="#000000"
|
||||
fgcolor="#FFFFFF"
|
||||
hudopacity="1.0"
|
||||
font="Sans"
|
||||
font_size="8"
|
||||
supported_games="holdem,razz,omahahi,omahahilo,studhi,studhilo">
|
||||
<layout fav_seat="0" height="547" max="8" width="794">
|
||||
<location seat="1" x="640" y="64"> </location>
|
||||
<location seat="2" x="650" y="230"> </location>
|
||||
|
@ -84,7 +115,16 @@
|
|||
<location seat="9" x="70" y="53"> </location>
|
||||
</layout>
|
||||
</site>
|
||||
<site enabled="False" site_name="Everleaf" table_finder="Everleaf.exe" screen_name="DO NOT NEED THIS YET" site_path="" HH_path="" decoder="everleaf_decode_table" converter="EverleafToFpdb" supported_games="holdem">
|
||||
|
||||
<site enabled="False"
|
||||
site_name="Everleaf"
|
||||
table_finder="Everleaf.exe"
|
||||
screen_name="YOUR SCREEN NAME HERE"
|
||||
site_path=""
|
||||
HH_path=""
|
||||
decoder="everleaf_decode_table"
|
||||
converter="EverleafToFpdb"
|
||||
supported_games="holdem">
|
||||
<layout fav_seat="0" height="547" max="8" width="794">
|
||||
<location seat="1" x="640" y="64"> </location>
|
||||
<location seat="2" x="650" y="230"> </location>
|
||||
|
@ -120,8 +160,10 @@
|
|||
</layout>
|
||||
</site>
|
||||
</supported_sites>
|
||||
|
||||
<supported_games>
|
||||
<game cols="3" db="fpdb" game_name="holdem" rows="2">
|
||||
|
||||
<game cols="3" db="fpdb" game_name="holdem" rows="2" aux="mucked">
|
||||
<stat click="tog_decorate" col="0" popup="default" row="0" stat_name="vpip" tip="tip1"> </stat>
|
||||
<stat click="tog_decorate" col="1" popup="default" row="0" stat_name="pfr" tip="tip1"> </stat>
|
||||
<stat click="tog_decorate" col="2" popup="default" row="0" stat_name="ffreq_1" tip="tip1"> </stat>
|
||||
|
@ -129,7 +171,8 @@
|
|||
<stat click="tog_decorate" col="1" popup="default" row="1" stat_name="wtsd" tip="tip1"> </stat>
|
||||
<stat click="tog_decorate" col="2" popup="default" row="1" stat_name="wmsd" tip="tip1"> </stat>
|
||||
</game>
|
||||
<game cols="3" db="fpdb" game_name="razz" rows="2">
|
||||
|
||||
<game cols="3" db="fpdb" game_name="razz" rows="2" aux="stud_mucked">
|
||||
<stat click="tog_decorate" col="0" popup="default" row="0" stat_name="vpip" tip="tip1"> </stat>
|
||||
<stat click="tog_decorate" col="1" popup="default" row="0" stat_name="pfr" tip="tip1"> </stat>
|
||||
<stat click="tog_decorate" col="2" popup="default" row="0" stat_name="ffreq_1" tip="tip1"> </stat>
|
||||
|
@ -137,7 +180,8 @@
|
|||
<stat click="tog_decorate" col="1" popup="default" row="1" stat_name="wtsd" tip="tip1"> </stat>
|
||||
<stat click="tog_decorate" col="2" popup="default" row="1" stat_name="wmsd" tip="tip1"> </stat>
|
||||
</game>
|
||||
<game cols="3" db="fpdb" game_name="omahahi" rows="2">
|
||||
|
||||
<game cols="3" db="fpdb" game_name="omahahi" rows="2" aux="mucked">
|
||||
<stat click="tog_decorate" col="0" popup="default" row="0" stat_name="vpip" tip="tip1"> </stat>
|
||||
<stat click="tog_decorate" col="1" popup="default" row="0" stat_name="pfr" tip="tip1"> </stat>
|
||||
<stat click="tog_decorate" col="2" popup="default" row="0" stat_name="ffreq_1" tip="tip1"> </stat>
|
||||
|
@ -145,7 +189,8 @@
|
|||
<stat click="tog_decorate" col="1" popup="default" row="1" stat_name="wtsd" tip="tip1"> </stat>
|
||||
<stat click="tog_decorate" col="2" popup="default" row="1" stat_name="wmsd" tip="tip1"> </stat>
|
||||
</game>
|
||||
<game cols="3" db="fpdb" game_name="omahahilo" rows="2">
|
||||
|
||||
<game cols="3" db="fpdb" game_name="omahahilo" rows="2" aux="mucked">
|
||||
<stat click="tog_decorate" col="0" popup="default" row="0" stat_name="vpip" tip="tip1"> </stat>
|
||||
<stat click="tog_decorate" col="1" popup="default" row="0" stat_name="pfr" tip="tip1"> </stat>
|
||||
<stat click="tog_decorate" col="2" popup="default" row="0" stat_name="ffreq_1" tip="tip1"> </stat>
|
||||
|
@ -153,7 +198,8 @@
|
|||
<stat click="tog_decorate" col="1" popup="default" row="1" stat_name="wtsd" tip="tip1"> </stat>
|
||||
<stat click="tog_decorate" col="2" popup="default" row="1" stat_name="wmsd" tip="tip1"> </stat>
|
||||
</game>
|
||||
<game cols="3" db="fpdb" game_name="studhi" rows="2">
|
||||
|
||||
<game cols="3" db="fpdb" game_name="studhi" rows="2" aux="stud_mucked">
|
||||
<stat click="tog_decorate" col="0" popup="default" row="0" stat_name="vpip" tip="tip1"> </stat>
|
||||
<stat click="tog_decorate" col="1" popup="default" row="0" stat_name="pfr" tip="tip1"> </stat>
|
||||
<stat click="tog_decorate" col="2" popup="default" row="0" stat_name="ffreq_1" tip="tip1"> </stat>
|
||||
|
@ -161,7 +207,8 @@
|
|||
<stat click="tog_decorate" col="1" popup="default" row="1" stat_name="wtsd" tip="tip1"> </stat>
|
||||
<stat click="tog_decorate" col="2" popup="default" row="1" stat_name="wmsd" tip="tip1"> </stat>
|
||||
</game>
|
||||
<game cols="3" db="fpdb" game_name="studhilo" rows="2">
|
||||
|
||||
<game cols="3" db="fpdb" game_name="studhilo" rows="2" aux="stud_mucked">
|
||||
<stat click="tog_decorate" col="0" popup="default" row="0" stat_name="vpip" tip="tip1"> </stat>
|
||||
<stat click="tog_decorate" col="1" popup="default" row="0" stat_name="pfr" tip="tip1"> </stat>
|
||||
<stat click="tog_decorate" col="2" popup="default" row="0" stat_name="ffreq_1" tip="tip1"> </stat>
|
||||
|
@ -170,6 +217,7 @@
|
|||
<stat click="tog_decorate" col="2" popup="default" row="1" stat_name="wmsd" tip="tip1"> </stat>
|
||||
</game>
|
||||
</supported_games>
|
||||
|
||||
<popup_windows>
|
||||
<pu pu_name="default">
|
||||
<pu_stat pu_stat_name="n"> </pu_stat>
|
||||
|
@ -196,15 +244,60 @@
|
|||
<pu_stat pu_stat_name="ffreq_4"> </pu_stat>
|
||||
</pu>
|
||||
</popup_windows>
|
||||
<import callFpdbHud = "True" interval = "10" ></import>
|
||||
<tv combinedStealFold = "True" combined2B3B = "True" combinedPostflop = "True"></tv>
|
||||
|
||||
<aux_windows>
|
||||
<aw card_ht="42" card_wd="30" class="Stud_mucked" cols="11" deck="Cards01.png" module="Mucked" name="stud_mucked" rows="8"> </aw>
|
||||
<aw class="Hello" module="Hello" name="Hello"> </aw>
|
||||
<aw class="Hello_Menu" module="Hello" name="Hello_menu"> </aw>
|
||||
<aw class="Hello_plus" module="Hello" name="Hello_plus"> </aw>
|
||||
<aw card_ht="42" card_wd="30" class="Flop_Mucked" deck="Cards01.png" module="Mucked" name="mucked" opacity="0.7" timeout="5">
|
||||
<layout height="546" max="6" width="792">
|
||||
<location seat="1" x="555" y="169"> </location>
|
||||
<location seat="2" x="572" y="276"> </location>
|
||||
<location seat="3" x="363" y="348"> </location>
|
||||
<location seat="4" x="150" y="273"> </location>
|
||||
<location seat="5" x="150" y="169"> </location>
|
||||
<location seat="6" x="363" y="113"> </location>
|
||||
<location common="1" x="323" y="232"> </location>
|
||||
</layout>
|
||||
<layout height="546" max="9" width="792">
|
||||
<location seat="1" x="486" y="113"> </location>
|
||||
<location seat="2" x="555" y="169"> </location>
|
||||
<location seat="3" x="572" y="276"> </location>
|
||||
<location seat="4" x="522" y="345"> </location>
|
||||
<location seat="5" x="363" y="348"> </location>
|
||||
<location seat="6" x="217" y="341"> </location>
|
||||
<location seat="7" x="150" y="273"> </location>
|
||||
<location seat="8" x="150" y="169"> </location>
|
||||
<location seat="9" x="230" y="115"> </location>
|
||||
<location common="1" x="323" y="232"> </location>
|
||||
</layout>
|
||||
<layout height="546" max="10" width="792">
|
||||
<location seat="1" x="486" y="113"> </location>
|
||||
<location seat="2" x="499" y="138"> </location>
|
||||
<location seat="3" x="522" y="212"> </location>
|
||||
<location seat="4" x="501" y="281"> </location>
|
||||
<location seat="5" x="402" y="323"> </location>
|
||||
<location seat="6" x="243" y="311"> </location>
|
||||
<location seat="7" x="203" y="262"> </location>
|
||||
<location seat="8" x="170" y="185"> </location>
|
||||
<location seat="9" x="183" y="128"> </location>
|
||||
<location seat="10" x="213" y="86"> </location>
|
||||
<location common="1" x="317" y="237"> </location>
|
||||
</layout>
|
||||
</aw>
|
||||
</aux_windows>
|
||||
|
||||
<hhcs>
|
||||
<hhc site="PokerStars" converter="PokerStarsToFpdb"/>
|
||||
<hhc site="Full Tilt Poker" converter="FulltiltToFpdb"/>
|
||||
<hhc site="Everleaf" converter="EverleafToFpdb"/>
|
||||
</hhcs>
|
||||
|
||||
<supported_databases>
|
||||
<database db_name="fpdb" db_server="mysql" db_ip="localhost" db_user="fpdb" db_pass="YOUR MYSQL PASSWORD" db_type="fpdb"> </database>
|
||||
<database db_name="fpdb" db_server="mysql" db_ip="localhost" db_user="fpdb" db_pass="YOUR MYSQL PASSWORD" db_type="fpdb"></database>
|
||||
</supported_databases>
|
||||
<mucked_windows>
|
||||
<mw mw_name="stud1" format="stud" rows="8" cols="11" deck="Cards01.png" card_wd="30" card_ht="42"> </mw>
|
||||
</mucked_windows>
|
||||
|
||||
</FreePokerToolsConfig>
|
||||
|
||||
|
||||
|
|
|
@ -51,6 +51,8 @@ import Database
|
|||
import Tables
|
||||
import Hud
|
||||
|
||||
aggregate_stats = {"ring": False, "tour": False} # config file!
|
||||
|
||||
class HUD_main(object):
|
||||
"""A main() object to own both the read_stdin thread and the gui."""
|
||||
# This class mainly provides state for controlling the multiple HUDs.
|
||||
|
@ -79,13 +81,14 @@ class HUD_main(object):
|
|||
|
||||
def kill_hud(self, event, table):
|
||||
# called by an event in the HUD, to kill this specific HUD
|
||||
self.hud_dict[table].kill()
|
||||
self.hud_dict[table].main_window.destroy()
|
||||
self.vb.remove(self.hud_dict[table].tablehudlabel)
|
||||
del(self.hud_dict[table])
|
||||
if table in self.hud_dict:
|
||||
self.hud_dict[table].kill()
|
||||
self.hud_dict[table].main_window.destroy()
|
||||
self.vb.remove(self.hud_dict[table].tablehudlabel)
|
||||
del(self.hud_dict[table])
|
||||
self.main_window.resize(1,1)
|
||||
|
||||
def create_HUD(self, new_hand_id, table, table_name, max, poker_game, is_tournament, stat_dict, cards):
|
||||
def create_HUD(self, new_hand_id, table, table_name, max, poker_game, stat_dict, cards):
|
||||
|
||||
def idle_func():
|
||||
|
||||
|
@ -108,9 +111,9 @@ class HUD_main(object):
|
|||
gtk.gdk.threads_leave()
|
||||
|
||||
self.hud_dict[table_name] = Hud.Hud(self, table, max, poker_game, self.config, self.db_connection)
|
||||
self.hud_dict[table_name].table_name = table_name
|
||||
self.hud_dict[table_name].stat_dict = stat_dict
|
||||
self.hud_dict[table_name].cards = cards
|
||||
|
||||
[aw.update_data(new_hand_id, self.db_connection) for aw in self.hud_dict[table_name].aux_windows]
|
||||
gobject.idle_add(idle_func)
|
||||
|
||||
|
@ -149,8 +152,8 @@ class HUD_main(object):
|
|||
# get basic info about the new hand from the db
|
||||
# if there is a db error, complain, skip hand, and proceed
|
||||
try:
|
||||
(table_name, max, poker_game) = self.db_connection.get_table_name(new_hand_id)
|
||||
stat_dict = self.db_connection.get_stats_from_hand(new_hand_id)
|
||||
(table_name, max, poker_game, type) = self.db_connection.get_table_name(new_hand_id)
|
||||
stat_dict = self.db_connection.get_stats_from_hand(new_hand_id, aggregate = aggregate_stats[type])
|
||||
cards = self.db_connection.get_cards(new_hand_id)
|
||||
comm_cards = self.db_connection.get_common_cards(new_hand_id)
|
||||
if comm_cards != {}: # stud!
|
||||
|
@ -160,15 +163,17 @@ class HUD_main(object):
|
|||
sys.stderr.write("Database error %s in hand %d. Skipping.\n" % (err, int(new_hand_id)))
|
||||
continue
|
||||
|
||||
# find out if this hand is from a tournament
|
||||
mat_obj = tourny_finder.search(table_name)
|
||||
if mat_obj:
|
||||
is_tournament = True
|
||||
(tour_number, tab_number) = mat_obj.group(1, 2)
|
||||
temp_key = tour_number
|
||||
if type == "tour": # hand is from a tournament
|
||||
mat_obj = tourny_finder.search(table_name)
|
||||
if mat_obj:
|
||||
(tour_number, tab_number) = mat_obj.group(1, 2)
|
||||
temp_key = tour_number
|
||||
else: # tourney, but can't get number and table
|
||||
print "could not find tournament: skipping "
|
||||
sys.stderr.write("Could not find tournament %d in hand %d. Skipping.\n" % (int(tour_number), int(new_hand_id)))
|
||||
continue
|
||||
|
||||
else:
|
||||
is_tournament = False
|
||||
(tour_number, tab_number) = (0, 0)
|
||||
temp_key = table_name
|
||||
|
||||
# Update an existing HUD
|
||||
|
@ -180,18 +185,18 @@ class HUD_main(object):
|
|||
|
||||
# Or create a new HUD
|
||||
else:
|
||||
if is_tournament:
|
||||
if type == "tour":
|
||||
tablewindow = Tables.discover_tournament_table(self.config, tour_number, tab_number)
|
||||
else:
|
||||
tablewindow = Tables.discover_table_by_name(self.config, table_name)
|
||||
|
||||
if tablewindow == None:
|
||||
# If no client window is found on the screen, complain and continue
|
||||
if is_tournament:
|
||||
if type == "tour":
|
||||
table_name = "%s %s" % (tour_number, tab_number)
|
||||
sys.stderr.write("table name "+table_name+" not found, skipping.\n")
|
||||
else:
|
||||
self.create_HUD(new_hand_id, tablewindow, temp_key, max, poker_game, is_tournament, stat_dict, cards)
|
||||
self.create_HUD(new_hand_id, tablewindow, temp_key, max, poker_game, stat_dict, cards)
|
||||
self.db_connection.connection.rollback()
|
||||
|
||||
if __name__== "__main__":
|
||||
sys.stderr.write("HUD_main starting\n")
|
||||
|
|
|
@ -125,7 +125,7 @@ class Hud:
|
|||
self.menu = gtk.Menu()
|
||||
self.item1 = gtk.MenuItem('Kill this HUD')
|
||||
self.menu.append(self.item1)
|
||||
self.item1.connect("activate", self.parent.kill_hud, self.table.name)
|
||||
self.item1.connect("activate", self.parent.kill_hud, self.table_name)
|
||||
self.item1.show()
|
||||
|
||||
self.item2 = gtk.MenuItem('Save Layout')
|
||||
|
@ -204,14 +204,14 @@ class Hud:
|
|||
def reposition_windows(self, *args):
|
||||
for w in self.stat_windows.itervalues():
|
||||
if type(w) == int:
|
||||
print "in reposition, w =", w
|
||||
# print "in reposition, w =", w
|
||||
continue
|
||||
print "in reposition, w =", w, w.x, w.y
|
||||
# print "in reposition, w =", w, w.x, w.y
|
||||
w.window.move(w.x, w.y)
|
||||
return True
|
||||
|
||||
def debug_stat_windows(self, *args):
|
||||
print self.table, "\n", self.main_window.window.get_transient_for()
|
||||
# print self.table, "\n", self.main_window.window.get_transient_for()
|
||||
for w in self.stat_windows:
|
||||
print self.stat_windows[w].window.window.get_transient_for()
|
||||
|
||||
|
|
|
@ -451,7 +451,7 @@ class Flop_Mucked(Aux_Window):
|
|||
def save_layout(self, *args):
|
||||
"""Save new layout back to the aux element in the config file."""
|
||||
new_locs = {}
|
||||
print "adj =", self.adj
|
||||
# print "adj =", self.adj
|
||||
for (i, pos) in self.positions.iteritems():
|
||||
if i != 'common':
|
||||
new_locs[self.adj[int(i)]] = (pos[0] - self.hud.table.x, pos[1] - self.hud.table.y)
|
||||
|
|
|
@ -73,7 +73,7 @@ follow : whether to tail -f the input"""
|
|||
["ring", "hold", "pl"],
|
||||
["ring", "hold", "fl"],
|
||||
["ring", "stud", "fl"],
|
||||
["ring", "draw", "fl"],
|
||||
#["ring", "draw", "fl"],
|
||||
["ring", "omaha", "pl"]
|
||||
]
|
||||
|
||||
|
|
486
pyfpdb/SQL.py
486
pyfpdb/SQL.py
|
@ -29,7 +29,7 @@ Set up all of the SQL statements for a given game and database type.
|
|||
|
||||
class Sql:
|
||||
|
||||
def __init__(self, game = 'holdem', type = 'PT3'):
|
||||
def __init__(self, game = 'holdem', type = 'PT3', db_server = 'mysql'):
|
||||
self.query = {}
|
||||
|
||||
############################################################################
|
||||
|
@ -172,148 +172,328 @@ class Sql:
|
|||
"""
|
||||
|
||||
self.query['get_stats_from_hand'] = """
|
||||
SELECT HudCache.playerId AS player_id,
|
||||
seatNo AS seat,
|
||||
name AS screen_name,
|
||||
sum(HDs) AS n,
|
||||
sum(street0VPI) AS vpip,
|
||||
sum(street0Aggr) AS pfr,
|
||||
sum(street0_3B4BChance) AS TB_opp_0,
|
||||
sum(street0_3B4BDone) AS TB_0,
|
||||
sum(street1Seen) AS saw_f,
|
||||
sum(street1Seen) AS saw_1,
|
||||
sum(street2Seen) AS saw_2,
|
||||
sum(street3Seen) AS saw_3,
|
||||
sum(street4Seen) AS saw_4,
|
||||
sum(sawShowdown) AS sd,
|
||||
sum(street1Aggr) AS aggr_1,
|
||||
sum(street2Aggr) AS aggr_2,
|
||||
sum(street3Aggr) AS aggr_3,
|
||||
sum(street4Aggr) AS aggr_4,
|
||||
sum(otherRaisedStreet1) AS was_raised_1,
|
||||
sum(otherRaisedStreet2) AS was_raised_2,
|
||||
sum(otherRaisedStreet3) AS was_raised_3,
|
||||
sum(otherRaisedStreet4) AS was_raised_4,
|
||||
sum(foldToOtherRaisedStreet1) AS f_freq_1,
|
||||
sum(foldToOtherRaisedStreet2) AS f_freq_2,
|
||||
sum(foldToOtherRaisedStreet3) AS f_freq_3,
|
||||
sum(foldToOtherRaisedStreet4) AS f_freq_4,
|
||||
sum(wonWhenSeenStreet1) AS w_w_s_1,
|
||||
sum(wonAtSD) AS wmsd,
|
||||
sum(stealAttemptChance) AS steal_opp,
|
||||
sum(stealAttempted) AS steal,
|
||||
sum(foldSbToStealChance) AS SBstolen,
|
||||
sum(foldedSbToSteal) AS SBnotDef,
|
||||
sum(foldBbToStealChance) AS BBstolen,
|
||||
sum(foldedBbToSteal) AS BBnotDef,
|
||||
sum(street1CBChance) AS CB_opp_1,
|
||||
sum(street1CBDone) AS CB_1,
|
||||
sum(street2CBChance) AS CB_opp_2,
|
||||
sum(street2CBDone) AS CB_2,
|
||||
sum(street3CBChance) AS CB_opp_3,
|
||||
sum(street3CBDone) AS CB_3,
|
||||
sum(street4CBChance) AS CB_opp_4,
|
||||
sum(street4CBDone) AS CB_4,
|
||||
sum(foldToStreet1CBChance) AS f_cb_opp_1,
|
||||
sum(foldToStreet1CBDone) AS f_cb_1,
|
||||
sum(foldToStreet2CBChance) AS f_cb_opp_2,
|
||||
sum(foldToStreet2CBDone) AS f_cb_2,
|
||||
sum(foldToStreet3CBChance) AS f_cb_opp_3,
|
||||
sum(foldToStreet3CBDone) AS f_cb_3,
|
||||
sum(foldToStreet4CBChance) AS f_cb_opp_4,
|
||||
sum(foldToStreet4CBDone) AS f_cb_4,
|
||||
sum(totalProfit) AS net,
|
||||
sum(street1CheckCallRaiseChance) AS ccr_opp_1,
|
||||
sum(street1CheckCallRaiseDone) AS ccr_1,
|
||||
sum(street2CheckCallRaiseChance) AS ccr_opp_2,
|
||||
sum(street2CheckCallRaiseDone) AS ccr_2,
|
||||
sum(street3CheckCallRaiseChance) AS ccr_opp_3,
|
||||
sum(street3CheckCallRaiseDone) AS ccr_3,
|
||||
sum(street4CheckCallRaiseChance) AS ccr_opp_4,
|
||||
sum(street4CheckCallRaiseDone) AS ccr_4
|
||||
FROM Hands
|
||||
INNER JOIN HandsPlayers ON (HandsPlayers.handId = %s)
|
||||
INNER JOIN HudCache ON ( HudCache.PlayerId = HandsPlayers.PlayerId+0
|
||||
AND HudCache.gametypeId+0 = Hands.gametypeId+0)
|
||||
INNER JOIN Players ON (Players.id = HandsPlayers.PlayerId+0)
|
||||
WHERE Hands.id = %s
|
||||
GROUP BY HudCache.PlayerId
|
||||
SELECT hc.playerId AS player_id,
|
||||
hp.seatNo AS seat,
|
||||
p.name AS screen_name,
|
||||
sum(hc.HDs) AS n,
|
||||
sum(hc.street0VPI) AS vpip,
|
||||
sum(hc.street0Aggr) AS pfr,
|
||||
sum(hc.street0_3BChance) AS TB_opp_0,
|
||||
sum(hc.street0_3BDone) AS TB_0,
|
||||
sum(hc.street1Seen) AS saw_f,
|
||||
sum(hc.street1Seen) AS saw_1,
|
||||
sum(hc.street2Seen) AS saw_2,
|
||||
sum(hc.street3Seen) AS saw_3,
|
||||
sum(hc.street4Seen) AS saw_4,
|
||||
sum(hc.sawShowdown) AS sd,
|
||||
sum(hc.street1Aggr) AS aggr_1,
|
||||
sum(hc.street2Aggr) AS aggr_2,
|
||||
sum(hc.street3Aggr) AS aggr_3,
|
||||
sum(hc.street4Aggr) AS aggr_4,
|
||||
sum(hc.otherRaisedStreet1) AS was_raised_1,
|
||||
sum(hc.otherRaisedStreet2) AS was_raised_2,
|
||||
sum(hc.otherRaisedStreet3) AS was_raised_3,
|
||||
sum(hc.otherRaisedStreet4) AS was_raised_4,
|
||||
sum(hc.foldToOtherRaisedStreet1) AS f_freq_1,
|
||||
sum(hc.foldToOtherRaisedStreet2) AS f_freq_2,
|
||||
sum(hc.foldToOtherRaisedStreet3) AS f_freq_3,
|
||||
sum(hc.foldToOtherRaisedStreet4) AS f_freq_4,
|
||||
sum(hc.wonWhenSeenStreet1) AS w_w_s_1,
|
||||
sum(hc.wonAtSD) AS wmsd,
|
||||
sum(hc.stealAttemptChance) AS steal_opp,
|
||||
sum(hc.stealAttempted) AS steal,
|
||||
sum(hc.foldSbToStealChance) AS SBstolen,
|
||||
sum(hc.foldedSbToSteal) AS SBnotDef,
|
||||
sum(hc.foldBbToStealChance) AS BBstolen,
|
||||
sum(hc.foldedBbToSteal) AS BBnotDef,
|
||||
sum(hc.street1CBChance) AS CB_opp_1,
|
||||
sum(hc.street1CBDone) AS CB_1,
|
||||
sum(hc.street2CBChance) AS CB_opp_2,
|
||||
sum(hc.street2CBDone) AS CB_2,
|
||||
sum(hc.street3CBChance) AS CB_opp_3,
|
||||
sum(hc.street3CBDone) AS CB_3,
|
||||
sum(hc.street4CBChance) AS CB_opp_4,
|
||||
sum(hc.street4CBDone) AS CB_4,
|
||||
sum(hc.foldToStreet1CBChance) AS f_cb_opp_1,
|
||||
sum(hc.foldToStreet1CBDone) AS f_cb_1,
|
||||
sum(hc.foldToStreet2CBChance) AS f_cb_opp_2,
|
||||
sum(hc.foldToStreet2CBDone) AS f_cb_2,
|
||||
sum(hc.foldToStreet3CBChance) AS f_cb_opp_3,
|
||||
sum(hc.foldToStreet3CBDone) AS f_cb_3,
|
||||
sum(hc.foldToStreet4CBChance) AS f_cb_opp_4,
|
||||
sum(hc.foldToStreet4CBDone) AS f_cb_4,
|
||||
sum(hc.totalProfit) AS net,
|
||||
sum(hc.street1CheckCallRaiseChance) AS ccr_opp_1,
|
||||
sum(hc.street1CheckCallRaiseDone) AS ccr_1,
|
||||
sum(hc.street2CheckCallRaiseChance) AS ccr_opp_2,
|
||||
sum(hc.street2CheckCallRaiseDone) AS ccr_2,
|
||||
sum(hc.street3CheckCallRaiseChance) AS ccr_opp_3,
|
||||
sum(hc.street3CheckCallRaiseDone) AS ccr_3,
|
||||
sum(hc.street4CheckCallRaiseChance) AS ccr_opp_4,
|
||||
sum(hc.street4CheckCallRaiseDone) AS ccr_4
|
||||
FROM Hands h
|
||||
INNER JOIN HandsPlayers hp ON (hp.handId = %s)
|
||||
INNER JOIN HudCache hc ON ( hc.PlayerId = hp.PlayerId+0
|
||||
AND hc.gametypeId+0 = h.gametypeId+0)
|
||||
INNER JOIN Players p ON (p.id = hp.PlayerId+0)
|
||||
WHERE h.id = %s
|
||||
AND hc.styleKey > %s
|
||||
/* styleKey is currently 'd' (for date) followed by a yyyymmdd
|
||||
date key. Set it to 0000000 or similar to get all records */
|
||||
/* also check activeseats here? even if only 3 groups eg 2-3/4-6/7+ ??
|
||||
e.g. could use a multiplier:
|
||||
AND h.seats > X / 1.25 and hp.seats < X * 1.25
|
||||
where X is the number of active players at the current table (and
|
||||
1.25 would be a config value so user could change it)
|
||||
*/
|
||||
GROUP BY hc.PlayerId, hp.seatNo, p.name
|
||||
"""
|
||||
|
||||
# same as above except stats are aggregated for all blind/limit levels
|
||||
self.query['get_stats_from_hand_aggregated'] = """
|
||||
SELECT HudCache.playerId AS player_id,
|
||||
sum(HDs) AS n,
|
||||
sum(street0VPI) AS vpip,
|
||||
sum(street0Aggr) AS pfr,
|
||||
sum(street0_3B4BChance) AS TB_opp_0,
|
||||
sum(street0_3B4BDone) AS TB_0,
|
||||
sum(street1Seen) AS saw_f,
|
||||
sum(street1Seen) AS saw_1,
|
||||
sum(street2Seen) AS saw_2,
|
||||
sum(street3Seen) AS saw_3,
|
||||
sum(street4Seen) AS saw_4,
|
||||
sum(sawShowdown) AS sd,
|
||||
sum(street1Aggr) AS aggr_1,
|
||||
sum(street2Aggr) AS aggr_2,
|
||||
sum(street3Aggr) AS aggr_3,
|
||||
sum(street4Aggr) AS aggr_4,
|
||||
sum(otherRaisedStreet1) AS was_raised_1,
|
||||
sum(otherRaisedStreet2) AS was_raised_2,
|
||||
sum(otherRaisedStreet3) AS was_raised_3,
|
||||
sum(otherRaisedStreet4) AS was_raised_4,
|
||||
sum(foldToOtherRaisedStreet1) AS f_freq_1,
|
||||
sum(foldToOtherRaisedStreet2) AS f_freq_2,
|
||||
sum(foldToOtherRaisedStreet3) AS f_freq_3,
|
||||
sum(foldToOtherRaisedStreet4) AS f_freq_4,
|
||||
sum(wonWhenSeenStreet1) AS w_w_s_1,
|
||||
sum(wonAtSD) AS wmsd,
|
||||
sum(stealAttemptChance) AS steal_opp,
|
||||
sum(stealAttempted) AS steal,
|
||||
sum(foldSbToStealChance) AS SBstolen,
|
||||
sum(foldedSbToSteal) AS SBnotDef,
|
||||
sum(foldBbToStealChance) AS BBstolen,
|
||||
sum(foldedBbToSteal) AS BBnotDef,
|
||||
sum(street1CBChance) AS CB_opp_1,
|
||||
sum(street1CBDone) AS CB_1,
|
||||
sum(street2CBChance) AS CB_opp_2,
|
||||
sum(street2CBDone) AS CB_2,
|
||||
sum(street3CBChance) AS CB_opp_3,
|
||||
sum(street3CBDone) AS CB_3,
|
||||
sum(street4CBChance) AS CB_opp_4,
|
||||
sum(street4CBDone) AS CB_4,
|
||||
sum(foldToStreet1CBChance) AS f_cb_opp_1,
|
||||
sum(foldToStreet1CBDone) AS f_cb_1,
|
||||
sum(foldToStreet2CBChance) AS f_cb_opp_2,
|
||||
sum(foldToStreet2CBDone) AS f_cb_2,
|
||||
sum(foldToStreet3CBChance) AS f_cb_opp_3,
|
||||
sum(foldToStreet3CBDone) AS f_cb_3,
|
||||
sum(foldToStreet4CBChance) AS f_cb_opp_4,
|
||||
sum(foldToStreet4CBDone) AS f_cb_4,
|
||||
sum(totalProfit) AS net,
|
||||
sum(street1CheckCallRaiseChance) AS ccr_opp_1,
|
||||
sum(street1CheckCallRaiseDone) AS ccr_1,
|
||||
sum(street2CheckCallRaiseChance) AS ccr_opp_2,
|
||||
sum(street2CheckCallRaiseDone) AS ccr_2,
|
||||
sum(street3CheckCallRaiseChance) AS ccr_opp_3,
|
||||
sum(street3CheckCallRaiseDone) AS ccr_3,
|
||||
sum(street4CheckCallRaiseChance) AS ccr_opp_4,
|
||||
sum(street4CheckCallRaiseDone) AS ccr_4
|
||||
FROM HudCache, Hands
|
||||
WHERE HudCache.PlayerId in
|
||||
(SELECT PlayerId FROM HandsPlayers
|
||||
WHERE handId = %s)
|
||||
AND Hands.id = %s
|
||||
AND HudCache.gametypeId in
|
||||
(SELECT gt1.id from Gametypes gt1, Gametypes gt2, Hands
|
||||
WHERE gt1.siteid = gt2.siteid
|
||||
AND gt1.type = gt2.type
|
||||
AND gt1.category = gt2.category
|
||||
AND gt1.limittype = gt2.limittype
|
||||
AND gt2.id = Hands.gametypeId
|
||||
AND Hands.id = %s)
|
||||
GROUP BY HudCache.PlayerId
|
||||
SELECT hc.playerId AS player_id,
|
||||
max(case when hc.gametypeId = h.gametypeId
|
||||
then hp.seatNo
|
||||
else -1
|
||||
end) AS seat,
|
||||
p.name AS screen_name,
|
||||
sum(hc.HDs) AS n,
|
||||
sum(hc.street0VPI) AS vpip,
|
||||
sum(hc.street0Aggr) AS pfr,
|
||||
sum(hc.street0_3BChance) AS TB_opp_0,
|
||||
sum(hc.street0_3BDone) AS TB_0,
|
||||
sum(hc.street1Seen) AS saw_f,
|
||||
sum(hc.street1Seen) AS saw_1,
|
||||
sum(hc.street2Seen) AS saw_2,
|
||||
sum(hc.street3Seen) AS saw_3,
|
||||
sum(hc.street4Seen) AS saw_4,
|
||||
sum(hc.sawShowdown) AS sd,
|
||||
sum(hc.street1Aggr) AS aggr_1,
|
||||
sum(hc.street2Aggr) AS aggr_2,
|
||||
sum(hc.street3Aggr) AS aggr_3,
|
||||
sum(hc.street4Aggr) AS aggr_4,
|
||||
sum(hc.otherRaisedStreet1) AS was_raised_1,
|
||||
sum(hc.otherRaisedStreet2) AS was_raised_2,
|
||||
sum(hc.otherRaisedStreet3) AS was_raised_3,
|
||||
sum(hc.otherRaisedStreet4) AS was_raised_4,
|
||||
sum(hc.foldToOtherRaisedStreet1) AS f_freq_1,
|
||||
sum(hc.foldToOtherRaisedStreet2) AS f_freq_2,
|
||||
sum(hc.foldToOtherRaisedStreet3) AS f_freq_3,
|
||||
sum(hc.foldToOtherRaisedStreet4) AS f_freq_4,
|
||||
sum(hc.wonWhenSeenStreet1) AS w_w_s_1,
|
||||
sum(hc.wonAtSD) AS wmsd,
|
||||
sum(hc.stealAttemptChance) AS steal_opp,
|
||||
sum(hc.stealAttempted) AS steal,
|
||||
sum(hc.foldSbToStealChance) AS SBstolen,
|
||||
sum(hc.foldedSbToSteal) AS SBnotDef,
|
||||
sum(hc.foldBbToStealChance) AS BBstolen,
|
||||
sum(hc.foldedBbToSteal) AS BBnotDef,
|
||||
sum(hc.street1CBChance) AS CB_opp_1,
|
||||
sum(hc.street1CBDone) AS CB_1,
|
||||
sum(hc.street2CBChance) AS CB_opp_2,
|
||||
sum(hc.street2CBDone) AS CB_2,
|
||||
sum(hc.street3CBChance) AS CB_opp_3,
|
||||
sum(hc.street3CBDone) AS CB_3,
|
||||
sum(hc.street4CBChance) AS CB_opp_4,
|
||||
sum(hc.street4CBDone) AS CB_4,
|
||||
sum(hc.foldToStreet1CBChance) AS f_cb_opp_1,
|
||||
sum(hc.foldToStreet1CBDone) AS f_cb_1,
|
||||
sum(hc.foldToStreet2CBChance) AS f_cb_opp_2,
|
||||
sum(hc.foldToStreet2CBDone) AS f_cb_2,
|
||||
sum(hc.foldToStreet3CBChance) AS f_cb_opp_3,
|
||||
sum(hc.foldToStreet3CBDone) AS f_cb_3,
|
||||
sum(hc.foldToStreet4CBChance) AS f_cb_opp_4,
|
||||
sum(hc.foldToStreet4CBDone) AS f_cb_4,
|
||||
sum(hc.totalProfit) AS net,
|
||||
sum(hc.street1CheckCallRaiseChance) AS ccr_opp_1,
|
||||
sum(hc.street1CheckCallRaiseDone) AS ccr_1,
|
||||
sum(hc.street2CheckCallRaiseChance) AS ccr_opp_2,
|
||||
sum(hc.street2CheckCallRaiseDone) AS ccr_2,
|
||||
sum(hc.street3CheckCallRaiseChance) AS ccr_opp_3,
|
||||
sum(hc.street3CheckCallRaiseDone) AS ccr_3,
|
||||
sum(hc.street4CheckCallRaiseChance) AS ccr_opp_4,
|
||||
sum(hc.street4CheckCallRaiseDone) AS ccr_4
|
||||
FROM Hands h
|
||||
INNER JOIN HandsPlayers hp ON (hp.handId = %s)
|
||||
INNER JOIN HudCache hc ON (hc.playerId = hp.playerId)
|
||||
INNER JOIN Players p ON (p.id = hc.playerId)
|
||||
WHERE h.id = %s
|
||||
AND hc.styleKey > %s
|
||||
/* styleKey is currently 'd' (for date) followed by a yyyymmdd
|
||||
date key. Set it to 0000000 or similar to get all records */
|
||||
/* also check activeseats here? even if only 3 groups eg 2-3/4-6/7+ ??
|
||||
e.g. could use a multiplier:
|
||||
AND h.seats > %s / 1.25 and hp.seats < %s * 1.25
|
||||
where %s is the number of active players at the current table (and
|
||||
1.25 would be a config value so user could change it)
|
||||
*/
|
||||
AND hc.gametypeId+0 in
|
||||
(SELECT gt1.id from Gametypes gt1, Gametypes gt2
|
||||
WHERE gt1.siteid = gt2.siteid
|
||||
AND gt1.type = gt2.type
|
||||
AND gt1.category = gt2.category
|
||||
AND gt1.limittype = gt2.limittype
|
||||
AND gt2.id = h.gametypeId)
|
||||
GROUP BY hc.PlayerId, p.name, hc.styleKey
|
||||
"""
|
||||
|
||||
if db_server == 'mysql':
|
||||
self.query['get_stats_from_hand_session'] = """
|
||||
SELECT hp.playerId AS player_id,
|
||||
hp.handId AS hand_id,
|
||||
hp.seatNo AS seat,
|
||||
p.name AS screen_name,
|
||||
h.seats AS seats,
|
||||
1 AS n,
|
||||
cast(hp2.street0VPI as <signed>integer) AS vpip,
|
||||
cast(hp2.street0Aggr as <signed>integer) AS pfr,
|
||||
cast(hp2.street0_3BChance as <signed>integer) AS TB_opp_0,
|
||||
cast(hp2.street0_3BDone as <signed>integer) AS TB_0,
|
||||
cast(hp2.street1Seen as <signed>integer) AS saw_f,
|
||||
cast(hp2.street1Seen as <signed>integer) AS saw_1,
|
||||
cast(hp2.street2Seen as <signed>integer) AS saw_2,
|
||||
cast(hp2.street3Seen as <signed>integer) AS saw_3,
|
||||
cast(hp2.street4Seen as <signed>integer) AS saw_4,
|
||||
cast(hp2.sawShowdown as <signed>integer) AS sd,
|
||||
cast(hp2.street1Aggr as <signed>integer) AS aggr_1,
|
||||
cast(hp2.street2Aggr as <signed>integer) AS aggr_2,
|
||||
cast(hp2.street3Aggr as <signed>integer) AS aggr_3,
|
||||
cast(hp2.street4Aggr as <signed>integer) AS aggr_4,
|
||||
cast(hp2.otherRaisedStreet1 as <signed>integer) AS was_raised_1,
|
||||
cast(hp2.otherRaisedStreet2 as <signed>integer) AS was_raised_2,
|
||||
cast(hp2.otherRaisedStreet3 as <signed>integer) AS was_raised_3,
|
||||
cast(hp2.otherRaisedStreet4 as <signed>integer) AS was_raised_4,
|
||||
cast(hp2.foldToOtherRaisedStreet1 as <signed>integer) AS f_freq_1,
|
||||
cast(hp2.foldToOtherRaisedStreet2 as <signed>integer) AS f_freq_2,
|
||||
cast(hp2.foldToOtherRaisedStreet3 as <signed>integer) AS f_freq_3,
|
||||
cast(hp2.foldToOtherRaisedStreet4 as <signed>integer) AS f_freq_4,
|
||||
cast(hp2.wonWhenSeenStreet1 as <signed>integer) AS w_w_s_1,
|
||||
cast(hp2.wonAtSD as <signed>integer) AS wmsd,
|
||||
cast(hp2.stealAttemptChance as <signed>integer) AS steal_opp,
|
||||
cast(hp2.stealAttempted as <signed>integer) AS steal,
|
||||
cast(hp2.foldSbToStealChance as <signed>integer) AS SBstolen,
|
||||
cast(hp2.foldedSbToSteal as <signed>integer) AS SBnotDef,
|
||||
cast(hp2.foldBbToStealChance as <signed>integer) AS BBstolen,
|
||||
cast(hp2.foldedBbToSteal as <signed>integer) AS BBnotDef,
|
||||
cast(hp2.street1CBChance as <signed>integer) AS CB_opp_1,
|
||||
cast(hp2.street1CBDone as <signed>integer) AS CB_1,
|
||||
cast(hp2.street2CBChance as <signed>integer) AS CB_opp_2,
|
||||
cast(hp2.street2CBDone as <signed>integer) AS CB_2,
|
||||
cast(hp2.street3CBChance as <signed>integer) AS CB_opp_3,
|
||||
cast(hp2.street3CBDone as <signed>integer) AS CB_3,
|
||||
cast(hp2.street4CBChance as <signed>integer) AS CB_opp_4,
|
||||
cast(hp2.street4CBDone as <signed>integer) AS CB_4,
|
||||
cast(hp2.foldToStreet1CBChance as <signed>integer) AS f_cb_opp_1,
|
||||
cast(hp2.foldToStreet1CBDone as <signed>integer) AS f_cb_1,
|
||||
cast(hp2.foldToStreet2CBChance as <signed>integer) AS f_cb_opp_2,
|
||||
cast(hp2.foldToStreet2CBDone as <signed>integer) AS f_cb_2,
|
||||
cast(hp2.foldToStreet3CBChance as <signed>integer) AS f_cb_opp_3,
|
||||
cast(hp2.foldToStreet3CBDone as <signed>integer) AS f_cb_3,
|
||||
cast(hp2.foldToStreet4CBChance as <signed>integer) AS f_cb_opp_4,
|
||||
cast(hp2.foldToStreet4CBDone as <signed>integer) AS f_cb_4,
|
||||
cast(hp2.totalProfit as <signed>integer) AS net,
|
||||
cast(hp2.street1CheckCallRaiseChance as <signed>integer) AS ccr_opp_1,
|
||||
cast(hp2.street1CheckCallRaiseDone as <signed>integer) AS ccr_1,
|
||||
cast(hp2.street2CheckCallRaiseChance as <signed>integer) AS ccr_opp_2,
|
||||
cast(hp2.street2CheckCallRaiseDone as <signed>integer) AS ccr_2,
|
||||
cast(hp2.street3CheckCallRaiseChance as <signed>integer) AS ccr_opp_3,
|
||||
cast(hp2.street3CheckCallRaiseDone as <signed>integer) AS ccr_3,
|
||||
cast(hp2.street4CheckCallRaiseChance as <signed>integer) AS ccr_opp_4,
|
||||
cast(hp2.street4CheckCallRaiseDone as <signed>integer) AS ccr_4
|
||||
FROM
|
||||
Hands h /* players in this hand */
|
||||
INNER JOIN Hands h2 ON (h2.id > %s AND h2.tableName = h.tableName)
|
||||
INNER JOIN HandsPlayers hp ON (h.id = hp.handId)
|
||||
INNER JOIN HandsPlayers hp2 ON (hp2.playerId+0 = hp.playerId+0 AND (hp2.handId = h2.id+0)) /* other hands by these players */
|
||||
INNER JOIN Players p ON (p.id = hp2.PlayerId+0)
|
||||
WHERE hp.handId = %s
|
||||
/* check activeseats once this data returned? (don't want to do that here as it might
|
||||
assume a session ended just because the number of seats dipped for a few hands)
|
||||
*/
|
||||
ORDER BY h.handStart desc, hp2.PlayerId
|
||||
/* order rows by handstart descending so that we can stop reading rows when
|
||||
there's a gap over X minutes between hands (ie. when we get back to start of
|
||||
the session */
|
||||
"""
|
||||
else: # assume postgresql
|
||||
self.query['get_stats_from_hand_session'] = """
|
||||
SELECT hp.playerId AS player_id,
|
||||
hp.handId AS hand_id,
|
||||
hp.seatNo AS seat,
|
||||
p.name AS screen_name,
|
||||
h.seats AS seats,
|
||||
1 AS n,
|
||||
cast(hp2.street0VPI as <signed>integer) AS vpip,
|
||||
cast(hp2.street0Aggr as <signed>integer) AS pfr,
|
||||
cast(hp2.street0_3BChance as <signed>integer) AS TB_opp_0,
|
||||
cast(hp2.street0_3BDone as <signed>integer) AS TB_0,
|
||||
cast(hp2.street1Seen as <signed>integer) AS saw_f,
|
||||
cast(hp2.street1Seen as <signed>integer) AS saw_1,
|
||||
cast(hp2.street2Seen as <signed>integer) AS saw_2,
|
||||
cast(hp2.street3Seen as <signed>integer) AS saw_3,
|
||||
cast(hp2.street4Seen as <signed>integer) AS saw_4,
|
||||
cast(hp2.sawShowdown as <signed>integer) AS sd,
|
||||
cast(hp2.street1Aggr as <signed>integer) AS aggr_1,
|
||||
cast(hp2.street2Aggr as <signed>integer) AS aggr_2,
|
||||
cast(hp2.street3Aggr as <signed>integer) AS aggr_3,
|
||||
cast(hp2.street4Aggr as <signed>integer) AS aggr_4,
|
||||
cast(hp2.otherRaisedStreet1 as <signed>integer) AS was_raised_1,
|
||||
cast(hp2.otherRaisedStreet2 as <signed>integer) AS was_raised_2,
|
||||
cast(hp2.otherRaisedStreet3 as <signed>integer) AS was_raised_3,
|
||||
cast(hp2.otherRaisedStreet4 as <signed>integer) AS was_raised_4,
|
||||
cast(hp2.foldToOtherRaisedStreet1 as <signed>integer) AS f_freq_1,
|
||||
cast(hp2.foldToOtherRaisedStreet2 as <signed>integer) AS f_freq_2,
|
||||
cast(hp2.foldToOtherRaisedStreet3 as <signed>integer) AS f_freq_3,
|
||||
cast(hp2.foldToOtherRaisedStreet4 as <signed>integer) AS f_freq_4,
|
||||
cast(hp2.wonWhenSeenStreet1 as <signed>integer) AS w_w_s_1,
|
||||
cast(hp2.wonAtSD as <signed>integer) AS wmsd,
|
||||
cast(hp2.stealAttemptChance as <signed>integer) AS steal_opp,
|
||||
cast(hp2.stealAttempted as <signed>integer) AS steal,
|
||||
cast(hp2.foldSbToStealChance as <signed>integer) AS SBstolen,
|
||||
cast(hp2.foldedSbToSteal as <signed>integer) AS SBnotDef,
|
||||
cast(hp2.foldBbToStealChance as <signed>integer) AS BBstolen,
|
||||
cast(hp2.foldedBbToSteal as <signed>integer) AS BBnotDef,
|
||||
cast(hp2.street1CBChance as <signed>integer) AS CB_opp_1,
|
||||
cast(hp2.street1CBDone as <signed>integer) AS CB_1,
|
||||
cast(hp2.street2CBChance as <signed>integer) AS CB_opp_2,
|
||||
cast(hp2.street2CBDone as <signed>integer) AS CB_2,
|
||||
cast(hp2.street3CBChance as <signed>integer) AS CB_opp_3,
|
||||
cast(hp2.street3CBDone as <signed>integer) AS CB_3,
|
||||
cast(hp2.street4CBChance as <signed>integer) AS CB_opp_4,
|
||||
cast(hp2.street4CBDone as <signed>integer) AS CB_4,
|
||||
cast(hp2.foldToStreet1CBChance as <signed>integer) AS f_cb_opp_1,
|
||||
cast(hp2.foldToStreet1CBDone as <signed>integer) AS f_cb_1,
|
||||
cast(hp2.foldToStreet2CBChance as <signed>integer) AS f_cb_opp_2,
|
||||
cast(hp2.foldToStreet2CBDone as <signed>integer) AS f_cb_2,
|
||||
cast(hp2.foldToStreet3CBChance as <signed>integer) AS f_cb_opp_3,
|
||||
cast(hp2.foldToStreet3CBDone as <signed>integer) AS f_cb_3,
|
||||
cast(hp2.foldToStreet4CBChance as <signed>integer) AS f_cb_opp_4,
|
||||
cast(hp2.foldToStreet4CBDone as <signed>integer) AS f_cb_4,
|
||||
cast(hp2.totalProfit as <signed>integer) AS net,
|
||||
cast(hp2.street1CheckCallRaiseChance as <signed>integer) AS ccr_opp_1,
|
||||
cast(hp2.street1CheckCallRaiseDone as <signed>integer) AS ccr_1,
|
||||
cast(hp2.street2CheckCallRaiseChance as <signed>integer) AS ccr_opp_2,
|
||||
cast(hp2.street2CheckCallRaiseDone as <signed>integer) AS ccr_2,
|
||||
cast(hp2.street3CheckCallRaiseChance as <signed>integer) AS ccr_opp_3,
|
||||
cast(hp2.street3CheckCallRaiseDone as <signed>integer) AS ccr_3,
|
||||
cast(hp2.street4CheckCallRaiseChance as <signed>integer) AS ccr_opp_4,
|
||||
cast(hp2.street4CheckCallRaiseDone as <signed>integer) AS ccr_4
|
||||
FROM Hands h /* this hand */
|
||||
INNER JOIN Hands h2 ON ( h2.id > %s /* other hands */
|
||||
AND h2.tableName = h.tableName)
|
||||
INNER JOIN HandsPlayers hp ON (h.id = hp.handId) /* players in this hand */
|
||||
INNER JOIN HandsPlayers hp2 ON ( hp2.playerId+0 = hp.playerId+0
|
||||
AND hp2.handId = h2.id) /* other hands by these players */
|
||||
INNER JOIN Players p ON (p.id = hp2.PlayerId+0)
|
||||
WHERE h.id = %s
|
||||
/* check activeseats once this data returned? (don't want to do that here as it might
|
||||
assume a session ended just because the number of seats dipped for a few hands)
|
||||
*/
|
||||
ORDER BY h.handStart desc, hp2.PlayerId
|
||||
/* order rows by handstart descending so that we can stop reading rows when
|
||||
there's a gap over X minutes between hands (ie. when we get back to start of
|
||||
the session */
|
||||
"""
|
||||
|
||||
self.query['get_players_from_hand'] = """
|
||||
SELECT HandsPlayers.playerId, seatNo, name
|
||||
|
@ -331,7 +511,7 @@ class Sql:
|
|||
"""
|
||||
|
||||
self.query['get_table_name'] = """
|
||||
select tableName, maxSeats, category
|
||||
select tableName, maxSeats, category, type
|
||||
from Hands,Gametypes
|
||||
where Hands.id = %s
|
||||
and Gametypes.id = Hands.gametypeId
|
||||
|
@ -349,13 +529,13 @@ class Sql:
|
|||
select
|
||||
seatNo AS seat_number,
|
||||
name AS screen_name,
|
||||
card1Value, card1Suit,
|
||||
card2Value, card2Suit,
|
||||
card3Value, card3Suit,
|
||||
card4Value, card4Suit,
|
||||
card5Value, card5Suit,
|
||||
card6Value, card6Suit,
|
||||
card7Value, card7Suit
|
||||
card1, /*card1Value, card1Suit, */
|
||||
card2, /*card2Value, card2Suit, */
|
||||
card3, /*card3Value, card3Suit, */
|
||||
card4, /*card4Value, card4Suit, */
|
||||
card5, /*card5Value, card5Suit, */
|
||||
card6, /*card6Value, card6Suit, */
|
||||
card7 /*card7Value, card7Suit */
|
||||
from HandsPlayers, Players
|
||||
where handID = %s and HandsPlayers.playerId = Players.id
|
||||
order by seatNo
|
||||
|
@ -377,9 +557,21 @@ class Sql:
|
|||
FROM Players, HandsActions, HandsPlayers
|
||||
WHERE HandsPlayers.handid = %s
|
||||
AND HandsPlayers.playerid = Players.id
|
||||
AND HandsActions.handPlayerId = HandsPlayers.id
|
||||
AND HandsActions.handsPlayerId = HandsPlayers.id
|
||||
ORDER BY street, actionno
|
||||
"""
|
||||
|
||||
if db_server == 'mysql':
|
||||
self.query['get_hand_1day_ago'] = """
|
||||
select coalesce(max(id),0)
|
||||
from hands
|
||||
where handstart < date_sub(utc_timestamp(), interval '1' day)"""
|
||||
else: # assume postgresql
|
||||
self.query['get_hand_1day_ago'] = """
|
||||
select coalesce(max(id),0)
|
||||
from hands
|
||||
where handstart < now() at time zone 'UTC' - interval '1 day'"""
|
||||
|
||||
if __name__== "__main__":
|
||||
# just print the default queries and exit
|
||||
s = Sql(game = 'razz', type = 'ptracks')
|
||||
|
|
121
pyfpdb/Stats.py
121
pyfpdb/Stats.py
|
@ -32,6 +32,8 @@
|
|||
# float(stat_dict[player]['vpip'])/float(stat_dict[player]['n']). You can see how the
|
||||
# keys of stat_dict relate to the column names in HudCache by inspecting
|
||||
# the proper section of the SQL.py module.
|
||||
# The stat_dict keys should be in lower case, i.e. vpip not VPIP, since
|
||||
# postgres returns the column names in lower case.
|
||||
# 3 You have to write a small function for each stat you want to add. See
|
||||
# the vpip() function for example. This function has to be protected from
|
||||
# exceptions, using something like the try:/except: paragraphs in vpip.
|
||||
|
@ -189,6 +191,27 @@ def wtsd(stat_dict, player):
|
|||
'% went to showdown'
|
||||
)
|
||||
|
||||
def wtsd_0(stat_dict, player):
|
||||
""" Went to SD when saw flop/4th."""
|
||||
stat = 0.0
|
||||
try:
|
||||
stat = float(stat_dict[player]['sd'])/float(stat_dict[player]['saw_f'])
|
||||
return (stat,
|
||||
'%2.0f' % (100*stat) + '%',
|
||||
'w=%2.0f' % (100*stat) + '%',
|
||||
'wtsd=%2.0f' % (100*stat) + '%',
|
||||
'(%d/%d)' % (stat_dict[player]['sd'], stat_dict[player]['saw_f']),
|
||||
'% went to showdown'
|
||||
)
|
||||
except:
|
||||
return (stat,
|
||||
'%2.0f' % (0) + '%',
|
||||
'w=%2.0f' % (0) + '%',
|
||||
'wtsd=%2.0f' % (0) + '%',
|
||||
'(%d/%d)' % (0, 0),
|
||||
'% went to showdown'
|
||||
)
|
||||
|
||||
def wmsd(stat_dict, player):
|
||||
""" Won $ at showdown."""
|
||||
stat = 0.0
|
||||
|
@ -210,6 +233,27 @@ def wmsd(stat_dict, player):
|
|||
'% won money at showdown'
|
||||
)
|
||||
|
||||
def wmsd_0(stat_dict, player):
|
||||
""" Won $ at showdown."""
|
||||
stat = 0.0
|
||||
try:
|
||||
stat = float(stat_dict[player]['wmsd'])/float(stat_dict[player]['sd'])
|
||||
return (stat,
|
||||
'%2.0f' % (100*stat) + '%',
|
||||
'w=%2.0f' % (100*stat) + '%',
|
||||
'wmsd=%2.0f' % (100*stat) + '%',
|
||||
'(%5.1f/%d)' % (float(stat_dict[player]['wmsd']), stat_dict[player]['sd']),
|
||||
'% won money at showdown'
|
||||
)
|
||||
except:
|
||||
return (stat,
|
||||
'%2.0f' % (0) + '%',
|
||||
'w=%2.0f' % (0) + '%',
|
||||
'wmsd=%2.0f' % (0) + '%',
|
||||
'(%d/%d)' % (0, 0),
|
||||
'% won money at showdown'
|
||||
)
|
||||
|
||||
def profit100_0(stat_dict, player):
|
||||
""" Profit won per 100 hands (no decimal places)."""
|
||||
stat = 0.0
|
||||
|
@ -311,17 +355,38 @@ def steal(stat_dict, player):
|
|||
)
|
||||
except:
|
||||
return (stat, 'NA', 'st=NA', 'steal=NA', '(0/0)', '% steal attempted')
|
||||
|
||||
def steal_0(stat_dict, player):
|
||||
""" Steal %."""
|
||||
stat = 0.0
|
||||
try:
|
||||
stat = float(stat_dict[player]['steal'])/float(stat_dict[player]['steal_opp'])
|
||||
return (stat,
|
||||
'%2.0f' % (100*stat) + '%',
|
||||
'st=%2.0f' % (100*stat) + '%',
|
||||
'steal=%2.0f' % (100*stat) + '%',
|
||||
'(%d/%d)' % (stat_dict[player]['steal'], stat_dict[player]['steal_opp']),
|
||||
'% steal attempted'
|
||||
)
|
||||
except:
|
||||
return (stat,
|
||||
'%2.0f' % (0) + '%',
|
||||
'st=%2.0f' % (0) + '%',
|
||||
'steal=%2.0f' % (0) + '%',
|
||||
'(%d/%d)' % (0, 0),
|
||||
'% steal attempted'
|
||||
)
|
||||
|
||||
def f_SB_steal(stat_dict, player):
|
||||
""" Folded SB to steal."""
|
||||
stat = 0.0
|
||||
try:
|
||||
stat = float(stat_dict[player]['SBnotDef'])/float(stat_dict[player]['SBstolen'])
|
||||
stat = float(stat_dict[player]['sbnotdef'])/float(stat_dict[player]['sbstolen'])
|
||||
return (stat,
|
||||
'%3.1f' % (100*stat) + '%',
|
||||
'fSB=%3.1f' % (100*stat) + '%',
|
||||
'fSB_s=%3.1f' % (100*stat) + '%',
|
||||
'(%d/%d)' % (stat_dict[player]['SBnotDef'], stat_dict[player]['SBstolen']),
|
||||
'(%d/%d)' % (stat_dict[player]['sbnotdef'], stat_dict[player]['sbstolen']),
|
||||
'% folded SB to steal'
|
||||
)
|
||||
except:
|
||||
|
@ -336,12 +401,32 @@ def f_BB_steal(stat_dict, player):
|
|||
""" Folded BB to steal."""
|
||||
stat = 0.0
|
||||
try:
|
||||
stat = float(stat_dict[player]['BBnotDef'])/float(stat_dict[player]['BBstolen'])
|
||||
stat = float(stat_dict[player]['bbnotdef'])/float(stat_dict[player]['bbstolen'])
|
||||
return (stat,
|
||||
'%3.1f' % (100*stat) + '%',
|
||||
'fBB=%3.1f' % (100*stat) + '%',
|
||||
'fBB_s=%3.1f' % (100*stat) + '%',
|
||||
'(%d/%d)' % (stat_dict[player]['BBnotDef'], stat_dict[player]['BBstolen']),
|
||||
'(%d/%d)' % (stat_dict[player]['bbnotdef'], stat_dict[player]['bbstolen']),
|
||||
'% folded BB to steal'
|
||||
)
|
||||
except:
|
||||
return (stat,
|
||||
'NA',
|
||||
'fBB=NA',
|
||||
'fBB_s=NA',
|
||||
'(0/0)',
|
||||
'% folded BB to steal')
|
||||
|
||||
def f_BB_steal_0(stat_dict, player):
|
||||
""" Folded BB to steal."""
|
||||
stat = 0.0
|
||||
try:
|
||||
stat = float(stat_dict[player]['bbnotdef'])/float(stat_dict[player]['bbstolen'])
|
||||
return (stat,
|
||||
'%2.0f' % (100*stat) + '%',
|
||||
'fBB=%2.0f' % (100*stat) + '%',
|
||||
'fBB_s=%2.0f' % (100*stat) + '%',
|
||||
'(%d/%d)' % (stat_dict[player]['bbnotdef'], stat_dict[player]['bbstolen']),
|
||||
'% folded BB to steal'
|
||||
)
|
||||
except:
|
||||
|
@ -356,12 +441,12 @@ def three_B_0(stat_dict, player):
|
|||
""" Three bet preflop/3rd."""
|
||||
stat = 0.0
|
||||
try:
|
||||
stat = float(stat_dict[player]['TB_0'])/float(stat_dict[player]['TB_opp_0'])
|
||||
stat = float(stat_dict[player]['tb_0'])/float(stat_dict[player]['tb_opp_0'])
|
||||
return (stat,
|
||||
'%3.1f' % (100*stat) + '%',
|
||||
'3B=%3.1f' % (100*stat) + '%',
|
||||
'3B_pf=%3.1f' % (100*stat) + '%',
|
||||
'(%d/%d)' % (stat_dict[player]['TB_0'], stat_dict[player]['TB_opp_0']),
|
||||
'(%d/%d)' % (stat_dict[player]['tb_0'], stat_dict[player]['tb_opp_0']),
|
||||
'% 3/4 Bet preflop/3rd'
|
||||
)
|
||||
except:
|
||||
|
@ -537,12 +622,12 @@ def cb_1(stat_dict, player):
|
|||
""" Flop continuation bet."""
|
||||
stat = 0.0
|
||||
try:
|
||||
stat = float(stat_dict[player]['CB_1'])/float(stat_dict[player]['CB_opp_1'])
|
||||
stat = float(stat_dict[player]['cb_1'])/float(stat_dict[player]['cb_opp_1'])
|
||||
return (stat,
|
||||
'%3.1f' % (100*stat) + '%',
|
||||
'cb1=%3.1f' % (100*stat) + '%',
|
||||
'cb_1=%3.1f' % (100*stat) + '%',
|
||||
'(%d/%d)' % (stat_dict[player]['CB_1'], stat_dict[player]['CB_opp_1']),
|
||||
'(%d/%d)' % (stat_dict[player]['cb_1'], stat_dict[player]['cb_opp_1']),
|
||||
'% continuation bet flop/4th'
|
||||
)
|
||||
except:
|
||||
|
@ -558,12 +643,12 @@ def cb_2(stat_dict, player):
|
|||
""" Turn continuation bet."""
|
||||
stat = 0.0
|
||||
try:
|
||||
stat = float(stat_dict[player]['CB_2'])/float(stat_dict[player]['CB_opp_2'])
|
||||
stat = float(stat_dict[player]['cb_2'])/float(stat_dict[player]['cb_opp_2'])
|
||||
return (stat,
|
||||
'%3.1f' % (100*stat) + '%',
|
||||
'cb2=%3.1f' % (100*stat) + '%',
|
||||
'cb_2=%3.1f' % (100*stat) + '%',
|
||||
'(%d/%d)' % (stat_dict[player]['CB_2'], stat_dict[player]['CB_opp_2']),
|
||||
'(%d/%d)' % (stat_dict[player]['cb_2'], stat_dict[player]['cb_opp_2']),
|
||||
'% continuation bet turn/5th'
|
||||
)
|
||||
except:
|
||||
|
@ -579,12 +664,12 @@ def cb_3(stat_dict, player):
|
|||
""" River continuation bet."""
|
||||
stat = 0.0
|
||||
try:
|
||||
stat = float(stat_dict[player]['CB_3'])/float(stat_dict[player]['CB_opp_3'])
|
||||
stat = float(stat_dict[player]['cb_3'])/float(stat_dict[player]['cb_opp_3'])
|
||||
return (stat,
|
||||
'%3.1f' % (100*stat) + '%',
|
||||
'cb3=%3.1f' % (100*stat) + '%',
|
||||
'cb_3=%3.1f' % (100*stat) + '%',
|
||||
'(%d/%d)' % (stat_dict[player]['CB_3'], stat_dict[player]['CB_opp_3']),
|
||||
'(%d/%d)' % (stat_dict[player]['cb_3'], stat_dict[player]['cb_opp_3']),
|
||||
'% continuation bet river/6th'
|
||||
)
|
||||
except:
|
||||
|
@ -600,12 +685,12 @@ def cb_4(stat_dict, player):
|
|||
""" 7th street continuation bet."""
|
||||
stat = 0.0
|
||||
try:
|
||||
stat = float(stat_dict[player]['CB_4'])/float(stat_dict[player]['CB_opp_4'])
|
||||
stat = float(stat_dict[player]['cb_4'])/float(stat_dict[player]['cb_opp_4'])
|
||||
return (stat,
|
||||
'%3.1f' % (100*stat) + '%',
|
||||
'cb4=%3.1f' % (100*stat) + '%',
|
||||
'cb_4=%3.1f' % (100*stat) + '%',
|
||||
'(%d/%d)' % (stat_dict[player]['CB_4'], stat_dict[player]['CB_opp_4']),
|
||||
'(%d/%d)' % (stat_dict[player]['cb_4'], stat_dict[player]['cb_opp_4']),
|
||||
'% continuation bet 7th'
|
||||
)
|
||||
except:
|
||||
|
@ -719,10 +804,10 @@ if __name__== "__main__":
|
|||
print "player = ", player, do_stat(stat_dict, player = player, stat = 'fold_f')
|
||||
print "player = ", player, do_stat(stat_dict, player = player, stat = 'wmsd')
|
||||
print "player = ", player, do_stat(stat_dict, player = player, stat = 'steal')
|
||||
print "player = ", player, do_stat(stat_dict, player = player, stat = 'f_SB_steal')
|
||||
print "player = ", player, do_stat(stat_dict, player = player, stat = 'f_BB_steal')
|
||||
print "player = ", player, do_stat(stat_dict, player = player, stat = 'three_B_0')
|
||||
print "player = ", player, do_stat(stat_dict, player = player, stat = 'WMsF')
|
||||
print "player = ", player, do_stat(stat_dict, player = player, stat = 'f_sb_steal')
|
||||
print "player = ", player, do_stat(stat_dict, player = player, stat = 'f_bb_steal')
|
||||
print "player = ", player, do_stat(stat_dict, player = player, stat = 'three_b_0')
|
||||
print "player = ", player, do_stat(stat_dict, player = player, stat = 'wmsf')
|
||||
print "player = ", player, do_stat(stat_dict, player = player, stat = 'a_freq_1')
|
||||
print "player = ", player, do_stat(stat_dict, player = player, stat = 'a_freq_2')
|
||||
print "player = ", player, do_stat(stat_dict, player = player, stat = 'a_freq_3')
|
||||
|
|
|
@ -135,7 +135,7 @@ def discover_posix(c):
|
|||
if re.search(params['table_finder'], listing):
|
||||
if 'Lobby' in listing: continue
|
||||
if 'Instant Hand History' in listing: continue
|
||||
if '\"Full Tilt Poker\"' in listing: continue
|
||||
# if '\"Full Tilt Poker\"' in listing: continue
|
||||
if 'History for table:' in listing: continue
|
||||
if 'has no name' in listing: continue
|
||||
info = decode_xwininfo(c, listing)
|
||||
|
@ -391,7 +391,7 @@ def discover_mac_by_name(c, tablename):
|
|||
if __name__=="__main__":
|
||||
c = Configuration.Config()
|
||||
|
||||
print discover_table_by_name(c, "Ringe")
|
||||
print discover_table_by_name(c, "Torino")
|
||||
# print discover_tournament_table(c, "118942908", "3")
|
||||
|
||||
tables = discover(c)
|
||||
|
|
195
pyfpdb/fpdb.py
195
pyfpdb/fpdb.py
|
@ -44,10 +44,11 @@ import GuiPositionalStats
|
|||
import GuiTableViewer
|
||||
import GuiAutoImport
|
||||
import GuiGraphViewer
|
||||
import GuiSessionViewer
|
||||
import FpdbSQLQueries
|
||||
import Configuration
|
||||
|
||||
VERSION = "0.10"
|
||||
VERSION = "0.11"
|
||||
|
||||
class fpdb:
|
||||
def tab_clicked(self, widget, tab_name):
|
||||
|
@ -105,30 +106,36 @@ class fpdb:
|
|||
#end def delete_event
|
||||
|
||||
def destroy(self, widget, data=None):
|
||||
self.quit(widget, data)
|
||||
self.quit(widget)
|
||||
#end def destroy
|
||||
|
||||
def dia_about(self, widget, data):
|
||||
def dia_about(self, widget, data=None):
|
||||
print "todo: implement dia_about",
|
||||
print " version = %s, requires database version %s" % (VERSION, "118")
|
||||
#end def dia_about
|
||||
|
||||
def dia_create_del_database(self, widget, data):
|
||||
def dia_create_del_database(self, widget, data=None):
|
||||
print "todo: implement dia_create_del_database"
|
||||
self.obtain_global_lock()
|
||||
#end def dia_create_del_database
|
||||
|
||||
def dia_create_del_user(self, widget, data):
|
||||
def dia_create_del_user(self, widget, data=None):
|
||||
print "todo: implement dia_create_del_user"
|
||||
self.obtain_global_lock()
|
||||
#end def dia_create_del_user
|
||||
|
||||
def dia_database_stats(self, widget, data):
|
||||
def dia_database_stats(self, widget, data=None):
|
||||
print "todo: implement dia_database_stats"
|
||||
#string=fpdb_db.getDbStats(db, cursor)
|
||||
#end def dia_database_stats
|
||||
|
||||
def dia_delete_db_parts(self, widget, data):
|
||||
def dia_database_sessions(self, widget, data=None):
|
||||
new_sessions_thread=GuiSessionViewer.GuiSessionViewer(self.config, self.querydict)
|
||||
self.threads.append(new_sessions_thread)
|
||||
sessions_tab=new_sessions_thread.get_vbox()
|
||||
self.add_and_display_tab(sessions_tab, "Sessions")
|
||||
|
||||
def dia_delete_db_parts(self, widget, data=None):
|
||||
print "todo: implement dia_delete_db_parts"
|
||||
self.obtain_global_lock()
|
||||
#end def dia_delete_db_parts
|
||||
|
@ -138,7 +145,7 @@ class fpdb:
|
|||
self.obtain_global_lock()
|
||||
#end def dia_edit_profile
|
||||
|
||||
def dia_export_db(self, widget, data):
|
||||
def dia_export_db(self, widget, data=None):
|
||||
print "todo: implement dia_export_db"
|
||||
self.obtain_global_lock()
|
||||
#end def dia_export_db
|
||||
|
@ -163,16 +170,16 @@ class fpdb:
|
|||
# return (user, pw, response)
|
||||
#end def dia_get_db_root_credentials
|
||||
|
||||
def dia_import_db(self, widget, data):
|
||||
def dia_import_db(self, widget, data=None):
|
||||
print "todo: implement dia_import_db"
|
||||
self.obtain_global_lock()
|
||||
#end def dia_import_db
|
||||
|
||||
def dia_licensing(self, widget, data):
|
||||
def dia_licensing(self, widget, data=None):
|
||||
print "todo: implement dia_licensing"
|
||||
#end def dia_licensing
|
||||
|
||||
def dia_load_profile(self, widget, data):
|
||||
def dia_load_profile(self, widget, data=None):
|
||||
"""Dialogue to select a file to load a profile from"""
|
||||
self.obtain_global_lock()
|
||||
chooser = gtk.FileChooserDialog(title="Please select a profile file to load",
|
||||
|
@ -188,7 +195,7 @@ class fpdb:
|
|||
print 'User cancelled loading profile'
|
||||
#end def dia_load_profile
|
||||
|
||||
def dia_recreate_tables(self, widget, data):
|
||||
def dia_recreate_tables(self, widget, data=None):
|
||||
"""Dialogue that asks user to confirm that he wants to delete and recreate the tables"""
|
||||
self.obtain_global_lock()
|
||||
|
||||
|
@ -205,12 +212,12 @@ class fpdb:
|
|||
print 'User cancelled recreating tables'
|
||||
#end def dia_recreate_tables
|
||||
|
||||
def dia_regression_test(self, widget, data):
|
||||
def dia_regression_test(self, widget, data=None):
|
||||
print "todo: implement dia_regression_test"
|
||||
self.obtain_global_lock()
|
||||
#end def dia_regression_test
|
||||
|
||||
def dia_save_profile(self, widget, data):
|
||||
def dia_save_profile(self, widget, data=None):
|
||||
print "todo: implement dia_save_profile"
|
||||
#end def dia_save_profile
|
||||
|
||||
|
@ -237,11 +244,89 @@ class fpdb:
|
|||
|
||||
def get_menu(self, window):
|
||||
"""returns the menu for this program"""
|
||||
accel_group = gtk.AccelGroup()
|
||||
self.item_factory = gtk.ItemFactory(gtk.MenuBar, "<main>", accel_group)
|
||||
self.item_factory.create_items(self.menu_items)
|
||||
fpdbmenu = """
|
||||
<ui>
|
||||
<menubar name="MenuBar">
|
||||
<menu action="main">
|
||||
<menuitem action="LoadProf"/>
|
||||
<menuitem action="EditProf"/>
|
||||
<menuitem action="SaveProf"/>
|
||||
<separator/>
|
||||
<menuitem action="Quit"/>
|
||||
</menu>
|
||||
<menu action="import">
|
||||
<menuitem action="bulkimp"/>
|
||||
<menuitem action="autoimp"/>
|
||||
<menuitem action="autorate"/>
|
||||
</menu>
|
||||
<menu action="viewers">
|
||||
<menuitem action="autoimp"/>
|
||||
<menuitem action="graphs"/>
|
||||
<menuitem action="handreplay"/>
|
||||
<menuitem action="playerdetails"/>
|
||||
<menuitem action="playerstats"/>
|
||||
<menuitem action="posnstats"/>
|
||||
<menuitem action="sessionreplay"/>
|
||||
<menuitem action="tableviewer"/>
|
||||
</menu>
|
||||
<menu action="database">
|
||||
<menuitem action="createdb"/>
|
||||
<menuitem action="createuser"/>
|
||||
<menuitem action="createtabs"/>
|
||||
<menuitem action="stats"/>
|
||||
<menuitem action="sessions"/>
|
||||
</menu>
|
||||
<menu action="help">
|
||||
<menuitem action="Abbrev"/>
|
||||
<separator/>
|
||||
<menuitem action="About"/>
|
||||
<menuitem action="License"/>
|
||||
</menu>
|
||||
</menubar>
|
||||
</ui>"""
|
||||
|
||||
uimanager = gtk.UIManager()
|
||||
accel_group = uimanager.get_accel_group()
|
||||
actiongroup = gtk.ActionGroup('UIManagerExample')
|
||||
|
||||
# Create actions
|
||||
actiongroup.add_actions([('main', None, '_Main'),
|
||||
('Quit', gtk.STOCK_QUIT, '_Quit me!', None, 'Quit the Program', self.quit),
|
||||
('LoadProf', None, '_Load Profile (broken)', '<control>L', 'Load your profile', self.dia_load_profile),
|
||||
('EditProf', None, '_Edit Profile (todo)', '<control>E', 'Edit your profile', self.dia_edit_profile),
|
||||
('SaveProf', None, '_Save Profile (todo)', '<control>S', 'Save your profile', self.dia_save_profile),
|
||||
('import', None, '_Import'),
|
||||
('bulkimp', None, '_Bulk Import', '<control>B', 'Bulk Import', self.tab_bulk_import),
|
||||
('autorate', None, 'Auto _Rating (todo)', '<control>R', 'Auto Rating (todo)', self.not_implemented),
|
||||
('viewers', None, '_Viewers'),
|
||||
('autoimp', None, '_Auto Import and HUD', '<control>A', 'Auto Import and HUD', self.tab_auto_import),
|
||||
('graphs', None, '_Graphs', '<control>G', 'Graphs', self.tabGraphViewer),
|
||||
('handreplay', None, 'Hand _Replayer (todo)', None, 'Hand Replayer (todo)', self.not_implemented),
|
||||
('playerdetails', None, 'Player _Details (todo)', None, 'Player Details (todo)', self.not_implemented),
|
||||
('playerstats', None, '_Player Stats (tabulated view)', '<control>P', 'Player Stats (tabulated view)', self.tab_player_stats),
|
||||
('posnstats', None, 'P_ositional Stats (tabulated view)', '<control>O', 'Positional Stats (tabulated view)', self.tab_positional_stats),
|
||||
('sessionreplay', None, '_Session Replayer (todo)', None, 'Session Replayer (todo)', self.not_implemented),
|
||||
('tableviewer', None, 'Poker_table Viewer (mostly obselete)', None, 'Poker_table Viewer (mostly obselete)', self.tab_table_viewer),
|
||||
('database', None, '_Database'),
|
||||
('createdb', None, 'Create or Delete _Database (todo)', None, 'Create or Delete Database', self.dia_create_del_database),
|
||||
('createuser', None, 'Create or Delete _User (todo)', None, 'Create or Delete User', self.dia_create_del_user),
|
||||
('createtabs', None, 'Create or Recreate _Tables', None, 'Create or Recreate Tables ', self.dia_recreate_tables),
|
||||
('stats', None, '_Statistics (todo)', None, 'View Database Statistics', self.dia_database_stats),
|
||||
('sessions', None, 'Sessions', None, 'View Sessions', self.dia_database_sessions),
|
||||
('help', None, '_Help'),
|
||||
('Abbrev', None, '_Abbrevations (todo)', None, 'List of Abbrevations', self.tab_abbreviations),
|
||||
('About', None, 'A_bout', None, 'About the program', self.dia_about),
|
||||
('License', None, '_License and Copying (todo)', None, 'License and Copying', self.dia_licensing),
|
||||
])
|
||||
actiongroup.get_action('Quit').set_property('short-label', '_Quit')
|
||||
|
||||
uimanager.insert_action_group(actiongroup, 0)
|
||||
merge_id = uimanager.add_ui_from_string(fpdbmenu)
|
||||
|
||||
# Create a MenuBar
|
||||
menubar = uimanager.get_widget('/MenuBar')
|
||||
window.add_accel_group(accel_group)
|
||||
return self.item_factory.get_widget("<main>")
|
||||
return menubar
|
||||
#end def get_menu
|
||||
|
||||
def load_profile(self):
|
||||
|
@ -287,9 +372,10 @@ class fpdb:
|
|||
|
||||
# Database connected to successfully, load queries to pass on to other classes
|
||||
self.querydict = FpdbSQLQueries.FpdbSQLQueries(self.db.get_backend_name())
|
||||
self.db.db.rollback()
|
||||
#end def load_profile
|
||||
|
||||
def not_implemented(self):
|
||||
def not_implemented(self, widget, data=None):
|
||||
print "todo: called unimplemented menu entry (users: pls ignore this)"#remove this once more entries are implemented
|
||||
#end def not_implemented
|
||||
|
||||
|
@ -297,7 +383,7 @@ class fpdb:
|
|||
print "todo: implement obtain_global_lock (users: pls ignore this)"
|
||||
#end def obtain_global_lock
|
||||
|
||||
def quit(self, widget, data):
|
||||
def quit(self, widget):
|
||||
print "Quitting normally"
|
||||
#check if current settings differ from profile, if so offer to save or abort
|
||||
self.db.disconnect()
|
||||
|
@ -308,11 +394,11 @@ class fpdb:
|
|||
print "todo: implement release_global_lock"
|
||||
#end def release_global_lock
|
||||
|
||||
def tab_abbreviations(self, widget, data):
|
||||
def tab_abbreviations(self, widget, data=None):
|
||||
print "todo: implement tab_abbreviations"
|
||||
#end def tab_abbreviations
|
||||
|
||||
def tab_auto_import(self, widget, data):
|
||||
def tab_auto_import(self, widget, data=None):
|
||||
"""opens the auto import tab"""
|
||||
new_aimp_thread=GuiAutoImport.GuiAutoImport(self.settings, self.config)
|
||||
self.threads.append(new_aimp_thread)
|
||||
|
@ -320,29 +406,29 @@ class fpdb:
|
|||
self.add_and_display_tab(aimp_tab, "Auto Import")
|
||||
#end def tab_auto_import
|
||||
|
||||
def tab_bulk_import(self, widget, data):
|
||||
def tab_bulk_import(self, widget, data=None):
|
||||
"""opens a tab for bulk importing"""
|
||||
#print "start of tab_bulk_import"
|
||||
new_import_thread=GuiBulkImport.GuiBulkImport(self.db, self.settings, self.config)
|
||||
new_import_thread=GuiBulkImport.GuiBulkImport(self.settings, self.config)
|
||||
self.threads.append(new_import_thread)
|
||||
bulk_tab=new_import_thread.get_vbox()
|
||||
self.add_and_display_tab(bulk_tab, "Bulk Import")
|
||||
#end def tab_bulk_import
|
||||
|
||||
def tab_player_stats(self, widget, data):
|
||||
new_ps_thread=GuiPlayerStats.GuiPlayerStats(self.db, self.config, self.querydict)
|
||||
def tab_player_stats(self, widget, data=None):
|
||||
new_ps_thread=GuiPlayerStats.GuiPlayerStats(self.config, self.querydict, self.window)
|
||||
self.threads.append(new_ps_thread)
|
||||
ps_tab=new_ps_thread.get_vbox()
|
||||
self.add_and_display_tab(ps_tab, "Player Stats")
|
||||
|
||||
def tab_positional_stats(self, widget, data):
|
||||
new_ps_thread=GuiPositionalStats.GuiPositionalStats(self.db, self.config, self.querydict)
|
||||
def tab_positional_stats(self, widget, data=None):
|
||||
new_ps_thread=GuiPositionalStats.GuiPositionalStats(self.config, self.querydict)
|
||||
self.threads.append(new_ps_thread)
|
||||
ps_tab=new_ps_thread.get_vbox()
|
||||
self.add_and_display_tab(ps_tab, "Positional Stats")
|
||||
|
||||
|
||||
def tab_main_help(self, widget, data):
|
||||
def tab_main_help(self, widget, data=None):
|
||||
"""Displays a tab with the main fpdb help screen"""
|
||||
#print "start of tab_main_help"
|
||||
mh_tab=gtk.Label("""Welcome to Fpdb!
|
||||
|
@ -352,7 +438,7 @@ This program is licensed under the AGPL3, see docs"""+os.sep+"agpl-3.0.txt")
|
|||
self.add_and_display_tab(mh_tab, "Help")
|
||||
#end def tab_main_help
|
||||
|
||||
def tab_table_viewer(self, widget, data):
|
||||
def tab_table_viewer(self, widget, data=None):
|
||||
"""opens a table viewer tab"""
|
||||
#print "start of tab_table_viewer"
|
||||
new_tv_thread=GuiTableViewer.GuiTableViewer(self.db, self.settings)
|
||||
|
@ -361,7 +447,7 @@ This program is licensed under the AGPL3, see docs"""+os.sep+"agpl-3.0.txt")
|
|||
self.add_and_display_tab(tv_tab, "Table Viewer")
|
||||
#end def tab_table_viewer
|
||||
|
||||
def tabGraphViewer(self, widget, data):
|
||||
def tabGraphViewer(self, widget, data=None):
|
||||
"""opens a graph viewer tab"""
|
||||
#print "start of tabGraphViewer"
|
||||
new_gv_thread=GuiGraphViewer.GuiGraphViewer(self.db, self.settings, self.querydict, self.config)
|
||||
|
@ -381,49 +467,9 @@ This program is licensed under the AGPL3, see docs"""+os.sep+"agpl-3.0.txt")
|
|||
self.window.connect("destroy", self.destroy)
|
||||
self.window.set_title("Free Poker DB - v%s or higher" % (VERSION, ))
|
||||
self.window.set_border_width(1)
|
||||
self.window.set_size_request(1020,400)
|
||||
self.window.set_default_size(900,720)
|
||||
self.window.set_resizable(True)
|
||||
|
||||
self.menu_items = (
|
||||
( "/_Main", None, None, 0, "<Branch>" ),
|
||||
( "/Main/_Load Profile (broken)", "<control>L", self.dia_load_profile, 0, None ),
|
||||
( "/Main/_Edit Profile (todo)", "<control>E", self.dia_edit_profile, 0, None ),
|
||||
( "/Main/_Save Profile (todo)", None, self.dia_save_profile, 0, None ),
|
||||
("/Main/sep1", None, None, 0, "<Separator>" ),
|
||||
("/Main/_Quit", "<control>Q", self.quit, 0, None ),
|
||||
("/_Import", None, None, 0, "<Branch>" ),
|
||||
("/Import/_Bulk Import", "<control>B", self.tab_bulk_import, 0, None ),
|
||||
("/Import/_Auto Import and HUD", "<control>A", self.tab_auto_import, 0, None ),
|
||||
("/Import/Auto _Rating (todo)", "<control>R", self.not_implemented, 0, None ),
|
||||
("/_Viewers", None, None, 0, "<Branch>" ),
|
||||
("/_Viewers/_Auto Import and HUD", "<control>A", self.tab_auto_import, 0, None ),
|
||||
("/Viewers/_Graphs", "<control>G", self.tabGraphViewer, 0, None ),
|
||||
("/Viewers/Hand _Replayer (todo)", None, self.not_implemented, 0, None ),
|
||||
("/Viewers/Player _Details (todo)", None, self.not_implemented, 0, None ),
|
||||
("/Viewers/_Player Stats (tabulated view)", None, self.tab_player_stats, 0, None ),
|
||||
("/Viewers/Positional Stats (tabulated view)", None, self.tab_positional_stats, 0, None ),
|
||||
("/Viewers/Starting _Hands (todo)", None, self.not_implemented, 0, None ),
|
||||
("/Viewers/_Session Replayer (todo)", None, self.not_implemented, 0, None ),
|
||||
("/Viewers/Poker_table Viewer (mostly obselete)", "<control>T", self.tab_table_viewer, 0, None ),
|
||||
#( "/Viewers/Tourney Replayer
|
||||
( "/_Database", None, None, 0, "<Branch>" ),
|
||||
( "/Database/Create or Delete _Database (todo)", None, self.dia_create_del_database, 0, None ),
|
||||
( "/Database/Create or Delete _User (todo)", None, self.dia_create_del_user, 0, None ),
|
||||
( "/Database/Create or Recreate _Tables", None, self.dia_recreate_tables, 0, None ),
|
||||
( "/Database/_Statistics (todo)", None, self.dia_database_stats, 0, None ),
|
||||
( "/D_ebugging", None, None, 0, "<Branch>" ),
|
||||
( "/Debugging/_Delete Parts of Database (todo)", None, self.dia_delete_db_parts, 0, None ),
|
||||
( "/Debugging/_Export DB (todo)", None, self.dia_export_db, 0, None ),
|
||||
( "/Debugging/_Import DB (todo)", None, self.dia_import_db, 0, None ),
|
||||
( "/Debugging/_Regression test (todo)", None, self.dia_regression_test, 0, None ),
|
||||
( "/_Help", None, None, 0, "<LastBranch>" ),
|
||||
( "/Help/_Main Help", "<control>H", self.tab_main_help, 0, None ),
|
||||
( "/Help/_Abbrevations (todo)", None, self.tab_abbreviations, 0, None ),
|
||||
( "/Help/sep1", None, None, 0, "<Separator>" ),
|
||||
( "/Help/A_bout (todo)", None, self.dia_about, 0, None ),
|
||||
( "/Help/_License and Copying (todo)", None, self.dia_licensing, 0, None )
|
||||
)
|
||||
|
||||
self.main_vbox = gtk.VBox(False, 1)
|
||||
self.main_vbox.set_border_width(1)
|
||||
self.window.add(self.main_vbox)
|
||||
|
@ -437,7 +483,7 @@ This program is licensed under the AGPL3, see docs"""+os.sep+"agpl-3.0.txt")
|
|||
self.tabs=[]
|
||||
self.tab_names=[]
|
||||
self.tab_buttons=[]
|
||||
self.tab_box = gtk.HBox(False,1)
|
||||
self.tab_box = gtk.HBox(True,1)
|
||||
self.main_vbox.pack_start(self.tab_box, False, True, 0)
|
||||
self.tab_box.show()
|
||||
#done tab bar
|
||||
|
@ -449,11 +495,12 @@ This program is licensed under the AGPL3, see docs"""+os.sep+"agpl-3.0.txt")
|
|||
|
||||
self.tab_main_help(None, None)
|
||||
|
||||
self.status_bar = gtk.Label("Status: Connected to "+self.db.get_backend_name()+" database named "+self.db.database+" on host "+self.db.host)
|
||||
self.status_bar = gtk.Label("Status: Connected to %s database named %s on host %s"%(self.db.get_backend_name(),self.db.database, self.db.host))
|
||||
self.main_vbox.pack_end(self.status_bar, False, True, 0)
|
||||
self.status_bar.show()
|
||||
|
||||
self.window.show()
|
||||
sys.stderr.write("fpdb starting ...")
|
||||
#end def __init__
|
||||
|
||||
def main(self):
|
||||
|
|
|
@ -59,22 +59,33 @@ class fpdb_db:
|
|||
self.database=database
|
||||
if backend==self.MYSQL_INNODB:
|
||||
import MySQLdb
|
||||
self.db=MySQLdb.connect(host = host, user = user, passwd = password, db = database, use_unicode=True)
|
||||
try:
|
||||
self.db = MySQLdb.connect(host = host, user = user, passwd = password, db = database, use_unicode=True)
|
||||
except:
|
||||
raise fpdb_simple.FpdbError("MySQL connection failed")
|
||||
elif backend==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)
|
||||
if self.host and self.user and self.password:
|
||||
self.db = psycopg2.connect(host = host,
|
||||
user = user,
|
||||
password = password,
|
||||
database = database)
|
||||
try:
|
||||
self.db = psycopg2.connect(host = host,
|
||||
user = user,
|
||||
password = password,
|
||||
database = database)
|
||||
except:
|
||||
raise fpdb_simple.FpdbError("PostgreSQL connection failed")
|
||||
# For local domain-socket connections, only DB name is
|
||||
# needed, and everything else is in fact undefined and/or
|
||||
# flat out wrong
|
||||
else:
|
||||
self.db = psycopg2.connect(database = database)
|
||||
try:
|
||||
self.db = psycopg2.connect(database = database)
|
||||
except:
|
||||
raise fpdb_simple.FpdbError("PostgreSQL connection failed")
|
||||
else:
|
||||
raise fpdb_simple.FpdbError("unrecognised database backend:"+backend)
|
||||
self.cursor=self.db.cursor()
|
||||
|
@ -136,7 +147,7 @@ class fpdb_db:
|
|||
|
||||
if(self.get_backend_name() == 'MySQL InnoDB'):
|
||||
#Databases with FOREIGN KEY support need this switched of before you can drop tables
|
||||
self.drop_referencial_integrity()
|
||||
self.drop_referential_integrity()
|
||||
|
||||
# Query the DB to see what tables exist
|
||||
self.cursor.execute(self.sql.query['list_tables'])
|
||||
|
@ -155,7 +166,7 @@ class fpdb_db:
|
|||
self.db.commit()
|
||||
#end def drop_tables
|
||||
|
||||
def drop_referencial_integrity(self):
|
||||
def drop_referential_integrity(self):
|
||||
"""Update all tables to remove foreign keys"""
|
||||
|
||||
self.cursor.execute(self.sql.query['list_tables'])
|
||||
|
@ -173,7 +184,7 @@ class fpdb_db:
|
|||
key = "`" + inner[j][0] + "_" + m.group() + "`"
|
||||
self.cursor.execute("ALTER TABLE " + inner[j][0] + " DROP FOREIGN KEY " + key)
|
||||
self.db.commit()
|
||||
#end drop_referencial_inegrity
|
||||
#end drop_referential_inegrity
|
||||
|
||||
def get_backend_name(self):
|
||||
"""Returns the name of the currently used backend"""
|
||||
|
|
|
@ -58,13 +58,14 @@ class Importer:
|
|||
self.cursor = None
|
||||
self.filelist = {}
|
||||
self.dirlist = {}
|
||||
self.siteIds = {}
|
||||
self.addToDirList = {}
|
||||
self.removeFromFileList = {} # to remove deleted files
|
||||
self.monitor = False
|
||||
self.updated = {} #Time last import was run {file:mtime}
|
||||
self.updated = {} #Time last import was run {file:mtime}
|
||||
self.lines = None
|
||||
self.faobs = None #File as one big string
|
||||
self.pos_in_file = {} # dict to remember how far we have read in the file
|
||||
self.faobs = None # File as one big string
|
||||
self.pos_in_file = {} # dict to remember how far we have read in the file
|
||||
#Set defaults
|
||||
self.callHud = self.config.get_import_parameters().get("callFpdbHud")
|
||||
|
||||
|
@ -73,6 +74,7 @@ class Importer:
|
|||
|
||||
self.fdb = fpdb_db.fpdb_db() # sets self.fdb.db self.fdb.cursor and self.fdb.sql
|
||||
self.fdb.do_connect(self.config)
|
||||
self.fdb.db.rollback()
|
||||
|
||||
#Set functions
|
||||
def setCallHud(self, value):
|
||||
|
@ -109,20 +111,32 @@ class Importer:
|
|||
def addImportFile(self, filename, site = "default", filter = "passthrough"):
|
||||
#TODO: test it is a valid file -> put that in config!!
|
||||
self.filelist[filename] = [site] + [filter]
|
||||
if site not in self.siteIds:
|
||||
# Get id from Sites table in DB
|
||||
self.fdb.cursor.execute(self.fdb.sql.query['getSiteId'], (site,))
|
||||
result = self.fdb.cursor.fetchall()
|
||||
if len(result) == 1:
|
||||
self.siteIds[site] = result[0][0]
|
||||
else:
|
||||
if len(result) == 0:
|
||||
print "[ERROR] Database ID for %s not found" % site
|
||||
else:
|
||||
print "[ERROR] More than 1 Database ID found for %s - Multiple currencies not implemented yet" % site
|
||||
|
||||
|
||||
# Called from GuiBulkImport to add a file or directory.
|
||||
def addBulkImportImportFileOrDir(self, inputPath,filter = "passthrough"):
|
||||
def addBulkImportImportFileOrDir(self, inputPath, site = "PokerStars"):
|
||||
"""Add a file or directory for bulk import"""
|
||||
|
||||
filter = self.config.hhcs[site].converter
|
||||
# Bulk import never monitors
|
||||
# if directory, add all files in it. Otherwise add single file.
|
||||
# TODO: only add sane files?
|
||||
if os.path.isdir(inputPath):
|
||||
for subdir in os.walk(inputPath):
|
||||
for file in subdir[2]:
|
||||
self.addImportFile(os.path.join(inputPath, subdir[0], file), site="default", filter=filter)
|
||||
self.addImportFile(os.path.join(inputPath, subdir[0], file), site=site, filter=filter)
|
||||
else:
|
||||
self.addImportFile(inputPath, site="default", filter=filter)
|
||||
self.addImportFile(inputPath, site=site, filter=filter)
|
||||
#Add a directory of files to filelist
|
||||
#Only one import directory per site supported.
|
||||
#dirlist is a hash of lists:
|
||||
|
@ -193,7 +207,7 @@ class Importer:
|
|||
self.addImportDirectory(self.dirlist[site][0], False, site, self.dirlist[site][1])
|
||||
|
||||
for file in self.filelist:
|
||||
if os.path.exists(file):
|
||||
if os.path.exists(file):
|
||||
stat_info = os.stat(file)
|
||||
try:
|
||||
lastupdate = self.updated[file]
|
||||
|
@ -212,15 +226,17 @@ class Importer:
|
|||
#if os.path.isdir(file):
|
||||
#self.import_file_dict(file, self.filelist[file][0], self.filelist[file][1])
|
||||
else:
|
||||
removeFromFileList[file] = True
|
||||
self.addToDirList = filter(lambda x: self.addImportDirectory(x, True, self.addToDirList[x][0], self.addToDirList[x][1]), self.addToDirList)
|
||||
|
||||
self.removeFromFileList[file] = True
|
||||
self.addToDirList = filter(lambda x: self.addImportDirectory(x, True, self.addToDirList[x][0], self.addToDirList[x][1]), self.addToDirList)
|
||||
|
||||
for file in self.removeFromFileList:
|
||||
if file in self.filelist:
|
||||
del self.filelist[file]
|
||||
|
||||
self.addToDirList = {}
|
||||
self.removeFromFileList = {}
|
||||
self.fdb.db.rollback()
|
||||
|
||||
|
||||
# This is now an internal function that should not be called directly.
|
||||
def import_file_dict(self, file, site, filter):
|
||||
|
@ -294,10 +310,9 @@ class Importer:
|
|||
print "TODO: implement importing tournament summaries"
|
||||
#self.faobs = readfile(inputFile)
|
||||
#self.parseTourneyHistory()
|
||||
return 0
|
||||
|
||||
site = fpdb_simple.recogniseSite(firstline)
|
||||
category = fpdb_simple.recogniseCategory(firstline)
|
||||
return (0,0,0,1,0)
|
||||
|
||||
category=fpdb_simple.recogniseCategory(firstline)
|
||||
|
||||
startpos = 0
|
||||
stored = 0 #counter
|
||||
|
@ -305,61 +320,30 @@ class Importer:
|
|||
partial = 0 #counter
|
||||
errors = 0 #counter
|
||||
|
||||
for i in xrange (len(self.lines)): #main loop, iterates through the lines of a file and calls the appropriate parser method
|
||||
if len(self.lines[i]) < 2:
|
||||
endpos = i
|
||||
hand = self.lines[startpos:endpos]
|
||||
for i in xrange (len(self.lines)):
|
||||
if (len(self.lines[i])<2): #Wierd way to detect for '\r\n' or '\n'
|
||||
endpos=i
|
||||
hand=self.lines[startpos:endpos]
|
||||
|
||||
if len(hand[0]) < 2:
|
||||
hand = hand[1:]
|
||||
|
||||
cancelled=False
|
||||
damaged=False
|
||||
if (site=="ftp"):
|
||||
for i in range (len(hand)):
|
||||
if hand[i].endswith(" has been canceled"): #this is their typo. this is a typo, right?
|
||||
cancelled = True
|
||||
if (len(hand[0])<2):
|
||||
hand=hand[1:]
|
||||
|
||||
#FTP generates lines looking like:
|
||||
#Seat 1: IOS Seat 2: kashman59 (big blind) showed [8c 9d] and won ($3.25) with a pair of Eights
|
||||
#ie. Seat X multiple times on the same line in the summary section, when a new player sits down in the
|
||||
#middle of the hand.
|
||||
#TODO: Deal with this properly, either fix the file or make the parsing code work with this line.
|
||||
if "Seat" in hand[i]:
|
||||
mo = re.search(" Seat [0-9]+: ", hand[i])
|
||||
if mo:
|
||||
print "mo=", mo, "\nmo.start=", mo.start(),"\nhand[i]=",hand[i]
|
||||
hand.insert(i+1, hand[i][mo.start()+1:])
|
||||
hand[i] = hand[i][0:mo.start()]
|
||||
|
||||
if len(hand) < 3:
|
||||
|
||||
if (len(hand)<3):
|
||||
pass
|
||||
#todo: the above 2 lines are kind of a dirty hack, the mentioned circumstances should be handled elsewhere but that doesnt work with DOS/Win EOL. actually this doesnt work.
|
||||
elif hand[0].endswith(" (partial)"): #partial hand - do nothing
|
||||
partial += 1
|
||||
elif "Seat" not in hand[1] and "Seat" not in hand[2] and "Seat" not in hand[3]:
|
||||
partial += 1
|
||||
elif cancelled or damaged:
|
||||
partial += 1
|
||||
if damaged:
|
||||
print """
|
||||
DEBUG: Partial hand triggered by a line containing 'Seat X:' twice. This is a
|
||||
bug in the FTP software when a player sits down in the middle of a hand.
|
||||
Adding a newline after the player name will fix the issue
|
||||
"""
|
||||
print "File: %s" %(file)
|
||||
print "Line: %s" %(startpos)
|
||||
else: #normal processing
|
||||
isTourney = fpdb_simple.isTourney(hand[0])
|
||||
#TODO: This is ugly - we didn't actually find the start of the
|
||||
# hand with the outer loop so we test again...
|
||||
else:
|
||||
isTourney=fpdb_simple.isTourney(hand[0])
|
||||
if not isTourney:
|
||||
hand = fpdb_simple.filterAnteBlindFold(site,hand)
|
||||
hand = fpdb_simple.filterAnteBlindFold(hand)
|
||||
self.hand=hand
|
||||
|
||||
|
||||
try:
|
||||
handsId = fpdb_parse_logic.mainParser(self.settings['db-backend'], self.fdb.db
|
||||
,self.fdb.cursor, site, category, hand, self.config)
|
||||
,self.fdb.cursor, self.siteIds[site], category, hand, self.config)
|
||||
self.fdb.db.commit()
|
||||
|
||||
|
||||
stored += 1
|
||||
if self.callHud:
|
||||
#print "call to HUD here. handsId:",handsId
|
||||
|
@ -367,37 +351,39 @@ class Importer:
|
|||
self.caller.pipe_to_hud.stdin.write("%s" % (handsId) + os.linesep)
|
||||
except fpdb_simple.DuplicateError:
|
||||
duplicates += 1
|
||||
self.fdb.db.rollback()
|
||||
except (ValueError), fe:
|
||||
errors += 1
|
||||
self.printEmailErrorMessage(errors, file, hand)
|
||||
|
||||
|
||||
if (self.settings['failOnError']):
|
||||
self.fdb.db.commit() #dont remove this, in case hand processing was cancelled.
|
||||
raise
|
||||
else:
|
||||
self.fdb.db.rollback()
|
||||
except (fpdb_simple.FpdbError), fe:
|
||||
errors += 1
|
||||
self.printEmailErrorMessage(errors, file, hand)
|
||||
|
||||
#fe.printStackTrace() #todo: get stacktrace
|
||||
self.fdb.db.rollback()
|
||||
|
||||
|
||||
if self.settings['failOnError']:
|
||||
self.fdb.db.commit() #dont remove this, in case hand processing was cancelled.
|
||||
raise
|
||||
|
||||
|
||||
if self.settings['minPrint']:
|
||||
if not ((stored+duplicates+partial+errors) % self.settings['minPrint']):
|
||||
print "stored:", stored, "duplicates:", duplicates, "partial:", partial, "errors:", errors
|
||||
if not ((stored+duplicates+errors) % self.settings['minPrint']):
|
||||
print "stored:", stored, "duplicates:", duplicates, "errors:", errors
|
||||
|
||||
if self.settings['handCount']:
|
||||
if ((stored+duplicates+partial+errors) >= self.settings['handCount']):
|
||||
if ((stored+duplicates+errors) >= self.settings['handCount']):
|
||||
if not self.settings['quiet']:
|
||||
print "quitting due to reaching the amount of hands to be imported"
|
||||
print "Total stored:", stored, "duplicates:", duplicates, "partial/damaged:", partial, "errors:", errors, " time:", (time() - starttime)
|
||||
print "Total stored:", stored, "duplicates:", duplicates, "errors:", errors, " time:", (time() - starttime)
|
||||
sys.exit(0)
|
||||
startpos = endpos
|
||||
ttime = time() - starttime
|
||||
print "\rTotal stored:", stored, "duplicates:", duplicates, "partial:", partial, "errors:", errors, " time:", ttime
|
||||
print "\rTotal stored:", stored, "duplicates:", duplicates, "errors:", errors, " time:", ttime
|
||||
|
||||
if not stored:
|
||||
if duplicates:
|
||||
|
@ -408,16 +394,11 @@ class Importer:
|
|||
else:
|
||||
print "failed to read a single hand from file:", inputFile
|
||||
handsId=0
|
||||
#todo: this will cause return of an unstored hand number if the last hand was error or partial
|
||||
#todo: this will cause return of an unstored hand number if the last hand was error
|
||||
self.fdb.db.commit()
|
||||
self.handsId=handsId
|
||||
return (stored, duplicates, partial, errors, ttime)
|
||||
|
||||
def parseTourneyHistory(self):
|
||||
print "Tourney history parser stub"
|
||||
#Find tournament boundaries.
|
||||
#print self.foabs
|
||||
|
||||
def printEmailErrorMessage(self, errors, filename, line):
|
||||
traceback.print_exc(file=sys.stderr)
|
||||
print "Error No.",errors,", please send the hand causing this to steffen@sycamoretest.info so I can fix it."
|
||||
|
|
|
@ -21,11 +21,11 @@ import fpdb_simple
|
|||
import fpdb_save_to_db
|
||||
|
||||
#parses a holdem hand
|
||||
def mainParser(backend, db, cursor, site, category, hand, config):
|
||||
def mainParser(backend, db, cursor, siteID, category, hand, config):
|
||||
category = fpdb_simple.recogniseCategory(hand[0])
|
||||
|
||||
|
||||
base = "hold" if category == "holdem" or category == "omahahi" or category == "omahahilo" else "stud"
|
||||
|
||||
|
||||
#part 0: create the empty arrays
|
||||
lineTypes = [] #char, valid values: header, name, cards, action, win, rake, ignore
|
||||
lineStreets = [] #char, valid values: (predeal, preflop, flop, turn, river)
|
||||
|
@ -34,9 +34,7 @@ def mainParser(backend, db, cursor, site, category, hand, config):
|
|||
|
||||
#part 1: read hand no and check for duplicate
|
||||
siteHandNo = fpdb_simple.parseSiteHandNo(hand[0])
|
||||
handStartTime = fpdb_simple.parseHandStartTime(hand[0], site)
|
||||
siteID = fpdb_simple.recogniseSiteID(cursor, site)
|
||||
#print "parse logic, siteID:",siteID,"site:",site
|
||||
handStartTime = fpdb_simple.parseHandStartTime(hand[0])
|
||||
|
||||
isTourney = fpdb_simple.isTourney(hand[0])
|
||||
smallBlindLine = 0
|
||||
|
@ -46,11 +44,9 @@ def mainParser(backend, db, cursor, site, category, hand, config):
|
|||
smallBlindLine = i
|
||||
break
|
||||
#print "small blind line:",smallBlindLine
|
||||
|
||||
|
||||
gametypeID = fpdb_simple.recogniseGametypeID(backend, db, cursor, hand[0], hand[smallBlindLine], siteID, category, isTourney)
|
||||
if isTourney:
|
||||
if site != "ps":
|
||||
raise fpdb_simple.FpdbError("tourneys are only supported on PS right now")
|
||||
siteTourneyNo = fpdb_simple.parseTourneyNo(hand[0])
|
||||
buyin = fpdb_simple.parseBuyin(hand[0])
|
||||
fee = fpdb_simple.parseFee(hand[0])
|
||||
|
@ -61,10 +57,10 @@ def mainParser(backend, db, cursor, site, category, hand, config):
|
|||
rebuyOrAddon = fpdb_simple.isRebuyOrAddon(hand[0])
|
||||
|
||||
tourneyTypeId = fpdb_simple.recogniseTourneyTypeId(cursor, siteID, buyin, fee, knockout, rebuyOrAddon)
|
||||
|
||||
|
||||
fpdb_simple.isAlreadyInDB(cursor, gametypeID, siteHandNo)
|
||||
|
||||
hand = fpdb_simple.filterCrap(site, hand, isTourney)
|
||||
hand = fpdb_simple.filterCrap(hand, isTourney)
|
||||
|
||||
#part 2: classify lines by type (e.g. cards, action, win, sectionchange) and street
|
||||
fpdb_simple.classifyLines(hand, category, lineTypes, lineStreets)
|
||||
|
@ -74,10 +70,10 @@ def mainParser(backend, db, cursor, site, category, hand, config):
|
|||
for i, line in enumerate(hand):
|
||||
if lineTypes[i] == "name":
|
||||
seatLines.append(line)
|
||||
|
||||
|
||||
names = fpdb_simple.parseNames(seatLines)
|
||||
playerIDs = fpdb_simple.recognisePlayerIDs(cursor, names, siteID)
|
||||
tmp = fpdb_simple.parseCashesAndSeatNos(seatLines, site)
|
||||
tmp = fpdb_simple.parseCashesAndSeatNos(seatLines)
|
||||
startCashes = tmp['startCashes']
|
||||
seatNos = tmp['seatNos']
|
||||
|
||||
|
@ -90,30 +86,27 @@ def mainParser(backend, db, cursor, site, category, hand, config):
|
|||
#part 4: take appropriate action for each line based on linetype
|
||||
for i, line in enumerate(hand):
|
||||
if lineTypes[i] == "cards":
|
||||
fpdb_simple.parseCardLine(site, category, lineStreets[i], line, names, cardValues, cardSuits, boardValues, boardSuits)
|
||||
fpdb_simple.parseCardLine(category, lineStreets[i], line, names, cardValues, cardSuits, boardValues, boardSuits)
|
||||
#if category=="studhilo":
|
||||
# print "hand[i]:", hand[i]
|
||||
# print "cardValues:", cardValues
|
||||
# print "cardSuits:", cardSuits
|
||||
elif lineTypes[i] == "action":
|
||||
fpdb_simple.parseActionLine(site, base, isTourney, line, lineStreets[i], playerIDs, names, actionTypes, allIns, actionAmounts, actionNos, actionTypeByNo)
|
||||
fpdb_simple.parseActionLine(base, isTourney, line, lineStreets[i], playerIDs, names, actionTypes, allIns, actionAmounts, actionNos, actionTypeByNo)
|
||||
elif lineTypes[i] == "win":
|
||||
fpdb_simple.parseWinLine(line, site, names, winnings, isTourney)
|
||||
fpdb_simple.parseWinLine(line, names, winnings, isTourney)
|
||||
elif lineTypes[i] == "rake":
|
||||
totalRake = 0 if isTourney else fpdb_simple.parseRake(line)
|
||||
fpdb_simple.splitRake(winnings, rakes, totalRake)
|
||||
elif lineTypes[i]=="header" or lineTypes[i]=="rake" or lineTypes[i]=="name" or lineTypes[i]=="ignore":
|
||||
pass
|
||||
elif lineTypes[i]=="ante":
|
||||
fpdb_simple.parseAnteLine(line, site, isTourney, names, antes)
|
||||
fpdb_simple.parseAnteLine(line, isTourney, names, antes)
|
||||
elif lineTypes[i]=="table":
|
||||
tableResult=fpdb_simple.parseTableLine(site, base, line)
|
||||
tableResult=fpdb_simple.parseTableLine(base, line)
|
||||
else:
|
||||
raise fpdb_simple.FpdbError("unrecognised lineType:"+lineTypes[i])
|
||||
|
||||
if site == "ftp":
|
||||
tableResult = fpdb_simple.parseTableLine(site, base, hand[0])
|
||||
|
||||
|
||||
maxSeats = tableResult['maxSeats']
|
||||
tableName = tableResult['tableName']
|
||||
#print "before part5, antes:", antes
|
||||
|
@ -128,7 +121,7 @@ def mainParser(backend, db, cursor, site, category, hand, config):
|
|||
|
||||
cursor.execute("SELECT limitType FROM Gametypes WHERE id=%s",(gametypeID, ))
|
||||
limit_type = cursor.fetchone()[0]
|
||||
fpdb_simple.convert3B4B(site, category, limit_type, actionTypes, actionAmounts)
|
||||
fpdb_simple.convert3B4B(category, limit_type, actionTypes, actionAmounts)
|
||||
|
||||
totalWinnings = sum(winnings)
|
||||
|
||||
|
@ -141,7 +134,7 @@ def mainParser(backend, db, cursor, site, category, hand, config):
|
|||
hudImportData = fpdb_simple.generateHudCacheData(playerIDs, base, category, actionTypes
|
||||
, allIns, actionTypeByNo, winnings, totalWinnings, None
|
||||
, actionTypes, actionAmounts, antes)
|
||||
|
||||
|
||||
if isTourney:
|
||||
ranks = map(lambda x: 0, names) # create an array of 0's equal to the length of names
|
||||
payin_amounts = fpdb_simple.calcPayin(len(names), buyin, fee)
|
||||
|
@ -165,7 +158,7 @@ def mainParser(backend, db, cursor, site, category, hand, config):
|
|||
, allIns, actionAmounts, actionNos, hudImportData, maxSeats
|
||||
, tableName, seatNos)
|
||||
else:
|
||||
raise fpdb_simple.FpdbError("unrecognised category") # it's impossible to get here, but w/e
|
||||
raise fpdb_simple.FpdbError("unrecognised category")
|
||||
else:
|
||||
if base == "hold":
|
||||
result = fpdb_save_to_db.ring_holdem_omaha(
|
||||
|
@ -183,7 +176,7 @@ def mainParser(backend, db, cursor, site, category, hand, config):
|
|||
, actionAmounts, actionNos, hudImportData, maxSeats, tableName
|
||||
, seatNos)
|
||||
else:
|
||||
raise fpdb_simple.FpdbError ("unrecognised category") # also impossible to get here
|
||||
raise fpdb_simple.FpdbError ("unrecognised category")
|
||||
db.commit()
|
||||
return result
|
||||
#end def mainParser
|
||||
|
|
|
@ -32,8 +32,7 @@ saveActions = True # set this to False to avoid storing action data
|
|||
# Pros: speeds up imports
|
||||
# Cons: no action data is saved, so you need to keep the hand histories
|
||||
# variance not available on stats page
|
||||
# no graphs
|
||||
|
||||
# : No graphs
|
||||
#stores a stud/razz hand into the database
|
||||
def ring_stud(config, backend, db, cursor, base, category, site_hand_no, gametype_id, hand_start_time
|
||||
,names, player_ids, start_cashes, antes, card_values, card_suits, winnings, rakes
|
||||
|
@ -55,7 +54,7 @@ def ring_stud(config, backend, db, cursor, base, category, site_hand_no, gametyp
|
|||
,start_cashes, antes, card_values
|
||||
,card_suits, winnings, rakes, seatNos)
|
||||
|
||||
fpdb_simple.storeHudCache(cursor, base, category, gametype_id, player_ids, hudImportData)
|
||||
fpdb_simple.storeHudCache(backend, cursor, base, category, gametype_id, hand_start_time, player_ids, hudImportData)
|
||||
|
||||
if saveActions:
|
||||
fpdb_simple.storeActions(cursor, hands_players_ids, action_types
|
||||
|
@ -83,17 +82,17 @@ def ring_holdem_omaha(config, backend, db, cursor, base, category, site_hand_no,
|
|||
t2 = time()
|
||||
|
||||
hands_id = fpdb_simple.storeHands(backend, db, cursor, site_hand_no, gametype_id
|
||||
,hand_start_time, names, tableName, maxSeats)
|
||||
,hand_start_time, names, tableName, maxSeats, hudImportData)
|
||||
t3 = time()
|
||||
hands_players_ids = fpdb_simple.store_hands_players_holdem_omaha(
|
||||
backend, db, cursor, category, hands_id, player_ids, start_cashes
|
||||
, positions, card_values, card_suits, winnings, rakes, seatNos)
|
||||
, positions, card_values, card_suits, winnings, rakes, seatNos, hudImportData)
|
||||
t4 = time()
|
||||
#print "ring holdem, backend=%d" % backend
|
||||
if fastStoreHudCache:
|
||||
fpdb_simple.storeHudCache2(backend, cursor, base, category, gametype_id, player_ids, hudImportData)
|
||||
fpdb_simple.storeHudCache2(backend, cursor, base, category, gametype_id, hand_start_time, player_ids, hudImportData)
|
||||
else:
|
||||
fpdb_simple.storeHudCache(cursor, base, category, gametype_id, player_ids, hudImportData)
|
||||
fpdb_simple.storeHudCache(backend, cursor, base, category, gametype_id, hand_start_time, player_ids, hudImportData)
|
||||
t5 = time()
|
||||
fpdb_simple.store_board_cards(cursor, hands_id, board_values, board_suits)
|
||||
t6 = time()
|
||||
|
@ -132,9 +131,9 @@ def tourney_holdem_omaha(config, backend, db, cursor, base, category, siteTourne
|
|||
|
||||
#print "tourney holdem, backend=%d" % backend
|
||||
if fastStoreHudCache:
|
||||
fpdb_simple.storeHudCache2(backend, cursor, base, category, gametype_id, player_ids, hudImportData)
|
||||
fpdb_simple.storeHudCache2(backend, cursor, base, category, gametype_id, hand_start_time, player_ids, hudImportData)
|
||||
else:
|
||||
fpdb_simple.storeHudCache(cursor, base, category, gametype_id, player_ids, hudImportData)
|
||||
fpdb_simple.storeHudCache(backend, cursor, base, category, gametype_id, hand_start_time, player_ids, hudImportData)
|
||||
|
||||
fpdb_simple.store_board_cards(cursor, hands_id, board_values, board_suits)
|
||||
|
||||
|
@ -166,7 +165,7 @@ def tourney_stud(config, backend, db, cursor, base, category, siteTourneyNo, buy
|
|||
, playerIds, startCashes, antes, cardValues, cardSuits
|
||||
, winnings, rakes, seatNos, tourneys_players_ids)
|
||||
|
||||
fpdb_simple.storeHudCache(cursor, base, category, gametypeId, playerIds, hudImportData)
|
||||
fpdb_simple.storeHudCache(backend, cursor, base, category, gametypeId, hand_start_time, playerIds, hudImportData)
|
||||
|
||||
if saveActions:
|
||||
fpdb_simple.storeActions(cursor, hands_players_ids, actionTypes, allIns, actionAmounts, actionNos)
|
||||
|
|
File diff suppressed because it is too large
Load Diff
Loading…
Reference in New Issue
Block a user