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

This commit is contained in:
sqlcoder 2010-06-05 16:54:18 +01:00
commit 30d5cf56ca
17 changed files with 180 additions and 65 deletions

View File

@ -1,3 +1,10 @@
free-poker-tools (0.20~git20100305) unstable; urgency=low
* New snapshot
* Version bumped to 0.20
-- Mika Bostrom <bostik+fpdb@bostik.iki.fi> Fri, 05 Mar 2010 08:38:52 +0200
free-poker-tools (0.12~git20100122) unstable; urgency=low free-poker-tools (0.12~git20100122) unstable; urgency=low
* New snapshot release with reworked import code * New snapshot release with reworked import code

View File

@ -3,8 +3,10 @@ import re
import codecs import codecs
import Options import Options
import HandHistoryConverter import HandHistoryConverter
import Configuration
(options, argv) = Options.fpdb_options() (options, argv) = Options.fpdb_options()
config = Configuration.Config()
filter = options.hhc filter = options.hhc
@ -13,7 +15,7 @@ filter_name = filter.replace("ToFpdb", "")
mod = __import__(filter) mod = __import__(filter)
obj = getattr(mod, filter_name, None) obj = getattr(mod, filter_name, None)
hhc = obj(autostart=False) hhc = obj(config, autostart=False)
if os.path.exists(options.infile): if os.path.exists(options.infile):
in_fh = codecs.open(options.infile, 'r', "utf8") in_fh = codecs.open(options.infile, 'r', "utf8")
@ -31,7 +33,7 @@ for a in m:
uniq = set(players) uniq = set(players)
for i, name in enumerate(uniq, 1): for i, name in enumerate(uniq):
filecontents = filecontents.replace(name, 'Player%d' %i) filecontents = filecontents.replace(name, 'Player%d' %i)
print filecontents print filecontents

View File

@ -26,7 +26,9 @@ import Configuration
encoder_to_utf = codecs.lookup('utf-8') encoder_to_utf = codecs.lookup('utf-8')
encoder_to_sys = codecs.lookup(Configuration.LOCALE_ENCODING) encoder_to_sys = codecs.lookup(Configuration.LOCALE_ENCODING)
coder_hex = codecs.lookup('hex_codec')
hex_coding = False #FIXME: Should only be on if db is not UTF8 - test in Database.py?
# I'm saving a few cycles with this one # I'm saving a few cycles with this one
not_needed1, not_needed2, not_needed3 = False, False, False not_needed1, not_needed2, not_needed3 = False, False, False
if Configuration.LOCALE_ENCODING == 'UTF8': if Configuration.LOCALE_ENCODING == 'UTF8':
@ -75,3 +77,19 @@ def to_gui(s):
except UnicodeEncodeError: except UnicodeEncodeError:
sys.stderr.write('Could not encode: "%s"\n' % s) sys.stderr.write('Could not encode: "%s"\n' % s)
raise raise
def to_hex(s):
try:
out = coder_hex.encode(s)[0]
return out
except UnicodeDecodeError:
sys.stderr.write('Could not convert: "%s"\n' % s)
return s
def from_hex(s):
try:
out = coder_hex.decode(s)[0]
return out
except UnicodeDecodeError:
sys.stderr.write('Could not convert: "%s"\n' % s)
return s

View File

