diff --git a/pyfpdb/Charset.py b/pyfpdb/Charset.py index 9c49f505..055ca714 100644 --- a/pyfpdb/Charset.py +++ b/pyfpdb/Charset.py @@ -26,7 +26,9 @@ import Configuration encoder_to_utf = codecs.lookup('utf-8') encoder_to_sys = codecs.lookup(Configuration.LOCALE_ENCODING) +coder_hex = codecs.lookup('hex_codec') +hex_coding = False #FIXME: Should only be on if db is not UTF8 - test in Database.py? # I'm saving a few cycles with this one not_needed1, not_needed2, not_needed3 = False, False, False if Configuration.LOCALE_ENCODING == 'UTF8': @@ -75,3 +77,19 @@ def to_gui(s): except UnicodeEncodeError: sys.stderr.write('Could not encode: "%s"\n' % s) raise + +def to_hex(s): + try: + out = coder_hex.encode(s)[0] + return out + except UnicodeDecodeError: + sys.stderr.write('Could not convert: "%s"\n' % s) + return s + +def from_hex(s): + try: + out = coder_hex.decode(s)[0] + return out + except UnicodeDecodeError: + sys.stderr.write('Could not convert: "%s"\n' % s) + return s diff --git a/pyfpdb/Configuration.py b/pyfpdb/Configuration.py index d0f81a1b..ee957e2d 100755 --- a/pyfpdb/Configuration.py +++ b/pyfpdb/Configuration.py @@ -412,6 +412,7 @@ class Import: self.interval = node.getAttribute("interval") self.callFpdbHud = node.getAttribute("callFpdbHud") self.hhArchiveBase = node.getAttribute("hhArchiveBase") + self.hhBulkPath = node.getAttribute("hhBulkPath") 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) @@ -452,6 +453,24 @@ class Tv: return (" combinedStealFold = %s\n combined2B3B = %s\n combinedPostflop = %s\n" % (self.combinedStealFold, self.combined2B3B, self.combinedPostflop) ) +class General(dict): + def __init__(self): + super(General, self).__init__() + + def add_elements(self, node): + # day_start - number n where 0.0 <= n < 24.0 representing start of day for user + # e.g. user could set to 4.0 for day to start at 4am local time + # [ HH_bulk_path was here - now moved to import section ] + for (name, value) in node.attributes.items(): + log.debug("config.general: adding %s = %s" % (name,value)) + self[name] = value + + def __str__(self): + s = "" + for k in self: + s = s + " %s = %s\n" % (k, self[k]) + return(s) + class Config: def __init__(self, file = None, dbname = ''): # "file" is a path to an xml file with the fpdb/HUD configuration @@ -506,7 +525,10 @@ class Config: self.popup_windows = {} self.db_selected = None # database the user would like to use self.tv = None + self.general = General() + for gen_node in doc.getElementsByTagName("general"): + self.general.add_elements(node=gen_node) # add/overwrite elements in self.general # s_sites = doc.getElementsByTagName("supported_sites") for site_node in doc.getElementsByTagName("site"): @@ -818,9 +840,14 @@ class Config: try: imp['interval'] = self.imp.interval except: imp['interval'] = 10 + # hhArchiveBase is the temp store for part-processed hand histories - should be redundant eventually try: imp['hhArchiveBase'] = self.imp.hhArchiveBase except: imp['hhArchiveBase'] = "~/.fpdb/HandHistories/" + # hhBulkPath is the default location for bulk imports (if set) + try: imp['hhBulkPath'] = self.imp.hhBulkPath + except: imp['hhBulkPath'] = "" + try: imp['saveActions'] = self.imp.saveActions except: imp['saveActions'] = True @@ -839,6 +866,8 @@ class Config: path = os.path.expanduser(self.supported_sites[site].HH_path) assert(os.path.isdir(path) or os.path.isfile(path)) # maybe it should try another site? paths['hud-defaultPath'] = paths['bulkImport-defaultPath'] = path + if self.imp.hhBulkPath: + paths['bulkImport-defaultPath'] = self.imp.hhBulkPath except AssertionError: paths['hud-defaultPath'] = paths['bulkImport-defaultPath'] = "** ERROR DEFAULT PATH IN CONFIG DOES NOT EXIST **" return paths @@ -987,6 +1016,9 @@ class Config: """Join the fpdb path to filename.""" return os.path.join(os.path.dirname(inspect.getfile(sys._getframe(0))), filename) + def get_general_params(self): + return( self.general ) + if __name__== "__main__": c = Config() diff --git a/pyfpdb/DerivedStats.py b/pyfpdb/DerivedStats.py index f5278b99..b222fc01 100644 --- a/pyfpdb/DerivedStats.py +++ b/pyfpdb/DerivedStats.py @@ -67,12 +67,12 @@ class DerivedStats(): self.handsplayers[player[1]]['street%dCBDone' %i] = False self.handsplayers[player[1]]['street%dCheckCallRaiseChance' %i] = False self.handsplayers[player[1]]['street%dCheckCallRaiseDone' %i] = False + self.handsplayers[player[1]]['otherRaisedStreet%d' %i] = False + self.handsplayers[player[1]]['foldToOtherRaisedStreet%d' %i] = False #FIXME - Everything below this point is incomplete. self.handsplayers[player[1]]['tourneyTypeId'] = 1 for i in range(1,5): - self.handsplayers[player[1]]['otherRaisedStreet%d' %i] = False - self.handsplayers[player[1]]['foldToOtherRaisedStreet%d' %i] = False self.handsplayers[player[1]]['foldToStreet%dCBChance' %i] = False self.handsplayers[player[1]]['foldToStreet%dCBDone' %i] = False @@ -139,6 +139,8 @@ class DerivedStats(): self.handsplayers[player[1]]['seatNo'] = player[0] self.handsplayers[player[1]]['startCash'] = int(100 * Decimal(player[2])) + # XXX: enumerate(list, start=x) is python 2.6 syntax; 'start' + #for i, street in enumerate(hand.actionStreets[2:], start=1): for i, street in enumerate(hand.actionStreets[2:]): self.seen(self.hand, i+1) @@ -146,6 +148,8 @@ class DerivedStats(): self.aggr(self.hand, i) self.calls(self.hand, i) self.bets(self.hand, i) + if i>0: + self.folds(self.hand, i) # Winnings is a non-negative value of money collected from the pot, which already includes the # rake taken out. hand.collectees is Decimal, database requires cents @@ -380,6 +384,7 @@ class DerivedStats(): CG: CheckCall would be a much better name for this. """ + # XXX: enumerate(list, start=x) is python 2.6 syntax; 'start' #for i, street in enumerate(hand.actionStreets[2:], start=1): for i, street in enumerate(hand.actionStreets[2:]): actions = hand.actions[hand.actionStreets[i+1]] @@ -408,10 +413,16 @@ class DerivedStats(): def aggr(self, hand, i): aggrers = set() + others = set() # Growl - actionStreets contains 'BLINDSANTES', which isn't actually an action street + + firstAggrMade=False for act in hand.actions[hand.actionStreets[i+1]]: + if firstAggrMade: + others.add(act[0]) if act[1] in ('completes', 'bets', 'raises'): aggrers.add(act[0]) + firstAggrMade=True for player in hand.players: #print "DEBUG: actionStreet[%s]: %s" %(hand.actionStreets[i+1], i) @@ -420,6 +431,12 @@ class DerivedStats(): else: self.handsplayers[player[1]]['street%sAggr' % i] = False + if i > 0 and len(aggrers) > 0: + for playername in others: + self.handsplayers[playername]['otherRaisedStreet%s' % i] = True + #print "DEBUG: otherRaised detected on handid %s for %s on actionStreet[%s]: %s" + # %(hand.handid, playername, hand.actionStreets[i+1], i) + def calls(self, hand, i): callers = [] for act in hand.actions[hand.actionStreets[i+1]]: @@ -429,11 +446,19 @@ class DerivedStats(): # CG - I'm sure this stat is wrong # Best guess is that raise = 2 bets def bets(self, hand, i): - betters = [] for act in hand.actions[hand.actionStreets[i+1]]: if act[1] in ('bets'): self.handsplayers[act[0]]['street%sBets' % i] = 1 + self.handsplayers[act[0]]['street%sBets' % i] + + def folds(self, hand, i): + for act in hand.actions[hand.actionStreets[i+1]]: + if act[1] in ('folds'): + if self.handsplayers[act[0]]['otherRaisedStreet%s' % i] == True: + self.handsplayers[act[0]]['foldToOtherRaisedStreet%s' % i] = True + #print "DEBUG: fold detected on handid %s for %s on actionStreet[%s]: %s" + # %(hand.handid, act[0],hand.actionStreets[i+1], i) + def countPlayers(self, hand): pass diff --git a/pyfpdb/Filters.py b/pyfpdb/Filters.py index c8e8e219..43f7819d 100644 --- a/pyfpdb/Filters.py +++ b/pyfpdb/Filters.py @@ -58,6 +58,11 @@ class Filters(threading.Thread): ,'limitsFL':'FL', 'limitsNL':'NL', 'limitsPL':'PL', 'ring':'Ring', 'tour':'Tourney' } + gen = self.conf.get_general_params() + self.day_start = 0 + if 'day_start' in gen: + self.day_start = float(gen['day_start']) + # Outer Packing box self.mainVBox = gtk.VBox(False, 0) @@ -864,18 +869,31 @@ class Filters(threading.Thread): self.end_date.set_text('') def __get_dates(self): + # self.day_start gives user's start of day in hours + offset = int(self.day_start * 3600) # calc day_start in seconds + t1 = self.start_date.get_text() t2 = self.end_date.get_text() if t1 == '': - t1 = '1970-01-01' + t1 = '1970-01-02' if t2 == '': t2 = '2020-12-12' - return (t1, t2) + s1 = strptime(t1, "%Y-%m-%d") # make time_struct + s2 = strptime(t2, "%Y-%m-%d") + e1 = mktime(s1) + offset # s1 is localtime, but returned time since epoch is UTC, then add the + e2 = mktime(s2) + offset # s2 is localtime, but returned time since epoch is UTC + e2 = e2 + 24 * 3600 - 1 # date test is inclusive, so add 23h 59m 59s to e2 + + adj_t1 = strftime("%Y-%m-%d %H:%M:%S", gmtime(e1)) # make adjusted string including time + adj_t2 = strftime("%Y-%m-%d %H:%M:%S", gmtime(e2)) + log.info("t1="+t1+" adj_t1="+adj_t1+'.') + + return (adj_t1, adj_t2) def __get_date(self, widget, calendar, entry, win): -# year and day are correct, month is 0..11 + # year and day are correct, month is 0..11 (year, month, day) = calendar.get_date() month += 1 ds = '%04d-%02d-%02d' % (year, month, day) diff --git a/pyfpdb/FulltiltToFpdb.py b/pyfpdb/FulltiltToFpdb.py index 10ecb8dd..2c6370e6 100755 --- a/pyfpdb/FulltiltToFpdb.py +++ b/pyfpdb/FulltiltToFpdb.py @@ -27,7 +27,7 @@ class Fulltilt(HandHistoryConverter): sitename = "Fulltilt" filetype = "text" - codepage = ["utf-16", "cp1252"] + codepage = ["utf-16", "cp1252", "utf-8"] siteId = 1 # Needs to match id entry in Sites database # Static regexes diff --git a/pyfpdb/GuiPlayerStats.py b/pyfpdb/GuiPlayerStats.py index 17419fd8..41e82ed8 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") + self.filters.registerButton2Name("_Refresh Stats") self.filters.registerButton2Callback(self.refreshStats) # ToDo: store in config @@ -567,7 +567,7 @@ class GuiPlayerStats (threading.Thread): query = query.replace("", "") groupLevels = "show" not in str(limits) if groupLevels: - query = query.replace("", "-1") + query = query.replace("", "p.name") # need to use p.name for sqlite posn stats to work else: query = query.replace("", "h.gameTypeId") diff --git a/pyfpdb/Hud.py b/pyfpdb/Hud.py index dcad0865..5dcccf3c 100644 --- a/pyfpdb/Hud.py +++ b/pyfpdb/Hud.py @@ -448,6 +448,8 @@ class Hud: if os.name == 'nt': if not win32gui.IsWindow(self.table.number): self.parent.kill_hud(self, self.table.name) + self.parent.kill_hud(self, self.table.name.split(" ")[0]) + #table.name is only a valid handle for ring games ! we are not killing tourney tables here. return False # anyone know how to do this in unix, or better yet, trap the X11 error that is triggered when executing the get_origin() for a closed window? if self.table.gdkhandle is not None: diff --git a/pyfpdb/PartyPokerToFpdb.py b/pyfpdb/PartyPokerToFpdb.py index f83c8672..5c60f179 100755 --- a/pyfpdb/PartyPokerToFpdb.py +++ b/pyfpdb/PartyPokerToFpdb.py @@ -261,6 +261,7 @@ class PartyPoker(HandHistoryConverter): if v[0] in self.pot.returned: self.collected[i][1] = Decimal(v[1]) - self.pot.returned[v[0]] self.collectees[v[0]] -= self.pot.returned[v[0]] + self.pot.returned[v[0]] = 0 return origTotalPot() return totalPot instancemethod = type(hand.totalPot) @@ -359,8 +360,14 @@ class PartyPoker(HandHistoryConverter): if hand.gametype['type'] == 'ring': try: assert noSmallBlind==False - m = self.re_PostSB.search(hand.handText) - hand.addBlind(m.group('PNAME'), 'small blind', m.group('SB')) + liveBlind = True + for m in self.re_PostSB.finditer(hand.handText): + if liveBlind: + hand.addBlind(m.group('PNAME'), 'small blind', m.group('SB')) + liveBlind = False + else: + # Post dead blinds as ante + hand.addBlind(m.group('PNAME'), 'secondsb', m.group('SB')) except: # no small blind hand.addBlind(None, None, None) @@ -432,7 +439,7 @@ class PartyPoker(HandHistoryConverter): if street == 'PREFLOP' and \ playerName in [item[0] for item in hand.actions['BLINDSANTES'] if item[2]!='ante']: # preflop raise from blind - hand.addRaiseBy( street, playerName, amount ) + hand.addCallandRaise( street, playerName, amount ) else: hand.addCallandRaise( street, playerName, amount ) elif actionType == 'calls': diff --git a/pyfpdb/PokerStarsToFpdb.py b/pyfpdb/PokerStarsToFpdb.py index c964faa5..79bef1ea 100644 --- a/pyfpdb/PokerStarsToFpdb.py +++ b/pyfpdb/PokerStarsToFpdb.py @@ -82,6 +82,8 @@ class PokerStars(HandHistoryConverter): # self.re_setHandInfoRegex('.*#(?P[0-9]+): Table (?P[ a-zA-Z]+) - \$?(?P[.0-9]+)/\$?(?P[.0-9]+) - (?P.*) - (?P
[0-9]+):(?P[0-9]+) ET - (?P[0-9]+)/(?P[0-9]+)/(?P[0-9]+)Table (?P
[ a-zA-Z]+)\nSeat (?P