diff --git a/packaging/debian/control b/packaging/debian/control index 784c4b40..c510e1c8 100644 --- a/packaging/debian/control +++ b/packaging/debian/control @@ -10,7 +10,8 @@ Architecture: all Section: games Priority: extra Depends: ${python:Depends}, python-gtk2, python-matplotlib, - python-support, mysql-server | postgresql | python-pysqlite2, + python-support, python-xlib, + mysql-server | postgresql | python-pysqlite2, python-psycopg2 | python-mysqldb Suggests: wine Description: free poker database with HUD diff --git a/pyfpdb/Configuration.py b/pyfpdb/Configuration.py index 3e3c00a3..7b8ff796 100755 --- a/pyfpdb/Configuration.py +++ b/pyfpdb/Configuration.py @@ -6,17 +6,17 @@ Handles HUD configuration files. """ # Copyright 2008, 2009, Ray E. Barker -# +# # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2 of the License, or # (at your option) any later version. -# +# # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. -# +# # You should have received a copy of the GNU General Public License # along with this program; if not, write to the Free Software # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA @@ -54,8 +54,10 @@ def get_exec_path(): """Returns the path to the fpdb.(py|exe) file we are executing""" if hasattr(sys, "frozen"): # compiled by py2exe return os.path.dirname(sys.executable) - else: - return os.path.dirname(sys.path[0]) + else: + print "argv=", sys.argv + pathname = os.path.dirname(sys.argv[0]) + return os.path.abspath(pathname) def get_config(file_name, fallback = True): """Looks in exec dir and in self.default_config_path for a config file.""" @@ -162,7 +164,7 @@ class Layout: if node.hasAttribute('fav_seat'): self.fav_seat = int( node.getAttribute('fav_seat') ) self.width = int( node.getAttribute('width') ) self.height = int( node.getAttribute('height') ) - + self.location = [] self.location = map(lambda x: None, range(self.max+1)) # fill array with max seats+1 empty entries @@ -181,7 +183,7 @@ class Layout: temp = temp + " Locations = " for i in range(1, len(self.location)): temp = temp + "(%d,%d)" % self.location[i] - + return temp + "\n" class Site: @@ -191,7 +193,7 @@ class Site: if os.path.exists(path): return os.path.abspath(path) return path - + self.site_name = node.getAttribute("site_name") self.table_finder = node.getAttribute("table_finder") self.screen_name = node.getAttribute("screen_name") @@ -211,7 +213,7 @@ class Site: self.ypad = node.getAttribute("ypad") self.layout = {} - print "Loading site", self.site_name + print "Loading site", self.site_name for layout_node in node.getElementsByTagName('layout'): lo = Layout(layout_node) @@ -224,7 +226,7 @@ class Site: self.hudopacity = 1.0 if self.hudopacity == "" else float(self.hudopacity) if self.use_frames == "": self.use_frames = False - if self.font == "": self.font = "Sans" + if self.font == "": self.font = "Sans" if self.hudbgcolor == "": self.hudbgcolor = "#000000" if self.hudfgcolor == "": self.hudfgcolor = "#FFFFFF" @@ -236,20 +238,20 @@ class Site: value = getattr(self, key) if callable(value): continue temp = temp + ' ' + key + " = " + str(value) + "\n" - + for layout in self.layout: temp = temp + "%s" % self.layout[layout] - + return temp - + class Stat: def __init__(self): pass - + def __str__(self): temp = " stat_name = %s, row = %d, col = %d, tip = %s, click = %s, popup = %s\n" % (self.stat_name, self.row, self.col, self.tip, self.click, self.popup) return temp - + class Game: def __init__(self, node): self.game_name = node.getAttribute("game_name") @@ -282,9 +284,9 @@ class Game: stat.hudprefix = stat_node.getAttribute("hudprefix") stat.hudsuffix = stat_node.getAttribute("hudsuffix") stat.hudcolor = stat_node.getAttribute("hudcolor") - + self.stats[stat.stat_name] = stat - + def __str__(self): temp = "Game = " + self.game_name + "\n" temp = temp + " rows = %d\n" % self.rows @@ -292,12 +294,12 @@ class Game: temp = temp + " xpad = %d\n" % self.xpad temp = temp + " ypad = %d\n" % self.ypad temp = temp + " aux = %s\n" % self.aux - + for stat in self.stats.keys(): temp = temp + "%s" % self.stats[stat] - + return temp - + class Database: def __init__(self, node): self.db_name = node.getAttribute("db_name") @@ -308,7 +310,7 @@ class Database: self.db_selected = string_to_bool(node.getAttribute("default"), default=False) log.debug("Database db_name:'%(name)s' db_server:'%(server)s' db_ip:'%(ip)s' db_user:'%(user)s' db_pass (not logged) selected:'%(sel)s'" \ % { 'name':self.db_name, 'server':self.db_server, 'ip':self.db_ip, 'user':self.db_user, 'sel':self.db_selected} ) - + def __str__(self): temp = 'Database = ' + self.db_name + '\n' for key in dir(self): @@ -356,7 +358,7 @@ class Popup: self.pu_stats = [] for stat_node in node.getElementsByTagName('pu_stat'): self.pu_stats.append(stat_node.getAttribute("pu_stat_name")) - + def __str__(self): temp = "Popup = " + self.name + "\n" for stat in self.pu_stats: @@ -381,16 +383,16 @@ class HudUI: self.node = node self.label = node.getAttribute('label') # + self.hud_style = node.getAttribute('stat_range') + self.hud_days = node.getAttribute('stat_days') self.aggregate_ring = string_to_bool(node.getAttribute('aggregate_ring_game_stats')) self.aggregate_tour = string_to_bool(node.getAttribute('aggregate_tourney_stats')) - self.hud_style = node.getAttribute('stat_aggregation_range') - self.hud_days = node.getAttribute('aggregation_days') self.agg_bb_mult = node.getAttribute('aggregation_level_multiplier') # - self.h_aggregate_ring = string_to_bool(node.getAttribute('aggregate_hero_ring_game_stats')) - self.h_aggregate_tour = string_to_bool(node.getAttribute('aggregate_hero_tourney_stats')) - self.h_hud_style = node.getAttribute('hero_stat_aggregation_range') - self.h_hud_days = node.getAttribute('hero_aggregation_days') + self.h_hud_style = node.getAttribute('hero_stat_range') + self.h_hud_days = node.getAttribute('hero_stat_days') + self.h_aggregate_ring = string_to_bool(node.getAttribute('aggregate_hero_ring_game_stats')) + self.h_aggregate_tour = string_to_bool(node.getAttribute('aggregate_hero_tourney_stats')) self.h_agg_bb_mult = node.getAttribute('hero_aggregation_level_multiplier') @@ -405,7 +407,7 @@ class Tv: self.combinedPostflop = string_to_bool(node.getAttribute("combinedPostflop"), default=True) def __str__(self): - return (" combinedStealFold = %s\n combined2B3B = %s\n combinedPostflop = %s\n" % + return (" combinedStealFold = %s\n combined2B3B = %s\n combinedPostflop = %s\n" % (self.combinedStealFold, self.combined2B3B, self.combinedPostflop) ) class Config: @@ -429,7 +431,7 @@ class Config: print "\nReading configuration file %s\n" % file try: doc = xml.dom.minidom.parse(file) - except: + except: log.error("Error parsing %s. See error log file." % (file)) traceback.print_exc(file=sys.stderr) print "press enter to continue" @@ -457,9 +459,9 @@ class Config: for game_node in doc.getElementsByTagName("game"): game = Game(node = game_node) self.supported_games[game.game_name] = game - + # parse databases defined by user in the section - # the user may select the actual database to use via commandline or by setting the selected="bool" + # the user may select the actual database to use via commandline or by setting the selected="bool" # attribute of the tag. if no database is explicitely selected, we use the first one we come across # s_dbs = doc.getElementsByTagName("supported_databases") #TODO: do we want to take all tags or all tags contained in @@ -471,7 +473,7 @@ class Config: if self.db_selected is None or db.db_selected: self.db_selected = db.db_name self.supported_databases[db.db_name] = db - #TODO: if the user may passes '' (empty string) as database name via command line, his choice is ignored + #TODO: if the user may passes '' (empty string) as database name via command line, his choice is ignored # ..when we parse the xml we allow for ''. there has to be a decission if to allow '' or not if dbname and dbname in self.supported_databases: self.db_selected = dbname @@ -521,7 +523,7 @@ class Config: def set_hhArchiveBase(self, path): self.imp.node.setAttribute("hhArchiveBase", path) - + def find_default_conf(self): if os.name == 'posix': config_path = os.path.join(os.path.expanduser("~"), '.fpdb', 'default.conf') @@ -553,7 +555,7 @@ class Config: def get_layout_node(self, site_node, layout): for layout_node in site_node.getElementsByTagName("layout"): - if layout_node.getAttribute("max") is None: + if layout_node.getAttribute("max") is None: return None if int( layout_node.getAttribute("max") ) == int( layout ): return layout_node @@ -637,7 +639,7 @@ class Config: elif self.supported_databases[name].db_server== DATABASE_TYPE_POSTGRESQL: db['db-backend'] = 3 elif self.supported_databases[name].db_server== DATABASE_TYPE_SQLITE: - db['db-backend'] = 4 + db['db-backend'] = 4 else: raise ValueError('Unsupported database backend: %s' % self.supported_databases[name].db_server) return db @@ -658,7 +660,7 @@ class Config: if db_server is not None: self.supported_databases[db_name].dp_server = db_server if db_type is not None: self.supported_databases[db_name].dp_type = db_type return - + def getDefaultSite(self): "Returns first enabled site or None" for site_name,site in self.supported_sites.iteritems(): @@ -721,7 +723,7 @@ class Config: return hui - + def get_import_parameters(self): imp = {} try: imp['callFpdbHud'] = self.imp.callFpdbHud @@ -747,10 +749,10 @@ 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 - except AssertionError: + except AssertionError: paths['hud-defaultPath'] = paths['bulkImport-defaultPath'] = "** ERROR DEFAULT PATH IN CONFIG DOES NOT EXIST **" return paths - + def get_frames(self, site = "PokerStars"): if site not in self.supported_sites: return False return self.supported_sites[site].use_frames == True @@ -770,7 +772,7 @@ class Config: else: colors['hudfgcolor'] = self.supported_sites[site].hudfgcolor return colors - + def get_default_font(self, site='PokerStars'): font = "Sans" font_size = "8" @@ -789,17 +791,17 @@ class Config: if location is not None: return location.location return ( - ( 0, 0), (684, 61), (689, 239), (692, 346), + ( 0, 0), (684, 61), (689, 239), (692, 346), (586, 393), (421, 440), (267, 440), ( 0, 361), - ( 0, 280), (121, 280), ( 46, 30) + ( 0, 280), (121, 280), ( 46, 30) ) - + def get_aux_locations(self, aux = "mucked", max = "9"): - + try: locations = self.aux_windows[aux].layout[max].location except: - locations = ( ( 0, 0), (684, 61), (689, 239), (692, 346), + locations = ( ( 0, 0), (684, 61), (689, 239), (692, 346), (586, 393), (421, 440), (267, 440), ( 0, 361), ( 0, 280), (121, 280), ( 46, 30) ) return locations @@ -810,7 +812,7 @@ class Config: return self.supported_sites.keys() else: return [site_name for (site_name, site) in self.supported_sites.items() if site.enabled] - + def get_site_parameters(self, site): """Returns a dict of the site parameters for the specified site""" parms = {} @@ -833,7 +835,7 @@ class Config: return parms def set_site_parameters(self, site_name, converter = None, decoder = None, - hudbgcolor = None, hudfgcolor = None, + hudbgcolor = None, hudfgcolor = None, hudopacity = None, screen_name = None, site_path = None, table_finder = None, HH_path = None, enabled = None, @@ -871,7 +873,7 @@ class Config: return param return None - + def get_game_parameters(self, name): """Get the configuration parameters for the named game.""" param = {} @@ -897,7 +899,7 @@ class Config: if __name__== "__main__": c = Config() - + print "\n----------- SUPPORTED SITES -----------" for s in c.supported_sites.keys(): print c.supported_sites[s] @@ -924,7 +926,7 @@ if __name__== "__main__": for w in c.hhcs.keys(): print c.hhcs[w] print "----------- END HAND HISTORY CONVERTERS -----------" - + print "\n----------- POPUP WINDOW FORMATS -----------" for w in c.popup_windows.keys(): print c.popup_windows[w] @@ -940,7 +942,7 @@ if __name__== "__main__": c.edit_layout("PokerStars", 6, locations=( (1, 1), (2, 2), (3, 3), (4, 4), (5, 5), (6, 6) )) c.save(file="testout.xml") - + print "db = ", c.get_db_parameters() # print "tv = ", c.get_tv_parameters() # print "imp = ", c.get_import_parameters() @@ -951,7 +953,7 @@ if __name__== "__main__": print c.get_aux_parameters(mw) print "mucked locations =", c.get_aux_locations('mucked', 9) -# c.edit_aux_layout('mucked', 9, locations = [(487, 113), (555, 469), (572, 276), (522, 345), +# c.edit_aux_layout('mucked', 9, locations = [(487, 113), (555, 469), (572, 276), (522, 345), # (333, 354), (217, 341), (150, 273), (150, 169), (230, 115)]) # print "mucked locations =", c.get_aux_locations('mucked', 9) diff --git a/pyfpdb/Database.py b/pyfpdb/Database.py index d2fb5651..dab9125f 100755 --- a/pyfpdb/Database.py +++ b/pyfpdb/Database.py @@ -432,16 +432,14 @@ class Database: print "*** Database Error: "+err[2]+"("+str(err[1])+"): "+str(sys.exc_info()[1]) def get_stats_from_hand( self, hand, type # type is "ring" or "tour" - , hud_params = {'aggregate_tour':False, 'aggregate_ring':False, 'hud_style':'A', 'hud_days':30, 'agg_bb_mult':100 - ,'h_aggregate_tour':False, 'h_aggregate_ring':False, 'h_hud_style':'S', 'h_hud_days':30, 'h_agg_bb_mult':100} + , hud_params = {'hud_style':'A', 'agg_bb_mult':1000 + ,'h_hud_style':'S', 'h_agg_bb_mult':1000} , hero_id = -1 ): - aggregate = hud_params['aggregate_tour'] if type == "tour" else hud_params['aggregate_ring'] hud_style = hud_params['hud_style'] - agg_bb_mult = hud_params['agg_bb_mult'] if aggregate else 1 - h_aggregate = hud_params['h_aggregate_tour'] if type == "tour" else hud_params['h_aggregate_ring'] + agg_bb_mult = hud_params['agg_bb_mult'] h_hud_style = hud_params['h_hud_style'] - h_agg_bb_mult = hud_params['h_agg_bb_mult'] if h_aggregate else 1 + h_agg_bb_mult = hud_params['h_agg_bb_mult'] stat_dict = {} if hud_style == 'S' or h_hud_style == 'S': @@ -456,6 +454,10 @@ class Database: stylekey = '0000000' # all stylekey values should be higher than this elif hud_style == 'S': stylekey = 'zzzzzzz' # all stylekey values should be lower than this + else: + stylekey = '0000000' + log.info('hud_style: %s' % hud_style) + #elif hud_style == 'H': # stylekey = date_nhands_ago needs array by player here ... @@ -465,16 +467,15 @@ class Database: h_stylekey = '0000000' # all stylekey values should be higher than this elif h_hud_style == 'S': h_stylekey = 'zzzzzzz' # all stylekey values should be lower than this + else: + h_stylekey = '000000' + log.info('h_hud_style: %s' % h_hud_style) + #elif h_hud_style == 'H': # h_stylekey = date_nhands_ago needs array by player here ... - #if aggregate: always use aggregate query now: use agg_bb_mult of 1 for no aggregation: query = 'get_stats_from_hand_aggregated' subs = (hand, hero_id, stylekey, agg_bb_mult, agg_bb_mult, hero_id, h_stylekey, h_agg_bb_mult, h_agg_bb_mult) - #print "agg query subs:", subs - #else: - # query = 'get_stats_from_hand' - # subs = (hand, stylekey) #print "get stats: hud style =", hud_style, "query =", query, "subs =", subs c = self.connection.cursor() @@ -1384,6 +1385,13 @@ class Database: pids[p], pdata[p]['startCash'], pdata[p]['seatNo'], + pdata[p]['card1'], + pdata[p]['card2'], + pdata[p]['card3'], + pdata[p]['card4'], + pdata[p]['card5'], + pdata[p]['card6'], + pdata[p]['card7'], pdata[p]['winnings'], pdata[p]['street0VPI'], pdata[p]['street1Seen'], @@ -1402,6 +1410,13 @@ class Database: playerId, startCash, seatNo, + card1, + card2, + card3, + card4, + card5, + card6, + card7, winnings, street0VPI, street1Seen, @@ -1415,6 +1430,8 @@ class Database: street4Aggr ) VALUES ( + %s, %s, + %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s @@ -1422,10 +1439,6 @@ class Database: # position, # tourneyTypeId, -# card1, -# card2, -# card3, -# card4, # startCards, # rake, # totalProfit, diff --git a/pyfpdb/DerivedStats.py b/pyfpdb/DerivedStats.py index 4b48f618..e4d59336 100644 --- a/pyfpdb/DerivedStats.py +++ b/pyfpdb/DerivedStats.py @@ -81,12 +81,13 @@ class DerivedStats(): self.hands['boardcard5'] = cards[4] #print "DEBUG: self.getStreetTotals = (%s, %s, %s, %s, %s)" % hand.getStreetTotals() - #FIXME: Pot size still in decimal, needs to be converted to cents - (self.hands['street1Pot'], - self.hands['street2Pot'], - self.hands['street3Pot'], - self.hands['street4Pot'], - self.hands['showdownPot']) = hand.getStreetTotals() + totals = hand.getStreetTotals() + totals = [int(100*i) for i in totals] + self.hands['street1Pot'] = totals[0] + self.hands['street2Pot'] = totals[1] + self.hands['street3Pot'] = totals[2] + self.hands['street4Pot'] = totals[3] + self.hands['showdownPot'] = totals[4] self.vpip(hand) # Gives playersVpi (num of players vpip) #print "DEBUG: vpip: %s" %(self.hands['playersVpi']) @@ -115,695 +116,22 @@ class DerivedStats(): for i, street in enumerate(hand.actionStreets[1:]): self.aggr(self.hand, i) + default_holecards = ["Xx", "Xx", "Xx", "Xx"] + + for street in hand.holeStreets: + for player in hand.players: + for i in range(1,8): self.handsplayers[player[1]]['card%d' % i] = 0 + if player[1] in hand.holecards[street].keys(): + self.handsplayers[player[1]]['card1'] = Card.encodeCard(hand.holecards[street][player[1]][1][0]) + self.handsplayers[player[1]]['card2'] = Card.encodeCard(hand.holecards[street][player[1]][1][1]) + try: + self.handsplayers[player[1]]['card3'] = Card.encodeCard(hand.holecards[street][player[1]][1][2]) + self.handsplayers[player[1]]['card4'] = Card.encodeCard(hand.holecards[street][player[1]][1][3]) + except IndexError: + # Just means no player cards for that street/game - continue + pass def assembleHudCache(self, hand): -# # def generateHudCacheData(player_ids, base, category, action_types, allIns, actionTypeByNo -# # ,winnings, totalWinnings, positions, actionTypes, actionAmounts, antes): -# #"""calculates data for the HUD during import. IMPORTANT: if you change this method make -# # sure to also change the following storage method and table_viewer.prepare_data if necessary -# #""" -# #print "generateHudCacheData, len(player_ids)=", len(player_ids) -# #setup subarrays of the result dictionary. -# street0VPI=[] -# street0Aggr=[] -# street0_3BChance=[] -# street0_3BDone=[] -# street1Seen=[] -# street2Seen=[] -# street3Seen=[] -# street4Seen=[] -# sawShowdown=[] -# street1Aggr=[] -# street2Aggr=[] -# street3Aggr=[] -# street4Aggr=[] -# otherRaisedStreet1=[] -# otherRaisedStreet2=[] -# otherRaisedStreet3=[] -# otherRaisedStreet4=[] -# foldToOtherRaisedStreet1=[] -# foldToOtherRaisedStreet2=[] -# foldToOtherRaisedStreet3=[] -# foldToOtherRaisedStreet4=[] -# wonWhenSeenStreet1=[] -# -# wonAtSD=[] -# stealAttemptChance=[] -# stealAttempted=[] -# hudDataPositions=[] -# -# street0Calls=[] -# street1Calls=[] -# street2Calls=[] -# street3Calls=[] -# street4Calls=[] -# street0Bets=[] -# street1Bets=[] -# street2Bets=[] -# street3Bets=[] -# street4Bets=[] -# #street0Raises=[] -# #street1Raises=[] -# #street2Raises=[] -# #street3Raises=[] -# #street4Raises=[] -# -# # Summary figures for hand table: -# result={} -# result['playersVpi']=0 -# result['playersAtStreet1']=0 -# result['playersAtStreet2']=0 -# result['playersAtStreet3']=0 -# result['playersAtStreet4']=0 -# result['playersAtShowdown']=0 -# result['street0Raises']=0 -# result['street1Raises']=0 -# result['street2Raises']=0 -# result['street3Raises']=0 -# result['street4Raises']=0 -# result['street1Pot']=0 -# result['street2Pot']=0 -# result['street3Pot']=0 -# result['street4Pot']=0 -# result['showdownPot']=0 -# -# firstPfRaiseByNo=-1 -# firstPfRaiserId=-1 -# firstPfRaiserNo=-1 -# firstPfCallByNo=-1 -# firstPfCallerId=-1 -# -# for i, action in enumerate(actionTypeByNo[0]): -# if action[1] == "bet": -# firstPfRaiseByNo = i -# firstPfRaiserId = action[0] -# for j, pid in enumerate(player_ids): -# if pid == firstPfRaiserId: -# firstPfRaiserNo = j -# break -# break -# for i, action in enumerate(actionTypeByNo[0]): -# if action[1] == "call": -# firstPfCallByNo = i -# firstPfCallerId = action[0] -# break -# firstPlayId = firstPfCallerId -# if firstPfRaiseByNo <> -1: -# if firstPfRaiseByNo < firstPfCallByNo or firstPfCallByNo == -1: -# firstPlayId = firstPfRaiserId -# -# -# cutoffId=-1 -# buttonId=-1 -# sbId=-1 -# bbId=-1 -# if base=="hold": -# for player, pos in enumerate(positions): -# if pos == 1: -# cutoffId = player_ids[player] -# if pos == 0: -# buttonId = player_ids[player] -# if pos == 'S': -# sbId = player_ids[player] -# if pos == 'B': -# bbId = player_ids[player] -# -# someoneStole=False -# -# #run a loop for each player preparing the actual values that will be commited to SQL -# for player in xrange(len(player_ids)): -# #set default values -# myStreet0VPI=False -# myStreet0Aggr=False -# myStreet0_3BChance=False -# myStreet0_3BDone=False -# myStreet1Seen=False -# myStreet2Seen=False -# myStreet3Seen=False -# myStreet4Seen=False -# mySawShowdown=False -# myStreet1Aggr=False -# myStreet2Aggr=False -# myStreet3Aggr=False -# myStreet4Aggr=False -# myOtherRaisedStreet1=False -# myOtherRaisedStreet2=False -# myOtherRaisedStreet3=False -# myOtherRaisedStreet4=False -# myFoldToOtherRaisedStreet1=False -# myFoldToOtherRaisedStreet2=False -# myFoldToOtherRaisedStreet3=False -# myFoldToOtherRaisedStreet4=False -# myWonWhenSeenStreet1=0.0 -# myWonAtSD=0.0 -# myStealAttemptChance=False -# myStealAttempted=False -# myStreet0Calls=0 -# myStreet1Calls=0 -# myStreet2Calls=0 -# myStreet3Calls=0 -# myStreet4Calls=0 -# myStreet0Bets=0 -# myStreet1Bets=0 -# myStreet2Bets=0 -# myStreet3Bets=0 -# myStreet4Bets=0 -# #myStreet0Raises=0 -# #myStreet1Raises=0 -# #myStreet2Raises=0 -# #myStreet3Raises=0 -# #myStreet4Raises=0 -# -# #calculate VPIP and PFR -# street=0 -# heroPfRaiseCount=0 -# for currentAction in action_types[street][player]: # finally individual actions -# if currentAction == "bet": -# myStreet0Aggr = True -# if currentAction == "bet" or currentAction == "call": -# myStreet0VPI = True -# -# if myStreet0VPI: -# result['playersVpi'] += 1 -# myStreet0Calls = action_types[street][player].count('call') -# myStreet0Bets = action_types[street][player].count('bet') -# # street0Raises = action_types[street][player].count('raise') bet count includes raises for now -# result['street0Raises'] += myStreet0Bets -# -# #PF3BChance and PF3B -# pfFold=-1 -# pfRaise=-1 -# if firstPfRaiseByNo != -1: -# for i, actionType in enumerate(actionTypeByNo[0]): -# if actionType[0] == player_ids[player]: -# if actionType[1] == "bet" and pfRaise == -1 and i > firstPfRaiseByNo: -# pfRaise = i -# if actionType[1] == "fold" and pfFold == -1: -# pfFold = i -# if pfFold == -1 or pfFold > firstPfRaiseByNo: -# myStreet0_3BChance = True -# if pfRaise > firstPfRaiseByNo: -# myStreet0_3BDone = True -# -# #steal calculations -# if base=="hold": -# if len(player_ids)>=3: # no point otherwise # was 5, use 3 to match pokertracker definition -# if positions[player]==1: -# if firstPfRaiserId==player_ids[player] \ -# and (firstPfCallByNo==-1 or firstPfCallByNo>firstPfRaiseByNo): -# myStealAttempted=True -# myStealAttemptChance=True -# if firstPlayId==cutoffId or firstPlayId==buttonId or firstPlayId==sbId or firstPlayId==bbId or firstPlayId==-1: -# myStealAttemptChance=True -# if positions[player]==0: -# if firstPfRaiserId==player_ids[player] \ -# and (firstPfCallByNo==-1 or firstPfCallByNo>firstPfRaiseByNo): -# myStealAttempted=True -# myStealAttemptChance=True -# if firstPlayId==buttonId or firstPlayId==sbId or firstPlayId==bbId or firstPlayId==-1: -# myStealAttemptChance=True -# if positions[player]=='S': -# if firstPfRaiserId==player_ids[player] \ -# and (firstPfCallByNo==-1 or firstPfCallByNo>firstPfRaiseByNo): -# myStealAttempted=True -# myStealAttemptChance=True -# if firstPlayId==sbId or firstPlayId==bbId or firstPlayId==-1: -# myStealAttemptChance=True -# if positions[player]=='B': -# pass -# -# if myStealAttempted: -# someoneStole=True -# -# -# #calculate saw* values -# isAllIn = False -# if any(i for i in allIns[0][player]): -# isAllIn = True -# if (len(action_types[1][player])>0 or isAllIn): -# myStreet1Seen = True -# -# if any(i for i in allIns[1][player]): -# isAllIn = True -# if (len(action_types[2][player])>0 or isAllIn): -# myStreet2Seen = True -# -# if any(i for i in allIns[2][player]): -# isAllIn = True -# if (len(action_types[3][player])>0 or isAllIn): -# myStreet3Seen = True -# -# #print "base:", base -# if base=="hold": -# mySawShowdown = True -# if any(actiontype == "fold" for actiontype in action_types[3][player]): -# mySawShowdown = False -# else: -# #print "in else" -# if any(i for i in allIns[3][player]): -# isAllIn = True -# if (len(action_types[4][player])>0 or isAllIn): -# #print "in if" -# myStreet4Seen = True -# -# mySawShowdown = True -# if any(actiontype == "fold" for actiontype in action_types[4][player]): -# mySawShowdown = False -# -# if myStreet1Seen: -# result['playersAtStreet1'] += 1 -# if myStreet2Seen: -# result['playersAtStreet2'] += 1 -# if myStreet3Seen: -# result['playersAtStreet3'] += 1 -# if myStreet4Seen: -# result['playersAtStreet4'] += 1 -# if mySawShowdown: -# result['playersAtShowdown'] += 1 -# -# #flop stuff -# street=1 -# if myStreet1Seen: -# if any(actiontype == "bet" for actiontype in action_types[street][player]): -# myStreet1Aggr = True -# -# myStreet1Calls = action_types[street][player].count('call') -# myStreet1Bets = action_types[street][player].count('bet') -# # street1Raises = action_types[street][player].count('raise') bet count includes raises for now -# result['street1Raises'] += myStreet1Bets -# -# for otherPlayer in xrange(len(player_ids)): -# if player==otherPlayer: -# pass -# else: -# for countOther in xrange(len(action_types[street][otherPlayer])): -# if action_types[street][otherPlayer][countOther]=="bet": -# myOtherRaisedStreet1=True -# for countOtherFold in xrange(len(action_types[street][player])): -# if action_types[street][player][countOtherFold]=="fold": -# myFoldToOtherRaisedStreet1=True -# -# #turn stuff - copy of flop with different vars -# street=2 -# if myStreet2Seen: -# if any(actiontype == "bet" for actiontype in action_types[street][player]): -# myStreet2Aggr = True -# -# myStreet2Calls = action_types[street][player].count('call') -# myStreet2Bets = action_types[street][player].count('bet') -# # street2Raises = action_types[street][player].count('raise') bet count includes raises for now -# result['street2Raises'] += myStreet2Bets -# -# for otherPlayer in xrange(len(player_ids)): -# if player==otherPlayer: -# pass -# else: -# for countOther in xrange(len(action_types[street][otherPlayer])): -# if action_types[street][otherPlayer][countOther]=="bet": -# myOtherRaisedStreet2=True -# for countOtherFold in xrange(len(action_types[street][player])): -# if action_types[street][player][countOtherFold]=="fold": -# myFoldToOtherRaisedStreet2=True -# -# #river stuff - copy of flop with different vars -# street=3 -# if myStreet3Seen: -# if any(actiontype == "bet" for actiontype in action_types[street][player]): -# myStreet3Aggr = True -# -# myStreet3Calls = action_types[street][player].count('call') -# myStreet3Bets = action_types[street][player].count('bet') -# # street3Raises = action_types[street][player].count('raise') bet count includes raises for now -# result['street3Raises'] += myStreet3Bets -# -# for otherPlayer in xrange(len(player_ids)): -# if player==otherPlayer: -# pass -# else: -# for countOther in xrange(len(action_types[street][otherPlayer])): -# if action_types[street][otherPlayer][countOther]=="bet": -# myOtherRaisedStreet3=True -# for countOtherFold in xrange(len(action_types[street][player])): -# if action_types[street][player][countOtherFold]=="fold": -# myFoldToOtherRaisedStreet3=True -# -# #stud river stuff - copy of flop with different vars -# street=4 -# if myStreet4Seen: -# if any(actiontype == "bet" for actiontype in action_types[street][player]): -# myStreet4Aggr=True -# -# myStreet4Calls = action_types[street][player].count('call') -# myStreet4Bets = action_types[street][player].count('bet') -# # street4Raises = action_types[street][player].count('raise') bet count includes raises for now -# result['street4Raises'] += myStreet4Bets -# -# for otherPlayer in xrange(len(player_ids)): -# if player==otherPlayer: -# pass -# else: -# for countOther in xrange(len(action_types[street][otherPlayer])): -# if action_types[street][otherPlayer][countOther]=="bet": -# myOtherRaisedStreet4=True -# for countOtherFold in xrange(len(action_types[street][player])): -# if action_types[street][player][countOtherFold]=="fold": -# myFoldToOtherRaisedStreet4=True -# -# if winnings[player] != 0: -# if myStreet1Seen: -# myWonWhenSeenStreet1 = winnings[player] / float(totalWinnings) -# if mySawShowdown: -# myWonAtSD=myWonWhenSeenStreet1 -# -# #add each value to the appropriate array -# street0VPI.append(myStreet0VPI) -# street0Aggr.append(myStreet0Aggr) -# street0_3BChance.append(myStreet0_3BChance) -# street0_3BDone.append(myStreet0_3BDone) -# street1Seen.append(myStreet1Seen) -# street2Seen.append(myStreet2Seen) -# street3Seen.append(myStreet3Seen) -# street4Seen.append(myStreet4Seen) -# sawShowdown.append(mySawShowdown) -# street1Aggr.append(myStreet1Aggr) -# street2Aggr.append(myStreet2Aggr) -# street3Aggr.append(myStreet3Aggr) -# street4Aggr.append(myStreet4Aggr) -# otherRaisedStreet1.append(myOtherRaisedStreet1) -# otherRaisedStreet2.append(myOtherRaisedStreet2) -# otherRaisedStreet3.append(myOtherRaisedStreet3) -# otherRaisedStreet4.append(myOtherRaisedStreet4) -# foldToOtherRaisedStreet1.append(myFoldToOtherRaisedStreet1) -# foldToOtherRaisedStreet2.append(myFoldToOtherRaisedStreet2) -# foldToOtherRaisedStreet3.append(myFoldToOtherRaisedStreet3) -# foldToOtherRaisedStreet4.append(myFoldToOtherRaisedStreet4) -# wonWhenSeenStreet1.append(myWonWhenSeenStreet1) -# wonAtSD.append(myWonAtSD) -# stealAttemptChance.append(myStealAttemptChance) -# stealAttempted.append(myStealAttempted) -# if base=="hold": -# pos=positions[player] -# if pos=='B': -# hudDataPositions.append('B') -# elif pos=='S': -# hudDataPositions.append('S') -# elif pos==0: -# hudDataPositions.append('D') -# elif pos==1: -# hudDataPositions.append('C') -# elif pos>=2 and pos<=4: -# hudDataPositions.append('M') -# elif pos>=5 and pos<=8: -# hudDataPositions.append('E') -# ### RHH Added this elif to handle being a dead hand before the BB (pos==9) -# elif pos==9: -# hudDataPositions.append('X') -# else: -# raise FpdbError("invalid position") -# elif base=="stud": -# #todo: stud positions and steals -# pass -# -# street0Calls.append(myStreet0Calls) -# street1Calls.append(myStreet1Calls) -# street2Calls.append(myStreet2Calls) -# street3Calls.append(myStreet3Calls) -# street4Calls.append(myStreet4Calls) -# street0Bets.append(myStreet0Bets) -# street1Bets.append(myStreet1Bets) -# street2Bets.append(myStreet2Bets) -# street3Bets.append(myStreet3Bets) -# street4Bets.append(myStreet4Bets) -# #street0Raises.append(myStreet0Raises) -# #street1Raises.append(myStreet1Raises) -# #street2Raises.append(myStreet2Raises) -# #street3Raises.append(myStreet3Raises) -# #street4Raises.append(myStreet4Raises) -# -# #add each array to the to-be-returned dictionary -# result['street0VPI']=street0VPI -# result['street0Aggr']=street0Aggr -# result['street0_3BChance']=street0_3BChance -# result['street0_3BDone']=street0_3BDone -# result['street1Seen']=street1Seen -# result['street2Seen']=street2Seen -# result['street3Seen']=street3Seen -# result['street4Seen']=street4Seen -# result['sawShowdown']=sawShowdown -# -# result['street1Aggr']=street1Aggr -# result['otherRaisedStreet1']=otherRaisedStreet1 -# result['foldToOtherRaisedStreet1']=foldToOtherRaisedStreet1 -# result['street2Aggr']=street2Aggr -# result['otherRaisedStreet2']=otherRaisedStreet2 -# result['foldToOtherRaisedStreet2']=foldToOtherRaisedStreet2 -# result['street3Aggr']=street3Aggr -# result['otherRaisedStreet3']=otherRaisedStreet3 -# result['foldToOtherRaisedStreet3']=foldToOtherRaisedStreet3 -# result['street4Aggr']=street4Aggr -# result['otherRaisedStreet4']=otherRaisedStreet4 -# result['foldToOtherRaisedStreet4']=foldToOtherRaisedStreet4 -# result['wonWhenSeenStreet1']=wonWhenSeenStreet1 -# result['wonAtSD']=wonAtSD -# result['stealAttemptChance']=stealAttemptChance -# result['stealAttempted']=stealAttempted -# result['street0Calls']=street0Calls -# result['street1Calls']=street1Calls -# result['street2Calls']=street2Calls -# result['street3Calls']=street3Calls -# result['street4Calls']=street4Calls -# result['street0Bets']=street0Bets -# result['street1Bets']=street1Bets -# result['street2Bets']=street2Bets -# result['street3Bets']=street3Bets -# result['street4Bets']=street4Bets -# #result['street0Raises']=street0Raises -# #result['street1Raises']=street1Raises -# #result['street2Raises']=street2Raises -# #result['street3Raises']=street3Raises -# #result['street4Raises']=street4Raises -# -# #now the various steal values -# foldBbToStealChance=[] -# foldedBbToSteal=[] -# foldSbToStealChance=[] -# foldedSbToSteal=[] -# for player in xrange(len(player_ids)): -# myFoldBbToStealChance=False -# myFoldedBbToSteal=False -# myFoldSbToStealChance=False -# myFoldedSbToSteal=False -# -# if base=="hold": -# if someoneStole and (positions[player]=='B' or positions[player]=='S') and firstPfRaiserId!=player_ids[player]: -# street=0 -# for count in xrange(len(action_types[street][player])):#individual actions -# if positions[player]=='B': -# myFoldBbToStealChance=True -# if action_types[street][player][count]=="fold": -# myFoldedBbToSteal=True -# if positions[player]=='S': -# myFoldSbToStealChance=True -# if action_types[street][player][count]=="fold": -# myFoldedSbToSteal=True -# -# -# foldBbToStealChance.append(myFoldBbToStealChance) -# foldedBbToSteal.append(myFoldedBbToSteal) -# foldSbToStealChance.append(myFoldSbToStealChance) -# foldedSbToSteal.append(myFoldedSbToSteal) -# result['foldBbToStealChance']=foldBbToStealChance -# result['foldedBbToSteal']=foldedBbToSteal -# result['foldSbToStealChance']=foldSbToStealChance -# result['foldedSbToSteal']=foldedSbToSteal -# -# #now CB -# street1CBChance=[] -# street1CBDone=[] -# didStreet1CB=[] -# for player in xrange(len(player_ids)): -# myStreet1CBChance=False -# myStreet1CBDone=False -# -# if street0VPI[player]: -# myStreet1CBChance=True -# if street1Aggr[player]: -# myStreet1CBDone=True -# didStreet1CB.append(player_ids[player]) -# -# street1CBChance.append(myStreet1CBChance) -# street1CBDone.append(myStreet1CBDone) -# result['street1CBChance']=street1CBChance -# result['street1CBDone']=street1CBDone -# -# #now 2B -# street2CBChance=[] -# street2CBDone=[] -# didStreet2CB=[] -# for player in xrange(len(player_ids)): -# myStreet2CBChance=False -# myStreet2CBDone=False -# -# if street1CBDone[player]: -# myStreet2CBChance=True -# if street2Aggr[player]: -# myStreet2CBDone=True -# didStreet2CB.append(player_ids[player]) -# -# street2CBChance.append(myStreet2CBChance) -# street2CBDone.append(myStreet2CBDone) -# result['street2CBChance']=street2CBChance -# result['street2CBDone']=street2CBDone -# -# #now 3B -# street3CBChance=[] -# street3CBDone=[] -# didStreet3CB=[] -# for player in xrange(len(player_ids)): -# myStreet3CBChance=False -# myStreet3CBDone=False -# -# if street2CBDone[player]: -# myStreet3CBChance=True -# if street3Aggr[player]: -# myStreet3CBDone=True -# didStreet3CB.append(player_ids[player]) -# -# street3CBChance.append(myStreet3CBChance) -# street3CBDone.append(myStreet3CBDone) -# result['street3CBChance']=street3CBChance -# result['street3CBDone']=street3CBDone -# -# #and 4B -# street4CBChance=[] -# street4CBDone=[] -# didStreet4CB=[] -# for player in xrange(len(player_ids)): -# myStreet4CBChance=False -# myStreet4CBDone=False -# -# if street3CBDone[player]: -# myStreet4CBChance=True -# if street4Aggr[player]: -# myStreet4CBDone=True -# didStreet4CB.append(player_ids[player]) -# -# street4CBChance.append(myStreet4CBChance) -# street4CBDone.append(myStreet4CBDone) -# result['street4CBChance']=street4CBChance -# result['street4CBDone']=street4CBDone -# -# -# result['position']=hudDataPositions -# -# foldToStreet1CBChance=[] -# foldToStreet1CBDone=[] -# foldToStreet2CBChance=[] -# foldToStreet2CBDone=[] -# foldToStreet3CBChance=[] -# foldToStreet3CBDone=[] -# foldToStreet4CBChance=[] -# foldToStreet4CBDone=[] -# -# for player in xrange(len(player_ids)): -# myFoldToStreet1CBChance=False -# myFoldToStreet1CBDone=False -# foldToStreet1CBChance.append(myFoldToStreet1CBChance) -# foldToStreet1CBDone.append(myFoldToStreet1CBDone) -# -# myFoldToStreet2CBChance=False -# myFoldToStreet2CBDone=False -# foldToStreet2CBChance.append(myFoldToStreet2CBChance) -# foldToStreet2CBDone.append(myFoldToStreet2CBDone) -# -# myFoldToStreet3CBChance=False -# myFoldToStreet3CBDone=False -# foldToStreet3CBChance.append(myFoldToStreet3CBChance) -# foldToStreet3CBDone.append(myFoldToStreet3CBDone) -# -# myFoldToStreet4CBChance=False -# myFoldToStreet4CBDone=False -# foldToStreet4CBChance.append(myFoldToStreet4CBChance) -# foldToStreet4CBDone.append(myFoldToStreet4CBDone) -# -# if len(didStreet1CB)>=1: -# generateFoldToCB(1, player_ids, didStreet1CB, street1CBDone, foldToStreet1CBChance, foldToStreet1CBDone, actionTypeByNo) -# -# if len(didStreet2CB)>=1: -# generateFoldToCB(2, player_ids, didStreet2CB, street2CBDone, foldToStreet2CBChance, foldToStreet2CBDone, actionTypeByNo) -# -# if len(didStreet3CB)>=1: -# generateFoldToCB(3, player_ids, didStreet3CB, street3CBDone, foldToStreet3CBChance, foldToStreet3CBDone, actionTypeByNo) -# -# if len(didStreet4CB)>=1: -# generateFoldToCB(4, player_ids, didStreet4CB, street4CBDone, foldToStreet4CBChance, foldToStreet4CBDone, actionTypeByNo) -# -# result['foldToStreet1CBChance']=foldToStreet1CBChance -# result['foldToStreet1CBDone']=foldToStreet1CBDone -# result['foldToStreet2CBChance']=foldToStreet2CBChance -# result['foldToStreet2CBDone']=foldToStreet2CBDone -# result['foldToStreet3CBChance']=foldToStreet3CBChance -# result['foldToStreet3CBDone']=foldToStreet3CBDone -# result['foldToStreet4CBChance']=foldToStreet4CBChance -# result['foldToStreet4CBDone']=foldToStreet4CBDone -# -# -# totalProfit=[] -# -# street1CheckCallRaiseChance=[] -# street1CheckCallRaiseDone=[] -# street2CheckCallRaiseChance=[] -# street2CheckCallRaiseDone=[] -# street3CheckCallRaiseChance=[] -# street3CheckCallRaiseDone=[] -# street4CheckCallRaiseChance=[] -# street4CheckCallRaiseDone=[] -# #print "b4 totprof calc, len(playerIds)=", len(player_ids) -# for pl in xrange(len(player_ids)): -# #print "pl=", pl -# myTotalProfit=winnings[pl] # still need to deduct other costs -# if antes: -# myTotalProfit=winnings[pl] - antes[pl] -# for i in xrange(len(actionTypes)): #iterate through streets -# #for j in xrange(len(actionTypes[i])): #iterate through names (using pl loop above) -# for k in xrange(len(actionTypes[i][pl])): #iterate through individual actions of that player on that street -# myTotalProfit -= actionAmounts[i][pl][k] -# -# myStreet1CheckCallRaiseChance=False -# myStreet1CheckCallRaiseDone=False -# myStreet2CheckCallRaiseChance=False -# myStreet2CheckCallRaiseDone=False -# myStreet3CheckCallRaiseChance=False -# myStreet3CheckCallRaiseDone=False -# myStreet4CheckCallRaiseChance=False -# myStreet4CheckCallRaiseDone=False -# -# #print "myTotalProfit=", myTotalProfit -# totalProfit.append(myTotalProfit) -# #print "totalProfit[]=", totalProfit -# -# street1CheckCallRaiseChance.append(myStreet1CheckCallRaiseChance) -# street1CheckCallRaiseDone.append(myStreet1CheckCallRaiseDone) -# street2CheckCallRaiseChance.append(myStreet2CheckCallRaiseChance) -# street2CheckCallRaiseDone.append(myStreet2CheckCallRaiseDone) -# street3CheckCallRaiseChance.append(myStreet3CheckCallRaiseChance) -# street3CheckCallRaiseDone.append(myStreet3CheckCallRaiseDone) -# street4CheckCallRaiseChance.append(myStreet4CheckCallRaiseChance) -# street4CheckCallRaiseDone.append(myStreet4CheckCallRaiseDone) -# -# result['totalProfit']=totalProfit -# #print "res[totalProfit]=", result['totalProfit'] -# -# result['street1CheckCallRaiseChance']=street1CheckCallRaiseChance -# result['street1CheckCallRaiseDone']=street1CheckCallRaiseDone -# result['street2CheckCallRaiseChance']=street2CheckCallRaiseChance -# result['street2CheckCallRaiseDone']=street2CheckCallRaiseDone -# result['street3CheckCallRaiseChance']=street3CheckCallRaiseChance -# result['street3CheckCallRaiseDone']=street3CheckCallRaiseDone -# result['street4CheckCallRaiseChance']=street4CheckCallRaiseChance -# result['street4CheckCallRaiseDone']=street4CheckCallRaiseDone -# return result -# #end def generateHudCacheData pass def vpip(self, hand): @@ -834,14 +162,19 @@ class DerivedStats(): self.hands['playersAtStreet4'] = 0 self.hands['playersAtShowdown'] = 0 + alliners = set() for (i, street) in enumerate(hand.actionStreets[2:]): - actors = {} - for act in hand.actions[street]: - actors[act[0]] = 1 - self.hands['playersAtStreet%s' % str(i+1)] = len(actors.keys()) - - #Need playersAtShowdown + actors = set() + for action in hand.actions[street]: + if len(action) > 2 and action[-1]: # allin + alliners.add(action[0]) + actors.add(action[0]) + if len(actors)==0 and len(alliners)<2: + alliners = set() + self.hands['playersAtStreet%d' % (i+1)] = len(set.union(alliners, actors)) + actions = hand.actions[hand.actionStreets[-1]] + self.hands['playersAtShowdown'] = len(set.union(self.pfba(actions) - self.pfba(actions, l=('folds',)), alliners)) def streetXRaises(self, hand): # self.actions[street] is a list of all actions in a tuple, contining the action as the second element @@ -849,11 +182,11 @@ class DerivedStats(): # No idea what this value is actually supposed to be # In theory its "num small bets paid to see flop/street4, including blind" which makes sense for limit. Not so useful for nl # Leaving empty for the moment, - self.hands['street0Raises'] = 0 # /* num small bets paid to see flop/street4, including blind */ - self.hands['street1Raises'] = 0 # /* num small bets paid to see turn/street5 */ - self.hands['street2Raises'] = 0 # /* num big bets paid to see river/street6 */ - self.hands['street3Raises'] = 0 # /* num big bets paid to see sd/street7 */ - self.hands['street4Raises'] = 0 # /* num big bets paid to see showdown */ + + for i in range(5): self.hands['street%dRaises' % i] = 0 + + for (i, street) in enumerate(hand.actionStreets[1:]): + self.hands['street%dRaises' % i] = len(filter( lambda action: action[1] in ('raises','bets'), hand.actions[street])) def seen(self, hand, i): pas = set() @@ -880,3 +213,16 @@ class DerivedStats(): def countPlayers(self, hand): pass + + def pfba(self, actions, f=None, l=None): + """Helper method. Returns set of PlayersFilteredByActions + + f - forbidden actions + l - limited to actions + """ + players = set() + for action in actions: + if l is not None and action[1] not in l: continue + if f is not None and action[1] in f: continue + players.add(action[0]) + return players diff --git a/pyfpdb/Exceptions.py b/pyfpdb/Exceptions.py index f7e9fa54..87015e3e 100644 --- a/pyfpdb/Exceptions.py +++ b/pyfpdb/Exceptions.py @@ -4,7 +4,7 @@ class FpdbError(Exception): def __str__(self): return repr(self.value) -class FpdbParseError(FpdbError): +class FpdbParseError(FpdbError): def __init__(self,value='',hid=''): self.value = value self.hid = hid @@ -17,8 +17,15 @@ class FpdbParseError(FpdbError): class FpdbDatabaseError(FpdbError): pass -class FpdbMySQLFailedError(FpdbDatabaseError): +class FpdbMySQLError(FpdbDatabaseError): pass +class FpdbMySQLAccessDenied(FpdbDatabaseError): + def __init__(self, value='', errmsg=''): + self.value = value + self.errmsg = errmsg + def __str__(self): + return repr(self.value +" " + self.errmsg) + class DuplicateError(FpdbError): pass diff --git a/pyfpdb/GuiBulkImport.py b/pyfpdb/GuiBulkImport.py index 3300b73f..ec262b08 100755 --- a/pyfpdb/GuiBulkImport.py +++ b/pyfpdb/GuiBulkImport.py @@ -53,7 +53,7 @@ class GuiBulkImport(): # Does the lock acquisition need to be more sophisticated for multiple dirs? # (see comment above about what to do if pipe already open) if self.settings['global_lock'].acquire(False): # returns false immediately if lock not acquired - try: + #try: print "\nGlobal lock taken ..." self.progressbar.set_text("Importing...") self.progressbar.pulse() @@ -116,10 +116,11 @@ class GuiBulkImport(): self.progressbar.set_text("Import Complete") self.progressbar.set_fraction(0) - except: - err = traceback.extract_tb(sys.exc_info()[2])[-1] - print "*** BulkImport Error: "+err[2]+"("+str(err[1])+"): "+str(sys.exc_info()[1]) - self.settings['global_lock'].release() + #except: + #err = traceback.extract_tb(sys.exc_info()[2])[-1] + #print "*** BulkImport Error: "+err[2]+"("+str(err[1])+"): "+str(sys.exc_info()[1]) + #self.settings['global_lock'].release() + self.settings['global_lock'].release() else: print "bulk-import aborted - global lock not available" diff --git a/pyfpdb/GuiGraphViewer.py b/pyfpdb/GuiGraphViewer.py index 670554e7..e6d0c6d2 100644 --- a/pyfpdb/GuiGraphViewer.py +++ b/pyfpdb/GuiGraphViewer.py @@ -216,6 +216,7 @@ class GuiGraphViewer (threading.Thread): #nametest = nametest.replace("L", "") lims = [int(x) for x in limits if x.isdigit()] + potlims = [int(x[0:-2]) for x in limits if len(x) > 2 and x[-2:] == 'pl'] nolims = [int(x[0:-2]) for x in limits if len(x) > 2 and x[-2:] == 'nl'] limittest = "and ( (gt.limitType = 'fl' and gt.bigBlind in " # and ( (limit and bb in()) or (nolimit and bb in ()) ) @@ -226,6 +227,14 @@ class GuiGraphViewer (threading.Thread): limittest = limittest + blindtest + ' ) ' else: limittest = limittest + '(-1) ) ' + limittest = limittest + " or (gt.limitType = 'pl' and gt.bigBlind in " + if potlims: + blindtest = str(tuple(potlims)) + blindtest = blindtest.replace("L", "") + blindtest = blindtest.replace(",)",")") + limittest = limittest + blindtest + ' ) ' + else: + limittest = limittest + '(-1) ) ' limittest = limittest + " or (gt.limitType = 'nl' and gt.bigBlind in " if nolims: blindtest = str(tuple(nolims)) @@ -234,6 +243,7 @@ class GuiGraphViewer (threading.Thread): limittest = limittest + blindtest + ' ) )' else: limittest = limittest + '(-1) ) )' + if type == 'ring': limittest = limittest + " and gt.type = 'ring' " elif type == 'tour': diff --git a/pyfpdb/GuiPlayerStats.py b/pyfpdb/GuiPlayerStats.py index 8b5f1f05..d65b9ab6 100644 --- a/pyfpdb/GuiPlayerStats.py +++ b/pyfpdb/GuiPlayerStats.py @@ -480,6 +480,7 @@ class GuiPlayerStats (threading.Thread): query = query.replace('', '') lims = [int(x) for x in limits if x.isdigit()] + potlims = [int(x[0:-2]) for x in limits if len(x) > 2 and x[-2:] == 'pl'] nolims = [int(x[0:-2]) for x in limits if len(x) > 2 and x[-2:] == 'nl'] bbtest = "and ( (gt.limitType = 'fl' and gt.bigBlind in " # and ( (limit and bb in()) or (nolimit and bb in ()) ) @@ -490,6 +491,14 @@ class GuiPlayerStats (threading.Thread): bbtest = bbtest + blindtest + ' ) ' else: bbtest = bbtest + '(-1) ) ' + bbtest = bbtest + " or (gt.limitType = 'pl' and gt.bigBlind in " + if potlims: + blindtest = str(tuple(potlims)) + blindtest = blindtest.replace("L", "") + blindtest = blindtest.replace(",)",")") + bbtest = bbtest + blindtest + ' ) ' + else: + bbtest = bbtest + '(-1) ) ' bbtest = bbtest + " or (gt.limitType = 'nl' and gt.bigBlind in " if nolims: blindtest = str(tuple(nolims)) @@ -544,7 +553,7 @@ class GuiPlayerStats (threading.Thread): # set flag in self.columns to show posn column [x for x in self.columns if x[0] == 'plposition'][0][1] = True else: - query = query.replace("", "'1'") + query = query.replace("", "gt.base") # unset flag in self.columns to hide posn column [x for x in self.columns if x[0] == 'plposition'][0][1] = False diff --git a/pyfpdb/HUD_config.xml.example b/pyfpdb/HUD_config.xml.example index 952a0dbf..b0f26c53 100644 --- a/pyfpdb/HUD_config.xml.example +++ b/pyfpdb/HUD_config.xml.example @@ -4,91 +4,95 @@ - [0-9]+):\s+ (Tournament\s\# # open paren of tournament info (?P\d+),\s @@ -62,7 +62,7 @@ class PokerStars(HandHistoryConverter): (?P.*$)""" % substitutions, re.MULTILINE|re.VERBOSE) - re_PlayerInfo = re.compile(""" + re_PlayerInfo = re.compile(u""" ^Seat\s(?P[0-9]+):\s (?P.*)\s \((%(LS)s)?(?P[.0-9]+)\sin\schips\)""" % substitutions, @@ -373,12 +373,9 @@ if __name__ == "__main__": parser.add_option("-i", "--input", dest="ipath", help="parse input hand history", default="regression-test-files/stars/horse/HH20090226 Natalie V - $0.10-$0.20 - HORSE.txt") parser.add_option("-o", "--output", dest="opath", help="output translation to", default="-") parser.add_option("-f", "--follow", dest="follow", help="follow (tail -f) the input", action="store_true", default=False) - parser.add_option("-q", "--quiet", - action="store_const", const=logging.CRITICAL, dest="verbosity", default=logging.INFO) - parser.add_option("-v", "--verbose", - action="store_const", const=logging.INFO, dest="verbosity") - parser.add_option("--vv", - action="store_const", const=logging.DEBUG, dest="verbosity") + #parser.add_option("-q", "--quiet", action="store_const", const=logging.CRITICAL, dest="verbosity", default=logging.INFO) + #parser.add_option("-v", "--verbose", action="store_const", const=logging.INFO, dest="verbosity") + #parser.add_option("--vv", action="store_const", const=logging.DEBUG, dest="verbosity") (options, args) = parser.parse_args() diff --git a/pyfpdb/SQL.py b/pyfpdb/SQL.py index 3846a371..9c74e1f1 100644 --- a/pyfpdb/SQL.py +++ b/pyfpdb/SQL.py @@ -1940,7 +1940,7 @@ class Sql: and h.seats - and to_char(h.handStart, 'YYYY-MM-DD') + and date(h.handStart) group by hgameTypeId ,hp.playerId ,gt.base @@ -1960,272 +1960,7 @@ class Sql: end ,upper(gt.limitType) desc - ,maxbigblind desc - ,s.name - """ - - if db_server == 'mysql': - self.query['playerStats'] = """ - SELECT - concat(upper(stats.limitType), ' ' - ,concat(upper(substring(stats.category,1,1)),substring(stats.category,2) ), ' ' - ,stats.name, ' ' - ,cast(stats.bigBlindDesc as char) - ) AS Game - ,stats.n - ,stats.vpip - ,stats.pfr - ,stats.pf3 - ,stats.steals - ,stats.saw_f - ,stats.sawsd - ,stats.wtsdwsf - ,stats.wmsd - ,stats.FlAFq - ,stats.TuAFq - ,stats.RvAFq - ,stats.PoFAFq - ,stats.Net - ,stats.BBper100 - ,stats.Profitperhand - ,case when hprof2.variance = -999 then '-' - else format(hprof2.variance, 2) - end AS Variance - ,stats.AvgSeats - FROM - (select /* stats from hudcache */ - gt.base - ,gt.category - ,upper(gt.limitType) as limitType - ,s.name - , AS bigBlindDesc - , AS gtId - ,sum(HDs) AS n - ,format(100.0*sum(street0VPI)/sum(HDs),1) AS vpip - ,format(100.0*sum(street0Aggr)/sum(HDs),1) AS pfr - ,case when sum(street0_3Bchance) = 0 then '0' - else format(100.0*sum(street0_3Bdone)/sum(street0_3Bchance),1) - end AS pf3 - ,case when sum(stealattemptchance) = 0 then '-' - else format(100.0*sum(stealattempted)/sum(stealattemptchance),1) - end AS steals - ,format(100.0*sum(street1Seen)/sum(HDs),1) AS saw_f - ,format(100.0*sum(sawShowdown)/sum(HDs),1) AS sawsd - ,case when sum(street1Seen) = 0 then '-' - else format(100.0*sum(sawShowdown)/sum(street1Seen),1) - end AS wtsdwsf - ,case when sum(sawShowdown) = 0 then '-' - else format(100.0*sum(wonAtSD)/sum(sawShowdown),1) - end AS wmsd - ,case when sum(street1Seen) = 0 then '-' - else format(100.0*sum(street1Aggr)/sum(street1Seen),1) - end AS FlAFq - ,case when sum(street2Seen) = 0 then '-' - else format(100.0*sum(street2Aggr)/sum(street2Seen),1) - end AS TuAFq - ,case when sum(street3Seen) = 0 then '-' - else format(100.0*sum(street3Aggr)/sum(street3Seen),1) - end AS RvAFq - ,case when sum(street1Seen)+sum(street2Seen)+sum(street3Seen) = 0 then '-' - else format(100.0*(sum(street1Aggr)+sum(street2Aggr)+sum(street3Aggr)) - /(sum(street1Seen)+sum(street2Seen)+sum(street3Seen)),1) - end AS PoFAFq - ,format(sum(totalProfit)/100.0,2) AS Net - ,format((sum(totalProfit/(gt.bigBlind+0.0))) / (sum(HDs)/100.0),2) - AS BBper100 - ,format( (sum(totalProfit)/100.0) / sum(HDs), 4) AS Profitperhand - ,format( sum(activeSeats*HDs)/(sum(HDs)+0.0), 2) AS AvgSeats - from Gametypes gt - inner join Sites s on s.Id = gt.siteId - inner join HudCache hc on hc.gameTypeId = gt.Id - where hc.playerId in - and - and hc.activeSeats - and concat( '20', substring(hc.styleKey,2,2), '-', substring(hc.styleKey,4,2), '-' - , substring(hc.styleKey,6,2) ) - group by gt.base - ,gt.category - - ,plposition - ,upper(gt.limitType) - ,s.name - having 1 = 1 - order by pname - ,gt.base - ,gt.category - - ,case when 'B' then 'B' - when 'S' then 'S' - else concat('Z', ) - end - - ,upper(gt.limitType) desc - ,maxbigblind desc - ,s.name - """ - elif db_server == 'postgresql': - self.query['playerDetailedStats'] = """ - select AS hgametypeid - , AS pname - ,gt.base - ,gt.category - ,upper(gt.limitType) AS limittype - ,s.name - ,min(gt.bigBlind) AS minbigblind - ,max(gt.bigBlind) AS maxbigblind - /*, AS gtid*/ - , AS plposition - ,count(1) AS n - ,100.0*sum(cast(hp.street0VPI as integer))/count(1) AS vpip - ,100.0*sum(cast(hp.street0Aggr as integer))/count(1) AS pfr - ,case when sum(cast(hp.street0_3Bchance as integer)) = 0 then -999 - else 100.0*sum(cast(hp.street0_3Bdone as integer))/sum(cast(hp.street0_3Bchance as integer)) - end AS pf3 - ,case when sum(cast(hp.stealattemptchance as integer)) = 0 then -999 - else 100.0*sum(cast(hp.stealattempted as integer))/sum(cast(hp.stealattemptchance as integer)) - end AS steals - ,100.0*sum(cast(hp.street1Seen as integer))/count(1) AS saw_f - ,100.0*sum(cast(hp.sawShowdown as integer))/count(1) AS sawsd - ,case when sum(cast(hp.street1Seen as integer)) = 0 then -999 - else 100.0*sum(cast(hp.sawShowdown as integer))/sum(cast(hp.street1Seen as integer)) - end AS wtsdwsf - ,case when sum(cast(hp.sawShowdown as integer)) = 0 then -999 - else 100.0*sum(cast(hp.wonAtSD as integer))/sum(cast(hp.sawShowdown as integer)) - end AS wmsd - ,case when sum(cast(hp.street1Seen as integer)) = 0 then -999 - else 100.0*sum(cast(hp.street1Aggr as integer))/sum(cast(hp.street1Seen as integer)) - end AS flafq - ,case when sum(cast(hp.street2Seen as integer)) = 0 then -999 - else 100.0*sum(cast(hp.street2Aggr as integer))/sum(cast(hp.street2Seen as integer)) - end AS tuafq - ,case when sum(cast(hp.street3Seen as integer)) = 0 then -999 - else 100.0*sum(cast(hp.street3Aggr as integer))/sum(cast(hp.street3Seen as integer)) - end AS rvafq - ,case when sum(cast(hp.street1Seen as integer))+sum(cast(hp.street2Seen as integer))+sum(cast(hp.street3Seen as integer)) = 0 then -999 - else 100.0*(sum(cast(hp.street1Aggr as integer))+sum(cast(hp.street2Aggr as integer))+sum(cast(hp.street3Aggr as integer))) - /(sum(cast(hp.street1Seen as integer))+sum(cast(hp.street2Seen as integer))+sum(cast(hp.street3Seen as integer))) - end AS pofafq - ,sum(hp.totalProfit)/100.0 AS net - ,sum(hp.rake)/100.0 AS rake - ,100.0*avg(hp.totalProfit/(gt.bigBlind+0.0)) AS bbper100 - ,avg(hp.totalProfit)/100.0 AS profitperhand - ,100.0*avg((hp.totalProfit+hp.rake)/(gt.bigBlind+0.0)) AS bb100xr - ,avg((hp.totalProfit+hp.rake)/100.0) AS profhndxr - ,avg(h.seats+0.0) AS avgseats - ,variance(hp.totalProfit/100.0) AS variance - from HandsPlayers hp - inner join Hands h on (h.id = hp.handId) - inner join Gametypes gt on (gt.Id = h.gameTypeId) - inner join Sites s on (s.Id = gt.siteId) - inner join Players p on (p.Id = hp.playerId) - where hp.playerId in - /*and hp.tourneysPlayersId IS NULL*/ - and h.seats - - - and to_char(h.handStart, 'YYYY-MM-DD') - group by hgameTypeId - ,pname - ,gt.base - ,gt.category - - ,plposition - ,upper(gt.limitType) - ,s.name - having 1 = 1 - order by pname - ,gt.base - ,gt.category - - ,case when 'B' then 'B' - when 'S' then 'S' - when '0' then 'Y' - else 'Z'|| - end - - ,upper(gt.limitType) desc - ,maxbigblind desc - ,s.name - """ - elif db_server == 'sqlite': - self.query['playerDetailedStats'] = """ - select AS hgametypeid - ,gt.base - ,gt.category - ,upper(gt.limitType) AS limittype - ,s.name - ,min(gt.bigBlind) AS minbigblind - ,max(gt.bigBlind) AS maxbigblind - /*, AS gtid*/ - , AS plposition - ,count(1) AS n - ,100.0*sum(cast(hp.street0VPI as integer))/count(1) AS vpip - ,100.0*sum(cast(hp.street0Aggr as integer))/count(1) AS pfr - ,case when sum(cast(hp.street0_3Bchance as integer)) = 0 then -999 - else 100.0*sum(cast(hp.street0_3Bdone as integer))/sum(cast(hp.street0_3Bchance as integer)) - end AS pf3 - ,case when sum(cast(hp.stealattemptchance as integer)) = 0 then -999 - else 100.0*sum(cast(hp.stealattempted as integer))/sum(cast(hp.stealattemptchance as integer)) - end AS steals - ,100.0*sum(cast(hp.street1Seen as integer))/count(1) AS saw_f - ,100.0*sum(cast(hp.sawShowdown as integer))/count(1) AS sawsd - ,case when sum(cast(hp.street1Seen as integer)) = 0 then -999 - else 100.0*sum(cast(hp.sawShowdown as integer))/sum(cast(hp.street1Seen as integer)) - end AS wtsdwsf - ,case when sum(cast(hp.sawShowdown as integer)) = 0 then -999 - else 100.0*sum(cast(hp.wonAtSD as integer))/sum(cast(hp.sawShowdown as integer)) - end AS wmsd - ,case when sum(cast(hp.street1Seen as integer)) = 0 then -999 - else 100.0*sum(cast(hp.street1Aggr as integer))/sum(cast(hp.street1Seen as integer)) - end AS flafq - ,case when sum(cast(hp.street2Seen as integer)) = 0 then -999 - else 100.0*sum(cast(hp.street2Aggr as integer))/sum(cast(hp.street2Seen as integer)) - end AS tuafq - ,case when sum(cast(hp.street3Seen as integer)) = 0 then -999 - else 100.0*sum(cast(hp.street3Aggr as integer))/sum(cast(hp.street3Seen as integer)) - end AS rvafq - ,case when sum(cast(hp.street1Seen as integer))+sum(cast(hp.street2Seen as integer))+sum(cast(hp.street3Seen as integer)) = 0 then -999 - else 100.0*(sum(cast(hp.street1Aggr as integer))+sum(cast(hp.street2Aggr as integer))+sum(cast(hp.street3Aggr as integer))) - /(sum(cast(hp.street1Seen as integer))+sum(cast(hp.street2Seen as integer))+sum(cast(hp.street3Seen as integer))) - end AS pofafq - ,sum(hp.totalProfit)/100.0 AS net - ,sum(hp.rake)/100.0 AS rake - ,100.0*avg(hp.totalProfit/(gt.bigBlind+0.0)) AS bbper100 - ,avg(hp.totalProfit)/100.0 AS profitperhand - ,100.0*avg((hp.totalProfit+hp.rake)/(gt.bigBlind+0.0)) AS bb100xr - ,avg((hp.totalProfit+hp.rake)/100.0) AS profhndxr - ,avg(h.seats+0.0) AS avgseats - ,variance(hp.totalProfit/100.0) AS variance - from HandsPlayers hp - inner join Hands h on (h.id = hp.handId) - inner join Gametypes gt on (gt.Id = h.gameTypeId) - inner join Sites s on (s.Id = gt.siteId) - where hp.playerId in - /*and hp.tourneysPlayersId IS NULL*/ - and h.seats - - - and to_char(h.handStart, 'YYYY-MM-DD') - group by hgameTypeId - ,hp.playerId - ,gt.base - ,gt.category - - ,plposition - ,upper(gt.limitType) - ,s.name - order by hp.playerId - ,gt.base - ,gt.category - - ,case when 'B' then 'B' - when 'S' then 'S' - when '0' then 'Y' - else 'Z'|| - end - - ,upper(gt.limitType) desc - ,maxbigblind desc + ,max(gt.bigBlind) desc ,s.name """ diff --git a/pyfpdb/fpdb.py b/pyfpdb/fpdb.py index 97cf8cf5..d0a5b815 100755 --- a/pyfpdb/fpdb.py +++ b/pyfpdb/fpdb.py @@ -41,7 +41,7 @@ if os.name == 'nt' and sys.version[0:3] not in ('2.5', '2.6') and '-r' not in sy else: pass #print "debug - not changing path" - + if os.name == 'nt': import win32api import win32con @@ -53,7 +53,7 @@ import threading import Options import string cl_options = string.join(sys.argv[1:]) -(options, sys.argv) = Options.fpdb_options() +(options, argv) = Options.fpdb_options() if not options.errorsToConsole: print "Note: error output is being diverted to fpdb-error-log.txt and HUD-error.txt. Any major error will be reported there _only_." @@ -80,7 +80,7 @@ import SQL import Database import FpdbSQLQueries import Configuration -from Exceptions import * +import Exceptions VERSION = "0.12" @@ -178,23 +178,23 @@ class fpdb: """obtains db root credentials from user""" self.warning_box("Unimplemented: Get Root Database Credentials") # user, pw=None, None -# +# # dialog=gtk.Dialog(title="DB Credentials needed", parent=None, flags=0, # buttons=(gtk.STOCK_CANCEL,gtk.RESPONSE_CANCEL,"Connect and recreate",gtk.RESPONSE_OK)) -# +# # label_warning1=gtk.Label("Please enter credentials for a database user for "+self.host+" that has permissions to create a database.") -# -# +# +# # label_user=gtk.Label("Username") # dialog.vbox.add(label_user) # label_user.show() -# +# # response=dialog.run() # dialog.destroy() # return (user, pw, response) def dia_import_db(self, widget, data=None): - self.warning_box("Unimplemented: Import Database") + self.warning_box("Unimplemented: Import Database") self.obtain_global_lock() self.release_global_lock() @@ -211,7 +211,7 @@ class fpdb: # chooser.set_filename(self.profile) # response = chooser.run() - # chooser.destroy() + # chooser.destroy() # if response == gtk.RESPONSE_OK: # self.load_profile(chooser.get_filename()) # elif response == gtk.RESPONSE_CANCEL: @@ -239,7 +239,7 @@ class fpdb: dia_confirm.destroy() if response == gtk.RESPONSE_YES: #if self.db.backend == self.fdb_lock.fdb.MYSQL_INNODB: - # mysql requires locks on all tables or none - easier to release this lock + # mysql requires locks on all tables or none - easier to release this lock # than lock all the other tables # ToDo: lock all other tables so that lock doesn't have to be released # self.release_global_lock() @@ -252,7 +252,7 @@ class fpdb: print 'User cancelled recreating tables' #if not lock_released: self.release_global_lock() - + def dia_recreate_hudcache(self, widget, data=None): if self.obtain_global_lock(): self.dia_confirm = gtk.MessageDialog(parent=None, flags=0, type=gtk.MESSAGE_WARNING, buttons=(gtk.BUTTONS_YES_NO), message_format="Confirm recreating HUD cache") @@ -314,7 +314,7 @@ class fpdb: entry.set_text(ds) win.destroy() self.dia_confirm.set_modal(True) - + def dia_regression_test(self, widget, data=None): self.warning_box("Unimplemented: Regression Test") self.obtain_global_lock() @@ -322,7 +322,7 @@ class fpdb: def dia_save_profile(self, widget, data=None): self.warning_box("Unimplemented: Save Profile (try saving a HUD layout, that should do it)") - + def diaSetupWizard(self, path): diaSetupWizard = gtk.Dialog(title="Fatal Error - Config File Missing", parent=None, flags=0, buttons=(gtk.STOCK_QUIT,gtk.RESPONSE_OK)) @@ -453,21 +453,25 @@ class fpdb: self.sql = SQL.Sql(db_server = self.settings['db-server']) try: self.db = Database.Database(self.config, sql = self.sql) - except FpdbMySQLFailedError: - self.warning_box("Unable to connect to MySQL! Is the MySQL server running?!", "FPDB ERROR") + except Exceptions.FpdbMySQLAccessDenied: + self.warning_box("MySQL Server reports: Access denied. Are your permissions set correctly?") exit() - except FpdbError: - #print "Failed to connect to %s database with username %s." % (self.settings['db-server'], self.settings['db-user']) - self.warning_box("Failed to connect to %s database with username %s." % (self.settings['db-server'], self.settings['db-user']), "FPDB ERROR") - err = traceback.extract_tb(sys.exc_info()[2])[-1] - print "*** Error: " + err[2] + "(" + str(err[1]) + "): " + str(sys.exc_info()[1]) - sys.stderr.write("Failed to connect to %s database with username %s." % (self.settings['db-server'], self.settings['db-user'])) - except: - #print "Failed to connect to %s database with username %s." % (self.settings['db-server'], self.settings['db-user']) - self.warning_box("Failed to connect to %s database with username %s." % (self.settings['db-server'], self.settings['db-user']), "FPDB ERROR") - err = traceback.extract_tb(sys.exc_info()[2])[-1] - print "*** Error: " + err[2] + "(" + str(err[1]) + "): " + str(sys.exc_info()[1]) - sys.stderr.write("Failed to connect to %s database with username %s." % (self.settings['db-server'], self.settings['db-user'])) + +# except FpdbMySQLFailedError: +# self.warning_box("Unable to connect to MySQL! Is the MySQL server running?!", "FPDB ERROR") +# exit() +# except FpdbError: +# #print "Failed to connect to %s database with username %s." % (self.settings['db-server'], self.settings['db-user']) +# self.warning_box("Failed to connect to %s database with username %s." % (self.settings['db-server'], self.settings['db-user']), "FPDB ERROR") +# err = traceback.extract_tb(sys.exc_info()[2])[-1] +# print "*** Error: " + err[2] + "(" + str(err[1]) + "): " + str(sys.exc_info()[1]) +# sys.stderr.write("Failed to connect to %s database with username %s." % (self.settings['db-server'], self.settings['db-user'])) +# except: +# #print "Failed to connect to %s database with username %s." % (self.settings['db-server'], self.settings['db-user']) +# self.warning_box("Failed to connect to %s database with username %s." % (self.settings['db-server'], self.settings['db-user']), "FPDB ERROR") +# err = traceback.extract_tb(sys.exc_info()[2])[-1] +# print "*** Error: " + err[2] + "(" + str(err[1]) + "): " + str(sys.exc_info()[1]) +# sys.stderr.write("Failed to connect to %s database with username %s." % (self.settings['db-server'], self.settings['db-user'])) if self.db.wrongDbVersion: diaDbVersionWarning = gtk.Dialog(title="Strong Warning - Invalid database version", parent=None, flags=0, buttons=(gtk.STOCK_OK,gtk.RESPONSE_OK)) @@ -496,7 +500,7 @@ class fpdb: # Database connected to successfully, load queries to pass on to other classes self.db.rollback() - + self.validate_config() def not_implemented(self, widget, data=None): @@ -624,7 +628,7 @@ This program is licensed under the AGPL3, see docs"""+os.sep+"agpl-3.0.txt") self.window.show() self.load_profile() - + self.statusIcon = gtk.StatusIcon() if os.path.exists('../gfx/fpdb-cards.png'): self.statusIcon.set_from_file('../gfx/fpdb-cards.png') @@ -643,19 +647,19 @@ This program is licensed under the AGPL3, see docs"""+os.sep+"agpl-3.0.txt") self.statusMenu.append(menuItem) self.statusIcon.connect('popup-menu', self.statusicon_menu, self.statusMenu) self.statusIcon.set_visible(True) - + self.window.connect('window-state-event', self.window_state_event_cb) sys.stderr.write("fpdb starting ...") - + def window_state_event_cb(self, window, event): print "window_state_event", event if event.changed_mask & gtk.gdk.WINDOW_STATE_ICONIFIED: # -20 = GWL_EXSTYLE can't find it in the pywin32 libs #bits = win32api.GetWindowLong(self.window.window.handle, -20) #bits = bits ^ (win32con.WS_EX_TOOLWINDOW | win32con.WS_EX_APPWINDOW) - + #win32api.SetWindowLong(self.window.window.handle, -20, bits) - + if event.new_window_state & gtk.gdk.WINDOW_STATE_ICONIFIED: self.window.hide() self.window.set_skip_taskbar_hint(True) @@ -665,7 +669,7 @@ This program is licensed under the AGPL3, see docs"""+os.sep+"agpl-3.0.txt") self.window.set_skip_pager_hint(False) # Tell GTK not to propagate this signal any further return True - + def statusicon_menu(self, widget, button, time, data = None): # we don't need to pass data here, since we do keep track of most all # our variables .. the example code that i looked at for this @@ -676,7 +680,7 @@ This program is licensed under the AGPL3, see docs"""+os.sep+"agpl-3.0.txt") data.show_all() data.popup(None, None, None, 3, time) pass - + def statusicon_activate(self, widget, data = None): # Let's allow the tray icon to toggle window visibility, the way # most other apps work @@ -686,7 +690,7 @@ This program is licensed under the AGPL3, see docs"""+os.sep+"agpl-3.0.txt") else: self.window.show() self.window.present() - + def warning_box(self, str, diatitle="FPDB WARNING"): diaWarning = gtk.Dialog(title=diatitle, parent=None, flags=0, buttons=(gtk.STOCK_OK,gtk.RESPONSE_OK)) @@ -697,7 +701,7 @@ This program is licensed under the AGPL3, see docs"""+os.sep+"agpl-3.0.txt") response = diaWarning.run() diaWarning.destroy() return response - + def validate_config(self): hhbase = self.config.get_import_parameters().get("hhArchiveBase") hhbase = os.path.expanduser(hhbase) @@ -716,7 +720,7 @@ This program is licensed under the AGPL3, see docs"""+os.sep+"agpl-3.0.txt") 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) fc.run() @@ -726,7 +730,7 @@ This program is licensed under the AGPL3, see docs"""+os.sep+"agpl-3.0.txt") self.config.save() self.load_profile() # we can't do this at the end of this func because load_profile calls this func fc.destroy() # TODO: loop this to make sure we get valid data back from it, because the open directory thing in GTK lets you select files and not select things and other stupid bullshit - + def main(self): gtk.main() return 0 diff --git a/pyfpdb/fpdb_db.py b/pyfpdb/fpdb_db.py index 27291d7f..7a2ea4fe 100644 --- a/pyfpdb/fpdb_db.py +++ b/pyfpdb/fpdb_db.py @@ -20,6 +20,7 @@ import os import re import sys import logging +import math from time import time, strftime from Exceptions import * @@ -53,6 +54,10 @@ class VARIANCE: def finalize(self): return float(var(self.store)) +class sqlitemath: + def mod(self, a, b): + return a%b + class fpdb_db: MYSQL_INNODB = 2 PGSQL = 3 @@ -77,10 +82,10 @@ class fpdb_db: self.connect(backend=db['db-backend'], host=db['db-host'], database=db['db-databaseName'], - user=db['db-user'], + user=db['db-user'], password=db['db-password']) #end def do_connect - + def connect(self, backend=None, host=None, database=None, user=None, password=None): """Connects a database with the given parameters""" @@ -95,12 +100,15 @@ class fpdb_db: import MySQLdb if use_pool: MySQLdb = pool.manage(MySQLdb, pool_size=5) -# try: - self.db = MySQLdb.connect(host=host, user=user, passwd=password, db=database, use_unicode=True) + try: + self.db = MySQLdb.connect(host=host, user=user, passwd=password, db=database, use_unicode=True) #TODO: Add port option -# except: -# raise FpdbMySQLFailedError("MySQL connection failed") - elif backend==fpdb_db.PGSQL: + except MySQLdb.Error, ex: + if ex.args[0] == 1045: + raise FpdbMySQLAccessDenied(ex.args[0], ex.args[1]) + else: + print "*** WARNING UNKNOWN MYSQL ERROR", ex + elif backend == fpdb_db.PGSQL: import psycopg2 import psycopg2.extensions if use_pool: @@ -126,8 +134,8 @@ class fpdb_db: if not connected: try: self.db = psycopg2.connect(host = host, - user = user, - password = password, + user = user, + password = password, database = database) except: msg = "PostgreSQL connection to database (%s) user (%s) failed. Are you sure the DB is running?" % (database, user) @@ -148,6 +156,9 @@ class fpdb_db: , detect_types=sqlite3.PARSE_DECLTYPES ) sqlite3.register_converter("bool", lambda x: bool(int(x))) sqlite3.register_adapter(bool, lambda x: "1" if x else "0") + self.db.create_function("floor", 1, math.floor) + tmp = sqlitemath() + self.db.create_function("mod", 2, tmp.mod) if use_numpy: self.db.create_aggregate("variance", 1, VARIANCE) else: @@ -179,13 +190,13 @@ class fpdb_db: self.cursor.close() self.db.close() #end def disconnect - + def reconnect(self, due_to_error=False): """Reconnects the DB""" #print "started fpdb_db.reconnect" self.disconnect(due_to_error) self.connect(self.backend, self.host, self.database, self.user, self.password) - + def get_backend_name(self): """Returns the name of the currently used backend""" if self.backend==2: @@ -197,7 +208,7 @@ class fpdb_db: else: raise FpdbError("invalid backend") #end def get_backend_name - + def get_db_info(self): return (self.host, self.database, self.user, self.password) #end def get_db_info diff --git a/pyfpdb/fpdb_simple.py b/pyfpdb/fpdb_simple.py index 3e2d6f5f..aaf74772 100644 --- a/pyfpdb/fpdb_simple.py +++ b/pyfpdb/fpdb_simple.py @@ -927,7 +927,7 @@ def recogniseTourneyTypeId(db, siteId, tourneySiteId, buyin, fee, knockout, rebu except: cursor.execute( """SELECT id FROM TourneyTypes WHERE siteId=%s AND buyin=%s AND fee=%s - AND knockout=%s AND rebuyOrAddon=%s""" + AND knockout=%s AND rebuyOrAddon=%s""".replace('%s', db.sql.query['placeholder']) , (siteId, buyin, fee, knockout, rebuyOrAddon) ) result = cursor.fetchone() #print "tried selecting tourneytypes.id, result:", result @@ -939,14 +939,14 @@ def recogniseTourneyTypeId(db, siteId, tourneySiteId, buyin, fee, knockout, rebu #print "insert new tourneytype record ..." try: cursor.execute( """INSERT INTO TourneyTypes (siteId, buyin, fee, knockout, rebuyOrAddon) - VALUES (%s, %s, %s, %s, %s)""" + VALUES (%s, %s, %s, %s, %s)""".replace('%s', db.sql.query['placeholder']) , (siteId, buyin, fee, knockout, rebuyOrAddon) ) ret = db.get_last_insert_id(cursor) except: #print "maybe tourneytype was created since select, try selecting again ..." cursor.execute( """SELECT id FROM TourneyTypes WHERE siteId=%s AND buyin=%s AND fee=%s - AND knockout=%s AND rebuyOrAddon=%s""" + AND knockout=%s AND rebuyOrAddon=%s""".replace('%s', db.sql.query['placeholder']) , (siteId, buyin, fee, knockout, rebuyOrAddon) ) result = cursor.fetchone() try: diff --git a/pyfpdb/test_Database.py b/pyfpdb/test_Database.py new file mode 100644 index 00000000..b348f741 --- /dev/null +++ b/pyfpdb/test_Database.py @@ -0,0 +1,68 @@ +# -*- coding: utf-8 -*- +import sqlite3 +import fpdb_db +import math + +# Should probably use our wrapper classes - creating sqlite db in memory +sqlite3.register_converter("bool", lambda x: bool(int(x))) +sqlite3.register_adapter(bool, lambda x: "1" if x else "0") + +con = sqlite3.connect(":memory:") +con.isolation_level = None + +#Floor function +con.create_function("floor", 1, math.floor) + +#Mod function +tmp = fpdb_db.sqlitemath() +con.create_function("mod", 2, tmp.mod) + +# Aggregate function VARIANCE() +con.create_aggregate("variance", 1, fpdb_db.VARIANCE) + + +cur = con.cursor() + +def testSQLiteVarianceFunction(): + cur.execute("CREATE TABLE test(i)") + cur.execute("INSERT INTO test(i) values (1)") + cur.execute("INSERT INTO test(i) values (2)") + cur.execute("INSERT INTO test(i) values (3)") + cur.execute("SELECT variance(i) from test") + result = cur.fetchone()[0] + + print "DEBUG: Testing variance function" + print "DEBUG: result: %s expecting: 0.666666 (result-expecting ~= 0.0): %s" % (result, (result - 0.66666)) + cur.execute("DROP TABLE test") + assert (result - 0.66666) <= 0.0001 + +def testSQLiteFloorFunction(): + vars = [0.1, 1.5, 2.6, 3.5, 4.9] + cur.execute("CREATE TABLE test(i float)") + for var in vars: + cur.execute("INSERT INTO test(i) values(%f)" % var) + cur.execute("SELECT floor(i) from test") + result = cur.fetchall() + print "DEBUG: result: %s" % result + answer = 0 + for i in result: + print "DEBUG: int(var): %s" % int(i[0]) + assert answer == int(i[0]) + answer = answer + 1 + cur.execute("DROP TABLE test") + +def testSQLiteModFunction(): + vars = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16 ,17, 18] + cur.execute("CREATE TABLE test(i int)") + for var in vars: + cur.execute("INSERT INTO test(i) values(%i)" % var) + cur.execute("SELECT mod(i,13) from test") + result = cur.fetchall() + idx = 0 + for i in result: + print "DEBUG: int(var): %s" % i[0] + assert vars[idx]%13 == int(i[0]) + idx = idx+1 + + assert 0 == 1 + cur.execute("DROP TABLE test")