@ -193,7 +193,7 @@ class Database:
# alter table t add constraint c foreign key (fkcol) references tab(rcol) # alter table t add constraint c foreign key (fkcol) references tab(rcol)
# (fkcol is used for foreigh key name) # (fkcol is used for foreigh key name)
# mysql to list indexes: # mysql to list indexes: (CG - "LIST INDEXES" should work too)
# SELECT table_name, index_name, non_unique, column_name # SELECT table_name, index_name, non_unique, column_name
# FROM INFORMATION_SCHEMA.STATISTICS # FROM INFORMATION_SCHEMA.STATISTICS
# WHERE table_name = 'tbl_name' # WHERE table_name = 'tbl_name'
@ -223,6 +223,7 @@ class Database:
# Note: index names must be unique across a schema # Note: index names must be unique across a schema
# CREATE INDEX idx ON tab(col) # CREATE INDEX idx ON tab(col)
# DROP INDEX idx # DROP INDEX idx
# SELECT * FROM PG_INDEXES
# SQLite notes: # SQLite notes:
@ -1075,7 +1076,7 @@ class Database:
c = self.get_cursor() c = self.get_cursor()
c.execute(self.sql.query['createSettingsTable']) c.execute(self.sql.query['createSettingsTable'])
log.debug(self.sql.query['createSitesTable']) log.debug("Creating tables")
c.execute(self.sql.query['createSitesTable']) c.execute(self.sql.query['createSitesTable'])
c.execute(self.sql.query['createGametypesTable']) c.execute(self.sql.query['createGametypesTable'])
c.execute(self.sql.query['createPlayersTable']) c.execute(self.sql.query['createPlayersTable'])
@ -1088,7 +1089,8 @@ class Database:
c.execute(self.sql.query['createHandsActionsTable']) c.execute(self.sql.query['createHandsActionsTable'])
c.execute(self.sql.query['createHudCacheTable']) c.execute(self.sql.query['createHudCacheTable'])
# create unique indexes: # Create unique indexes:
log.debug("Creating unique indexes")
c.execute(self.sql.query['addTourneyIndex']) c.execute(self.sql.query['addTourneyIndex'])
c.execute(self.sql.query['addHandsIndex']) c.execute(self.sql.query['addHandsIndex'])
c.execute(self.sql.query['addPlayersIndex']) c.execute(self.sql.query['addPlayersIndex'])
@ -1162,7 +1164,8 @@ class Database:
self.connection.set_isolation_level(0) # allow table/index operations to work self.connection.set_isolation_level(0) # allow table/index operations to work
for idx in self.indexes[self.backend]: for idx in self.indexes[self.backend]:
if self.backend == self.MYSQL_INNODB: if self.backend == self.MYSQL_INNODB:
print "creating mysql index ", idx['tab'], idx['col'] print "Creating mysql index %s %s" %(idx['tab'], idx['col'])
log.debug("Creating sqlite index %s %s" %(idx['tab'], idx['col']))
try: try:
s = "create index %s on %s(%s)" % (idx['col'],idx['tab'],idx['col']) s = "create index %s on %s(%s)" % (idx['col'],idx['tab'],idx['col'])
self.get_cursor().execute(s) self.get_cursor().execute(s)
@ -1170,21 +1173,23 @@ class Database:
print " create idx failed: " + str(sys.exc_info()) print " create idx failed: " + str(sys.exc_info())
elif self.backend == self.PGSQL: elif self.backend == self.PGSQL:
# mod to use tab_col for index name? # mod to use tab_col for index name?
print "creating pg index ", idx['tab'], idx['col'] print "Creating pg index %s %s" %(idx['tab'], idx['col'])
log.debug("Creating sqlite index %s %s" %(idx['tab'], idx['col']))
try: try:
s = "create index %s_%s_idx on %s(%s)" % (idx['tab'], idx['col'], idx['tab'], idx['col']) s = "create index %s_%s_idx on %s(%s)" % (idx['tab'], idx['col'], idx['tab'], idx['col'])
self.get_cursor().execute(s) self.get_cursor().execute(s)
except: except:
print " create idx failed: " + str(sys.exc_info()) print " create idx failed: " + str(sys.exc_info())
elif self.backend == self.SQLITE: elif self.backend == self.SQLITE:
log.debug("Creating sqlite index %s %s" % (idx['tab'], idx['col'])) print "Creating sqlite index %s %s" %(idx['tab'], idx['col'])
log.debug("Creating sqlite index %s %s" %(idx['tab'], idx['col']))
try: try:
s = "create index %s_%s_idx on %s(%s)" % (idx['tab'], idx['col'], idx['tab'], idx['col']) s = "create index %s_%s_idx on %s(%s)" % (idx['tab'], idx['col'], idx['tab'], idx['col'])
self.get_cursor().execute(s) self.get_cursor().execute(s)
except: except:
log.debug("Create idx failed: " + str(sys.exc_info())) log.debug("Create idx failed: " + str(sys.exc_info()))
else: else:
print "Only MySQL, Postgres and SQLite supported so far" print "Unknown database: MySQL, Postgres and SQLite supported"
return -1 return -1
if self.backend == self.PGSQL: if self.backend == self.PGSQL:
self.connection.set_isolation_level(1) # go back to normal isolation level self.connection.set_isolation_level(1) # go back to normal isolation level
@ -1215,8 +1220,15 @@ class Database:
% (idx['tab'],idx['col']) ) % (idx['tab'],idx['col']) )
except: except:
print " drop idx failed: " + str(sys.exc_info()) print " drop idx failed: " + str(sys.exc_info())
elif self.backend == self.SQLITE:
print "Dropping sqlite index ", idx['tab'], idx['col']
try:
self.get_cursor().execute( "drop index %s_%s_idx"
% (idx['tab'],idx['col']) )
except:
print " drop idx failed: " + str(sys.exc_info())
else: else:
print "Only MySQL and Postgres supported so far" print "Only MySQL, Postgres and SQLITE supported, what are you trying to use?"
return -1 return -1
if self.backend == self.PGSQL: if self.backend == self.PGSQL:
self.connection.set_isolation_level(1) # go back to normal isolation level self.connection.set_isolation_level(1) # go back to normal isolation level

View File

