Merge branch 'master' of git://git.assembla.com/fpdboz

Conflicts:
	pyfpdb/Configuration.py
This commit is contained in:
Eratosthenes 2010-01-25 12:06:11 -05:00
commit 7683590898
17 changed files with 223 additions and 81 deletions

View File

@ -1,8 +1,8 @@
free-poker-tools (0.12-1) unstable; urgency=low free-poker-tools (0.12~git20100122) unstable; urgency=low
* New release * New snapshot release with reworked import code
-- Mika Bostrom <bostik+fpdb@bostik.iki.fi> Mon, 26 Oct 2009 17:49:07 +0200 -- Mika Bostrom <bostik+fpdb@bostik.iki.fi> Fri, 22 Jan 2010 09:25:27 +0200
free-poker-tools (0.11.3+git20091023) unstable; urgency=low free-poker-tools (0.11.3+git20091023) unstable; urgency=low

View File

@ -4,12 +4,12 @@
#This program is free software: you can redistribute it and/or modify #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 #it under the terms of the GNU Affero General Public License as published by
#the Free Software Foundation, version 3 of the License. #the Free Software Foundation, version 3 of the License.
# #
#This program is distributed in the hope that it will be useful, #This program is distributed in the hope that it will be useful,
#but WITHOUT ANY WARRANTY; without even the implied warranty of #but WITHOUT ANY WARRANTY; without even the implied warranty of
#MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the #MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
#GNU General Public License for more details. #GNU General Public License for more details.
# #
#You should have received a copy of the GNU Affero General Public License #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/>. #along with this program. If not, see <http://www.gnu.org/licenses/>.
#In the "official" distribution you can find the license in #In the "official" distribution you can find the license in
@ -69,7 +69,7 @@ def twoStartCards(value1, suit1, value2, suit2):
ret = 13 * (value2-2) + (value1-2) + 1 ret = 13 * (value2-2) + (value1-2) + 1
else: else:
ret = 13 * (value1-2) + (value2-2) + 1 ret = 13 * (value1-2) + (value2-2) + 1
# print "twoStartCards(", value1, suit1, value2, suit2, ")=", ret # print "twoStartCards(", value1, suit1, value2, suit2, ")=", ret
return ret return ret
@ -108,7 +108,7 @@ def fourStartCards(value1, suit1, value2, suit2, value3, suit3, value4, suit4):
# SSSS (K, J, 6, 3) # SSSS (K, J, 6, 3)
# - 13C4 = 715 possibilities # - 13C4 = 715 possibilities
# SSSx (K, J, 6),(3) # SSSx (K, J, 6),(3)
# - 13C3 * 13 = 3718 possibilities # - 13C3 * 13 = 3718 possibilities
# SSxy (K, J),(6),(3) # SSxy (K, J),(6),(3)
# - 13C2 * 13*13 = 13182 possibilities # - 13C2 * 13*13 = 13182 possibilities
# SSHH (K, J),(6, 3) # SSHH (K, J),(6, 3)
@ -131,7 +131,7 @@ suitFromCardList = ['', '2h', '3h', '4h', '5h', '6h', '7h', '8h', '9h', 'Th', 'J
, '2s', '3s', '4s', '5s', '6s', '7s', '8s', '9s', 'Ts', 'Js', 'Qs', 'Ks', 'As' , '2s', '3s', '4s', '5s', '6s', '7s', '8s', '9s', 'Ts', 'Js', 'Qs', 'Ks', 'As'
] ]
def valueSuitFromCard(card): def valueSuitFromCard(card):
""" Function to convert a card stored in the database (int 0-52) into value """ Function to convert a card stored in the database (int 0-52) into value
and suit like 9s, 4c etc """ and suit like 9s, 4c etc """
global suitFromCardList global suitFromCardList
if card < 0 or card > 52 or not card: if card < 0 or card > 52 or not card:
@ -158,5 +158,5 @@ if __name__ == '__main__':
print "card %2d = %s card %2d = %s card %2d = %s card %2d = %s" % \ print "card %2d = %s card %2d = %s card %2d = %s card %2d = %s" % \
(i, valueSuitFromCard(i), i+13, valueSuitFromCard(i+13), i+26, valueSuitFromCard(i+26), i+39, valueSuitFromCard(i+39)) (i, valueSuitFromCard(i), i+13, valueSuitFromCard(i+13), i+26, valueSuitFromCard(i+26), i+39, valueSuitFromCard(i+39))
print print
print encodeCard('7c') print encodeCard('7c')

52
pyfpdb/Charset.py Normal file
View File

@ -0,0 +1,52 @@
#!/usr/bin/python
#Copyright 2010 Mika Bostrom
#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.
# String manipulation
import codecs
# Settings
import Configuration
encoder_to_utf = codecs.lookup('utf-8')
encoder_to_sys = codecs.lookup(Configuration.LOCALE_ENCODING)
# I'm saving a few cycles with this one
not_needed = False
if Configuration.LOCALE_ENCODING == 'utf-8':
not_needed = True
def to_utf8(s):
if not_needed: return s
try:
#(_out, _len) = encoder_to_utf.encode(s)
_out = unicode(s, Configuration.LOCALE_ENCODING).encode('utf-8')
return _out
except UnicodeDecodeError:
print 'Could not convert: "%s"' % s
raise
def to_gui(s):
if not_needed: return s
try:
(_out, _len) = encoder_to_sys.encode(s)
return _out
except UnicodeDecodeError:
print 'Could not convert: "%s"' % s
raise

View File

