From cf6e818ae5ae784ee778cdc11b9c204337f70da1 Mon Sep 17 00:00:00 2001 From: Carl Gherardi Date: Mon, 14 Dec 2009 16:45:08 +0800 Subject: [PATCH 01/41] [NEWIMPORT] Enable NEWIMPORT by defaul --- pyfpdb/Configuration.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pyfpdb/Configuration.py b/pyfpdb/Configuration.py index 996ef60c..bf8689a6 100755 --- a/pyfpdb/Configuration.py +++ b/pyfpdb/Configuration.py @@ -125,7 +125,7 @@ DATABASE_TYPES = ( DATABASE_TYPE_MYSQL, ) -NEWIMPORT = False +NEWIMPORT = True ######################################################################## def string_to_bool(string, default=True): From f03a9c287fba9398aba1eff20a17e5b398656d99 Mon Sep 17 00:00:00 2001 From: Worros Date: Thu, 17 Dec 2009 15:53:12 +0800 Subject: [PATCH 02/41] Add some code to kinda detect hand cancellation hhc.readHandInfo(self) hhc.readPlayerStacks(self) hhc.compilePlayerRegexs(self) hhc.markStreets(self) Is the order, the first correctly failing regex is markStreets --- pyfpdb/Hand.py | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/pyfpdb/Hand.py b/pyfpdb/Hand.py index 6901340e..32140256 100644 --- a/pyfpdb/Hand.py +++ b/pyfpdb/Hand.py @@ -54,6 +54,7 @@ class Hand(object): self.starttime = 0 self.handText = handText self.handid = 0 + self.cancelled = False self.dbid_hands = 0 self.dbid_pids = None self.dbid_gt = 0 @@ -263,6 +264,8 @@ If a player has None chips he won't be added.""" log.debug("markStreets:\n"+ str(self.streets)) else: log.error("markstreets didn't match") + log.error(" - Assuming hand cancelled") + self.cancelled = True def checkPlayerExists(self,player): if player not in [p[1] for p in self.players]: @@ -613,6 +616,8 @@ class HoldemOmahaHand(Hand): hhc.readPlayerStacks(self) hhc.compilePlayerRegexs(self) hhc.markStreets(self) + if self.cancelled: + return hhc.readBlinds(self) hhc.readAntes(self) hhc.readButton(self) From 26fc0b592837765c515277fc1f0b373b9934667b Mon Sep 17 00:00:00 2001 From: Worros Date: Thu, 17 Dec 2009 18:42:50 +0800 Subject: [PATCH 03/41] Add ability to import Stars archive files. PokerStars support can provide a HH archive. The format is similar but not the same as a a standard hh format as it contains an additional line "Hand #X" between each hand. Patch adds an option -s to GuiBulkImport, which when specified will strip these lines out and continue parsing. --- pyfpdb/GuiBulkImport.py | 4 ++++ pyfpdb/Hand.py | 1 + pyfpdb/HandHistoryConverter.py | 8 +++++++- pyfpdb/fpdb_import.py | 19 +++++++++++++------ 4 files changed, 25 insertions(+), 7 deletions(-) diff --git a/pyfpdb/GuiBulkImport.py b/pyfpdb/GuiBulkImport.py index 7db420c7..16131ab2 100755 --- a/pyfpdb/GuiBulkImport.py +++ b/pyfpdb/GuiBulkImport.py @@ -326,6 +326,8 @@ def main(argv=None): help="How often to print a one-line status report (0 (default) means never)") parser.add_option("-u", "--usage", action="store_true", dest="usage", default=False, help="Print some useful one liners") + parser.add_option("-s", "--starsarchive", action="store_true", dest="starsArchive", default=False, + help="Do the required conversion for Stars Archive format (ie. as provided by support") (options, argv) = parser.parse_args(args = argv) if options.usage == True: @@ -369,6 +371,8 @@ def main(argv=None): importer.setThreads(-1) importer.addBulkImportImportFileOrDir(os.path.expanduser(options.filename), site=options.filtername) importer.setCallHud(False) + if options.starsArchive: + importer.setStarsArchive(True) (stored, dups, partial, errs, ttime) = importer.runImport() importer.clearFileList() print 'GuiBulkImport done: Stored: %d \tDuplicates: %d \tPartial: %d \tErrors: %d in %s seconds - %.0f/sec'\ diff --git a/pyfpdb/Hand.py b/pyfpdb/Hand.py index 32140256..3467216a 100644 --- a/pyfpdb/Hand.py +++ b/pyfpdb/Hand.py @@ -266,6 +266,7 @@ If a player has None chips he won't be added.""" log.error("markstreets didn't match") log.error(" - Assuming hand cancelled") self.cancelled = True + raise FpdbParseError def checkPlayerExists(self,player): if player not in [p[1] for p in self.players]: diff --git a/pyfpdb/HandHistoryConverter.py b/pyfpdb/HandHistoryConverter.py index 27bb9b1a..a18797df 100644 --- a/pyfpdb/HandHistoryConverter.py +++ b/pyfpdb/HandHistoryConverter.py @@ -57,7 +57,7 @@ class HandHistoryConverter(): codepage = "cp1252" - def __init__(self, in_path = '-', out_path = '-', follow=False, index=0, autostart=True): + def __init__(self, in_path = '-', out_path = '-', follow=False, index=0, autostart=True, starsArchive=False): """\ in_path (default '-' = sys.stdin) out_path (default '-' = sys.stdout) @@ -66,6 +66,7 @@ follow : whether to tail -f the input""" log.info("HandHistory init - %s subclass, in_path '%s'; out_path '%s'" % (self.sitename, in_path, out_path) ) self.index = 0 + self.starsArchive = starsArchive self.in_path = in_path self.out_path = out_path @@ -254,6 +255,11 @@ which it expects to find at self.re_TailSplitHands -- see for e.g. Everleaf.py. self.readFile() self.obs = self.obs.strip() self.obs = self.obs.replace('\r\n', '\n') + if self.starsArchive == True: + log.debug("Converting starsArchive format to readable") + m = re.compile('^Hand #\d+', re.MULTILINE) + self.obs = m.sub('', self.obs) + if self.obs is None or self.obs == "": log.info("Read no hands.") return [] diff --git a/pyfpdb/fpdb_import.py b/pyfpdb/fpdb_import.py index 7b3dd4f1..8921d9d8 100644 --- a/pyfpdb/fpdb_import.py +++ b/pyfpdb/fpdb_import.py @@ -91,6 +91,7 @@ class Importer: self.settings.setdefault("writeQMaxWait", 10) # not used self.settings.setdefault("dropIndexes", "don't drop") self.settings.setdefault("dropHudCache", "don't drop") + self.settings.setdefault("starsArchive", False) self.writeq = None self.database = Database.Database(self.config, sql = self.sql) @@ -134,6 +135,9 @@ class Importer: def setDropHudCache(self, value): self.settings['dropHudCache'] = value + def setStarsArchive(self, value): + self.settings['starsArchive'] = value + # def setWatchTime(self): # self.updated = time() @@ -425,7 +429,7 @@ class Importer: mod = __import__(filter) obj = getattr(mod, filter_name, None) if callable(obj): - hhc = obj(in_path = file, out_path = out_path, index = 0) # Index into file 0 until changeover + hhc = obj(in_path = file, out_path = out_path, index = 0, starsArchive = self.settings['starsArchive']) # Index into file 0 until changeover if hhc.getStatus() and self.NEWIMPORT == False: (stored, duplicates, partial, errors, ttime) = self.import_fpdb_file(db, out_path, site, q) elif hhc.getStatus() and self.NEWIMPORT == True: @@ -435,11 +439,14 @@ class Importer: to_hud = [] for hand in handlist: - #try, except duplicates here? - hand.prepInsert(self.database) - hand.insert(self.database) - if self.callHud and hand.dbid_hands != 0: - to_hud.append(hand.dbid_hands) + if hand is not None: + #try, except duplicates here? + hand.prepInsert(self.database) + hand.insert(self.database) + if self.callHud and hand.dbid_hands != 0: + to_hud.append(hand.dbid_hands) + else: + log.error("Hand processed but empty") self.database.commit() #pipe the Hands.id out to the HUD From 1093b1e43c3a12af748e0768cd71513e70d6d060 Mon Sep 17 00:00:00 2001 From: Worros Date: Fri, 18 Dec 2009 10:27:09 +0800 Subject: [PATCH 04/41] Remove dead code --- pyfpdb/fpdb_import.py | 160 +----------------------------------------- 1 file changed, 1 insertion(+), 159 deletions(-) diff --git a/pyfpdb/fpdb_import.py b/pyfpdb/fpdb_import.py index 8921d9d8..21aa5d5c 100644 --- a/pyfpdb/fpdb_import.py +++ b/pyfpdb/fpdb_import.py @@ -430,9 +430,7 @@ class Importer: obj = getattr(mod, filter_name, None) if callable(obj): hhc = obj(in_path = file, out_path = out_path, index = 0, starsArchive = self.settings['starsArchive']) # Index into file 0 until changeover - if hhc.getStatus() and self.NEWIMPORT == False: - (stored, duplicates, partial, errors, ttime) = self.import_fpdb_file(db, out_path, site, q) - elif hhc.getStatus() and self.NEWIMPORT == True: + if hhc.getStatus() and self.NEWIMPORT == True: #This code doesn't do anything yet handlist = hhc.getProcessedHands() self.pos_in_file[file] = hhc.getLastCharacterRead() @@ -468,162 +466,6 @@ class Importer: return (stored, duplicates, partial, errors, ttime) - def import_fpdb_file(self, db, file, site, q): - starttime = time() - last_read_hand = 0 - loc = 0 - (stored, duplicates, partial, errors, ttime) = (0, 0, 0, 0, 0) - # print "file =", file - if file == "stdin": - inputFile = sys.stdin - else: - if os.path.exists(file): - inputFile = open(file, "rU") - else: - self.removeFromFileList[file] = True - return (0, 0, 0, 1, 0) - try: - loc = self.pos_in_file[file] - #size = os.path.getsize(file) - #print "loc =", loc, 'size =', size - except KeyError: - pass - # Read input file into class and close file - inputFile.seek(loc) - #tmplines = inputFile.readlines() - #if tmplines == None or tmplines == []: - # print "tmplines = ", tmplines - #else: - # print "tmplines[0] =", tmplines[0] - self.lines = fpdb_simple.removeTrailingEOL(inputFile.readlines()) - self.pos_in_file[file] = inputFile.tell() - inputFile.close() - - x = clock() - (stored, duplicates, partial, errors, ttime, handsId) = self.import_fpdb_lines(db, self.lines, starttime, file, site, q) - - db.commit() - y = clock() - ttime = y - x - #ttime = time() - starttime - if q is None: - log.info("Total stored: %(stored)d\tduplicates:%(duplicates)d\terrors:%(errors)d\ttime:%(ttime)s" % locals()) - - if not stored: - if duplicates: - for line_no in xrange(len(self.lines)): - if self.lines[line_no].find("Game #") != -1: - final_game_line = self.lines[line_no] - handsId=fpdb_simple.parseSiteHandNo(final_game_line) - else: - print "failed to read a single hand from file:", inputFile - handsId = 0 - #todo: this will cause return of an unstored hand number if the last hand was error - self.handsId = handsId - - return (stored, duplicates, partial, errors, ttime) - # end def import_fpdb_file - - - def import_fpdb_lines(self, db, lines, starttime, file, site, q = None): - """Import an fpdb hand history held in the list lines, could be one hand or many""" - - #db.lock_for_insert() # should be ok when using one thread, but doesn't help?? - while gtk.events_pending(): - gtk.main_iteration(False) - - try: # sometimes we seem to be getting an empty self.lines, in which case, we just want to return. - firstline = lines[0] - except: - # just skip the debug message and return silently: - #print "DEBUG: import_fpdb_file: failed on lines[0]: '%s' '%s' '%s' '%s' " %( file, site, lines, loc) - return (0,0,0,1,0,0) - - if "Tournament Summary" in firstline: - print "TODO: implement importing tournament summaries" - #self.faobs = readfile(inputFile) - #self.parseTourneyHistory() - return (0,0,0,1,0,0) - - category = fpdb_simple.recogniseCategory(firstline) - - startpos = 0 - stored = 0 #counter - duplicates = 0 #counter - partial = 0 #counter - errors = 0 #counter - ttime = 0 - handsId = 0 - - for i in xrange(len(lines)): - if len(lines[i]) < 2: #Wierd way to detect for '\r\n' or '\n' - endpos = i - hand = lines[startpos:endpos] - - if len(hand[0]) < 2: - hand=hand[1:] - - if len(hand) < 3: - pass - #TODO: This is ugly - we didn't actually find the start of the - # hand with the outer loop so we test again... - else: - isTourney = fpdb_simple.isTourney(hand[0]) - if not isTourney: - hand = fpdb_simple.filterAnteBlindFold(hand) - self.hand = hand - - try: - handsId = fpdb_parse_logic.mainParser( self.settings, self.siteIds[site] - , category, hand, self.config - , db, q ) - db.commit() - - stored += 1 - if self.callHud: - #print "call to HUD here. handsId:",handsId - #pipe the Hands.id out to the HUD - # print "fpdb_import: sending hand to hud", handsId, "pipe =", self.caller.pipe_to_hud - try: - self.caller.pipe_to_hud.stdin.write("%s" % (handsId) + os.linesep) - except IOError: # hud closed - self.callHud = False - pass # continue import without hud - except Exceptions.DuplicateError: - duplicates += 1 - db.rollback() - except (ValueError), fe: - errors += 1 - self.printEmailErrorMessage(errors, file, hand) - - if (self.settings['failOnError']): - db.commit() #dont remove this, in case hand processing was cancelled. - raise - else: - db.rollback() - except (fpdb_simple.FpdbError), fe: - errors += 1 - self.printEmailErrorMessage(errors, file, hand) - db.rollback() - - if self.settings['failOnError']: - db.commit() #dont remove this, in case hand processing was cancelled. - raise - - if self.settings['minPrint']: - if not ((stored+duplicates+errors) % self.settings['minPrint']): - print "stored:", stored, " duplicates:", duplicates, "errors:", errors - - if self.settings['handCount']: - if ((stored+duplicates+errors) >= self.settings['handCount']): - if not self.settings['quiet']: - print "quitting due to reaching the amount of hands to be imported" - print "Total stored:", stored, "duplicates:", duplicates, "errors:", errors, " time:", (time() - starttime) - sys.exit(0) - startpos = endpos - return (stored, duplicates, partial, errors, ttime, handsId) - # end def import_fpdb_lines - def printEmailErrorMessage(self, errors, filename, line): traceback.print_exc(file=sys.stderr) print "Error No.",errors,", please send the hand causing this to steffen@sycamoretest.info so I can fix it." From 975eb360ef96d3f669269117c9fe78f151662379 Mon Sep 17 00:00:00 2001 From: Worros Date: Fri, 18 Dec 2009 10:27:43 +0800 Subject: [PATCH 05/41] [NEWIMPORT] Add stubbed variable to insert --- pyfpdb/Database.py | 3 ++- pyfpdb/SQL.py | 5 +++-- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/pyfpdb/Database.py b/pyfpdb/Database.py index 9d1f3f85..72b41336 100644 --- a/pyfpdb/Database.py +++ b/pyfpdb/Database.py @@ -1651,7 +1651,8 @@ class Database: pdata[p]['street2CheckCallRaiseDone'], pdata[p]['street3CheckCallRaiseChance'], pdata[p]['street3CheckCallRaiseDone'], - pdata[p]['street4CheckCallRaiseChance'] + pdata[p]['street4CheckCallRaiseChance'], + pdata[p]['street4CheckCallRaiseDone'] ) ) q = self.sql.query['store_hands_players'] diff --git a/pyfpdb/SQL.py b/pyfpdb/SQL.py index c0319dfe..56c1f388 100644 --- a/pyfpdb/SQL.py +++ b/pyfpdb/SQL.py @@ -3404,10 +3404,11 @@ class Sql: street2CheckCallRaiseDone, street3CheckCallRaiseChance, street3CheckCallRaiseDone, - street4CheckCallRaiseChance + street4CheckCallRaiseChance, + street4CheckCallRaiseDone ) VALUES ( - %s, %s, %s, %s, + %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, From 2b7d34c4842e40b9d8fdb950eefd23c99068e95d Mon Sep 17 00:00:00 2001 From: Worros Date: Fri, 18 Dec 2009 13:32:09 +0800 Subject: [PATCH 06/41] [NEWIMPORT] Fix syntax to be 2.5 compatible. Python 2.6 enumerate() function contains a useful 'start' paramater, apparently this did not exist in 2.5. Patch frim Mika Bostrom --- pyfpdb/DerivedStats.py | 20 +++++++++++++------- 1 file changed, 13 insertions(+), 7 deletions(-) diff --git a/pyfpdb/DerivedStats.py b/pyfpdb/DerivedStats.py index 1a34db1e..5943a10f 100644 --- a/pyfpdb/DerivedStats.py +++ b/pyfpdb/DerivedStats.py @@ -168,8 +168,10 @@ class DerivedStats(): for player in hand.players: hcs = hand.join_holecards(player[1], asList=True) hcs = hcs + [u'0x', u'0x', u'0x', u'0x', u'0x'] - for i, card in enumerate(hcs[:7], 1): - self.handsplayers[player[1]]['card%s' % i] = Card.encodeCard(card) + #for i, card in enumerate(hcs[:7], 1): #Python 2.6 syntax + # self.handsplayers[player[1]]['card%s' % i] = Card.encodeCard(card) + for i, card in enumerate(hcs[:7]): + self.handsplayers[player[1]]['card%s' % (i+1)] = Card.encodeCard(card) # position, @@ -266,13 +268,17 @@ class DerivedStats(): # Then no bets before the player with initiatives first action on current street # ie. if player on street-1 had initiative # and no donkbets occurred - for i, street in enumerate(hand.actionStreets[2:], start=1): - name = self.lastBetOrRaiser(hand.actionStreets[i]) + + # XXX: enumerate(list, start=x) is python 2.6 syntax; 'start' + # came there + #for i, street in enumerate(hand.actionStreets[2:], start=1): + for i, street in enumerate(hand.actionStreets[2:]: + name = self.lastBetOrRaiser(hand.actionStreets[i+1]) if name: - chance = self.noBetsBefore(hand.actionStreets[i+1], name) - self.handsplayers[name]['street%dCBChance' %i] = True + chance = self.noBetsBefore(hand.actionStreets[i+2], name) + self.handsplayers[name]['street%dCBChance' % (i+1)] = True if chance == True: - self.handsplayers[name]['street%dCBDone' %i] = self.betStreet(hand.actionStreets[i+1], name) + self.handsplayers[name]['street%dCBDone' % (i+1)] = self.betStreet(hand.actionStreets[i+2], name) def seen(self, hand, i): pas = set() From d5608fa7a7d6e86447b037d4ed9b1a07ac467fde Mon Sep 17 00:00:00 2001 From: steffen123 Date: Sun, 20 Dec 2009 12:01:26 +0000 Subject: [PATCH 07/41] support PS tourneys with euro buyin --- pyfpdb/fpdb_simple.py | 18 ++++++++++++++---- 1 file changed, 14 insertions(+), 4 deletions(-) diff --git a/pyfpdb/fpdb_simple.py b/pyfpdb/fpdb_simple.py index 1c22f6e6..5f0c6507 100644 --- a/pyfpdb/fpdb_simple.py +++ b/pyfpdb/fpdb_simple.py @@ -1,4 +1,5 @@ #!/usr/bin/python +# -*- coding: iso-8859-15 -*- #Copyright 2008 Steffen Jobbagy-Felso #This program is free software: you can redistribute it and/or modify @@ -538,7 +539,11 @@ def parseAnteLine(line, isTourney, names, antes): #returns the buyin of a tourney in cents def parseBuyin(topline): pos1 = topline.find("$")+1 - pos2 = topline.find("+") + if pos1 != 0: + pos2 = topline.find("+") + else: + pos1 = topline.find("€")+3 + pos2 = topline.find("+") return float2int(topline[pos1:pos2]) #parses a card line and changes the passed arrays accordingly @@ -635,9 +640,14 @@ def parseCashesAndSeatNos(lines): #returns the buyin of a tourney in cents def parseFee(topline): - pos1=topline.find("$")+1 - pos1=topline.find("$",pos1)+1 - pos2=topline.find(" ", pos1) + pos1 = topline.find("$")+1 + if pos1 != 0: + pos1 = topline.find("$", pos1)+1 + pos2 = topline.find(" ", pos1) + else: + pos1 = topline.find("€")+3 + pos1 = topline.find("€", pos1)+3 + pos2 = topline.find(" ", pos1) return float2int(topline[pos1:pos2]) #returns a datetime object with the starttime indicated in the given topline From babf0a039aa3332547e50b1f9e61f223ff9f6237 Mon Sep 17 00:00:00 2001 From: Worros Date: Mon, 21 Dec 2009 09:21:41 +0800 Subject: [PATCH 08/41] PartyPoker - No Disconnect fix Fix from Neko on 2+2 http://forumserver.twoplustwo.com/showpost.php?p=15495528&postcount=2374 "Finally got around to checking this out. Seems great so far. I had issues with some of my party hands that were on No Disconnect protect tables but adding the No DP regex in the PartyToFpdb hand converter seems to have fixed it for me." --- pyfpdb/PartyPokerToFpdb.py | 1 + 1 file changed, 1 insertion(+) diff --git a/pyfpdb/PartyPokerToFpdb.py b/pyfpdb/PartyPokerToFpdb.py index 4ed0c965..4cf64547 100755 --- a/pyfpdb/PartyPokerToFpdb.py +++ b/pyfpdb/PartyPokerToFpdb.py @@ -89,6 +89,7 @@ class PartyPoker(HandHistoryConverter): (?P[a-zA-Z0-9 ]+)\s+ (?: \#|\(|)(?P\d+)\)?\s+ (?:[^ ]+\s+\#(?P\d+).+)? # table number for mtt + (\(No\sDP\)\s)? \((?PReal|Play)\s+Money\)\s+ # FIXME: check if play money is correct Seat\s+(?P