@ -67,12 +67,12 @@ class DerivedStats():
self.handsplayers[player[1]]['street%dCBDone' %i] = False self.handsplayers[player[1]]['street%dCBDone' %i] = False
self.handsplayers[player[1]]['street%dCheckCallRaiseChance' %i] = False self.handsplayers[player[1]]['street%dCheckCallRaiseChance' %i] = False
self.handsplayers[player[1]]['street%dCheckCallRaiseDone' %i] = False self.handsplayers[player[1]]['street%dCheckCallRaiseDone' %i] = False
self.handsplayers[player[1]]['otherRaisedStreet%d' %i] = False
self.handsplayers[player[1]]['foldToOtherRaisedStreet%d' %i] = False
#FIXME - Everything below this point is incomplete. #FIXME - Everything below this point is incomplete.
self.handsplayers[player[1]]['tourneyTypeId'] = 1 self.handsplayers[player[1]]['tourneyTypeId'] = 1
for i in range(1,5): for i in range(1,5):
self.handsplayers[player[1]]['otherRaisedStreet%d' %i] = False
self.handsplayers[player[1]]['foldToOtherRaisedStreet%d' %i] = False
self.handsplayers[player[1]]['foldToStreet%dCBChance' %i] = False self.handsplayers[player[1]]['foldToStreet%dCBChance' %i] = False
self.handsplayers[player[1]]['foldToStreet%dCBDone' %i] = False self.handsplayers[player[1]]['foldToStreet%dCBDone' %i] = False
@ -139,6 +139,8 @@ class DerivedStats():
self.handsplayers[player[1]]['seatNo'] = player[0] self.handsplayers[player[1]]['seatNo'] = player[0]
self.handsplayers[player[1]]['startCash'] = int(100 * Decimal(player[2])) self.handsplayers[player[1]]['startCash'] = int(100 * Decimal(player[2]))
# XXX: enumerate(list, start=x) is python 2.6 syntax; 'start'
#for i, street in enumerate(hand.actionStreets[2:], start=1):
for i, street in enumerate(hand.actionStreets[2:]): for i, street in enumerate(hand.actionStreets[2:]):
self.seen(self.hand, i+1) self.seen(self.hand, i+1)
@ -146,6 +148,8 @@ class DerivedStats():
self.aggr(self.hand, i) self.aggr(self.hand, i)
self.calls(self.hand, i) self.calls(self.hand, i)
self.bets(self.hand, i) self.bets(self.hand, i)
if i>0:
self.folds(self.hand, i)
# Winnings is a non-negative value of money collected from the pot, which already includes the # Winnings is a non-negative value of money collected from the pot, which already includes the
# rake taken out. hand.collectees is Decimal, database requires cents # rake taken out. hand.collectees is Decimal, database requires cents
@ -368,8 +372,8 @@ class DerivedStats():
name = self.lastBetOrRaiser(hand.actionStreets[i+1]) name = self.lastBetOrRaiser(hand.actionStreets[i+1])
if name: if name:
chance = self.noBetsBefore(hand.actionStreets[i+2], name) chance = self.noBetsBefore(hand.actionStreets[i+2], name)
self.handsplayers[name]['street%dCBChance' % (i+1)] = True
if chance == True: if chance == True:
self.handsplayers[name]['street%dCBChance' % (i+1)] = True
self.handsplayers[name]['street%dCBDone' % (i+1)] = self.betStreet(hand.actionStreets[i+2], name) self.handsplayers[name]['street%dCBDone' % (i+1)] = self.betStreet(hand.actionStreets[i+2], name)
def calcCheckCallRaise(self, hand): def calcCheckCallRaise(self, hand):
@ -380,6 +384,7 @@ class DerivedStats():
CG: CheckCall would be a much better name for this. CG: CheckCall would be a much better name for this.
""" """
# XXX: enumerate(list, start=x) is python 2.6 syntax; 'start'
#for i, street in enumerate(hand.actionStreets[2:], start=1): #for i, street in enumerate(hand.actionStreets[2:], start=1):
for i, street in enumerate(hand.actionStreets[2:]): for i, street in enumerate(hand.actionStreets[2:]):
actions = hand.actions[hand.actionStreets[i+1]] actions = hand.actions[hand.actionStreets[i+1]]
@ -408,10 +413,16 @@ class DerivedStats():
def aggr(self, hand, i): def aggr(self, hand, i):
aggrers = set() aggrers = set()
others = set()
# Growl - actionStreets contains 'BLINDSANTES', which isn't actually an action street # Growl - actionStreets contains 'BLINDSANTES', which isn't actually an action street
firstAggrMade=False
for act in hand.actions[hand.actionStreets[i+1]]: for act in hand.actions[hand.actionStreets[i+1]]:
if firstAggrMade:
others.add(act[0])
if act[1] in ('completes', 'bets', 'raises'): if act[1] in ('completes', 'bets', 'raises'):
aggrers.add(act[0]) aggrers.add(act[0])
firstAggrMade=True
for player in hand.players: for player in hand.players:
#print "DEBUG: actionStreet[%s]: %s" %(hand.actionStreets[i+1], i) #print "DEBUG: actionStreet[%s]: %s" %(hand.actionStreets[i+1], i)
@ -420,6 +431,12 @@ class DerivedStats():
else: else:
self.handsplayers[player[1]]['street%sAggr' % i] = False self.handsplayers[player[1]]['street%sAggr' % i] = False
if i > 0 and len(aggrers) > 0:
for playername in others:
self.handsplayers[playername]['otherRaisedStreet%s' % i] = True
#print "DEBUG: otherRaised detected on handid %s for %s on actionStreet[%s]: %s"
# %(hand.handid, playername, hand.actionStreets[i+1], i)
def calls(self, hand, i): def calls(self, hand, i):
callers = [] callers = []
for act in hand.actions[hand.actionStreets[i+1]]: for act in hand.actions[hand.actionStreets[i+1]]:
@ -429,11 +446,19 @@ class DerivedStats():
# CG - I'm sure this stat is wrong # CG - I'm sure this stat is wrong
# Best guess is that raise = 2 bets # Best guess is that raise = 2 bets
def bets(self, hand, i): def bets(self, hand, i):
betters = []
for act in hand.actions[hand.actionStreets[i+1]]: for act in hand.actions[hand.actionStreets[i+1]]:
if act[1] in ('bets'): if act[1] in ('bets'):
self.handsplayers[act[0]]['street%sBets' % i] = 1 + self.handsplayers[act[0]]['street%sBets' % i] self.handsplayers[act[0]]['street%sBets' % i] = 1 + self.handsplayers[act[0]]['street%sBets' % i]
def folds(self, hand, i):
for act in hand.actions[hand.actionStreets[i+1]]:
if act[1] in ('folds'):
if self.handsplayers[act[0]]['otherRaisedStreet%s' % i] == True:
self.handsplayers[act[0]]['foldToOtherRaisedStreet%s' % i] = True
#print "DEBUG: fold detected on handid %s for %s on actionStreet[%s]: %s"
# %(hand.handid, act[0],hand.actionStreets[i+1], i)
def countPlayers(self, hand): def countPlayers(self, hand):
pass pass

