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

Conflicts:
	pyfpdb/DerivedStats.py
This commit is contained in:
steffen123 2010-06-07 03:08:07 +02:00
commit e72b7364b8
17 changed files with 177 additions and 42 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

@ -412,6 +412,7 @@ class Import:
self.interval = node.getAttribute("interval") self.interval = node.getAttribute("interval")
self.callFpdbHud = node.getAttribute("callFpdbHud") self.callFpdbHud = node.getAttribute("callFpdbHud")
self.hhArchiveBase = node.getAttribute("hhArchiveBase") self.hhArchiveBase = node.getAttribute("hhArchiveBase")
self.hhBulkPath = node.getAttribute("hhBulkPath")
self.saveActions = string_to_bool(node.getAttribute("saveActions"), default=True) self.saveActions = string_to_bool(node.getAttribute("saveActions"), default=True)
self.fastStoreHudCache = string_to_bool(node.getAttribute("fastStoreHudCache"), default=False) self.fastStoreHudCache = string_to_bool(node.getAttribute("fastStoreHudCache"), default=False)
self.saveStarsHH = string_to_bool(node.getAttribute("saveStarsHH"), default=False) self.saveStarsHH = string_to_bool(node.getAttribute("saveStarsHH"), default=False)
@ -452,6 +453,24 @@ class Tv:
return (" combinedStealFold = %s\n combined2B3B = %s\n combinedPostflop = %s\n" % return (" combinedStealFold = %s\n combined2B3B = %s\n combinedPostflop = %s\n" %
(self.combinedStealFold, self.combined2B3B, self.combinedPostflop) ) (self.combinedStealFold, self.combined2B3B, self.combinedPostflop) )
class General(dict):
def __init__(self):
super(General, self).__init__()
def add_elements(self, node):
# day_start - number n where 0.0 <= n < 24.0 representing start of day for user
# e.g. user could set to 4.0 for day to start at 4am local time
# [ HH_bulk_path was here - now moved to import section ]
for (name, value) in node.attributes.items():
log.debug("config.general: adding %s = %s" % (name,value))
self[name] = value
def __str__(self):
s = ""
for k in self:
s = s + " %s = %s\n" % (k, self[k])
return(s)
class Config: class Config:
def __init__(self, file = None, dbname = ''): def __init__(self, file = None, dbname = ''):
# "file" is a path to an xml file with the fpdb/HUD configuration # "file" is a path to an xml file with the fpdb/HUD configuration
@ -506,7 +525,10 @@ class Config:
self.popup_windows = {} self.popup_windows = {}
self.db_selected = None # database the user would like to use self.db_selected = None # database the user would like to use
self.tv = None self.tv = None
self.general = General()
for gen_node in doc.getElementsByTagName("general"):
self.general.add_elements(node=gen_node) # add/overwrite elements in self.general
# s_sites = doc.getElementsByTagName("supported_sites") # s_sites = doc.getElementsByTagName("supported_sites")
for site_node in doc.getElementsByTagName("site"): for site_node in doc.getElementsByTagName("site"):
@ -818,9 +840,14 @@ class Config:
try: imp['interval'] = self.imp.interval try: imp['interval'] = self.imp.interval
except: imp['interval'] = 10 except: imp['interval'] = 10
# hhArchiveBase is the temp store for part-processed hand histories - should be redundant eventually
try: imp['hhArchiveBase'] = self.imp.hhArchiveBase try: imp['hhArchiveBase'] = self.imp.hhArchiveBase
except: imp['hhArchiveBase'] = "~/.fpdb/HandHistories/" except: imp['hhArchiveBase'] = "~/.fpdb/HandHistories/"
# hhBulkPath is the default location for bulk imports (if set)
try: imp['hhBulkPath'] = self.imp.hhBulkPath
except: imp['hhBulkPath'] = ""
try: imp['saveActions'] = self.imp.saveActions try: imp['saveActions'] = self.imp.saveActions
except: imp['saveActions'] = True except: imp['saveActions'] = True
@ -839,6 +866,8 @@ class Config:
path = os.path.expanduser(self.supported_sites[site].HH_path) path = os.path.expanduser(self.supported_sites[site].HH_path)
assert(os.path.isdir(path) or os.path.isfile(path)) # maybe it should try another site? assert(os.path.isdir(path) or os.path.isfile(path)) # maybe it should try another site?
paths['hud-defaultPath'] = paths['bulkImport-defaultPath'] = path paths['hud-defaultPath'] = paths['bulkImport-defaultPath'] = path
if self.imp.hhBulkPath:
paths['bulkImport-defaultPath'] = self.imp.hhBulkPath
except AssertionError: except AssertionError:
paths['hud-defaultPath'] = paths['bulkImport-defaultPath'] = "** ERROR DEFAULT PATH IN CONFIG DOES NOT EXIST **" paths['hud-defaultPath'] = paths['bulkImport-defaultPath'] = "** ERROR DEFAULT PATH IN CONFIG DOES NOT EXIST **"
return paths return paths
@ -987,6 +1016,9 @@ class Config:
"""Join the fpdb path to filename.""" """Join the fpdb path to filename."""
return os.path.join(os.path.dirname(inspect.getfile(sys._getframe(0))), filename) return os.path.join(os.path.dirname(inspect.getfile(sys._getframe(0))), filename)
def get_general_params(self):
return( self.general )
if __name__== "__main__": if __name__== "__main__":
c = Config() c = Config()

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

