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

This commit is contained in:
Mika Bostrom 2010-03-04 16:03:11 +02:00
commit 2856b90828
17 changed files with 161 additions and 91 deletions

View File

@ -1,5 +1,5 @@
README.txt README.txt
updated 26 March 2009, REB updated 22 February 2010, REB
fpdb - Free Poker Database fpdb - Free Poker Database
@ -29,7 +29,7 @@ fpdb supports:
Omaha (incl Hi/low) Omaha (incl Hi/low)
7 Card Stud (incl Hi/low) 7 Card Stud (incl Hi/low)
Razz Razz
Draw support is under development Triple Draw and Badugi
Mixed Games -- HUD under development Mixed Games -- HUD under development
Operating Systems: Operating Systems:
@ -38,23 +38,38 @@ fpdb supports:
Mac OS/X -- no support for HUD Mac OS/X -- no support for HUD
Databases: Databases:
SQLite configured by default
MySQL MySQL
PostgreSQL PostgreSQL
SQLite under development
Downloads: Downloads:
Releases: http://sourceforge.net/project/showfiles.php?group_id=226872 Releases: http://sourceforge.net/project/showfiles.php?group_id=226872
Development code via git: http://www.assembla.com/spaces/free_poker_tools/trac_git_tool Development code via git: http://www.assembla.com/spaces/free_poker_tools/trac_git_tool
Developers: Developers:
At least 7 people have contributed code or patches. Others are welcome. At least 10 people have contributed code or patches. Others are welcome.
Source Code:
If you received fpdb as the Windows compressed exe, then you did not
receive souce code for fpdb or the included libraries. If you wish, you can
obtain the source code here:
fpdb: see Downloads, above.
python: http://python.org/
gtk: http://www.gtk.org/download.html
pygtk: http://www.pygtk.org/downloads.html
psycopg2: http://initd.org/pub/software/psycopg/
mysqldb: http://sourceforge.net/projects/mysql-python/files/
sqlalchemy: http://www.sqlalchemy.org/download.html
numpy: http://www.scipy.org/Download
matplotlib: http://sourceforge.net/projects/matplotlib/files/
License License
======= =======
Trademarks of third parties have been used under Fair Use or similar laws. Trademarks of third parties have been used under Fair Use or similar laws.
Copyright 2008 Steffen Jobbagy-Felso Copyright 2008 Steffen Jobbagy-Felso
Copyright 2009 Ray E. Barker Copyright 2009,2010 Ray E. Barker
Permission is granted to copy, distribute and/or modify this Permission is granted to copy, distribute and/or modify this
document under the terms of the GNU Free Documentation License, document under the terms of the GNU Free Documentation License,
Version 1.2 as published by the Free Software Foundation; with Version 1.2 as published by the Free Software Foundation; with

View File

@ -414,6 +414,7 @@ class Import:
self.hhArchiveBase = node.getAttribute("hhArchiveBase") self.hhArchiveBase = node.getAttribute("hhArchiveBase")
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)
def __str__(self): def __str__(self):
return " interval = %s\n callFpdbHud = %s\n hhArchiveBase = %s\n saveActions = %s\n fastStoreHudCache = %s\n" \ return " interval = %s\n callFpdbHud = %s\n hhArchiveBase = %s\n saveActions = %s\n fastStoreHudCache = %s\n" \
@ -469,7 +470,8 @@ class Config:
self.file = file self.file = file
self.dir_self = get_exec_path() self.dir_self = get_exec_path()
self.dir_config = os.path.dirname(self.file) # self.dir_config = os.path.dirname(self.file)
self.dir_config = get_default_config_path()
self.dir_log = os.path.join(self.dir_config, 'log') self.dir_log = os.path.join(self.dir_config, 'log')
self.dir_database = os.path.join(self.dir_config, 'database') self.dir_database = os.path.join(self.dir_config, 'database')
self.log_file = os.path.join(self.dir_log, 'fpdb-log.txt') self.log_file = os.path.join(self.dir_log, 'fpdb-log.txt')
@ -822,8 +824,12 @@ class Config:
try: imp['saveActions'] = self.imp.saveActions try: imp['saveActions'] = self.imp.saveActions
except: imp['saveActions'] = True except: imp['saveActions'] = True
try: imp['saveStarsHH'] = self.imp.saveStarsHH
except: imp['saveStarsHH'] = False
try: imp['fastStoreHudCache'] = self.imp.fastStoreHudCache try: imp['fastStoreHudCache'] = self.imp.fastStoreHudCache
except: imp['fastStoreHudCache'] = True except: imp['fastStoreHudCache'] = True
return imp return imp
def get_default_paths(self, site = None): def get_default_paths(self, site = None):