@ -48,6 +48,7 @@ import Configuration
import SQL import SQL
import Card import Card
import Tourney import Tourney
import Charset
from Exceptions import * from Exceptions import *
log = Configuration.get_logger("logging.conf", config = "db") log = Configuration.get_logger("logging.conf", config = "db")
@ -359,28 +360,6 @@ class Database:
cards['common'] = c.fetchone() cards['common'] = c.fetchone()
return cards return cards
def convert_cards(self, d):
ranks = ('', '', '2', '3', '4', '5', '6', '7', '8', '9', 'T', 'J', 'Q', 'K', 'A')
cards = ""
for i in xrange(1, 8):
# key = 'card' + str(i) + 'Value'
# if not d.has_key(key): continue
# if d[key] == None:
# break
# elif d[key] == 0:
# cards += "xx"
# else:
# cards += ranks[d['card' + str(i) + 'Value']] + d['card' +str(i) + 'Suit']
cv = "card%dvalue" % i
if cv not in d or d[cv] is None:
break
elif d[cv] == 0:
cards += "xx"
else:
cs = "card%dsuit" % i
cards = "%s%s%s" % (cards, ranks[d[cv]], d[cs])
return cards
def get_action_from_hand(self, hand_no): def get_action_from_hand(self, hand_no):
action = [ [], [], [], [], [] ] action = [ [], [], [], [], [] ]
c = self.connection.cursor() c = self.connection.cursor()
@ -617,7 +596,8 @@ class Database:
if site_id is None: if site_id is None:
site_id = -1 site_id = -1
c = self.get_cursor() c = self.get_cursor()
c.execute(self.sql.query['get_player_names'], (like_player_name, site_id, site_id)) p_name = Charset.to_utf8(like_player_name)
c.execute(self.sql.query['get_player_names'], (p_name, site_id, site_id))
rows = c.fetchall() rows = c.fetchall()
return rows return rows

View File