@ -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)
@ -382,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]]
@ -433,6 +436,12 @@ class DerivedStats():
self.handsplayers[playername]['otherRaisedStreet%s' % i] = True self.handsplayers[playername]['otherRaisedStreet%s' % i] = True
#print "otherRaised detected on handid "+str(hand.handid)+" for "+playername+" on street "+str(i) #print "otherRaised detected on handid "+str(hand.handid)+" for "+playername+" on street "+str(i)
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]]:
@ -446,13 +455,13 @@ class DerivedStats():
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): def folds(self, hand, i):
for act in hand.actions[hand.actionStreets[i+1]]: for act in hand.actions[hand.actionStreets[i+1]]:
if act[1] in ('folds'): if act[1] in ('folds'):
if self.handsplayers[act[0]]['otherRaisedStreet%s' % i] == True: if self.handsplayers[act[0]]['otherRaisedStreet%s' % i] == True:
self.handsplayers[act[0]]['foldToOtherRaisedStreet%s' % i] = True self.handsplayers[act[0]]['foldToOtherRaisedStreet%s' % i] = True
#print "fold detected on handid "+str(hand.handid)+" for "+act[0]+" on street "+str(i) #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

@ -58,6 +58,11 @@ class Filters(threading.Thread):
,'limitsFL':'FL', 'limitsNL':'NL', 'limitsPL':'PL', 'ring':'Ring', 'tour':'Tourney' ,'limitsFL':'FL', 'limitsNL':'NL', 'limitsPL':'PL', 'ring':'Ring', 'tour':'Tourney'
} }
gen = self.conf.get_general_params()
self.day_start = 0
if 'day_start' in gen:
self.day_start = float(gen['day_start'])
# Outer Packing box # Outer Packing box
self.mainVBox = gtk.VBox(False, 0) self.mainVBox = gtk.VBox(False, 0)
@ -864,18 +869,31 @@ class Filters(threading.Thread):
self.end_date.set_text('') self.end_date.set_text('')
def __get_dates(self): def __get_dates(self):
# self.day_start gives user's start of day in hours
offset = int(self.day_start * 3600) # calc day_start in seconds
t1 = self.start_date.get_text() t1 = self.start_date.get_text()
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'
return (t1, t2) s1 = strptime(t1, "%Y-%m-%d") # make time_struct
s2 = strptime(t2, "%Y-%m-%d")
e1 = mktime(s1) + offset # s1 is localtime, but returned time since epoch is UTC, then add the
e2 = mktime(s2) + offset # s2 is localtime, but returned time since epoch is UTC
e2 = e2 + 24 * 3600 - 1 # date test is inclusive, so add 23h 59m 59s to e2
adj_t1 = strftime("%Y-%m-%d %H:%M:%S", gmtime(e1)) # make adjusted string including time
adj_t2 = strftime("%Y-%m-%d %H:%M:%S", gmtime(e2))
log.info("t1="+t1+" adj_t1="+adj_t1+'.')
return (adj_t1, adj_t2)
def __get_date(self, widget, calendar, entry, win): def __get_date(self, widget, calendar, entry, win):
# year and day are correct, month is 0..11 # year and day are correct, month is 0..11
(year, month, day) = calendar.get_date() (year, month, day) = calendar.get_date()
month += 1 month += 1
ds = '%04d-%02d-%02d' % (year, month, day) ds = '%04d-%02d-%02d' % (year, month, day)

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

@ -81,7 +81,7 @@ class GuiPlayerStats (threading.Thread):
self.filters = Filters.Filters(self.db, self.conf, self.sql, display = filters_display) self.filters = Filters.Filters(self.db, self.conf, self.sql, display = filters_display)
self.filters.registerButton1Name("_Filters") self.filters.registerButton1Name("_Filters")
self.filters.registerButton1Callback(self.showDetailFilter) self.filters.registerButton1Callback(self.showDetailFilter)
self.filters.registerButton2Name("_Refresh") self.filters.registerButton2Name("_Refresh Stats")
self.filters.registerButton2Callback(self.refreshStats) self.filters.registerButton2Callback(self.refreshStats)
# ToDo: store in config # ToDo: store in config
@ -567,7 +567,7 @@ class GuiPlayerStats (threading.Thread):
query = query.replace("<orderbyhgameTypeId>", "") query = query.replace("<orderbyhgameTypeId>", "")
groupLevels = "show" not in str(limits) groupLevels = "show" not in str(limits)
if groupLevels: if groupLevels:
query = query.replace("<hgameTypeId>", "-1") query = query.replace("<hgameTypeId>", "p.name") # need to use p.name for sqlite posn stats to work
else: else:
query = query.replace("<hgameTypeId>", "h.gameTypeId") query = query.replace("<hgameTypeId>", "h.gameTypeId")

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