View File

@ -917,7 +917,6 @@ class Database:
print "warning: constraint %s_%s_fkey not dropped: %s, continuing ..." \ print "warning: constraint %s_%s_fkey not dropped: %s, continuing ..." \
% (fk['fktab'],fk['fkcol'], str(sys.exc_value).rstrip('\n')) % (fk['fktab'],fk['fkcol'], str(sys.exc_value).rstrip('\n'))
else: else:
print "Only MySQL and Postgres supported so far"
return -1 return -1
for idx in self.indexes[self.backend]: for idx in self.indexes[self.backend]:
@ -952,7 +951,6 @@ class Database:
print "warning: index %s_%s_idx not dropped %s, continuing ..." \ print "warning: index %s_%s_idx not dropped %s, continuing ..." \
% (idx['tab'],idx['col'], str(sys.exc_value).rstrip('\n')) % (idx['tab'],idx['col'], str(sys.exc_value).rstrip('\n'))
else: else:
print "Error: Only MySQL and Postgres supported so far"
return -1 return -1
if self.backend == self.PGSQL: if self.backend == self.PGSQL:
@ -1007,7 +1005,6 @@ class Database:
except: except:
print " create fk failed: " + str(sys.exc_info()) print " create fk failed: " + str(sys.exc_info())
else: else:
print "Only MySQL and Postgres supported so far"
return -1 return -1
for idx in self.indexes[self.backend]: for idx in self.indexes[self.backend]:
@ -1029,7 +1026,6 @@ class Database:
except: except:
print " create index failed: " + str(sys.exc_info()) print " create index failed: " + str(sys.exc_info())
else: else:
print "Only MySQL and Postgres supported so far"
return -1 return -1
if self.backend == self.PGSQL: if self.backend == self.PGSQL:

View File

@ -162,7 +162,7 @@ class DerivedStats():
self.handsplayers[player]['wonAtSD'] = 1.0 self.handsplayers[player]['wonAtSD'] = 1.0
for player in hand.pot.committed: for player in hand.pot.committed:
self.handsplayers[player]['totalProfit'] = int(self.handsplayers[player]['winnings'] - (100*hand.pot.committed[player])) self.handsplayers[player]['totalProfit'] = int(self.handsplayers[player]['winnings'] - (100*hand.pot.committed[player])- (100*hand.pot.common[player]))
self.calcCBets(hand) self.calcCBets(hand)
@ -345,9 +345,9 @@ class DerivedStats():
for action in hand.actions[hand.actionStreets[1]]: for action in hand.actions[hand.actionStreets[1]]:
# FIXME: fill other(3|4)BStreet0 - i have no idea what does it mean # FIXME: fill other(3|4)BStreet0 - i have no idea what does it mean
pname, aggr = action[0], action[1] in ('raises', 'bets') pname, aggr = action[0], action[1] in ('raises', 'bets')
self.handsplayers[pname]['street0_3BChance'] = bet_level == 2 self.handsplayers[pname]['street0_3BChance'] = self.handsplayers[pname]['street0_3BChance'] or bet_level == 2
self.handsplayers[pname]['street0_4BChance'] = bet_level == 3 self.handsplayers[pname]['street0_4BChance'] = bet_level == 3
self.handsplayers[pname]['street0_3BDone'] = aggr and (self.handsplayers[pname]['street0_3BChance']) self.handsplayers[pname]['street0_3BDone'] = self.handsplayers[pname]['street0_3BDone'] or (aggr and self.handsplayers[pname]['street0_3BChance'])
self.handsplayers[pname]['street0_4BDone'] = aggr and (self.handsplayers[pname]['street0_4BChance']) self.handsplayers[pname]['street0_4BDone'] = aggr and (self.handsplayers[pname]['street0_4BChance'])
if aggr: if aggr:
bet_level += 1 bet_level += 1

View File

@ -65,8 +65,8 @@ class Fulltilt(HandHistoryConverter):
(\s\((?P<TURBO>Turbo)\))?)|(?P<UNREADABLE_INFO>.+)) (\s\((?P<TURBO>Turbo)\))?)|(?P<UNREADABLE_INFO>.+))
''', re.VERBOSE) ''', re.VERBOSE)
re_Button = re.compile('^The button is in seat #(?P<BUTTON>\d+)', re.MULTILINE) re_Button = re.compile('^The button is in seat #(?P<BUTTON>\d+)', re.MULTILINE)
re_PlayerInfo = re.compile('Seat (?P<SEAT>[0-9]+): (?P<PNAME>.{3,15}) \(\$(?P<CASH>[,.0-9]+)\)$', re.MULTILINE) re_PlayerInfo = re.compile('Seat (?P<SEAT>[0-9]+): (?P<PNAME>.{2,15}) \(\$(?P<CASH>[,.0-9]+)\)$', re.MULTILINE)
re_TourneyPlayerInfo = re.compile('Seat (?P<SEAT>[0-9]+): (?P<PNAME>.{3,15}) \(\$?(?P<CASH>[,.0-9]+)\)(, is sitting out)?$', re.MULTILINE) re_TourneyPlayerInfo = re.compile('Seat (?P<SEAT>[0-9]+): (?P<PNAME>.{2,15}) \(\$?(?P<CASH>[,.0-9]+)\)(, is sitting out)?$', re.MULTILINE)
re_Board = re.compile(r"\[(?P<CARDS>.+)\]") re_Board = re.compile(r"\[(?P<CARDS>.+)\]")
#static regex for tourney purpose #static regex for tourney purpose
@ -128,6 +128,7 @@ class Fulltilt(HandHistoryConverter):
player_re = "(?P<PNAME>" + "|".join(map(re.escape, players)) + ")" player_re = "(?P<PNAME>" + "|".join(map(re.escape, players)) + ")"
logging.debug("player_re: " + player_re) logging.debug("player_re: " + player_re)
self.re_PostSB = re.compile(r"^%s posts the small blind of \$?(?P<SB>[.0-9]+)" % player_re, re.MULTILINE) self.re_PostSB = re.compile(r"^%s posts the small blind of \$?(?P<SB>[.0-9]+)" % player_re, re.MULTILINE)
self.re_PostDead = re.compile(r"^%s posts a dead small blind of \$?(?P<SB>[.0-9]+)" % player_re, re.MULTILINE)
self.re_PostBB = re.compile(r"^%s posts (the big blind of )?\$?(?P<BB>[.0-9]+)" % player_re, re.MULTILINE) self.re_PostBB = re.compile(r"^%s posts (the big blind of )?\$?(?P<BB>[.0-9]+)" % player_re, re.MULTILINE)
self.re_Antes = re.compile(r"^%s antes \$?(?P<ANTE>[.0-9]+)" % player_re, re.MULTILINE) self.re_Antes = re.compile(r"^%s antes \$?(?P<ANTE>[.0-9]+)" % player_re, re.MULTILINE)
self.re_BringIn = re.compile(r"^%s brings in for \$?(?P<BRINGIN>[.0-9]+)" % player_re, re.MULTILINE) self.re_BringIn = re.compile(r"^%s brings in for \$?(?P<BRINGIN>[.0-9]+)" % player_re, re.MULTILINE)
@ -298,6 +299,8 @@ class Fulltilt(HandHistoryConverter):
hand.addBlind(m.group('PNAME'), 'small blind', m.group('SB')) hand.addBlind(m.group('PNAME'), 'small blind', m.group('SB'))
except: # no small blind except: # no small blind
hand.addBlind(None, None, None) hand.addBlind(None, None, None)
for a in self.re_PostDead.finditer(hand.handText):
hand.addBlind(a.group('PNAME'), 'secondsb', a.group('SB'))
for a in self.re_PostBB.finditer(hand.handText): for a in self.re_PostBB.finditer(hand.handText):
hand.addBlind(a.group('PNAME'), 'big blind', a.group('BB')) hand.addBlind(a.group('PNAME'), 'big blind', a.group('BB'))
for a in self.re_PostBoth.finditer(hand.handText): for a in self.re_PostBoth.finditer(hand.handText):

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 Stats") self.filters.registerButton2Name("_Refresh")
self.filters.registerButton2Callback(self.refreshStats) self.filters.registerButton2Callback(self.refreshStats)
# ToDo: store in config # ToDo: store in config
@ -92,7 +92,7 @@ class GuiPlayerStats (threading.Thread):
, ["hand", False, "Hand", 0.0, "%s", "str"] # true not allowed for this line , ["hand", False, "Hand", 0.0, "%s", "str"] # true not allowed for this line
, ["plposition", False, "Posn", 1.0, "%s", "str"] # true not allowed for this line (set in code) , ["plposition", False, "Posn", 1.0, "%s", "str"] # true not allowed for this line (set in code)
, ["pname", False, "Name", 0.0, "%s", "str"] # true not allowed for this line (set in code) , ["pname", False, "Name", 0.0, "%s", "str"] # true not allowed for this line (set in code)
, ["n", True, "Hds", 1.0, "%d", "str"] , ["n", True, "Hds", 1.0, "%1.0f", "str"]
, ["avgseats", False, "Seats", 1.0, "%3.1f", "str"] , ["avgseats", False, "Seats", 1.0, "%3.1f", "str"]
, ["vpip", True, "VPIP", 1.0, "%3.1f", "str"] , ["vpip", True, "VPIP", 1.0, "%3.1f", "str"]
, ["pfr", True, "PFR", 1.0, "%3.1f", "str"] , ["pfr", True, "PFR", 1.0, "%3.1f", "str"]
@ -481,7 +481,23 @@ class GuiPlayerStats (threading.Thread):
else: else:
gametest = "and gt.category IS NULL" gametest = "and gt.category IS NULL"
query = query.replace("<game_test>", gametest) query = query.replace("<game_test>", gametest)
sitetest = ""
q = []
for m in self.filters.display.items():
if m[0] == 'Sites' and m[1]:
for n in sitenos:
q.append(n)
if len(q) > 0:
sitetest = str(tuple(q))
sitetest = sitetest.replace("L", "")
sitetest = sitetest.replace(",)",")")
sitetest = sitetest.replace("u'","'")
sitetest = "and gt.siteId in %s" % sitetest
else:
sitetest = "and gt.siteId IS NULL"
query = query.replace("<site_test>", sitetest)
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']:
@ -539,7 +555,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>", "p.name") query = query.replace("<hgameTypeId>", "-1")
else: else:
query = query.replace("<hgameTypeId>", "h.gameTypeId") query = query.replace("<hgameTypeId>", "h.gameTypeId")

View File

@ -61,7 +61,7 @@ import Hud
# get config and set up logger # get config and set up logger
c = Configuration.Config(file=options.config) c = Configuration.Config(file=options.config, dbname=options.dbname)
log = Configuration.get_logger("logging.conf", "hud", log_dir=c.dir_log, log_file='HUD-log.txt') log = Configuration.get_logger("logging.conf", "hud", log_dir=c.dir_log, log_file='HUD-log.txt')
@ -78,14 +78,14 @@ class HUD_main(object):
try: try:
if not options.errorsToConsole: if not options.errorsToConsole:
fileName = os.path.join(self.config.dir_log, 'HUD-errors.txt') fileName = os.path.join(self.config.dir_log, 'HUD-errors.txt')
print "Note: error output is being diverted to:\n"+fileName \ print "Note: error output is being diverted to:\n"+fileName \
+ "\nAny major error will be reported there _only_.\n" + "\nAny major error will be reported there _only_.\n"
log.info("Note: error output is being diverted to:"+fileName) log.info("Note: error output is being diverted to:"+fileName)
log.info("Any major error will be reported there _only_.") log.info("Any major error will be reported there _only_.")
errorFile = open(fileName, 'w', 0) errorFile = open(fileName, 'w', 0)
sys.stderr = errorFile sys.stderr = errorFile
sys.stderr.write("HUD_main: starting ...\n") sys.stderr.write("HUD_main: starting ...\n")
self.hud_dict = {} self.hud_dict = {}
self.hud_params = self.config.get_hud_ui_parameters() self.hud_params = self.config.get_hud_ui_parameters()
@ -237,7 +237,7 @@ class HUD_main(object):
try: try:
(table_name, max, poker_game, type, site_id, site_name, num_seats, tour_number, tab_number) = \ (table_name, max, poker_game, type, site_id, site_name, num_seats, tour_number, tab_number) = \
self.db_connection.get_table_info(new_hand_id) self.db_connection.get_table_info(new_hand_id)
except Exception, err: except Exception:
log.error("db error: skipping %s" % new_hand_id) log.error("db error: skipping %s" % new_hand_id)
continue continue
t1 = time.time() t1 = time.time()

View File

@ -323,8 +323,10 @@ For sites (currently only Carbon Poker) which record "all in" as a special actio
self.stacks[player] -= Decimal(ante) self.stacks[player] -= Decimal(ante)
act = (player, 'posts', "ante", ante, self.stacks[player]==0) act = (player, 'posts', "ante", ante, self.stacks[player]==0)
self.actions['BLINDSANTES'].append(act) self.actions['BLINDSANTES'].append(act)
self.pot.addMoney(player, Decimal(ante)) # self.pot.addMoney(player, Decimal(ante))
self.pot.addCommonMoney(player, Decimal(ante))
#I think the antes should be common money, don't have enough hand history to check
def addBlind(self, player, blindtype, amount): def addBlind(self, player, blindtype, amount):
# if player is None, it's a missing small blind. # if player is None, it's a missing small blind.
# The situation we need to cover are: # The situation we need to cover are:
@ -342,14 +344,16 @@ For sites (currently only Carbon Poker) which record "all in" as a special actio
self.actions['BLINDSANTES'].append(act) self.actions['BLINDSANTES'].append(act)
if blindtype == 'both': if blindtype == 'both':
amount = self.bb # work with the real ammount. limit games are listed as $1, $2, where
# the SB 0.50 and the BB is $1, after the turn the minimum bet amount is $2....
amount = self.bb
self.bets['BLINDSANTES'][player].append(Decimal(self.sb)) self.bets['BLINDSANTES'][player].append(Decimal(self.sb))
self.pot.addCommonMoney(Decimal(self.sb)) self.pot.addCommonMoney(player, Decimal(self.sb))
if blindtype == 'secondsb': if blindtype == 'secondsb':
amount = Decimal(0) amount = Decimal(0)
self.bets['BLINDSANTES'][player].append(Decimal(self.sb)) self.bets['BLINDSANTES'][player].append(Decimal(self.sb))
self.pot.addCommonMoney(Decimal(self.sb)) self.pot.addCommonMoney(player, Decimal(self.sb))
self.bets['PREFLOP'][player].append(Decimal(amount)) self.bets['PREFLOP'][player].append(Decimal(amount))
self.pot.addMoney(player, Decimal(amount)) self.pot.addMoney(player, Decimal(amount))
@ -511,10 +515,7 @@ Card ranks will be uppercased
self.totalcollected = 0; self.totalcollected = 0;
#self.collected looks like [[p1,amount][px,amount]] #self.collected looks like [[p1,amount][px,amount]]
for entry in self.collected: for entry in self.collected:
self.totalcollected += Decimal(entry[1]) self.totalcollected += Decimal(entry[1])
def getGameTypeAsString(self): def getGameTypeAsString(self):
"""\ """\
@ -994,11 +995,12 @@ class DrawHand(Hand):
self.lastBet['DEAL'] = Decimal(amount) self.lastBet['DEAL'] = Decimal(amount)
elif blindtype == 'both': elif blindtype == 'both':
# extra small blind is 'dead' # extra small blind is 'dead'
self.lastBet['DEAL'] = Decimal(self.bb) amount = Decimal(amount)/3
amount += amount
self.lastBet['DEAL'] = Decimal(amount)
self.posted = self.posted + [[player,blindtype]] self.posted = self.posted + [[player,blindtype]]
#print "DEBUG: self.posted: %s" %(self.posted) #print "DEBUG: self.posted: %s" %(self.posted)
def addShownCards(self, cards, player, shown=True, mucked=False, dealt=False): def addShownCards(self, cards, player, shown=True, mucked=False, dealt=False):
if player == self.hero: # we have hero's cards just update shown/mucked if player == self.hero: # we have hero's cards just update shown/mucked
if shown: self.shown.add(player) if shown: self.shown.add(player)
@ -1413,7 +1415,7 @@ class Pot(object):
self.contenders = set() self.contenders = set()
self.committed = {} self.committed = {}
self.streettotals = {} self.streettotals = {}
self.common = Decimal(0) self.common = {}
self.total = None self.total = None
self.returned = {} self.returned = {}
self.sym = u'$' # this is the default currency symbol self.sym = u'$' # this is the default currency symbol
@ -1423,13 +1425,14 @@ class Pot(object):
def addPlayer(self,player): def addPlayer(self,player):
self.committed[player] = Decimal(0) self.committed[player] = Decimal(0)
self.common[player] = Decimal(0)
def addFold(self, player): def addFold(self, player):
# addFold must be called when a player folds # addFold must be called when a player folds
self.contenders.discard(player) self.contenders.discard(player)
def addCommonMoney(self, amount): def addCommonMoney(self, player, amount):
self.common += amount self.common[player] += amount
def addMoney(self, player, amount): def addMoney(self, player, amount):
# addMoney must be called for any actions that put money in the pot, in the order they occur # addMoney must be called for any actions that put money in the pot, in the order they occur
@ -1437,7 +1440,7 @@ class Pot(object):
self.committed[player] += amount self.committed[player] += amount
def markTotal(self, street): def markTotal(self, street):
self.streettotals[street] = sum(self.committed.values()) + self.common self.streettotals[street] = sum(self.committed.values()) + sum(self.common.values())
def getTotalAtStreet(self, street): def getTotalAtStreet(self, street):
if street in self.streettotals: if street in self.streettotals:
@ -1445,11 +1448,11 @@ class Pot(object):
return 0 return 0
def end(self): def end(self):
self.total = sum(self.committed.values()) + self.common self.total = sum(self.committed.values()) + sum(self.common.values())
# Return any uncalled bet. # Return any uncalled bet.
committed = sorted([ (v,k) for (k,v) in self.committed.items()]) committed = sorted([ (v,k) for (k,v) in self.committed.items()])
print "DEBUG: committed: %s" % committed #print "DEBUG: committed: %s" % committed
#ERROR below. lastbet is correct in most cases, but wrong when #ERROR below. lastbet is correct in most cases, but wrong when
# additional money is committed to the pot in cash games # additional money is committed to the pot in cash games
# due to an additional sb being posted. (Speculate that # due to an additional sb being posted. (Speculate that

View File

@ -69,6 +69,7 @@ out_path (default '-' = sys.stdout)
follow : whether to tail -f the input""" follow : whether to tail -f the input"""
self.config = config self.config = config
self.import_parameters = self.config.get_import_parameters()
#log = Configuration.get_logger("logging.conf", "parser", log_dir=self.config.dir_log) #log = Configuration.get_logger("logging.conf", "parser", log_dir=self.config.dir_log)
log.info("HandHistory init - %s subclass, in_path '%s'; out_path '%s'" % (self.sitename, in_path, out_path) ) log.info("HandHistory init - %s subclass, in_path '%s'; out_path '%s'" % (self.sitename, in_path, out_path) )
@ -87,12 +88,8 @@ follow : whether to tail -f the input"""
if in_path == '-': if in_path == '-':
self.in_fh = sys.stdin self.in_fh = sys.stdin
self.out_fh = get_out_fh(out_path, self.import_parameters)
if out_path == '-':
self.out_fh = sys.stdout
else:
# TODO: out_path should be sanity checked.
self.out_fh = sys.stdout
self.follow = follow self.follow = follow
self.compiledPlayers = set() self.compiledPlayers = set()
self.maxseats = 10 self.maxseats = 10
@ -446,8 +443,8 @@ or None if we fail to get the info """
def guessMaxSeats(self, hand): def guessMaxSeats(self, hand):
"""Return a guess at maxseats when not specified in HH.""" """Return a guess at maxseats when not specified in HH."""
# if some other code prior to this has already set it, return it # if some other code prior to this has already set it, return it
if maxseats > 1 and maxseats < 11: if self.maxseats > 1 and self.maxseats < 11:
return maxseats return self.maxseats
mo = self.maxOccSeat(hand) mo = self.maxOccSeat(hand)
if mo == 10: return 10 #that was easy if mo == 10: return 10 #that was easy
@ -515,3 +512,23 @@ def getSiteHhc(config, sitename):
hhcName = config.supported_sites[sitename].converter hhcName = config.supported_sites[sitename].converter
hhcModule = __import__(hhcName) hhcModule = __import__(hhcName)
return getattr(hhcModule, hhcName[:-6]) return getattr(hhcModule, hhcName[:-6])
def get_out_fh(out_path, parameters):
if out_path == '-':
return(sys.stdout)
elif parameters['saveStarsHH']:
out_dir = os.path.dirname(out_path)
if not os.path.isdir(out_dir) and out_dir != '':
try:
os.makedirs(out_dir)
except: # we get a WindowsError here in Windows.. pretty sure something else for Linux :D
log.error("Unable to create output directory %s for HHC!" % out_dir)
print "*** ERROR: UNABLE TO CREATE OUTPUT DIRECTORY", out_dir
else:
log.info("Created directory '%s'" % out_dir)
try:
return(codecs.open(out_path, 'w', 'utf8'))
except:
log.error("out_path %s couldn't be opened" % (out_path))
else:
return(sys.stdout)