View File

@ -876,7 +876,7 @@ class Filters(threading.Thread):
t2 = self.end_date.get_text() t2 = self.end_date.get_text()
if t1 == '': if t1 == '':
t1 = '1970-01-01' t1 = '1970-01-02'
if t2 == '': if t2 == '':
t2 = '2020-12-12' t2 = '2020-12-12'

View File

@ -27,7 +27,7 @@ class Fulltilt(HandHistoryConverter):
sitename = "Fulltilt" sitename = "Fulltilt"
filetype = "text" filetype = "text"
codepage = ["utf-16", "cp1252"] codepage = ["utf-16", "cp1252", "utf-8"]
siteId = 1 # Needs to match id entry in Sites database siteId = 1 # Needs to match id entry in Sites database
# Static regexes # Static regexes

View File

@ -33,7 +33,7 @@ try:
from matplotlib.backends.backend_gtkagg import NavigationToolbar2GTKAgg as NavigationToolbar from matplotlib.backends.backend_gtkagg import NavigationToolbar2GTKAgg as NavigationToolbar
from matplotlib.finance import candlestick2 from matplotlib.finance import candlestick2
from numpy import diff, nonzero, sum, cumsum, max, min from numpy import diff, nonzero, sum, cumsum, max, min, append
# from matplotlib.dates import DateFormatter, WeekdayLocator, HourLocator, \ # from matplotlib.dates import DateFormatter, WeekdayLocator, HourLocator, \
# DayLocator, MONDAY, timezone # DayLocator, MONDAY, timezone
@ -184,7 +184,7 @@ class GuiSessionViewer (threading.Thread):
sitenos.append(siteids[site]) sitenos.append(siteids[site])
_q = self.sql.query['getPlayerId'] _q = self.sql.query['getPlayerId']
_name = Charset.to_utf8(heroes[site]) _name = Charset.to_utf8(heroes[site])
print 'DEBUG(_name) :: %s' % _name #print 'DEBUG(_name) :: %s' % _name
self.cursor.execute(_q, (_name,)) # arg = tuple 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:
@ -241,6 +241,9 @@ class GuiSessionViewer (threading.Thread):
#end def fillStatsFrame(self, vbox): #end def fillStatsFrame(self, vbox):
def generateDatasets(self, playerids, sitenos, limits, seats): def generateDatasets(self, playerids, sitenos, limits, seats):
THRESHOLD = 1800 # Minimum number of seconds between consecutive hands before being considered a new session
PADDING = 5 # Additional time in minutes to add to a session, session startup, shutdown etc (FiXME: user configurable)
# Get a list of all handids and their timestampts # Get a list of all handids and their timestampts
#FIXME: Query still need to filter on blind levels #FIXME: Query still need to filter on blind levels
@ -255,23 +258,31 @@ class GuiSessionViewer (threading.Thread):
q = q.replace("<ampersand_s>", "%s") q = q.replace("<ampersand_s>", "%s")
self.db.cursor.execute(q) self.db.cursor.execute(q)
THRESHOLD = 1800
hands = self.db.cursor.fetchall() hands = self.db.cursor.fetchall()
# Take that list and create an array of the time between hands # Take that list and create an array of the time between hands
times = map(lambda x:long(x[0]), hands) times = map(lambda x:long(x[0]), hands)
handids = map(lambda x:int(x[1]), hands) handids = map(lambda x:int(x[1]), hands)
winnings = map(lambda x:float(x[4]), hands) winnings = map(lambda x:float(x[4]), hands)
print "DEBUG: len(times) %s" %(len(times)) #print "DEBUG: len(times) %s" %(len(times))
diffs = diff(times) # This array is the difference in starttime between consecutive hands diffs = diff(times) # This array is the difference in starttime between consecutive hands
index = nonzero(diff(times) > THRESHOLD) # This array represents the indexes into 'times' for start/end times of sessions diffs2 = append(diffs,THRESHOLD + 1) # Append an additional session to the end of the diffs, so the next line
# ie. times[index[0][0]] is the end of the first session # includes an index into the last 'session'
index = nonzero(diffs2 > THRESHOLD) # This array represents the indexes into 'times' for start/end times of sessions
# times[index[0][0]] is the end of the first session,
#print "DEBUG: len(index[0]) %s" %(len(index[0])) #print "DEBUG: len(index[0]) %s" %(len(index[0]))
if len(index[0]) > 0:
#print "DEBUG: index[0][0] %s" %(index[0][0])
#print "DEBUG: index %s" %(index)
pass
else:
index = [[0]]
#print "DEBUG: index %s" %(index) #print "DEBUG: index %s" %(index)
#print "DEBUG: index[0][0] %s" %(index[0][0]) #print "DEBUG: index[0][0] %s" %(index[0][0])
pass
total = 0 total = 0
last_idx = 0 first_idx = 0
lowidx = 0 lowidx = 0
uppidx = 0 uppidx = 0
opens = [] opens = []
@ -281,27 +292,36 @@ class GuiSessionViewer (threading.Thread):
results = [] results = []
cum_sum = cumsum(winnings) cum_sum = cumsum(winnings)
cum_sum = cum_sum/100 cum_sum = cum_sum/100
sid = 1
# Take all results and format them into a list for feeding into gui model. # Take all results and format them into a list for feeding into gui model.
for i in range(len(index[0])): for i in range(len(index[0])):
sid = i # Session id hds = index[0][i] - first_idx + 1 # Number of hands in session
hds = index[0][i] - last_idx # Number of hands in session
if hds > 0: if hds > 0:
stime = strftime("%d/%m/%Y %H:%M", localtime(times[last_idx])) # Formatted start time stime = strftime("%d/%m/%Y %H:%M", localtime(times[first_idx])) # Formatted start time
etime = strftime("%d/%m/%Y %H:%M", localtime(times[index[0][i]])) # Formatted end time etime = strftime("%d/%m/%Y %H:%M", localtime(times[index[0][i]])) # Formatted end time
hph = (times[index[0][i]] - times[last_idx])/60 # Hands per hour minutesplayed = (times[index[0][i]] - times[first_idx])/60
won = sum(winnings[last_idx:index[0][i]])/100.0 if minutesplayed == 0:
hwm = max(cum_sum[last_idx:index[0][i]]) minutesplayed = 1
lwm = min(cum_sum[last_idx:index[0][i]]) minutesplayed = minutesplayed + PADDING
#print "DEBUG: range: (%s, %s) - (min, max): (%s, %s)" %(last_idx, index[0][i], hwm, lwm) hph = hds*60/minutesplayed # Hands per hour
won = sum(winnings[first_idx:index[0][i]])/100.0
hwm = max(cum_sum[first_idx:index[0][i]])
lwm = min(cum_sum[first_idx:index[0][i]])
open = (sum(winnings[:first_idx]))/100
close = (sum(winnings[:index[0][i]]))/100
#print "DEBUG: range: (%s, %s) - (min, max): (%s, %s) - (open,close): (%s, %s)" %(first_idx, index[0][i], lwm, hwm, open, close)
results.append([sid, hds, stime, etime, hph, won]) results.append([sid, hds, stime, etime, hph, won])
opens.append((sum(winnings[:last_idx]))/100) opens.append(open)
closes.append((sum(winnings[:index[0][i]]))/100) closes.append(close)
highs.append(hwm) highs.append(hwm)
lows.append(lwm) lows.append(lwm)
#print "Hands in session %4s: %4s Start: %s End: %s HPH: %s Profit: %s" %(sid, hds, stime, etime, hph, won) #print "DEBUG: Hands in session %4s: %4s Start: %s End: %s HPH: %s Profit: %s" %(sid, hds, stime, etime, hph, won)
total = total + (index[0][i] - last_idx) total = total + (index[0][i] - first_idx)
last_idx = index[0][i] + 1 first_idx = index[0][i] + 1
sid = sid+1
else:
print "hds <= 0"
return (results, opens, closes, highs, lows) return (results, opens, closes, highs, lows)
@ -330,11 +350,6 @@ class GuiSessionViewer (threading.Thread):
def generateGraph(self, opens, closes, highs, lows): def generateGraph(self, opens, closes, highs, lows):
self.clearGraphData() self.clearGraphData()
#FIXME: Weird - first data entry is crashing this for me
opens = opens[1:]
closes = closes[1:]
highs = highs[1:]
lows = lows[1:]
# print "DEBUG:" # print "DEBUG:"
# print "highs = %s" % highs # print "highs = %s" % highs
# print "lows = %s" % lows # print "lows = %s" % lows