@ -137,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()
@ -152,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()

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

@ -82,6 +82,8 @@ class PokerStars(HandHistoryConverter):
# 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) 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)
# revised re including timezone (not currently used):
#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]+) \(?(?P<TZ>[A-Z0-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])
@ -138,7 +140,7 @@ class PokerStars(HandHistoryConverter):
tmp = handText[0:100] tmp = handText[0:100]
log.error("determineGameType: Unable to recognise gametype from: '%s'" % tmp) log.error("determineGameType: Unable to recognise gametype from: '%s'" % tmp)
log.error("determineGameType: Raising FpdbParseError") log.error("determineGameType: Raising FpdbParseError")
raise 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
@ -192,7 +194,7 @@ class PokerStars(HandHistoryConverter):
except KeyError: except KeyError:
log.error("determineGameType: Lim_Blinds has no lookup for '%s'" % mg['BB']) log.error("determineGameType: Lim_Blinds has no lookup for '%s'" % mg['BB'])
log.error("determineGameType: Raising FpdbParseError") log.error("determineGameType: Raising FpdbParseError")
raise 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
@ -214,14 +216,28 @@ class PokerStars(HandHistoryConverter):
log.debug("readHandInfo: %s" % info) log.debug("readHandInfo: %s" % info)
for key in info: for key in info:
if key == 'DATETIME': if key == 'DATETIME':
#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] # (both dates are parsed so ET date overrides the other)
#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
m1 = self.re_DateTime.finditer(info[key]) m1 = self.re_DateTime.finditer(info[key])
# 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]) # 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])
datetimestr = "2000/01/01 00:00:00" # default used if time not found (stops import crashing, but handstart will be wrong)
for a in m1: 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')) 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") #tz = a.group('TZ') # just assume ET??
#print " tz = ", tz, " datetime =", datetimestr
hand.starttime = datetime.datetime.strptime(datetimestr, "%Y/%m/%d %H:%M:%S") # also timezone at end, e.g. " ET"
# approximate rules for ET daylight savings time:
if ( hand.starttime.month == 12 # all of Dec
or (hand.starttime.month == 11 and hand.starttime.day > 4) # and most of November
or hand.starttime.month < 3 # and all of Jan/Feb
or (hand.starttime.month == 3 and hand.starttime.day < 11) ): # and 1st 10 days of March
offset = datetime.timedelta(hours=5) # are EST: assume 5 hour offset (ET without daylight saving)
else:
offset = datetime.timedelta(hours=4) # rest is EDT: assume 4 hour offset (ET with daylight saving)
# adjust time into UTC:
hand.starttime = hand.starttime + offset
#print " tz = %s start = %s" % (tz, str(hand.starttime))
if key == 'HID': if key == 'HID':
hand.handid = info[key] hand.handid = info[key]
if key == 'TOURNO': if key == 'TOURNO':

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
################################################################## ##################################################################
@ -1921,7 +1933,7 @@ class Sql:
and h.seats <seats_test> and h.seats <seats_test>
<flagtest> <flagtest>
<gtbigBlind_test> <gtbigBlind_test>
and date_format(h.handStart, '%Y-%m-%d') <datestest> and date_format(h.handStart, '%Y-%m-%d %T') <datestest>
group by hgameTypeId group by hgameTypeId
,pname ,pname
,gt.base ,gt.base
@ -2006,7 +2018,7 @@ class Sql:
and h.seats <seats_test> and h.seats <seats_test>
<flagtest> <flagtest>
<gtbigBlind_test> <gtbigBlind_test>
and to_char(h.handStart, 'YYYY-MM-DD') <datestest> and to_char(h.handStart, 'YYYY-MM-DD HH24:MI:SS') <datestest>
group by hgameTypeId group by hgameTypeId
,pname ,pname
,gt.base ,gt.base
@ -2092,7 +2104,7 @@ class Sql:
and h.seats <seats_test> and h.seats <seats_test>
<flagtest> <flagtest>
<gtbigBlind_test> <gtbigBlind_test>
and date(h.handStart) <datestest> and datetime(h.handStart) <datestest>
group by hgameTypeId group by hgameTypeId
,hp.playerId ,hp.playerId
,gt.base ,gt.base

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: