From 4636e244ea99eff81248afb36aa5c39ea58bfcb3 Mon Sep 17 00:00:00 2001 From: Gerko de Roo Date: Sun, 31 Jan 2010 17:58:48 +0100 Subject: [PATCH 01/24] Codec errors seem to lock up HUD with windows. I've made a trap for each error that I observed. don't want to halt the program so I return the original string. The de/recoding is not needed for >95% of the playernames anyway. --- pyfpdb/Charset.py | 24 +++++++++++++++++++++--- 1 file changed, 21 insertions(+), 3 deletions(-) diff --git a/pyfpdb/Charset.py b/pyfpdb/Charset.py index 6b5e6b7c..02b5c098 100644 --- a/pyfpdb/Charset.py +++ b/pyfpdb/Charset.py @@ -41,7 +41,13 @@ def to_utf8(s): return _out except UnicodeDecodeError: sys.stderr.write('Could not convert: "%s"\n' % s) - raise + return s + except UnicodeEncodeError: + sys.stderr.write('Could not convert: "%s"\n' % s) + return s + except TypeError: + sys.stderr.write('Could not convert: "%s"\n' % s) + return s def to_db_utf8(s): if not_needed2: return s @@ -51,7 +57,13 @@ def to_db_utf8(s): return _out except UnicodeDecodeError: sys.stderr.write('Could not convert: "%s"\n' % s) - raise + return s + except UnicodeEncodeError: + sys.stderr.write('Could not convert: "%s"\n' % s) + return s + except TypeError: + sys.stderr.write('Could not convert: "%s"\n' % s) + return s def to_gui(s): if not_needed3: return s @@ -61,5 +73,11 @@ def to_gui(s): return _out except UnicodeDecodeError: sys.stderr.write('Could not convert: "%s"\n' % s) - raise + return s + except UnicodeEncodeError: + sys.stderr.write('Could not convert: "%s"\n' % s) + return s + except TypeError: + sys.stderr.write('Could not convert: "%s"\n' % s) + return s From 0db3cecf650c65ad4cd57a421a5cc91e83c18f89 Mon Sep 17 00:00:00 2001 From: Gerko de Roo Date: Sat, 13 Feb 2010 20:41:01 +0100 Subject: [PATCH 02/24] Action Reg_ex updated Due to the added end of line marker to eliminate playersnames that start with card, all-in actions are no longer supported. --- pyfpdb/PokerStarsToFpdb.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pyfpdb/PokerStarsToFpdb.py b/pyfpdb/PokerStarsToFpdb.py index 90a8bfd0..39eb0892 100755 --- a/pyfpdb/PokerStarsToFpdb.py +++ b/pyfpdb/PokerStarsToFpdb.py @@ -102,7 +102,7 @@ class PokerStars(HandHistoryConverter): self.re_HeroCards = re.compile(r"^Dealt to %(PLYR)s(?: \[(?P.+?)\])?( \[(?P.+?)\])" % subst, re.MULTILINE) self.re_Action = re.compile(r""" ^%(PLYR)s:(?P\sbets|\schecks|\sraises|\scalls|\sfolds|\sdiscards|\sstands\spat) - (\s(%(CUR)s)?(?P[.\d]+))?(\sto\s%(CUR)s(?P[.\d]+))? # the number discarded goes in + (\s(%(CUR)s)?(?P[.\d]+))?(\sto\s%(CUR)s(?P[.\d]+))?(\sand\sis\sall-in)? # the number discarded goes in (\scards?(\s\[(?P.+?)\])?)?$""" % subst, re.MULTILINE|re.VERBOSE) self.re_ShowdownAction = re.compile(r"^%s: shows \[(?P.*)\]" % player_re, re.MULTILINE) From 466988ea4acc1736358bcdca234ee56c5478b111 Mon Sep 17 00:00:00 2001 From: Gerko de Roo Date: Sat, 13 Feb 2010 22:44:00 +0100 Subject: [PATCH 03/24] Tournement support for PartyPoker --- pyfpdb/PartyPokerToFpdb.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/pyfpdb/PartyPokerToFpdb.py b/pyfpdb/PartyPokerToFpdb.py index 1d1d0e4d..5fdeae0c 100755 --- a/pyfpdb/PartyPokerToFpdb.py +++ b/pyfpdb/PartyPokerToFpdb.py @@ -465,8 +465,9 @@ class PartyPoker(HandHistoryConverter): def getTableTitleRe(type, table_name=None, tournament = None, table_number=None): "Returns string to search in windows titles" if type=="tour": - print 'party', 'getTableTitleRe', "%s.+Table\s#%s" % (table_name, table_number) - return "%s.+Table\s#%s" % (table_name, table_number) + TableName = table_name.split(" ") + print 'party', 'getTableTitleRe', "%s.+Table\s#%s" % (TableName[0], table_number) + return "%s.+Table\s#%s" % (TableName[0], table_number) else: print 'party', 'getTableTitleRe', table_number return table_name From a27bc45f6dbc2bb954f98c991ae86a7458ef7bbf Mon Sep 17 00:00:00 2001 From: Gerko de Roo Date: Thu, 18 Feb 2010 16:17:08 +0100 Subject: [PATCH 04/24] fix for dead blinds and antes in the player stat calculation Posted dead blinds messed up the rake and profit calculation in the player stats. This fix should also work for antes The fix has been done for omaha and holdem game types (without antes) I don't have draw or stud hands to check this --- pyfpdb/DerivedStats.py | 2 +- pyfpdb/Hand.py | 36 ++++++++++++++++++++---------------- pyfpdb/PokerStarsToFpdb.py | 18 ++++++++---------- 3 files changed, 29 insertions(+), 27 deletions(-) diff --git a/pyfpdb/DerivedStats.py b/pyfpdb/DerivedStats.py index 166034a5..32c7c874 100644 --- a/pyfpdb/DerivedStats.py +++ b/pyfpdb/DerivedStats.py @@ -162,7 +162,7 @@ class DerivedStats(): self.handsplayers[player]['wonAtSD'] = 1.0 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) diff --git a/pyfpdb/Hand.py b/pyfpdb/Hand.py index 73dd7600..c5e2dea7 100644 --- a/pyfpdb/Hand.py +++ b/pyfpdb/Hand.py @@ -321,8 +321,10 @@ For sites (currently only Carbon Poker) which record "all in" as a special actio self.stacks[player] -= Decimal(ante) act = (player, 'posts', "ante", ante, self.stacks[player]==0) 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): # if player is None, it's a missing small blind. # The situation we need to cover are: @@ -340,9 +342,12 @@ For sites (currently only Carbon Poker) which record "all in" as a special actio self.actions['BLINDSANTES'].append(act) if blindtype == 'both': - amount = self.bb - self.bets['BLINDSANTES'][player].append(Decimal(self.sb)) - self.pot.addCommonMoney(Decimal(self.sb)) + # 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 = Decimal(amount)/3 + self.bets['BLINDSANTES'][player].append(amount) + self.pot.addCommonMoney(player, amount) + amount += amount self.bets['PREFLOP'][player].append(Decimal(amount)) self.pot.addMoney(player, Decimal(amount)) @@ -504,10 +509,7 @@ Card ranks will be uppercased self.totalcollected = 0; #self.collected looks like [[p1,amount][px,amount]] for entry in self.collected: - self.totalcollected += Decimal(entry[1]) - - - + self.totalcollected += Decimal(entry[1]) def getGameTypeAsString(self): """\ @@ -986,11 +988,12 @@ class DrawHand(Hand): self.lastBet['DEAL'] = Decimal(amount) elif blindtype == 'both': # 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]] #print "DEBUG: self.posted: %s" %(self.posted) - 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 shown: self.shown.add(player) @@ -1405,7 +1408,7 @@ class Pot(object): self.contenders = set() self.committed = {} self.streettotals = {} - self.common = Decimal(0) + self.common = {} self.total = None self.returned = {} self.sym = u'$' # this is the default currency symbol @@ -1415,13 +1418,14 @@ class Pot(object): def addPlayer(self,player): self.committed[player] = Decimal(0) + self.common[player] = Decimal(0) def addFold(self, player): # addFold must be called when a player folds self.contenders.discard(player) - def addCommonMoney(self, amount): - self.common += amount + def addCommonMoney(self, player, amount): + self.common[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 @@ -1429,7 +1433,7 @@ class Pot(object): self.committed[player] += amount 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): if street in self.streettotals: @@ -1437,7 +1441,7 @@ class Pot(object): return 0 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. committed = sorted([ (v,k) for (k,v) in self.committed.items()]) diff --git a/pyfpdb/PokerStarsToFpdb.py b/pyfpdb/PokerStarsToFpdb.py index 39066b8e..6874c708 100644 --- a/pyfpdb/PokerStarsToFpdb.py +++ b/pyfpdb/PokerStarsToFpdb.py @@ -287,16 +287,14 @@ class PokerStars(HandHistoryConverter): hand.addBringIn(m.group('PNAME'), m.group('BRINGIN')) def readBlinds(self, hand): - try: - count = 0 - for a in self.re_PostSB.finditer(hand.handText): - if count == 0: - hand.addBlind(a.group('PNAME'), 'small blind', a.group('SB')) - count = 1 - else: - hand.addAnte(a.group('PNAME'), a.group('SB')) - except: # no small blind - hand.addBlind(None, None, None) + liveBlind = True + for a in self.re_PostSB.finditer(hand.handText): + if liveBlind: + hand.addBlind(a.group('PNAME'), 'small blind', a.group('SB')) + liveBlind = False + else: + # Post dead blinds as ante + hand.addAnte(a.group('PNAME'), a.group('SB')) for a in self.re_PostBB.finditer(hand.handText): hand.addBlind(a.group('PNAME'), 'big blind', a.group('BB')) for a in self.re_PostBoth.finditer(hand.handText): From 35a604dcc6094fd4cedb6a53e0100ef29d09b244 Mon Sep 17 00:00:00 2001 From: Gerko de Roo Date: Thu, 18 Feb 2010 16:39:51 +0100 Subject: [PATCH 05/24] Add support for posting dead small blind --- pyfpdb/FulltiltToFpdb.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/pyfpdb/FulltiltToFpdb.py b/pyfpdb/FulltiltToFpdb.py index af55fd41..4ee12fa4 100755 --- a/pyfpdb/FulltiltToFpdb.py +++ b/pyfpdb/FulltiltToFpdb.py @@ -128,6 +128,7 @@ class Fulltilt(HandHistoryConverter): player_re = "(?P" + "|".join(map(re.escape, players)) + ")" logging.debug("player_re: " + player_re) self.re_PostSB = re.compile(r"^%s posts the small blind of \$?(?P[.0-9]+)" % player_re, re.MULTILINE) + self.re_PostDead = re.compile(r"^%s posts a dead small blind of \$?(?P[.0-9]+)" % player_re, re.MULTILINE) self.re_PostBB = re.compile(r"^%s posts (the big blind of )?\$?(?P[.0-9]+)" % player_re, re.MULTILINE) self.re_Antes = re.compile(r"^%s antes \$?(?P[.0-9]+)" % player_re, re.MULTILINE) self.re_BringIn = re.compile(r"^%s brings in for \$?(?P[.0-9]+)" % player_re, re.MULTILINE) @@ -298,6 +299,8 @@ class Fulltilt(HandHistoryConverter): hand.addBlind(m.group('PNAME'), 'small blind', m.group('SB')) except: # no small blind hand.addBlind(None, None, None) + for a in self.re_PostDead.finditer(hand.handText): + hand.addAnte(a.group('PNAME'), a.group('SB')) for a in self.re_PostBB.finditer(hand.handText): hand.addBlind(a.group('PNAME'), 'big blind', a.group('BB')) for a in self.re_PostBoth.finditer(hand.handText): From 97ec91c165c79329406b8748911493ba043cf04a Mon Sep 17 00:00:00 2001 From: Eratosthenes Date: Thu, 18 Feb 2010 16:00:12 -0500 Subject: [PATCH 06/24] Revert fix removing the creation of folders for converted HHs. --- pyfpdb/HandHistoryConverter.py | 18 +++++++++++++++++- 1 file changed, 17 insertions(+), 1 deletion(-) diff --git a/pyfpdb/HandHistoryConverter.py b/pyfpdb/HandHistoryConverter.py index 4bf7564d..41d5b39a 100644 --- a/pyfpdb/HandHistoryConverter.py +++ b/pyfpdb/HandHistoryConverter.py @@ -92,7 +92,23 @@ follow : whether to tail -f the input""" self.out_fh = sys.stdout else: # TODO: out_path should be sanity checked. - self.out_fh = sys.stdout + out_dir = os.path.dirname(self.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 + # TODO: pop up a box to allow person to choose output directory? + # TODO: shouldn't that be done when we startup, actually? + else: + log.info("Created directory '%s'" % out_dir) + try: + self.out_fh = codecs.open(self.out_path, 'w', 'utf8') + except: + log.error("out_path %s couldn't be opened" % (self.out_path)) + else: + log.debug("out_path %s opened as %s" % (self.out_path, self.out_fh)) self.follow = follow self.compiledPlayers = set() self.maxseats = 10 From 6272c057b93fadf675159414e31d4db7ea0739b4 Mon Sep 17 00:00:00 2001 From: Gerko de Roo Date: Thu, 18 Feb 2010 22:12:01 +0100 Subject: [PATCH 07/24] Pokerstar Big and Small blind for limit games now derived form lookup table. This also needs to be done for PokerStars, don't know for the other sites.... --- pyfpdb/Hand.py | 11 +++++------ pyfpdb/PokerStarsToFpdb.py | 30 ++++++++++++++++++++---------- 2 files changed, 25 insertions(+), 16 deletions(-) diff --git a/pyfpdb/Hand.py b/pyfpdb/Hand.py index 262ac4ad..b740a341 100644 --- a/pyfpdb/Hand.py +++ b/pyfpdb/Hand.py @@ -344,15 +344,14 @@ For sites (currently only Carbon Poker) which record "all in" as a special actio if blindtype == 'both': # 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 = Decimal(amount)/3 - self.bets['BLINDSANTES'][player].append(amount) - self.pot.addCommonMoney(player, amount) - amount += amount + amount = self.bb + self.bets['BLINDSANTES'][player].append(Decimal(self.sb)) + self.pot.addCommonMoney(player, Decimal(self.sb)) if blindtype == 'secondsb': amount = Decimal(0) 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.pot.addMoney(player, Decimal(amount)) @@ -1450,7 +1449,7 @@ class Pot(object): # Return any uncalled bet. 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 # additional money is committed to the pot in cash games # due to an additional sb being posted. (Speculate that diff --git a/pyfpdb/PokerStarsToFpdb.py b/pyfpdb/PokerStarsToFpdb.py index 87574e9d..8c222e12 100644 --- a/pyfpdb/PokerStarsToFpdb.py +++ b/pyfpdb/PokerStarsToFpdb.py @@ -140,6 +140,14 @@ class PokerStars(HandHistoryConverter): mg = m.groupdict() # 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' } games = { # base, category "Hold'em" : ('hold','holdem'), @@ -173,6 +181,10 @@ class PokerStars(HandHistoryConverter): else: info['type'] = 'tour' + if info['limitType'] == 'fl' and info['bb'] != None: + 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. return info @@ -287,16 +299,14 @@ class PokerStars(HandHistoryConverter): hand.addBringIn(m.group('PNAME'), m.group('BRINGIN')) def readBlinds(self, hand): - try: - count = 0 - for a in self.re_PostSB.finditer(hand.handText): - if count == 0: - hand.addBlind(a.group('PNAME'), 'small blind', a.group('SB')) - count = 1 - else: - hand.addBlind(a.group('PNAME'), 'secondsb', a.group('SB')) - except: # no small blind - hand.addBlind(None, None, None) + liveBlind = True + for a in self.re_PostSB.finditer(hand.handText): + if liveBlind: + hand.addBlind(a.group('PNAME'), 'small blind', a.group('SB')) + liveBlind = False + else: + # Post dead blinds as ante + hand.addBlind(a.group('PNAME'), 'secondsb', a.group('SB')) for a in self.re_PostBB.finditer(hand.handText): hand.addBlind(a.group('PNAME'), 'big blind', a.group('BB')) for a in self.re_PostBoth.finditer(hand.handText): From aceb94d26055cf05bd7fdbbda74eb9bb712d5489 Mon Sep 17 00:00:00 2001 From: Gerko de Roo Date: Thu, 18 Feb 2010 22:24:25 +0100 Subject: [PATCH 08/24] Oops... Lookup is only for ring games.... --- pyfpdb/PokerStarsToFpdb.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pyfpdb/PokerStarsToFpdb.py b/pyfpdb/PokerStarsToFpdb.py index 8c222e12..946d5ea2 100644 --- a/pyfpdb/PokerStarsToFpdb.py +++ b/pyfpdb/PokerStarsToFpdb.py @@ -181,7 +181,7 @@ class PokerStars(HandHistoryConverter): else: info['type'] = 'tour' - if info['limitType'] == 'fl' and info['bb'] != None: + 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] From af6dbc8d5fffda420f27ea9a37a58f2dcbfb95c6 Mon Sep 17 00:00:00 2001 From: Gerko de Roo Date: Thu, 18 Feb 2010 22:32:53 +0100 Subject: [PATCH 09/24] Copied same dead blind procedure from Pokerstars to Full Tilt --- pyfpdb/FulltiltToFpdb.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pyfpdb/FulltiltToFpdb.py b/pyfpdb/FulltiltToFpdb.py index 4ee12fa4..2a3050ab 100755 --- a/pyfpdb/FulltiltToFpdb.py +++ b/pyfpdb/FulltiltToFpdb.py @@ -300,7 +300,7 @@ class Fulltilt(HandHistoryConverter): except: # no small blind hand.addBlind(None, None, None) for a in self.re_PostDead.finditer(hand.handText): - hand.addAnte(a.group('PNAME'), a.group('SB')) + hand.addBlind(a.group('PNAME'), 'secondsb', a.group('SB')) for a in self.re_PostBB.finditer(hand.handText): hand.addBlind(a.group('PNAME'), 'big blind', a.group('BB')) for a in self.re_PostBoth.finditer(hand.handText): From c33575911d12e6e9af5e383103eeac2ba68ff1af Mon Sep 17 00:00:00 2001 From: Eratosthenes Date: Fri, 19 Feb 2010 17:50:45 -0500 Subject: [PATCH 10/24] Don't make folders or files for Stars format HHs. --- pyfpdb/HandHistoryConverter.py | 48 +++++++++++++++++++--------------- pyfpdb/fpdb.py | 35 +++++++++++++------------ 2 files changed, 45 insertions(+), 38 deletions(-) diff --git a/pyfpdb/HandHistoryConverter.py b/pyfpdb/HandHistoryConverter.py index 41d5b39a..0edaaed0 100644 --- a/pyfpdb/HandHistoryConverter.py +++ b/pyfpdb/HandHistoryConverter.py @@ -69,6 +69,7 @@ out_path (default '-' = sys.stdout) follow : whether to tail -f the input""" 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.info("HandHistory init - %s subclass, in_path '%s'; out_path '%s'" % (self.sitename, in_path, out_path) ) @@ -87,28 +88,8 @@ follow : whether to tail -f the input""" if in_path == '-': 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. - out_dir = os.path.dirname(self.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 - # TODO: pop up a box to allow person to choose output directory? - # TODO: shouldn't that be done when we startup, actually? - else: - log.info("Created directory '%s'" % out_dir) - try: - self.out_fh = codecs.open(self.out_path, 'w', 'utf8') - except: - log.error("out_path %s couldn't be opened" % (self.out_path)) - else: - log.debug("out_path %s opened as %s" % (self.out_path, self.out_fh)) self.follow = follow self.compiledPlayers = set() self.maxseats = 10 @@ -531,3 +512,28 @@ def getSiteHhc(config, sitename): hhcName = config.supported_sites[sitename].converter hhcModule = __import__(hhcName) return getattr(hhcModule, hhcName[:-6]) + +def get_out_fh(out_path, parameters): + if out_path == '-': + return(sys.stdout) + elif parameters['saveStarsHH']: + # TODO: out_path should be sanity checked. + out_dir = os.path.dirname(self.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 + # TODO: pop up a box to allow person to choose output directory? + # TODO: shouldn't that be done when we startup, actually? + else: + log.info("Created directory '%s'" % out_dir) + try: + return(codecs.open(self.out_path, 'w', 'utf8')) + except: + log.error("out_path %s couldn't be opened" % (self.out_path)) + else: + log.debug("out_path %s opened as %s" % (self.out_path, self.out_fh)) + else: + return(sys.stdout) \ No newline at end of file diff --git a/pyfpdb/fpdb.py b/pyfpdb/fpdb.py index 55b19a3b..0abffcd0 100755 --- a/pyfpdb/fpdb.py +++ b/pyfpdb/fpdb.py @@ -997,23 +997,24 @@ This program is licensed under the AGPL3, see docs"""+os.sep+"agpl-3.0.txt") return response def validate_config(self): - hhbase = self.config.get_import_parameters().get("hhArchiveBase") - hhbase = os.path.expanduser(hhbase) - #hhdir = os.path.join(hhbase,site) - hhdir = hhbase - if not os.path.isdir(hhdir): - diapath = gtk.MessageDialog(parent=None, flags=0, type=gtk.MESSAGE_WARNING, buttons=(gtk.BUTTONS_YES_NO), message_format="Setup hh dir") - 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.format_secondary_text(diastring) - response = diapath.run() - diapath.destroy() - if response == gtk.RESPONSE_YES: - try: - os.makedirs(hhdir) - except: - self.warning_box("WARNING: Unable to create hand output directory. Importing is not likely to work until this is fixed.") - elif response == gtk.RESPONSE_NO: - self.select_hhArchiveBase() + if self.config.get_import_parameters().get('saveStarsHH'): + hhbase = self.config.get_import_parameters().get("hhArchiveBase") + hhbase = os.path.expanduser(hhbase) + #hhdir = os.path.join(hhbase,site) + hhdir = hhbase + if not os.path.isdir(hhdir): + diapath = gtk.MessageDialog(parent=None, flags=0, type=gtk.MESSAGE_WARNING, buttons=(gtk.BUTTONS_YES_NO), message_format="Setup hh dir") + 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.format_secondary_text(diastring) + response = diapath.run() + diapath.destroy() + if response == gtk.RESPONSE_YES: + try: + os.makedirs(hhdir) + except: + self.warning_box("WARNING: Unable to create hand output directory. Importing is not likely to work until this is fixed.") + elif response == gtk.RESPONSE_NO: + self.select_hhArchiveBase() 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) From a9ec972ba595022535377aeff3015dcb8df049cd Mon Sep 17 00:00:00 2001 From: Eratosthenes Date: Fri, 19 Feb 2010 20:14:34 -0500 Subject: [PATCH 11/24] Clean some pylint errors and obsolete TODOs. --- pyfpdb/HandHistoryConverter.py | 17 ++++++----------- 1 file changed, 6 insertions(+), 11 deletions(-) diff --git a/pyfpdb/HandHistoryConverter.py b/pyfpdb/HandHistoryConverter.py index 0edaaed0..2053eba9 100644 --- a/pyfpdb/HandHistoryConverter.py +++ b/pyfpdb/HandHistoryConverter.py @@ -443,8 +443,8 @@ or None if we fail to get the info """ def guessMaxSeats(self, hand): """Return a guess at maxseats when not specified in HH.""" # if some other code prior to this has already set it, return it - if maxseats > 1 and maxseats < 11: - return maxseats + if self.maxseats > 1 and self.maxseats < 11: + return self.maxseats mo = self.maxOccSeat(hand) if mo == 10: return 10 #that was easy @@ -517,23 +517,18 @@ def get_out_fh(out_path, parameters): if out_path == '-': return(sys.stdout) elif parameters['saveStarsHH']: - # TODO: out_path should be sanity checked. - out_dir = os.path.dirname(self.out_path) + 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 - # TODO: pop up a box to allow person to choose output directory? - # TODO: shouldn't that be done when we startup, actually? else: log.info("Created directory '%s'" % out_dir) try: - return(codecs.open(self.out_path, 'w', 'utf8')) + return(codecs.open(out_path, 'w', 'utf8')) except: - log.error("out_path %s couldn't be opened" % (self.out_path)) - else: - log.debug("out_path %s opened as %s" % (self.out_path, self.out_fh)) + log.error("out_path %s couldn't be opened" % (out_path)) else: - return(sys.stdout) \ No newline at end of file + return(sys.stdout) From ae59fa715b6bd56cfd65a52c7f281e46630ce410 Mon Sep 17 00:00:00 2001 From: Eratosthenes Date: Sat, 20 Feb 2010 11:24:07 -0500 Subject: [PATCH 12/24] Correctly pass dbname to config. Clean some pylint complaints. --- pyfpdb/HUD_main.py | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/pyfpdb/HUD_main.py b/pyfpdb/HUD_main.py index 2ea223f4..92f888d8 100755 --- a/pyfpdb/HUD_main.py +++ b/pyfpdb/HUD_main.py @@ -61,7 +61,7 @@ import Hud # 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') @@ -78,14 +78,14 @@ class HUD_main(object): try: if not options.errorsToConsole: - fileName = os.path.join(self.config.dir_log, 'HUD-errors.txt') - print "Note: error output is being diverted to:\n"+fileName \ - + "\nAny major error will be reported there _only_.\n" - log.info("Note: error output is being diverted to:"+fileName) - log.info("Any major error will be reported there _only_.") - errorFile = open(fileName, 'w', 0) - sys.stderr = errorFile - sys.stderr.write("HUD_main: starting ...\n") + fileName = os.path.join(self.config.dir_log, 'HUD-errors.txt') + print "Note: error output is being diverted to:\n"+fileName \ + + "\nAny major error will be reported there _only_.\n" + log.info("Note: error output is being diverted to:"+fileName) + log.info("Any major error will be reported there _only_.") + errorFile = open(fileName, 'w', 0) + sys.stderr = errorFile + sys.stderr.write("HUD_main: starting ...\n") self.hud_dict = {} self.hud_params = self.config.get_hud_ui_parameters() @@ -237,7 +237,7 @@ class HUD_main(object): try: (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) - except Exception, err: + except Exception: log.error("db error: skipping %s" % new_hand_id) continue t1 = time.time() From 21396e101ef4eadb1e90cf9dc759d231deacaaba Mon Sep 17 00:00:00 2001 From: Eratosthenes Date: Sat, 20 Feb 2010 11:55:52 -0500 Subject: [PATCH 13/24] Create saveStarsHH option in import. --- pyfpdb/Configuration.py | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/pyfpdb/Configuration.py b/pyfpdb/Configuration.py index f7694e90..9112072e 100755 --- a/pyfpdb/Configuration.py +++ b/pyfpdb/Configuration.py @@ -414,6 +414,7 @@ class Import: self.hhArchiveBase = node.getAttribute("hhArchiveBase") self.saveActions = string_to_bool(node.getAttribute("saveActions"), default=True) self.fastStoreHudCache = string_to_bool(node.getAttribute("fastStoreHudCache"), default=False) + self.saveStarsHH = string_to_bool(node.getAttribute("saveStarsHH"), default=False) def __str__(self): return " interval = %s\n callFpdbHud = %s\n hhArchiveBase = %s\n saveActions = %s\n fastStoreHudCache = %s\n" \ @@ -808,8 +809,12 @@ class Config: try: imp['saveActions'] = self.imp.saveActions except: imp['saveActions'] = True + try: imp['saveStarsHH'] = self.imp.saveStarsHH + except: imp['saveStarsHH'] = False + try: imp['fastStoreHudCache'] = self.imp.fastStoreHudCache except: imp['fastStoreHudCache'] = True + return imp def get_default_paths(self, site = None): From da124770af5ccdb44794422f16290f72350bcc8a Mon Sep 17 00:00:00 2001 From: Eratosthenes Date: Mon, 22 Feb 2010 11:45:52 -0500 Subject: [PATCH 14/24] Add souce code locations for 3rd party libs + minor update. --- docs/readme.txt | 25 ++++++++++++++++++++----- 1 file changed, 20 insertions(+), 5 deletions(-) diff --git a/docs/readme.txt b/docs/readme.txt index 03e071d3..e3dbac23 100644 --- a/docs/readme.txt +++ b/docs/readme.txt @@ -1,5 +1,5 @@ README.txt -updated 26 March 2009, REB +updated 22 February 2010, REB fpdb - Free Poker Database @@ -29,7 +29,7 @@ fpdb supports: Omaha (incl Hi/low) 7 Card Stud (incl Hi/low) Razz - Draw support is under development + Triple Draw and Badugi Mixed Games -- HUD under development Operating Systems: @@ -38,23 +38,38 @@ fpdb supports: Mac OS/X -- no support for HUD Databases: + SQLite configured by default MySQL PostgreSQL - SQLite under development Downloads: 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 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 ======= Trademarks of third parties have been used under Fair Use or similar laws. 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 document under the terms of the GNU Free Documentation License, Version 1.2 as published by the Free Software Foundation; with From 9dac1f1b8409966d7bdc6c968e85ef808c685473 Mon Sep 17 00:00:00 2001 From: Gerko de Roo Date: Tue, 23 Feb 2010 18:55:09 +0100 Subject: [PATCH 15/24] When all players are selected in player stats The site filter settings were bypassed. This fix only selects all players from selected sites --- pyfpdb/GuiPlayerStats.py | 24 ++++++++++++++++++++---- pyfpdb/SQL.py | 3 +++ 2 files changed, 23 insertions(+), 4 deletions(-) diff --git a/pyfpdb/GuiPlayerStats.py b/pyfpdb/GuiPlayerStats.py index 047c1ff1..39c6c727 100644 --- a/pyfpdb/GuiPlayerStats.py +++ b/pyfpdb/GuiPlayerStats.py @@ -81,7 +81,7 @@ class GuiPlayerStats (threading.Thread): self.filters = Filters.Filters(self.db, self.conf, self.sql, display = filters_display) self.filters.registerButton1Name("_Filters") self.filters.registerButton1Callback(self.showDetailFilter) - self.filters.registerButton2Name("_Refresh Stats") + self.filters.registerButton2Name("_Refresh") self.filters.registerButton2Callback(self.refreshStats) # ToDo: store in config @@ -481,7 +481,23 @@ class GuiPlayerStats (threading.Thread): else: gametest = "and gt.category IS NULL" query = query.replace("", 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("", sitetest) + if seats: query = query.replace('', 'between ' + str(seats['from']) + ' and ' + str(seats['to'])) if 'show' in seats and seats['show']: @@ -520,7 +536,7 @@ class GuiPlayerStats (threading.Thread): blindtest = str(tuple(nolims)) blindtest = blindtest.replace("L", "") blindtest = blindtest.replace(",)",")") - bbtest = bbtest + blindtest + ' ) ) )' + bbtest = bbtest + blindtest + ' ) )' else: bbtest = bbtest + '(-1) ) )' if type == 'ring': @@ -539,7 +555,7 @@ class GuiPlayerStats (threading.Thread): query = query.replace("", "") groupLevels = "show" not in str(limits) if groupLevels: - query = query.replace("", "p.name") + query = query.replace("", "-1") else: query = query.replace("", "h.gameTypeId") diff --git a/pyfpdb/SQL.py b/pyfpdb/SQL.py index 6db24fb4..570edb34 100644 --- a/pyfpdb/SQL.py +++ b/pyfpdb/SQL.py @@ -1915,6 +1915,7 @@ class Sql: inner join Players p on (p.Id = hp.playerId) where hp.playerId in + /*and hp.tourneysPlayersId IS NULL*/ and h.seats @@ -1999,6 +2000,7 @@ class Sql: inner join Players p on (p.Id = hp.playerId) where hp.playerId in + /*and hp.tourneysPlayersId IS NULL*/ and h.seats @@ -2085,6 +2087,7 @@ class Sql: inner join Players p on (p.Id = hp.playerId) where hp.playerId in + /*and hp.tourneysPlayersId IS NULL*/ and h.seats From 03880bbc63f7635821b5ff5ac75796d83ef6a94a Mon Sep 17 00:00:00 2001 From: Eratosthenes Date: Wed, 24 Feb 2010 10:28:12 -0500 Subject: [PATCH 16/24] Trivial refactor of get_stats_from_hand for readability. --- pyfpdb/Database.py | 43 ++++++++++++++++++++++++------------------- 1 file changed, 24 insertions(+), 19 deletions(-) diff --git a/pyfpdb/Database.py b/pyfpdb/Database.py index 0303aad2..76addf59 100644 --- a/pyfpdb/Database.py +++ b/pyfpdb/Database.py @@ -643,6 +643,29 @@ class Database: , hero_id = -1 , num_seats = 6 ): + + (hud_style, h_hud_style, query, subs) = self.prep_aggregation(hand, hud_params, hero_id, num_seats) + + c = self.connection.cursor() + +# now get the stats + stat_dict = {} + c.execute(self.sql.query[query], subs) + colnames = [desc[0] for desc in c.description] + for row in c.fetchall(): + playerid = row[0] + if (playerid == hero_id and h_hud_style != 'S') or (playerid != hero_id and hud_style != 'S'): + t_dict = {} + for name, val in zip(colnames, row): + t_dict[name.lower()] = val +# print t_dict + stat_dict[t_dict['player_id']] = t_dict + + return stat_dict + + def prep_aggregation(self, hand, hud_params, hero_id, num_seats): +# This sorts through the all the info having to do with aggregation +# and returns what get_stats needs. hud_style = hud_params['hud_style'] agg_bb_mult = hud_params['agg_bb_mult'] seats_style = hud_params['seats_style'] @@ -652,8 +675,6 @@ class Database: h_seats_style = hud_params['h_seats_style'] h_seats_cust_nums = hud_params['h_seats_cust_nums'] - stat_dict = {} - if seats_style == 'A': seats_min, seats_max = 0, 10 elif seats_style == 'C': @@ -715,23 +736,7 @@ class Database: subs = (hand ,hero_id, stylekey, agg_bb_mult, agg_bb_mult, seats_min, seats_max # hero params ,hero_id, h_stylekey, h_agg_bb_mult, h_agg_bb_mult, h_seats_min, h_seats_max) # villain params - - #print "get stats: hud style =", hud_style, "query =", query, "subs =", subs - c = self.connection.cursor() - -# now get the stats - c.execute(self.sql.query[query], subs) - colnames = [desc[0] for desc in c.description] - for row in c.fetchall(): - playerid = row[0] - if (playerid == hero_id and h_hud_style != 'S') or (playerid != hero_id and hud_style != 'S'): - t_dict = {} - for name, val in zip(colnames, row): - t_dict[name.lower()] = val -# print t_dict - stat_dict[t_dict['player_id']] = t_dict - - return stat_dict + return (hud_style, h_hud_style, query, subs) # uses query on handsplayers instead of hudcache to get stats on just this session def get_stats_from_hand_session(self, hand, stat_dict, hero_id From 04e8f117d5ebd47a29307328002d5f1bc49449ef Mon Sep 17 00:00:00 2001 From: Eratosthenes Date: Wed, 24 Feb 2010 17:06:36 -0500 Subject: [PATCH 17/24] Revert "Trivial refactor of get_stats_from_hand for readability." This reverts commit 03880bbc63f7635821b5ff5ac75796d83ef6a94a. --- pyfpdb/Database.py | 43 +++++++++++++++++++------------------------ 1 file changed, 19 insertions(+), 24 deletions(-) diff --git a/pyfpdb/Database.py b/pyfpdb/Database.py index 76addf59..0303aad2 100644 --- a/pyfpdb/Database.py +++ b/pyfpdb/Database.py @@ -643,29 +643,6 @@ class Database: , hero_id = -1 , num_seats = 6 ): - - (hud_style, h_hud_style, query, subs) = self.prep_aggregation(hand, hud_params, hero_id, num_seats) - - c = self.connection.cursor() - -# now get the stats - stat_dict = {} - c.execute(self.sql.query[query], subs) - colnames = [desc[0] for desc in c.description] - for row in c.fetchall(): - playerid = row[0] - if (playerid == hero_id and h_hud_style != 'S') or (playerid != hero_id and hud_style != 'S'): - t_dict = {} - for name, val in zip(colnames, row): - t_dict[name.lower()] = val -# print t_dict - stat_dict[t_dict['player_id']] = t_dict - - return stat_dict - - def prep_aggregation(self, hand, hud_params, hero_id, num_seats): -# This sorts through the all the info having to do with aggregation -# and returns what get_stats needs. hud_style = hud_params['hud_style'] agg_bb_mult = hud_params['agg_bb_mult'] seats_style = hud_params['seats_style'] @@ -675,6 +652,8 @@ class Database: h_seats_style = hud_params['h_seats_style'] h_seats_cust_nums = hud_params['h_seats_cust_nums'] + stat_dict = {} + if seats_style == 'A': seats_min, seats_max = 0, 10 elif seats_style == 'C': @@ -736,7 +715,23 @@ class Database: subs = (hand ,hero_id, stylekey, agg_bb_mult, agg_bb_mult, seats_min, seats_max # hero params ,hero_id, h_stylekey, h_agg_bb_mult, h_agg_bb_mult, h_seats_min, h_seats_max) # villain params - return (hud_style, h_hud_style, query, subs) + + #print "get stats: hud style =", hud_style, "query =", query, "subs =", subs + c = self.connection.cursor() + +# now get the stats + c.execute(self.sql.query[query], subs) + colnames = [desc[0] for desc in c.description] + for row in c.fetchall(): + playerid = row[0] + if (playerid == hero_id and h_hud_style != 'S') or (playerid != hero_id and hud_style != 'S'): + t_dict = {} + for name, val in zip(colnames, row): + t_dict[name.lower()] = val +# print t_dict + stat_dict[t_dict['player_id']] = t_dict + + return stat_dict # uses query on handsplayers instead of hudcache to get stats on just this session def get_stats_from_hand_session(self, hand, stat_dict, hero_id From 5c0e4cb0c2b623effbd8d91d6191d69ca9f8ab8d Mon Sep 17 00:00:00 2001 From: Eratosthenes Date: Thu, 25 Feb 2010 20:28:41 -0500 Subject: [PATCH 18/24] Use correct dirs for database and log. --- pyfpdb/Configuration.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/pyfpdb/Configuration.py b/pyfpdb/Configuration.py index d87014e6..d0f81a1b 100755 --- a/pyfpdb/Configuration.py +++ b/pyfpdb/Configuration.py @@ -470,7 +470,8 @@ class Config: self.file = file 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_database = os.path.join(self.dir_config, 'database') self.log_file = os.path.join(self.dir_log, 'fpdb-log.txt') From aca5682daf4fe6a4402ef47592c77a01b3c7ae28 Mon Sep 17 00:00:00 2001 From: Eratosthenes Date: Thu, 25 Feb 2010 21:32:49 -0500 Subject: [PATCH 19/24] Get rid of erroneous error message. --- pyfpdb/XTables.py | 1 - 1 file changed, 1 deletion(-) diff --git a/pyfpdb/XTables.py b/pyfpdb/XTables.py index a14debc1..28737002 100644 --- a/pyfpdb/XTables.py +++ b/pyfpdb/XTables.py @@ -89,7 +89,6 @@ class Table(Table_Window): # break if window_number is None: - print "Window %s not found. Skipping." % search_string return None # my_geo = self.window.get_geometry() From daeee37b6b04017a7dff151b8b63f7102affc7cd Mon Sep 17 00:00:00 2001 From: sqlcoder Date: Sat, 27 Feb 2010 13:56:19 +0000 Subject: [PATCH 20/24] default dbname option is overriding 'default=true' selection in config file --- pyfpdb/Options.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pyfpdb/Options.py b/pyfpdb/Options.py index 6570dbe4..bda28259 100644 --- a/pyfpdb/Options.py +++ b/pyfpdb/Options.py @@ -27,7 +27,7 @@ def fpdb_options(): action="store_true", help="If passed error output will go to the console rather than .") parser.add_option("-d", "--databaseName", - dest="dbname", default="fpdb", + dest="dbname", help="Overrides the default database name") parser.add_option("-c", "--configFile", dest="config", default=None, From 4ed82b1f183d192ed6544ff890cbb9d600305afb Mon Sep 17 00:00:00 2001 From: sqlcoder Date: Sat, 27 Feb 2010 15:47:24 +0000 Subject: [PATCH 21/24] comment out DEBUG print --- pyfpdb/Hand.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pyfpdb/Hand.py b/pyfpdb/Hand.py index 56a11063..e9626522 100644 --- a/pyfpdb/Hand.py +++ b/pyfpdb/Hand.py @@ -1449,7 +1449,7 @@ class Pot(object): # Return any uncalled bet. 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 # additional money is committed to the pot in cash games # due to an additional sb being posted. (Speculate that From 6a6d1b1b2c8ffd6e2352db726b9322ba2974cfed Mon Sep 17 00:00:00 2001 From: sqlcoder Date: Sat, 27 Feb 2010 18:41:30 +0000 Subject: [PATCH 22/24] fix 3bet stat (was being set to false if someone else 4bet) --- pyfpdb/Database.py | 4 ---- pyfpdb/DerivedStats.py | 4 ++-- 2 files changed, 2 insertions(+), 6 deletions(-) diff --git a/pyfpdb/Database.py b/pyfpdb/Database.py index d0fe733b..f51ce5f5 100644 --- a/pyfpdb/Database.py +++ b/pyfpdb/Database.py @@ -917,7 +917,6 @@ class Database: print "warning: constraint %s_%s_fkey not dropped: %s, continuing ..." \ % (fk['fktab'],fk['fkcol'], str(sys.exc_value).rstrip('\n')) else: - print "Only MySQL and Postgres supported so far" return -1 for idx in self.indexes[self.backend]: @@ -952,7 +951,6 @@ class Database: print "warning: index %s_%s_idx not dropped %s, continuing ..." \ % (idx['tab'],idx['col'], str(sys.exc_value).rstrip('\n')) else: - print "Error: Only MySQL and Postgres supported so far" return -1 if self.backend == self.PGSQL: @@ -1007,7 +1005,6 @@ class Database: except: print " create fk failed: " + str(sys.exc_info()) else: - print "Only MySQL and Postgres supported so far" return -1 for idx in self.indexes[self.backend]: @@ -1029,7 +1026,6 @@ class Database: except: print " create index failed: " + str(sys.exc_info()) else: - print "Only MySQL and Postgres supported so far" return -1 if self.backend == self.PGSQL: diff --git a/pyfpdb/DerivedStats.py b/pyfpdb/DerivedStats.py index dddbec8b..b13e7463 100644 --- a/pyfpdb/DerivedStats.py +++ b/pyfpdb/DerivedStats.py @@ -345,9 +345,9 @@ class DerivedStats(): for action in hand.actions[hand.actionStreets[1]]: # FIXME: fill other(3|4)BStreet0 - i have no idea what does it mean 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_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']) if aggr: bet_level += 1 From 6a176090407b5fc5542b795441a224b4c52fa5ee Mon Sep 17 00:00:00 2001 From: Worros Date: Tue, 2 Mar 2010 15:51:40 +0800 Subject: [PATCH 23/24] FullTilt: Playernames can be 2 chars long Found a hand history where the playername was 'OG'. The parser assumed player names were a minimum of 3 characters. --- pyfpdb/FulltiltToFpdb.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pyfpdb/FulltiltToFpdb.py b/pyfpdb/FulltiltToFpdb.py index 2a3050ab..10ecb8dd 100755 --- a/pyfpdb/FulltiltToFpdb.py +++ b/pyfpdb/FulltiltToFpdb.py @@ -65,8 +65,8 @@ class Fulltilt(HandHistoryConverter): (\s\((?PTurbo)\))?)|(?P.+)) ''', re.VERBOSE) re_Button = re.compile('^The button is in seat #(?P