@ -29,6 +29,7 @@ import gobject
import Configuration import Configuration
import fpdb_db import fpdb_db
import FpdbSQLQueries import FpdbSQLQueries
import Charset
class Filters(threading.Thread): class Filters(threading.Thread):
def __init__(self, db, config, qdict, display = {}, debug=True): def __init__(self, db, config, qdict, display = {}, debug=True):
@ -56,7 +57,7 @@ class Filters(threading.Thread):
,'limitstitle':'Limits:', 'seatstitle':'Number of Players:' ,'limitstitle':'Limits:', 'seatstitle':'Number of Players:'
,'groupstitle':'Grouping:', 'posnshow':'Show Position Stats:' ,'groupstitle':'Grouping:', 'posnshow':'Show Position Stats:'
,'groupsall':'All Players' ,'groupsall':'All Players'
,'limitsFL':'FL', 'limitsNL':'NL', 'ring':'Ring', 'tour':'Tourney' ,'limitsFL':'FL', 'limitsNL':'NL', 'limitsPL':'PL', 'ring':'Ring', 'tour':'Tourney'
} }
# For use in date ranges. # For use in date ranges.
@ -107,6 +108,7 @@ class Filters(threading.Thread):
self.cbAllLimits = None self.cbAllLimits = None
self.cbFL = None self.cbFL = None
self.cbNL = None self.cbNL = None
self.cbPL = None
self.rb = {} # radio buttons for ring/tour self.rb = {} # radio buttons for ring/tour
self.type = None # ring/tour self.type = None # ring/tour
self.types = {} # list of all ring/tour values self.types = {} # list of all ring/tour values
@ -191,6 +193,9 @@ class Filters(threading.Thread):
def getSites(self): def getSites(self):
return self.sites return self.sites
def getGames(self):
return self.games
def getSiteIds(self): def getSiteIds(self):
return self.siteid return self.siteid
@ -238,6 +243,7 @@ class Filters(threading.Thread):
print "DEBUG: %s was toggled %s" % (data, ("OFF", "ON")[widget.get_active()]) print "DEBUG: %s was toggled %s" % (data, ("OFF", "ON")[widget.get_active()])
def createPlayerLine(self, hbox, site, player): def createPlayerLine(self, hbox, site, player):
print 'DEBUG :: add:"%s"' % player
label = gtk.Label(site +" id:") label = gtk.Label(site +" id:")
hbox.pack_start(label, False, False, 0) hbox.pack_start(label, False, False, 0)
@ -254,13 +260,17 @@ class Filters(threading.Thread):
completion.set_model(liststore) completion.set_model(liststore)
completion.set_text_column(0) completion.set_text_column(0)
names = self.db.get_player_names(self.conf) # (config=self.conf, site_id=None, like_player_name="%") names = self.db.get_player_names(self.conf) # (config=self.conf, site_id=None, like_player_name="%")
for n in names: for n in names: # list of single-element "tuples"
liststore.append(n) _n = Charset.to_gui(n[0])
_nt = (_n, )
liststore.append(_nt)
self.__set_hero_name(pname, site) self.__set_hero_name(pname, site)
def __set_hero_name(self, w, site): def __set_hero_name(self, w, site):
self.heroes[site] = w.get_text() _name = w.get_text()
_guiname = Charset.to_gui(_name)
self.heroes[site] = _guiname
# print "DEBUG: setting heroes[%s]: %s"%(site, self.heroes[site]) # print "DEBUG: setting heroes[%s]: %s"%(site, self.heroes[site])
def __set_num_hands(self, w, val): def __set_num_hands(self, w, val):
@ -280,6 +290,7 @@ class Filters(threading.Thread):
cb = gtk.CheckButton(game) cb = gtk.CheckButton(game)
cb.connect('clicked', self.__set_game_select, game) cb.connect('clicked', self.__set_game_select, game)
hbox.pack_start(cb, False, False, 0) hbox.pack_start(cb, False, False, 0)
cb.set_active(True)
def createLimitLine(self, hbox, limit, ltext): def createLimitLine(self, hbox, limit, ltext):
cb = gtk.CheckButton(str(ltext)) cb = gtk.CheckButton(str(ltext))
@ -303,7 +314,7 @@ class Filters(threading.Thread):
#print w.get_active() #print w.get_active()
self.limits[limit] = w.get_active() self.limits[limit] = w.get_active()
print "self.limit[%s] set to %s" %(limit, self.limits[limit]) print "self.limit[%s] set to %s" %(limit, self.limits[limit])
if limit.isdigit() or (len(limit) > 2 and limit[-2:] == 'nl'): if limit.isdigit() or (len(limit) > 2 and (limit[-2:] == 'nl' or limit[-2:] == 'fl' or limit[-2:] == 'pl')):
if self.limits[limit]: if self.limits[limit]:
if self.cbNoLimits is not None: if self.cbNoLimits is not None:
self.cbNoLimits.set_active(False) self.cbNoLimits.set_active(False)
@ -314,9 +325,12 @@ class Filters(threading.Thread):
if limit.isdigit(): if limit.isdigit():
if self.cbFL is not None: if self.cbFL is not None:
self.cbFL.set_active(False) self.cbFL.set_active(False)
else: elif (len(limit) > 2 and (limit[-2:] == 'nl')):
if self.cbNL is not None: if self.cbNL is not None:
self.cbNL.set_active(False) self.cbNL.set_active(False)
else:
if self.cbPL is not None:
self.cbPL.set_active(False)
elif limit == "all": elif limit == "all":
if self.limits[limit]: if self.limits[limit]:
#for cb in self.cbLimits.values(): #for cb in self.cbLimits.values():
@ -325,6 +339,8 @@ class Filters(threading.Thread):
self.cbFL.set_active(True) self.cbFL.set_active(True)
if self.cbNL is not None: if self.cbNL is not None:
self.cbNL.set_active(True) self.cbNL.set_active(True)
if self.cbPL is not None:
self.cbPL.set_active(True)
elif limit == "none": elif limit == "none":
if self.limits[limit]: if self.limits[limit]:
for cb in self.cbLimits.values(): for cb in self.cbLimits.values():
@ -333,6 +349,8 @@ class Filters(threading.Thread):
self.cbNL.set_active(False) self.cbNL.set_active(False)
if self.cbFL is not None: if self.cbFL is not None:
self.cbFL.set_active(False) self.cbFL.set_active(False)
if self.cbPL is not None:
self.cbPL.set_active(False)
elif limit == "fl": elif limit == "fl":
if not self.limits[limit]: if not self.limits[limit]:
# only toggle all fl limits off if they are all currently on # only toggle all fl limits off if they are all currently on
@ -384,6 +402,30 @@ class Filters(threading.Thread):
self.rb['tour'].set_active(True) self.rb['tour'].set_active(True)
elif self.type == 'tour': elif self.type == 'tour':
self.rb['ring'].set_active(True) self.rb['ring'].set_active(True)
elif limit == "pl":
if not self.limits[limit]:
# only toggle all nl limits off if they are all currently on
# this stops turning one off from cascading into 'nl' box off
# and then all nl limits being turned off
all_nl_on = True
for cb in self.cbLimits.values():
t = cb.get_children()[0].get_text()
if "pl" in t and len(t) > 2:
if not cb.get_active():
all_nl_on = False
found = {'ring':False, 'tour':False}
for cb in self.cbLimits.values():
t = cb.get_children()[0].get_text()
if "pl" in t and len(t) > 2:
if self.limits[limit] or all_nl_on:
cb.set_active(self.limits[limit])
found[self.types[t]] = True
if self.limits[limit]:
if not found[self.type]:
if self.type == 'ring':
self.rb['tour'].set_active(True)
elif self.type == 'tour':
self.rb['ring'].set_active(True)
elif limit == "ring": elif limit == "ring":
print "set", limit, "to", self.limits[limit] print "set", limit, "to", self.limits[limit]
if self.limits[limit]: if self.limits[limit]:
@ -417,7 +459,8 @@ class Filters(threading.Thread):
vbox.pack_start(hBox, False, True, 0) vbox.pack_start(hBox, False, True, 0)
player = self.conf.supported_sites[site].screen_name player = self.conf.supported_sites[site].screen_name
self.createPlayerLine(hBox, site, player) _pname = Charset.to_gui(player)
self.createPlayerLine(hBox, site, _pname)
if "GroupsAll" in display and display["GroupsAll"] == True: if "GroupsAll" in display and display["GroupsAll"] == True:
hbox = gtk.HBox(False, 0) hbox = gtk.HBox(False, 0)
@ -479,7 +522,7 @@ class Filters(threading.Thread):
self.cursor.execute(self.sql.query['getLimits2']) self.cursor.execute(self.sql.query['getLimits2'])
# selects limitType, bigBlind # selects limitType, bigBlind
result = self.db.cursor.fetchall() result = self.db.cursor.fetchall()
found = {'nl':False, 'fl':False, 'ring':False, 'tour':False} found = {'nl':False, 'fl':False, 'pl':False, 'ring':False, 'tour':False}
if len(result) >= 1: if len(result) >= 1:
hbox = gtk.HBox(True, 0) hbox = gtk.HBox(True, 0)
@ -497,14 +540,18 @@ class Filters(threading.Thread):
vbox2.pack_start(hbox, False, False, 0) vbox2.pack_start(hbox, False, False, 0)
else: else:
vbox3.pack_start(hbox, False, False, 0) vbox3.pack_start(hbox, False, False, 0)
if line[1] == 'fl': if line[0] == 'ring':
name = str(line[2]) if line[1] == 'fl':
found['fl'] = True name = str(line[2])
else: found['fl'] = True
name = str(line[2])+line[1] elif line[1] == 'pl':
found['nl'] = True name = str(line[2])+line[1]
self.cbLimits[name] = self.createLimitLine(hbox, name, name) found['pl'] = True
self.types[name] = line[0] else:
name = str(line[2])+line[1]
found['nl'] = True
self.cbLimits[name] = self.createLimitLine(hbox, name, name)
self.types[name] = line[0]
found[line[0]] = True # type is ring/tour found[line[0]] = True # type is ring/tour
self.type = line[0] # if only one type, set it now self.type = line[0] # if only one type, set it now
if "LimitSep" in display and display["LimitSep"] == True and len(result) >= 2: if "LimitSep" in display and display["LimitSep"] == True and len(result) >= 2:
@ -532,6 +579,9 @@ class Filters(threading.Thread):
hbox = gtk.HBox(False, 0) hbox = gtk.HBox(False, 0)
vbox3.pack_start(hbox, False, False, 0) vbox3.pack_start(hbox, False, False, 0)
self.cbNL = self.createLimitLine(hbox, 'nl', self.filterText['limitsNL']) self.cbNL = self.createLimitLine(hbox, 'nl', self.filterText['limitsNL'])
hbox = gtk.HBox(False, 0)
vbox3.pack_start(hbox, False, False, 0)
self.cbPL = self.createLimitLine(hbox, 'pl', self.filterText['limitsPL'])
dest = vbox2 # for ring/tour buttons dest = vbox2 # for ring/tour buttons
else: else:
print "INFO: No games returned from database" print "INFO: No games returned from database"