View File

@ -27,7 +27,7 @@ def fpdb_options():
action="store_true", action="store_true",
help="If passed error output will go to the console rather than .") help="If passed error output will go to the console rather than .")
parser.add_option("-d", "--databaseName", parser.add_option("-d", "--databaseName",
dest="dbname", default="fpdb", dest="dbname",
help="Overrides the default database name") help="Overrides the default database name")
parser.add_option("-c", "--configFile", parser.add_option("-c", "--configFile",
dest="config", default=None, dest="config", default=None,

View File

@ -465,8 +465,9 @@ class PartyPoker(HandHistoryConverter):
def getTableTitleRe(type, table_name=None, tournament = None, table_number=None): def getTableTitleRe(type, table_name=None, tournament = None, table_number=None):
"Returns string to search in windows titles" "Returns string to search in windows titles"
if type=="tour": if type=="tour":
print 'party', 'getTableTitleRe', "%s.+Table\s#%s" % (table_name, table_number) TableName = table_name.split(" ")
return "%s.+Table\s#%s" % (table_name, table_number) print 'party', 'getTableTitleRe', "%s.+Table\s#%s" % (TableName[0], table_number)
return "%s.+Table\s#%s" % (TableName[0], table_number)
else: else:
print 'party', 'getTableTitleRe', table_number print 'party', 'getTableTitleRe', table_number
return table_name return table_name

30
pyfpdb/PokerStarsToFpdb.py Executable file → Normal file
View File

@ -140,6 +140,14 @@ class PokerStars(HandHistoryConverter):
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'),
'0.50': ('0.10', '0.25'), '1.00': ('0.25', '0.50'), '2.00': ('0.50', '1.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'),
'100.00': ('25.00', '50.00'),'200.00': ('50.00', '100.00'),'400.00': ('100.00', '200.00'),
'1000.00': ('250.00', '500.00')}
limits = { 'No Limit':'nl', 'Pot Limit':'pl', 'Limit':'fl' } limits = { 'No Limit':'nl', 'Pot Limit':'pl', 'Limit':'fl' }
games = { # base, category games = { # base, category
"Hold'em" : ('hold','holdem'), "Hold'em" : ('hold','holdem'),
@ -173,6 +181,10 @@ class PokerStars(HandHistoryConverter):
else: else:
info['type'] = 'tour' info['type'] = 'tour'
if info['limitType'] == 'fl' and info['bb'] != None and info['type'] == 'ring':
info['sb'] = Lim_Blinds[mg['BB']][0]
info['bb'] = Lim_Blinds[mg['BB']][1]
# 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
@ -287,16 +299,14 @@ class PokerStars(HandHistoryConverter):
hand.addBringIn(m.group('PNAME'), m.group('BRINGIN')) hand.addBringIn(m.group('PNAME'), m.group('BRINGIN'))
def readBlinds(self, hand): def readBlinds(self, hand):
try: liveBlind = True
count = 0 for a in self.re_PostSB.finditer(hand.handText):
for a in self.re_PostSB.finditer(hand.handText): if liveBlind:
if count == 0: hand.addBlind(a.group('PNAME'), 'small blind', a.group('SB'))
hand.addBlind(a.group('PNAME'), 'small blind', a.group('SB')) liveBlind = False
count = 1 else:
else: # Post dead blinds as ante
hand.addBlind(a.group('PNAME'), 'secondsb', a.group('SB')) hand.addBlind(a.group('PNAME'), 'secondsb', a.group('SB'))
except: # no small blind
hand.addBlind(None, None, None)
for a in self.re_PostBB.finditer(hand.handText): for a in self.re_PostBB.finditer(hand.handText):
hand.addBlind(a.group('PNAME'), 'big blind', a.group('BB')) hand.addBlind(a.group('PNAME'), 'big blind', a.group('BB'))
for a in self.re_PostBoth.finditer(hand.handText): for a in self.re_PostBoth.finditer(hand.handText):

View File

@ -1916,6 +1916,7 @@ class Sql:
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> <game_test>
<site_test>
/*and hp.tourneysPlayersId IS NULL*/ /*and hp.tourneysPlayersId IS NULL*/
and h.seats <seats_test> and h.seats <seats_test>
<flagtest> <flagtest>
@ -2000,6 +2001,7 @@ class Sql:
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> <game_test>
<site_test>
/*and hp.tourneysPlayersId IS NULL*/ /*and hp.tourneysPlayersId IS NULL*/
and h.seats <seats_test> and h.seats <seats_test>
<flagtest> <flagtest>
@ -2086,6 +2088,7 @@ class Sql:
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> <game_test>
<site_test>
/*and hp.tourneysPlayersId IS NULL*/ /*and hp.tourneysPlayersId IS NULL*/
and h.seats <seats_test> and h.seats <seats_test>
<flagtest> <flagtest>

View File

@ -89,7 +89,6 @@ class Table(Table_Window):
# break # break
if window_number is None: if window_number is None:
print "Window %s not found. Skipping." % search_string
return None return None
# my_geo = self.window.get_geometry() # my_geo = self.window.get_geometry()

View File

@ -1025,23 +1025,24 @@ This program is licensed under the AGPL3, see docs"""+os.sep+"agpl-3.0.txt")
return response return response
def validate_config(self): def validate_config(self):
hhbase = self.config.get_import_parameters().get("hhArchiveBase") if self.config.get_import_parameters().get('saveStarsHH'):
hhbase = os.path.expanduser(hhbase) hhbase = self.config.get_import_parameters().get("hhArchiveBase")
#hhdir = os.path.join(hhbase,site) hhbase = os.path.expanduser(hhbase)
hhdir = hhbase #hhdir = os.path.join(hhbase,site)
if not os.path.isdir(hhdir): hhdir = hhbase
diapath = gtk.MessageDialog(parent=None, flags=0, type=gtk.MESSAGE_WARNING, buttons=(gtk.BUTTONS_YES_NO), message_format="Setup hh dir") if not os.path.isdir(hhdir):
diastring = "WARNING: Unable to find output hh directory %s\n\n Press YES to create this directory, or NO to select a new one." % hhdir diapath = gtk.MessageDialog(parent=None, flags=0, type=gtk.MESSAGE_WARNING, buttons=(gtk.BUTTONS_YES_NO), message_format="Setup hh dir")
diapath.format_secondary_text(diastring) diastring = "WARNING: Unable to find output hh directory %s\n\n Press YES to create this directory, or NO to select a new one." % hhdir
response = diapath.run() diapath.format_secondary_text(diastring)
diapath.destroy() response = diapath.run()
if response == gtk.RESPONSE_YES: diapath.destroy()
try: if response == gtk.RESPONSE_YES:
os.makedirs(hhdir) try:
except: os.makedirs(hhdir)
self.warning_box("WARNING: Unable to create hand output directory. Importing is not likely to work until this is fixed.") except:
elif response == gtk.RESPONSE_NO: self.warning_box("WARNING: Unable to create hand output directory. Importing is not likely to work until this is fixed.")
self.select_hhArchiveBase() elif response == gtk.RESPONSE_NO:
self.select_hhArchiveBase()
def select_hhArchiveBase(self, widget=None): def select_hhArchiveBase(self, widget=None):
fc = gtk.FileChooserDialog(title="Select HH Output Directory", parent=None, action=gtk.FILE_CHOOSER_ACTION_SELECT_FOLDER, buttons=(gtk.STOCK_OPEN,gtk.RESPONSE_OK), backend=None) fc = gtk.FileChooserDialog(title="Select HH Output Directory", parent=None, action=gtk.FILE_CHOOSER_ACTION_SELECT_FOLDER, buttons=(gtk.STOCK_OPEN,gtk.RESPONSE_OK), backend=None)

View File

@ -1,7 +1,7 @@
rem .bat script to run fpdb rem .bat script to run fpdb
cd pyfpdb cd pyfpdb
fpdb.exe fpdb.exe

0
run_fpdb.py Executable file → Normal file
View File