View File

@ -274,15 +274,16 @@ If a player has None chips he won't be added."""
self.streets.update(match.groupdict()) self.streets.update(match.groupdict())
log.debug("markStreets:\n"+ str(self.streets)) log.debug("markStreets:\n"+ str(self.streets))
else: else:
tmp = self.handText[0:100]
log.error("markstreets didn't match") log.error("markstreets didn't match")
log.error(" - Assuming hand cancelled") log.error(" - Assuming hand cancelled")
self.cancelled = True self.cancelled = True
raise FpdbParseError raise FpdbParseError("FpdbParseError: markStreets appeared to fail: First 100 chars: '%s'" % tmp)
def checkPlayerExists(self,player): def checkPlayerExists(self,player):
if player not in [p[1] for p in self.players]: if player not in [p[1] for p in self.players]:
print "checkPlayerExists", player, "fail" print "DEBUG: checkPlayerExists %s fail" % player
raise FpdbParseError raise FpdbParseError("checkPlayerExists: '%s' failed." % player)
@ -1487,9 +1488,9 @@ class Pot(object):
if self.sym is None: if self.sym is None:
self.sym = "C" self.sym = "C"
if self.total is None: if self.total is None:
print "call Pot.end() before printing pot total" print "DEBUG: call Pot.end() before printing pot total"
# NB if I'm sure end() is idempotent, call it here. # NB if I'm sure end() is idempotent, call it here.
raise FpdbParseError raise FpdbParseError("FpdbError in printing Hand object")
ret = "Total pot %s%.2f" % (self.sym, self.total) ret = "Total pot %s%.2f" % (self.sym, self.total)
if len(self.pots) < 2: if len(self.pots) < 2:

View File

@ -62,7 +62,7 @@ class HandHistoryConverter():
codepage = "cp1252" codepage = "cp1252"
def __init__(self, config, in_path = '-', out_path = '-', follow=False, index=0, autostart=True, starsArchive=False): def __init__(self, config, in_path = '-', out_path = '-', follow=False, index=0, autostart=True, starsArchive=False, ftpArchive=False):
"""\ """\
in_path (default '-' = sys.stdin) in_path (default '-' = sys.stdin)
out_path (default '-' = sys.stdout) out_path (default '-' = sys.stdout)
@ -75,6 +75,7 @@ follow : whether to tail -f the input"""
self.index = index self.index = index
self.starsArchive = starsArchive self.starsArchive = starsArchive
self.ftpArchive = ftpArchive
self.in_path = in_path self.in_path = in_path
self.out_path = out_path self.out_path = out_path
@ -136,8 +137,7 @@ Otherwise, finish at EOF.
self.numHands += 1 self.numHands += 1
except FpdbParseError, e: except FpdbParseError, e:
self.numErrors += 1 self.numErrors += 1
log.warning("Failed to convert hand %s" % e.hid) log.warning("HHC.start(follow): processHand failed: Exception msg: '%s'" % e)
log.warning("Exception msg: '%s'" % str(e))
log.debug(handText) log.debug(handText)
else: else:
handsList = self.allHandsAsList() handsList = self.allHandsAsList()
@ -151,8 +151,7 @@ Otherwise, finish at EOF.
self.processedHands.append(self.processHand(handText)) self.processedHands.append(self.processHand(handText))
except FpdbParseError, e: except FpdbParseError, e:
self.numErrors += 1 self.numErrors += 1
log.warning("Failed to convert hand %s" % e.hid) log.warning("HHC.start(): processHand failed: Exception msg: '%s'" % e)
log.warning("Exception msg: '%s'" % str(e))
log.debug(handText) log.debug(handText)
self.numHands = len(handsList) self.numHands = len(handsList)
endtime = time.time() endtime = time.time()
@ -247,6 +246,11 @@ which it expects to find at self.re_TailSplitHands -- see for e.g. Everleaf.py.
m = re.compile('^Hand #\d+', re.MULTILINE) m = re.compile('^Hand #\d+', re.MULTILINE)
self.obs = m.sub('', self.obs) self.obs = m.sub('', self.obs)
if self.ftpArchive == True:
log.debug("Converting ftpArchive format to readable")
m = re.compile('^\*\*\*\*\*\*+\s#\s\d+\s\*\*\*\*\*+$', re.MULTILINE)
self.obs = m.sub('', self.obs)
if self.obs is None or self.obs == "": if self.obs is None or self.obs == "":
log.info("Read no hands.") log.info("Read no hands.")
return [] return []

View File

@ -448,6 +448,8 @@ class Hud:
if os.name == 'nt': if os.name == 'nt':
if not win32gui.IsWindow(self.table.number): if not win32gui.IsWindow(self.table.number):
self.parent.kill_hud(self, self.table.name) self.parent.kill_hud(self, self.table.name)
self.parent.kill_hud(self, self.table.name.split(" ")[0])
#table.name is only a valid handle for ring games ! we are not killing tourney tables here.
return False return False
# anyone know how to do this in unix, or better yet, trap the X11 error that is triggered when executing the get_origin() for a closed window? # anyone know how to do this in unix, or better yet, trap the X11 error that is triggered when executing the get_origin() for a closed window?
if self.table.gdkhandle is not None: if self.table.gdkhandle is not None:

View File

@ -261,6 +261,7 @@ class PartyPoker(HandHistoryConverter):
if v[0] in self.pot.returned: if v[0] in self.pot.returned:
self.collected[i][1] = Decimal(v[1]) - self.pot.returned[v[0]] self.collected[i][1] = Decimal(v[1]) - self.pot.returned[v[0]]
self.collectees[v[0]] -= self.pot.returned[v[0]] self.collectees[v[0]] -= self.pot.returned[v[0]]
self.pot.returned[v[0]] = 0
return origTotalPot() return origTotalPot()
return totalPot return totalPot
instancemethod = type(hand.totalPot) instancemethod = type(hand.totalPot)
@ -359,8 +360,14 @@ class PartyPoker(HandHistoryConverter):
if hand.gametype['type'] == 'ring': if hand.gametype['type'] == 'ring':
try: try:
assert noSmallBlind==False assert noSmallBlind==False
m = self.re_PostSB.search(hand.handText) liveBlind = True
for m in self.re_PostSB.finditer(hand.handText):
if liveBlind:
hand.addBlind(m.group('PNAME'), 'small blind', m.group('SB')) hand.addBlind(m.group('PNAME'), 'small blind', m.group('SB'))
liveBlind = False
else:
# Post dead blinds as ante
hand.addBlind(m.group('PNAME'), 'secondsb', m.group('SB'))
except: # no small blind except: # no small blind
hand.addBlind(None, None, None) hand.addBlind(None, None, None)
@ -432,7 +439,7 @@ class PartyPoker(HandHistoryConverter):
if street == 'PREFLOP' and \ if street == 'PREFLOP' and \
playerName in [item[0] for item in hand.actions['BLINDSANTES'] if item[2]!='ante']: playerName in [item[0] for item in hand.actions['BLINDSANTES'] if item[2]!='ante']:
# preflop raise from blind # preflop raise from blind
hand.addRaiseBy( street, playerName, amount ) hand.addCallandRaise( street, playerName, amount )
else: else:
hand.addCallandRaise( street, playerName, amount ) hand.addCallandRaise( street, playerName, amount )
elif actionType == 'calls': elif actionType == 'calls':

View File

@ -137,13 +137,16 @@ class PokerStars(HandHistoryConverter):
info = {} info = {}
m = self.re_GameInfo.search(handText) m = self.re_GameInfo.search(handText)
if not m: if not m:
print "DEBUG: determineGameType(): did not match" tmp = handText[0:100]
return None log.error("determineGameType: Unable to recognise gametype from: '%s'" % tmp)
log.error("determineGameType: Raising FpdbParseError")
raise FpdbParseError("Unable to recognise gametype from: '%s'" % tmp)
mg = m.groupdict() mg = m.groupdict()
# translations from captured groups to fpdb info strings # translations from captured groups to fpdb info strings
Lim_Blinds = { '0.04': ('0.01', '0.02'), '0.10': ('0.02', '0.05'), '0.20': ('0.05', '0.10'), Lim_Blinds = { '0.04': ('0.01', '0.02'), '0.10': ('0.02', '0.05'), '0.20': ('0.05', '0.10'),
'0.50': ('0.10', '0.25'), '1.00': ('0.25', '0.50'), '2.00': ('0.50', '1.00'), '0.50': ('0.10', '0.25'), '1.00': ('0.25', '0.50'), '2.00': ('0.50', '1.00'),
'2': ('0.50', '1.00'), '4': ('1.00', '2.00'), '6': ('1.00', '3.00'),
'4.00': ('1.00', '2.00'), '6.00': ('1.00', '3.00'), '10.00': ('2.00', '5.00'), '4.00': ('1.00', '2.00'), '6.00': ('1.00', '3.00'), '10.00': ('2.00', '5.00'),
'20.00': ('5.00', '10.00'), '30.00': ('10.00', '15.00'), '60.00': ('15.00', '30.00'), '20.00': ('5.00', '10.00'), '30.00': ('10.00', '15.00'), '60.00': ('15.00', '30.00'),
'100.00': ('25.00', '50.00'),'200.00': ('50.00', '100.00'),'400.00': ('100.00', '200.00'), '100.00': ('25.00', '50.00'),'200.00': ('50.00', '100.00'),'400.00': ('100.00', '200.00'),
@ -185,8 +188,13 @@ class PokerStars(HandHistoryConverter):
info['type'] = 'tour' info['type'] = 'tour'
if info['limitType'] == 'fl' and info['bb'] is not None and info['type'] == 'ring' and info['base'] != 'stud': if info['limitType'] == 'fl' and info['bb'] is not None and info['type'] == 'ring' and info['base'] != 'stud':
try:
info['sb'] = Lim_Blinds[mg['BB']][0] info['sb'] = Lim_Blinds[mg['BB']][0]
info['bb'] = Lim_Blinds[mg['BB']][1] info['bb'] = Lim_Blinds[mg['BB']][1]
except KeyError:
log.error("determineGameType: Lim_Blinds has no lookup for '%s'" % mg['BB'])
log.error("determineGameType: Raising FpdbParseError")
raise FpdbParseError("Lim_Blinds has no lookup for '%s'" % mg['BB'])
# NB: SB, BB must be interpreted as blinds or bets depending on limit type. # NB: SB, BB must be interpreted as blinds or bets depending on limit type.
return info return info

View File

@ -51,6 +51,18 @@ class Sql:
WHERE type='table' WHERE type='table'
ORDER BY name;""" ORDER BY name;"""
################################
# List indexes
################################
if db_server == 'mysql':
self.query['list_tables'] = """SHOW INDEXES"""
elif db_server == 'postgresql':
self.query['list_tables'] = """SELECT tablename, indexname FROM PG_INDEXES"""
elif db_server == 'sqlite':
self.query['list_tables'] = """SELECT name FROM sqlite_master
WHERE type='index'
ORDER BY name;"""
################################################################## ##################################################################
# Drop Tables - MySQL, PostgreSQL and SQLite all share same syntax # Drop Tables - MySQL, PostgreSQL and SQLite all share same syntax
################################################################## ##################################################################

View File

@ -57,6 +57,7 @@ import re
# FreePokerTools modules # FreePokerTools modules
import Configuration import Configuration
import Database import Database
import Charset
re_Places = re.compile("_[0-9]$") re_Places = re.compile("_[0-9]$")
@ -67,7 +68,7 @@ import codecs
encoder = codecs.lookup(Configuration.LOCALE_ENCODING) encoder = codecs.lookup(Configuration.LOCALE_ENCODING)
def do_tip(widget, tip): def do_tip(widget, tip):
(_tip, _len) = encoder.encode(tip) _tip = Charset.to_utf8(tip)
widget.set_tooltip_text(_tip) widget.set_tooltip_text(_tip)
def do_stat(stat_dict, player = 24, stat = 'vpip'): def do_stat(stat_dict, player = 24, stat = 'vpip'):
@ -277,7 +278,7 @@ def fold_f(stat_dict, player):
""" Folded flop/4th.""" """ Folded flop/4th."""
stat = 0.0 stat = 0.0
try: try:
stat = float(stat_dict[player]['fold_2'])/fold(stat_dict[player]['saw_f']) stat = float(stat_dict[player]['fold_2'])/float(stat_dict[player]['saw_f'])
return (stat, return (stat,
'%3.1f' % (100*stat) + '%', '%3.1f' % (100*stat) + '%',
'ff=%3.1f' % (100*stat) + '%', 'ff=%3.1f' % (100*stat) + '%',

View File

@ -110,7 +110,7 @@ import Database
import Configuration import Configuration
import Exceptions import Exceptions
VERSION = "0.12" VERSION = "0.20"
class fpdb: class fpdb:

View File

@ -468,6 +468,7 @@ class Importer:
errors = getattr(hhc, 'numErrors') errors = getattr(hhc, 'numErrors')
stored = getattr(hhc, 'numHands') stored = getattr(hhc, 'numHands')
stored -= duplicates stored -= duplicates
stored -= errors
else: else:
# conversion didn't work # conversion didn't work
# TODO: appropriate response? # TODO: appropriate response?