View File

@ -44,6 +44,7 @@ except ImportError, inst:
import fpdb_import import fpdb_import
import Database import Database
import Filters import Filters
import Charset
class GuiGraphViewer (threading.Thread): class GuiGraphViewer (threading.Thread):
@ -137,6 +138,8 @@ class GuiGraphViewer (threading.Thread):
heroes = self.filters.getHeroes() heroes = self.filters.getHeroes()
siteids = self.filters.getSiteIds() siteids = self.filters.getSiteIds()
limits = self.filters.getLimits() limits = self.filters.getLimits()
games = self.filters.getGames()
for i in ('show', 'none'): for i in ('show', 'none'):
if i in limits: if i in limits:
limits.remove(i) limits.remove(i)
@ -145,7 +148,8 @@ class GuiGraphViewer (threading.Thread):
if sites[site] == True: if sites[site] == True:
sitenos.append(siteids[site]) sitenos.append(siteids[site])
c = self.db.get_cursor() c = self.db.get_cursor()
c.execute(self.sql.query['getPlayerId'], (heroes[site],)) _hname = Charset.to_utf8(heroes[site])
c.execute(self.sql.query['getPlayerId'], (_hname,))
result = c.fetchall() result = c.fetchall()
if len(result) == 1: if len(result) == 1:
playerids.append( int(result[0][0]) ) playerids.append( int(result[0][0]) )
@ -171,7 +175,7 @@ class GuiGraphViewer (threading.Thread):
#Get graph data from DB #Get graph data from DB
starttime = time() starttime = time()
(green, blue, red) = self.getRingProfitGraph(playerids, sitenos, limits) (green, blue, red) = self.getRingProfitGraph(playerids, sitenos, limits, games)
print "Graph generated in: %s" %(time() - starttime) print "Graph generated in: %s" %(time() - starttime)
self.ax.set_title("Profit graph for ring games") self.ax.set_title("Profit graph for ring games")
@ -212,7 +216,7 @@ class GuiGraphViewer (threading.Thread):
#end of def showClicked #end of def showClicked
def getRingProfitGraph(self, names, sites, limits): def getRingProfitGraph(self, names, sites, limits, games):
tmp = self.sql.query['getRingProfitAllHandsPlayerIdSite'] tmp = self.sql.query['getRingProfitAllHandsPlayerIdSite']
# print "DEBUG: getRingProfitGraph" # print "DEBUG: getRingProfitGraph"
start_date, end_date = self.filters.getDates() start_date, end_date = self.filters.getDates()
@ -224,6 +228,22 @@ class GuiGraphViewer (threading.Thread):
sitetest = str(tuple(sites)) sitetest = str(tuple(sites))
#nametest = nametest.replace("L", "") #nametest = nametest.replace("L", "")
q = []
for m in self.filters.display.items():
if m[0] == 'Games' and m[1]:
for n in games:
if games[n]:
q.append(n)
if len(q) > 0:
gametest = str(tuple(q))
gametest = gametest.replace("L", "")
gametest = gametest.replace(",)",")")
gametest = gametest.replace("u'","'")
gametest = "and gt.category in %s" % gametest
else:
gametest = "and gt.category IS NULL"
tmp = tmp.replace("<game_test>", gametest)
lims = [int(x) for x in limits if x.isdigit()] lims = [int(x) for x in limits if x.isdigit()]
potlims = [int(x[0:-2]) for x in limits if len(x) > 2 and x[-2:] == 'pl'] potlims = [int(x[0:-2]) for x in limits if len(x) > 2 and x[-2:] == 'pl']
nolims = [int(x[0:-2]) for x in limits if len(x) > 2 and x[-2:] == 'nl'] nolims = [int(x[0:-2]) for x in limits if len(x) > 2 and x[-2:] == 'nl']

View File

@ -29,6 +29,7 @@ import fpdb_import
import Database import Database
import fpdb_db import fpdb_db
import Filters import Filters
import Charset
colalias,colshow,colheading,colxalign,colformat,coltype = 0,1,2,3,4,5 colalias,colshow,colheading,colxalign,colformat,coltype = 0,1,2,3,4,5
ranks = {'x':0, '2':2, '3':3, '4':4, '5':5, '6':6, '7':7, '8':8, '9':9, 'T':10, 'J':11, 'Q':12, 'K':13, 'A':14} ranks = {'x':0, '2':2, '3':3, '4':4, '5':5, '6':6, '7':7, '8':8, '9':9, 'T':10, 'J':11, 'Q':12, 'K':13, 'A':14}
@ -64,7 +65,7 @@ class GuiPlayerStats (threading.Thread):
filters_display = { "Heroes" : True, filters_display = { "Heroes" : True,
"Sites" : True, "Sites" : True,
"Games" : False, "Games" : True,
"Limits" : True, "Limits" : True,
"LimitSep" : True, "LimitSep" : True,
"LimitType" : True, "LimitType" : True,
@ -180,6 +181,7 @@ class GuiPlayerStats (threading.Thread):
seats = self.filters.getSeats() seats = self.filters.getSeats()
groups = self.filters.getGroups() groups = self.filters.getGroups()
dates = self.filters.getDates() dates = self.filters.getDates()
games = self.filters.getGames()
sitenos = [] sitenos = []
playerids = [] playerids = []
@ -189,7 +191,8 @@ class GuiPlayerStats (threading.Thread):
sitenos.append(siteids[site]) sitenos.append(siteids[site])
# Nasty hack to deal with multiple sites + same player name -Eric # Nasty hack to deal with multiple sites + same player name -Eric
que = self.sql.query['getPlayerId'] + " AND siteId=%d" % siteids[site] que = self.sql.query['getPlayerId'] + " AND siteId=%d" % siteids[site]
self.cursor.execute(que, (heroes[site],)) _hname = Charset.to_utf8(heroes[site])
self.cursor.execute(que, (_hname,))
result = self.db.cursor.fetchall() result = self.db.cursor.fetchall()
if len(result) == 1: if len(result) == 1:
playerids.append(result[0][0]) playerids.append(result[0][0])
@ -205,9 +208,9 @@ class GuiPlayerStats (threading.Thread):
print "No limits found" print "No limits found"
return return
self.createStatsTable(vbox, playerids, sitenos, limits, type, seats, groups, dates) self.createStatsTable(vbox, playerids, sitenos, limits, type, seats, groups, dates, games)
def createStatsTable(self, vbox, playerids, sitenos, limits, type, seats, groups, dates): def createStatsTable(self, vbox, playerids, sitenos, limits, type, seats, groups, dates, games):
starttime = time() starttime = time()
# Scrolled window for summary table # Scrolled window for summary table
@ -223,7 +226,7 @@ class GuiPlayerStats (threading.Thread):
# gridnum - index for grid data structures # gridnum - index for grid data structures
flags = [False, self.filters.getNumHands(), 0] flags = [False, self.filters.getNumHands(), 0]
self.addGrid(swin, 'playerDetailedStats', flags, playerids self.addGrid(swin, 'playerDetailedStats', flags, playerids
,sitenos, limits, type, seats, groups, dates) ,sitenos, limits, type, seats, groups, dates, games)
# Separator # Separator
vbox2 = gtk.VBox(False, 0) vbox2 = gtk.VBox(False, 0)
@ -243,7 +246,7 @@ class GuiPlayerStats (threading.Thread):
flags[0] = True flags[0] = True
flags[2] = 1 flags[2] = 1
self.addGrid(swin, 'playerDetailedStats', flags, playerids self.addGrid(swin, 'playerDetailedStats', flags, playerids
,sitenos, limits, type, seats, groups, dates) ,sitenos, limits, type, seats, groups, dates, games)
self.db.rollback() self.db.rollback()
print "Stats page displayed in %4.2f seconds" % (time() - starttime) print "Stats page displayed in %4.2f seconds" % (time() - starttime)
@ -317,7 +320,7 @@ class GuiPlayerStats (threading.Thread):
print "***sortcols error: " + str(sys.exc_info()[1]) print "***sortcols error: " + str(sys.exc_info()[1])
print "\n".join( [e[0]+':'+str(e[1])+" "+e[2] for e in err] ) print "\n".join( [e[0]+':'+str(e[1])+" "+e[2] for e in err] )
def addGrid(self, vbox, query, flags, playerids, sitenos, limits, type, seats, groups, dates): def addGrid(self, vbox, query, flags, playerids, sitenos, limits, type, seats, groups, dates, games):
counter = 0 counter = 0
row = 0 row = 0
sqlrow = 0 sqlrow = 0
@ -325,7 +328,7 @@ class GuiPlayerStats (threading.Thread):
else: holecards,grid = flags[0],flags[2] else: holecards,grid = flags[0],flags[2]
tmp = self.sql.query[query] tmp = self.sql.query[query]
tmp = self.refineQuery(tmp, flags, playerids, sitenos, limits, type, seats, groups, dates) tmp = self.refineQuery(tmp, flags, playerids, sitenos, limits, type, seats, groups, dates, games)
self.cursor.execute(tmp) self.cursor.execute(tmp)
result = self.cursor.fetchall() result = self.cursor.fetchall()
colnames = [desc[0].lower() for desc in self.cursor.description] colnames = [desc[0].lower() for desc in self.cursor.description]
@ -428,7 +431,7 @@ class GuiPlayerStats (threading.Thread):
#end def addGrid(self, query, vars, playerids, sitenos, limits, type, seats, groups, dates): #end def addGrid(self, query, vars, playerids, sitenos, limits, type, seats, groups, dates):
def refineQuery(self, query, flags, playerids, sitenos, limits, type, seats, groups, dates): def refineQuery(self, query, flags, playerids, sitenos, limits, type, seats, groups, dates, games):
having = '' having = ''
if not flags: if not flags:
holecards = False holecards = False
@ -466,6 +469,23 @@ class GuiPlayerStats (threading.Thread):
query = query.replace("<playerName>", pname) query = query.replace("<playerName>", pname)
query = query.replace("<havingclause>", having) query = query.replace("<havingclause>", having)
gametest = ""
q = []
for m in self.filters.display.items():
if m[0] == 'Games' and m[1]:
for n in games:
if games[n]:
q.append(n)
if len(q) > 0:
gametest = str(tuple(q))
gametest = gametest.replace("L", "")
gametest = gametest.replace(",)",")")
gametest = gametest.replace("u'","'")
gametest = "and gt.category in %s" % gametest
else:
gametest = "and gt.category IS NULL"
query = query.replace("<game_test>", gametest)
if seats: if seats:
query = query.replace('<seats_test>', 'between ' + str(seats['from']) + ' and ' + str(seats['to'])) query = query.replace('<seats_test>', 'between ' + str(seats['from']) + ' and ' + str(seats['to']))
if 'show' in seats and seats['show']: if 'show' in seats and seats['show']:

View File

@ -47,6 +47,7 @@ import fpdb_import
import Database import Database
import Filters import Filters
import FpdbSQLQueries import FpdbSQLQueries
import Charset
class GuiSessionViewer (threading.Thread): class GuiSessionViewer (threading.Thread):
def __init__(self, config, querylist, mainwin, debug=True): def __init__(self, config, querylist, mainwin, debug=True):
@ -181,7 +182,10 @@ class GuiSessionViewer (threading.Thread):
for site in sites: for site in sites:
if sites[site] == True: if sites[site] == True:
sitenos.append(siteids[site]) sitenos.append(siteids[site])
self.cursor.execute(self.sql.query['getPlayerId'], (heroes[site],)) _q = self.sql.query['getPlayerId']
_name = Charset.to_utf8(heroes[site])
print 'DEBUG(_name) :: %s' % _name
self.cursor.execute(_q, (_name,)) # arg = tuple
result = self.db.cursor.fetchall() result = self.db.cursor.fetchall()
if len(result) == 1: if len(result) == 1:
playerids.append(result[0][0]) playerids.append(result[0][0])

View File

@ -79,7 +79,8 @@ class GuiTableViewer (threading.Thread):
#then the data rows #then the data rows
for player in range(len(self.player_names)): for player in range(len(self.player_names)):
tmp=[] tmp=[]
tmp.append(self.player_names[player][0]) p_name = Charset.to_gui(self.player_names[player][0])
tmp.append(p_name)
seatCount=len(self.player_names) seatCount=len(self.player_names)
if seatCount>=8: if seatCount>=8:

View File

@ -192,7 +192,7 @@ dealt whether they were seen in a 'dealt to' line
self.holecards[street][player] = [open, closed] self.holecards[street][player] = [open, closed]
def prepInsert(self, db): def prepInsert(self, db):
##### #####
# Players, Gametypes, TourneyTypes are all shared functions that are needed for additional tables # Players, Gametypes, TourneyTypes are all shared functions that are needed for additional tables
# These functions are intended for prep insert eventually # These functions are intended for prep insert eventually
##### #####
@ -617,6 +617,8 @@ class HoldemOmahaHand(Hand):
# which then invokes a 'addXXX' callback # which then invokes a 'addXXX' callback
if builtFrom == "HHC": if builtFrom == "HHC":
hhc.readHandInfo(self) hhc.readHandInfo(self)
if self.gametype['type'] == 'tour':
self.tablename = "%s %s" % (self.tourNo, self.tablename)
hhc.readPlayerStacks(self) hhc.readPlayerStacks(self)
hhc.compilePlayerRegexs(self) hhc.compilePlayerRegexs(self)
hhc.markStreets(self) hhc.markStreets(self)
@ -681,7 +683,6 @@ class HoldemOmahaHand(Hand):
def join_holecards(self, player, asList=False): def join_holecards(self, player, asList=False):
"""With asList = True it returns the set cards for a player including down cards if they aren't know""" """With asList = True it returns the set cards for a player including down cards if they aren't know"""
# FIXME: This should actually return
hcs = [u'0x', u'0x', u'0x', u'0x'] hcs = [u'0x', u'0x', u'0x', u'0x']
for street in self.holeStreets: for street in self.holeStreets:
@ -912,6 +913,8 @@ class DrawHand(Hand):
# Populate the draw hand. # Populate the draw hand.
if builtFrom == "HHC": if builtFrom == "HHC":
hhc.readHandInfo(self) hhc.readHandInfo(self)
if self.gametype['type'] == 'tour':
self.tablename = "%s %s" % (self.tourNo, self.tablename)
hhc.readPlayerStacks(self) hhc.readPlayerStacks(self)
hhc.compilePlayerRegexs(self) hhc.compilePlayerRegexs(self)
hhc.markStreets(self) hhc.markStreets(self)
@ -1106,6 +1109,8 @@ class StudHand(Hand):
# which then invokes a 'addXXX' callback # which then invokes a 'addXXX' callback
if builtFrom == "HHC": if builtFrom == "HHC":
hhc.readHandInfo(self) hhc.readHandInfo(self)
if self.gametype['type'] == 'tour':
self.tablename = "%s %s" % (self.tourNo, self.tablename)
hhc.readPlayerStacks(self) hhc.readPlayerStacks(self)
hhc.compilePlayerRegexs(self) hhc.compilePlayerRegexs(self)
hhc.markStreets(self) hhc.markStreets(self)

View File

@ -292,8 +292,7 @@ which it expects to find at self.re_TailSplitHands -- see for e.g. Everleaf.py.
log.info("Unsupported game type: %s" % gametype) log.info("Unsupported game type: %s" % gametype)
if hand: if hand:
if Configuration.NEWIMPORT == False: #hand.writeHand(self.out_fh)
hand.writeHand(self.out_fh)
return hand return hand
else: else:
log.info("Unsupported game type: %s" % gametype) log.info("Unsupported game type: %s" % gametype)

View File

@ -676,6 +676,11 @@ class Stat_Window:
return True return True
if event.button == 1: # left button event if event.button == 1: # left button event
# close on double click for a stat window
# for those that don't have a mouse with middle button
if event.type == gtk.gdk._2BUTTON_PRESS:
self.window.hide()
return True
# TODO: make position saving save sizes as well? # TODO: make position saving save sizes as well?
if event.state & gtk.gdk.SHIFT_MASK: if event.state & gtk.gdk.SHIFT_MASK:
self.window.begin_resize_drag(gtk.gdk.WINDOW_EDGE_SOUTH_EAST, event.button, int(event.x_root), int(event.y_root), event.time) self.window.begin_resize_drag(gtk.gdk.WINDOW_EDGE_SOUTH_EAST, event.button, int(event.x_root), int(event.y_root), event.time)

View File

@ -81,6 +81,7 @@ class PokerStars(HandHistoryConverter):
re_Board = re.compile(r"\[(?P<CARDS>.+)\]") re_Board = re.compile(r"\[(?P<CARDS>.+)\]")
# self.re_setHandInfoRegex('.*#(?P<HID>[0-9]+): Table (?P<TABLE>[ a-zA-Z]+) - \$?(?P<SB>[.0-9]+)/\$?(?P<BB>[.0-9]+) - (?P<GAMETYPE>.*) - (?P<HR>[0-9]+):(?P<MIN>[0-9]+) ET - (?P<YEAR>[0-9]+)/(?P<MON>[0-9]+)/(?P<DAY>[0-9]+)Table (?P<TABLE>[ a-zA-Z]+)\nSeat (?P<BUTTON>[0-9]+)') # self.re_setHandInfoRegex('.*#(?P<HID>[0-9]+): Table (?P<TABLE>[ a-zA-Z]+) - \$?(?P<SB>[.0-9]+)/\$?(?P<BB>[.0-9]+) - (?P<GAMETYPE>.*) - (?P<HR>[0-9]+):(?P<MIN>[0-9]+) ET - (?P<YEAR>[0-9]+)/(?P<MON>[0-9]+)/(?P<DAY>[0-9]+)Table (?P<TABLE>[ a-zA-Z]+)\nSeat (?P<BUTTON>[0-9]+)')
re_DateTime = re.compile("""(?P<Y>[0-9]{4})\/(?P<M>[0-9]{2})\/(?P<D>[0-9]{2})[\- ]+(?P<H>[0-9]+):(?P<MIN>[0-9]+):(?P<S>[0-9]+)""", re.MULTILINE)
def compilePlayerRegexs(self, hand): def compilePlayerRegexs(self, hand):
players = set([player[1] for player in hand.players]) players = set([player[1] for player in hand.players])
@ -97,7 +98,7 @@ class PokerStars(HandHistoryConverter):
self.re_PostBB = re.compile(r"^%(PLYR)s: posts big blind %(CUR)s(?P<BB>[.0-9]+)" % subst, re.MULTILINE) self.re_PostBB = re.compile(r"^%(PLYR)s: posts big blind %(CUR)s(?P<BB>[.0-9]+)" % subst, re.MULTILINE)
self.re_Antes = re.compile(r"^%(PLYR)s: posts the ante %(CUR)s(?P<ANTE>[.0-9]+)" % subst, re.MULTILINE) self.re_Antes = re.compile(r"^%(PLYR)s: posts the ante %(CUR)s(?P<ANTE>[.0-9]+)" % subst, re.MULTILINE)
self.re_BringIn = re.compile(r"^%(PLYR)s: brings[- ]in( low|) for %(CUR)s(?P<BRINGIN>[.0-9]+)" % subst, re.MULTILINE) self.re_BringIn = re.compile(r"^%(PLYR)s: brings[- ]in( low|) for %(CUR)s(?P<BRINGIN>[.0-9]+)" % subst, re.MULTILINE)
self.re_PostBoth = re.compile(r"^%(PLYR)s: posts small \& big blinds \[%(CUR)s (?P<SBBB>[.0-9]+)" % subst, re.MULTILINE) self.re_PostBoth = re.compile(r"^%(PLYR)s: posts small \& big blinds %(CUR)s(?P<SBBB>[.0-9]+)" % subst, re.MULTILINE)
self.re_HeroCards = re.compile(r"^Dealt to %(PLYR)s(?: \[(?P<OLDCARDS>.+?)\])?( \[(?P<NEWCARDS>.+?)\])" % subst, re.MULTILINE) self.re_HeroCards = re.compile(r"^Dealt to %(PLYR)s(?: \[(?P<OLDCARDS>.+?)\])?( \[(?P<NEWCARDS>.+?)\])" % subst, re.MULTILINE)
self.re_Action = re.compile(r""" self.re_Action = re.compile(r"""
^%(PLYR)s:(?P<ATYPE>\sbets|\schecks|\sraises|\scalls|\sfolds|\sdiscards|\sstands\spat) ^%(PLYR)s:(?P<ATYPE>\sbets|\schecks|\sraises|\scalls|\sfolds|\sdiscards|\sstands\spat)
@ -105,7 +106,7 @@ class PokerStars(HandHistoryConverter):
(\scards?(\s\[(?P<DISCARDED>.+?)\])?)?""" (\scards?(\s\[(?P<DISCARDED>.+?)\])?)?"""
% subst, re.MULTILINE|re.VERBOSE) % subst, re.MULTILINE|re.VERBOSE)
self.re_ShowdownAction = re.compile(r"^%s: shows \[(?P<CARDS>.*)\]" % player_re, re.MULTILINE) self.re_ShowdownAction = re.compile(r"^%s: shows \[(?P<CARDS>.*)\]" % player_re, re.MULTILINE)
self.re_CollectPot = re.compile(r"Seat (?P<SEAT>[0-9]+): %(PLYR)s (\(button\) |\(small blind\) |\(big blind\) )?(collected|showed \[.*\] and won) \(%(CUR)s(?P<POT>[.\d]+)\)(, mucked| with.*|)" % subst, re.MULTILINE) self.re_CollectPot = re.compile(r"Seat (?P<SEAT>[0-9]+): %(PLYR)s (\(button\) |\(small blind\) |\(big blind\) |\(button\) \(small blind\) )?(collected|showed \[.*\] and won) \(%(CUR)s(?P<POT>[.\d]+)\)(, mucked| with.*|)" % subst, re.MULTILINE)
self.re_sitsOut = re.compile("^%s sits out" % player_re, re.MULTILINE) self.re_sitsOut = re.compile("^%s sits out" % player_re, re.MULTILINE)
self.re_ShownCards = re.compile("^Seat (?P<SEAT>[0-9]+): %s (\(.*\) )?(?P<SHOWED>showed|mucked) \[(?P<CARDS>.*)\].*" % player_re, re.MULTILINE) self.re_ShownCards = re.compile("^Seat (?P<SEAT>[0-9]+): %s (\(.*\) )?(?P<SHOWED>showed|mucked) \[(?P<CARDS>.*)\].*" % player_re, re.MULTILINE)
@ -194,12 +195,13 @@ class PokerStars(HandHistoryConverter):
#2008/11/12 10:00:48 CET [2008/11/12 4:00:48 ET] #2008/11/12 10:00:48 CET [2008/11/12 4:00:48 ET]
#2008/08/17 - 01:14:43 (ET) #2008/08/17 - 01:14:43 (ET)
#2008/09/07 06:23:14 ET #2008/09/07 06:23:14 ET
m2 = re.search("(?P<Y>[0-9]{4})\/(?P<M>[0-9]{2})\/(?P<D>[0-9]{2})[\- ]+(?P<H>[0-9]+):(?P<MIN>[0-9]+):(?P<S>[0-9]+)", info[key]) m1 = self.re_DateTime.finditer(info[key])
datetimestr = "%s/%s/%s %s:%s:%s" % (m2.group('Y'), m2.group('M'),m2.group('D'),m2.group('H'),m2.group('MIN'),m2.group('S')) # m2 = re.search("(?P<Y>[0-9]{4})\/(?P<M>[0-9]{2})\/(?P<D>[0-9]{2})[\- ]+(?P<H>[0-9]+):(?P<MIN>[0-9]+):(?P<S>[0-9]+)", info[key])
for a in m1:
datetimestr = "%s/%s/%s %s:%s:%s" % (a.group('Y'), a.group('M'),a.group('D'),a.group('H'),a.group('MIN'),a.group('S'))
hand.starttime = datetime.datetime.strptime(datetimestr, "%Y/%m/%d %H:%M:%S") hand.starttime = datetime.datetime.strptime(datetimestr, "%Y/%m/%d %H:%M:%S")
if key == 'HID': if key == 'HID':
hand.handid = info[key] hand.handid = info[key]
if key == 'TOURNO': if key == 'TOURNO':
hand.tourNo = info[key] hand.tourNo = info[key]
if key == 'BUYIN': if key == 'BUYIN':

View File

@ -1881,6 +1881,7 @@ class Sql:
inner join Sites s on (s.Id = gt.siteId) inner join Sites s on (s.Id = gt.siteId)
inner join Players p on (p.Id = hp.playerId) inner join Players p on (p.Id = hp.playerId)
where hp.playerId in <player_test> where hp.playerId in <player_test>
<game_test>
/*and hp.tourneysPlayersId IS NULL*/ /*and hp.tourneysPlayersId IS NULL*/
and h.seats <seats_test> and h.seats <seats_test>
<flagtest> <flagtest>
@ -1964,6 +1965,7 @@ class Sql:
inner join Sites s on (s.Id = gt.siteId) inner join Sites s on (s.Id = gt.siteId)
inner join Players p on (p.Id = hp.playerId) inner join Players p on (p.Id = hp.playerId)
where hp.playerId in <player_test> where hp.playerId in <player_test>
<game_test>
/*and hp.tourneysPlayersId IS NULL*/ /*and hp.tourneysPlayersId IS NULL*/
and h.seats <seats_test> and h.seats <seats_test>
<flagtest> <flagtest>
@ -2047,6 +2049,7 @@ class Sql:
inner join Gametypes gt on (gt.Id = h.gameTypeId) inner join Gametypes gt on (gt.Id = h.gameTypeId)
inner join Sites s on (s.Id = gt.siteId) inner join Sites s on (s.Id = gt.siteId)
where hp.playerId in <player_test> where hp.playerId in <player_test>
<game_test>
/*and hp.tourneysPlayersId IS NULL*/ /*and hp.tourneysPlayersId IS NULL*/
and h.seats <seats_test> and h.seats <seats_test>
<flagtest> <flagtest>
@ -2573,6 +2576,7 @@ class Sql:
AND h.handStart > '<startdate_test>' AND h.handStart > '<startdate_test>'
AND h.handStart < '<enddate_test>' AND h.handStart < '<enddate_test>'
<limit_test> <limit_test>
<game_test>
AND hp.tourneysPlayersId IS NULL AND hp.tourneysPlayersId IS NULL
GROUP BY h.handStart, hp.handId, hp.sawShowdown, hp.totalProfit GROUP BY h.handStart, hp.handId, hp.sawShowdown, hp.totalProfit
ORDER BY h.handStart""" ORDER BY h.handStart"""

View File

@ -62,9 +62,13 @@ import Database
re_Places = re.compile("_[0-9]$") re_Places = re.compile("_[0-9]$")
re_Percent = re.compile("%$") re_Percent = re.compile("%$")
# String manipulation
import codecs
encoder = codecs.lookup(Configuration.LOCALE_ENCODING)
def do_tip(widget, tip): def do_tip(widget, tip):
widget.set_tooltip_text(tip) (_tip, _len) = encoder.encode(tip)
widget.set_tooltip_text(_tip)
def do_stat(stat_dict, player = 24, stat = 'vpip'): def do_stat(stat_dict, player = 24, stat = 'vpip'):
match = re_Places.search(stat) match = re_Places.search(stat)

View File

@ -98,8 +98,6 @@ class Importer:
for i in xrange(self.settings['threads']): for i in xrange(self.settings['threads']):
self.writerdbs.append( Database.Database(self.config, sql = self.sql) ) self.writerdbs.append( Database.Database(self.config, sql = self.sql) )
self.NEWIMPORT = Configuration.NEWIMPORT
clock() # init clock in windows clock() # init clock in windows
#Set functions #Set functions
@ -433,7 +431,7 @@ class Importer:
else: else:
self.pos_in_file[file] = 0 self.pos_in_file[file] = 0
hhc = obj(in_path = file, out_path = out_path, index = idx, starsArchive = self.settings['starsArchive']) hhc = obj(in_path = file, out_path = out_path, index = idx, starsArchive = self.settings['starsArchive'])
if hhc.getStatus() and self.NEWIMPORT == True: if hhc.getStatus():
handlist = hhc.getProcessedHands() handlist = hhc.getProcessedHands()
self.pos_in_file[file] = hhc.getLastCharacterRead() self.pos_in_file[file] = hhc.getLastCharacterRead()
to_hud = [] to_hud = []
@ -451,7 +449,9 @@ class Importer:
# Call hudcache update if not in bulk import mode # Call hudcache update if not in bulk import mode
# FIXME: Need to test for bulk import that isn't rebuilding the cache # FIXME: Need to test for bulk import that isn't rebuilding the cache
if self.callHud: if self.callHud:
hand.updateHudCache(self.database) for hand in handlist:
if hand is not None:
hand.updateHudCache(self.database)
self.database.commit() self.database.commit()
#pipe the Hands.id out to the HUD #pipe the Hands.id out to the HUD

View File

@ -178,11 +178,7 @@ def testDrawImport():
(stored, dups, partial, errs, ttime) = importer.runImport() (stored, dups, partial, errs, ttime) = importer.runImport()
importer.clearFileList() importer.clearFileList()
except FpdbError: except FpdbError:
if Configuration.NEWIMPORT == False: assert 0 == 1
#Old import code doesn't support draw
pass
else:
assert 0 == 1
# Should actually do some testing here # Should actually do some testing here
assert 1 == 1 assert 1 == 1