From 97ec91c165c79329406b8748911493ba043cf04a Mon Sep 17 00:00:00 2001 From: Eratosthenes Date: Thu, 18 Feb 2010 16:00:12 -0500 Subject: [PATCH 01/10] Revert fix removing the creation of folders for converted HHs. --- pyfpdb/HandHistoryConverter.py | 18 +++++++++++++++++- 1 file changed, 17 insertions(+), 1 deletion(-) diff --git a/pyfpdb/HandHistoryConverter.py b/pyfpdb/HandHistoryConverter.py index 4bf7564d..41d5b39a 100644 --- a/pyfpdb/HandHistoryConverter.py +++ b/pyfpdb/HandHistoryConverter.py @@ -92,7 +92,23 @@ follow : whether to tail -f the input""" self.out_fh = sys.stdout else: # TODO: out_path should be sanity checked. - self.out_fh = sys.stdout + out_dir = os.path.dirname(self.out_path) + if not os.path.isdir(out_dir) and out_dir != '': + try: + os.makedirs(out_dir) + except: # we get a WindowsError here in Windows.. pretty sure something else for Linux :D + log.error("Unable to create output directory %s for HHC!" % out_dir) + print "*** ERROR: UNABLE TO CREATE OUTPUT DIRECTORY", out_dir + # TODO: pop up a box to allow person to choose output directory? + # TODO: shouldn't that be done when we startup, actually? + else: + log.info("Created directory '%s'" % out_dir) + try: + self.out_fh = codecs.open(self.out_path, 'w', 'utf8') + except: + log.error("out_path %s couldn't be opened" % (self.out_path)) + else: + log.debug("out_path %s opened as %s" % (self.out_path, self.out_fh)) self.follow = follow self.compiledPlayers = set() self.maxseats = 10 From c33575911d12e6e9af5e383103eeac2ba68ff1af Mon Sep 17 00:00:00 2001 From: Eratosthenes Date: Fri, 19 Feb 2010 17:50:45 -0500 Subject: [PATCH 02/10] Don't make folders or files for Stars format HHs. --- pyfpdb/HandHistoryConverter.py | 48 +++++++++++++++++++--------------- pyfpdb/fpdb.py | 35 +++++++++++++------------ 2 files changed, 45 insertions(+), 38 deletions(-) diff --git a/pyfpdb/HandHistoryConverter.py b/pyfpdb/HandHistoryConverter.py index 41d5b39a..0edaaed0 100644 --- a/pyfpdb/HandHistoryConverter.py +++ b/pyfpdb/HandHistoryConverter.py @@ -69,6 +69,7 @@ out_path (default '-' = sys.stdout) follow : whether to tail -f the input""" self.config = config + self.import_parameters = self.config.get_import_parameters() #log = Configuration.get_logger("logging.conf", "parser", log_dir=self.config.dir_log) log.info("HandHistory init - %s subclass, in_path '%s'; out_path '%s'" % (self.sitename, in_path, out_path) ) @@ -87,28 +88,8 @@ follow : whether to tail -f the input""" if in_path == '-': self.in_fh = sys.stdin + self.out_fh = get_out_fh(out_path, self.import_parameters) - if out_path == '-': - self.out_fh = sys.stdout - else: - # TODO: out_path should be sanity checked. - out_dir = os.path.dirname(self.out_path) - if not os.path.isdir(out_dir) and out_dir != '': - try: - os.makedirs(out_dir) - except: # we get a WindowsError here in Windows.. pretty sure something else for Linux :D - log.error("Unable to create output directory %s for HHC!" % out_dir) - print "*** ERROR: UNABLE TO CREATE OUTPUT DIRECTORY", out_dir - # TODO: pop up a box to allow person to choose output directory? - # TODO: shouldn't that be done when we startup, actually? - else: - log.info("Created directory '%s'" % out_dir) - try: - self.out_fh = codecs.open(self.out_path, 'w', 'utf8') - except: - log.error("out_path %s couldn't be opened" % (self.out_path)) - else: - log.debug("out_path %s opened as %s" % (self.out_path, self.out_fh)) self.follow = follow self.compiledPlayers = set() self.maxseats = 10 @@ -531,3 +512,28 @@ def getSiteHhc(config, sitename): hhcName = config.supported_sites[sitename].converter hhcModule = __import__(hhcName) return getattr(hhcModule, hhcName[:-6]) + +def get_out_fh(out_path, parameters): + if out_path == '-': + return(sys.stdout) + elif parameters['saveStarsHH']: + # TODO: out_path should be sanity checked. + out_dir = os.path.dirname(self.out_path) + if not os.path.isdir(out_dir) and out_dir != '': + try: + os.makedirs(out_dir) + except: # we get a WindowsError here in Windows.. pretty sure something else for Linux :D + log.error("Unable to create output directory %s for HHC!" % out_dir) + print "*** ERROR: UNABLE TO CREATE OUTPUT DIRECTORY", out_dir + # TODO: pop up a box to allow person to choose output directory? + # TODO: shouldn't that be done when we startup, actually? + else: + log.info("Created directory '%s'" % out_dir) + try: + return(codecs.open(self.out_path, 'w', 'utf8')) + except: + log.error("out_path %s couldn't be opened" % (self.out_path)) + else: + log.debug("out_path %s opened as %s" % (self.out_path, self.out_fh)) + else: + return(sys.stdout) \ No newline at end of file diff --git a/pyfpdb/fpdb.py b/pyfpdb/fpdb.py index 55b19a3b..0abffcd0 100755 --- a/pyfpdb/fpdb.py +++ b/pyfpdb/fpdb.py @@ -997,23 +997,24 @@ This program is licensed under the AGPL3, see docs"""+os.sep+"agpl-3.0.txt") return response def validate_config(self): - hhbase = self.config.get_import_parameters().get("hhArchiveBase") - hhbase = os.path.expanduser(hhbase) - #hhdir = os.path.join(hhbase,site) - hhdir = hhbase - if not os.path.isdir(hhdir): - diapath = gtk.MessageDialog(parent=None, flags=0, type=gtk.MESSAGE_WARNING, buttons=(gtk.BUTTONS_YES_NO), message_format="Setup hh dir") - diastring = "WARNING: Unable to find output hh directory %s\n\n Press YES to create this directory, or NO to select a new one." % hhdir - diapath.format_secondary_text(diastring) - response = diapath.run() - diapath.destroy() - if response == gtk.RESPONSE_YES: - try: - os.makedirs(hhdir) - except: - self.warning_box("WARNING: Unable to create hand output directory. Importing is not likely to work until this is fixed.") - elif response == gtk.RESPONSE_NO: - self.select_hhArchiveBase() + if self.config.get_import_parameters().get('saveStarsHH'): + hhbase = self.config.get_import_parameters().get("hhArchiveBase") + hhbase = os.path.expanduser(hhbase) + #hhdir = os.path.join(hhbase,site) + hhdir = hhbase + if not os.path.isdir(hhdir): + diapath = gtk.MessageDialog(parent=None, flags=0, type=gtk.MESSAGE_WARNING, buttons=(gtk.BUTTONS_YES_NO), message_format="Setup hh dir") + diastring = "WARNING: Unable to find output hh directory %s\n\n Press YES to create this directory, or NO to select a new one." % hhdir + diapath.format_secondary_text(diastring) + response = diapath.run() + diapath.destroy() + if response == gtk.RESPONSE_YES: + try: + os.makedirs(hhdir) + except: + self.warning_box("WARNING: Unable to create hand output directory. Importing is not likely to work until this is fixed.") + elif response == gtk.RESPONSE_NO: + self.select_hhArchiveBase() def select_hhArchiveBase(self, widget=None): fc = gtk.FileChooserDialog(title="Select HH Output Directory", parent=None, action=gtk.FILE_CHOOSER_ACTION_SELECT_FOLDER, buttons=(gtk.STOCK_OPEN,gtk.RESPONSE_OK), backend=None) From a9ec972ba595022535377aeff3015dcb8df049cd Mon Sep 17 00:00:00 2001 From: Eratosthenes Date: Fri, 19 Feb 2010 20:14:34 -0500 Subject: [PATCH 03/10] Clean some pylint errors and obsolete TODOs. --- pyfpdb/HandHistoryConverter.py | 17 ++++++----------- 1 file changed, 6 insertions(+), 11 deletions(-) diff --git a/pyfpdb/HandHistoryConverter.py b/pyfpdb/HandHistoryConverter.py index 0edaaed0..2053eba9 100644 --- a/pyfpdb/HandHistoryConverter.py +++ b/pyfpdb/HandHistoryConverter.py @@ -443,8 +443,8 @@ or None if we fail to get the info """ def guessMaxSeats(self, hand): """Return a guess at maxseats when not specified in HH.""" # if some other code prior to this has already set it, return it - if maxseats > 1 and maxseats < 11: - return maxseats + if self.maxseats > 1 and self.maxseats < 11: + return self.maxseats mo = self.maxOccSeat(hand) if mo == 10: return 10 #that was easy @@ -517,23 +517,18 @@ def get_out_fh(out_path, parameters): if out_path == '-': return(sys.stdout) elif parameters['saveStarsHH']: - # TODO: out_path should be sanity checked. - out_dir = os.path.dirname(self.out_path) + out_dir = os.path.dirname(out_path) if not os.path.isdir(out_dir) and out_dir != '': try: os.makedirs(out_dir) except: # we get a WindowsError here in Windows.. pretty sure something else for Linux :D log.error("Unable to create output directory %s for HHC!" % out_dir) print "*** ERROR: UNABLE TO CREATE OUTPUT DIRECTORY", out_dir - # TODO: pop up a box to allow person to choose output directory? - # TODO: shouldn't that be done when we startup, actually? else: log.info("Created directory '%s'" % out_dir) try: - return(codecs.open(self.out_path, 'w', 'utf8')) + return(codecs.open(out_path, 'w', 'utf8')) except: - log.error("out_path %s couldn't be opened" % (self.out_path)) - else: - log.debug("out_path %s opened as %s" % (self.out_path, self.out_fh)) + log.error("out_path %s couldn't be opened" % (out_path)) else: - return(sys.stdout) \ No newline at end of file + return(sys.stdout) From ae59fa715b6bd56cfd65a52c7f281e46630ce410 Mon Sep 17 00:00:00 2001 From: Eratosthenes Date: Sat, 20 Feb 2010 11:24:07 -0500 Subject: [PATCH 04/10] Correctly pass dbname to config. Clean some pylint complaints. --- pyfpdb/HUD_main.py | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/pyfpdb/HUD_main.py b/pyfpdb/HUD_main.py index 2ea223f4..92f888d8 100755 --- a/pyfpdb/HUD_main.py +++ b/pyfpdb/HUD_main.py @@ -61,7 +61,7 @@ import Hud # get config and set up logger -c = Configuration.Config(file=options.config) +c = Configuration.Config(file=options.config, dbname=options.dbname) log = Configuration.get_logger("logging.conf", "hud", log_dir=c.dir_log, log_file='HUD-log.txt') @@ -78,14 +78,14 @@ class HUD_main(object): try: if not options.errorsToConsole: - fileName = os.path.join(self.config.dir_log, 'HUD-errors.txt') - print "Note: error output is being diverted to:\n"+fileName \ - + "\nAny major error will be reported there _only_.\n" - log.info("Note: error output is being diverted to:"+fileName) - log.info("Any major error will be reported there _only_.") - errorFile = open(fileName, 'w', 0) - sys.stderr = errorFile - sys.stderr.write("HUD_main: starting ...\n") + fileName = os.path.join(self.config.dir_log, 'HUD-errors.txt') + print "Note: error output is being diverted to:\n"+fileName \ + + "\nAny major error will be reported there _only_.\n" + log.info("Note: error output is being diverted to:"+fileName) + log.info("Any major error will be reported there _only_.") + errorFile = open(fileName, 'w', 0) + sys.stderr = errorFile + sys.stderr.write("HUD_main: starting ...\n") self.hud_dict = {} self.hud_params = self.config.get_hud_ui_parameters() @@ -237,7 +237,7 @@ class HUD_main(object): try: (table_name, max, poker_game, type, site_id, site_name, num_seats, tour_number, tab_number) = \ self.db_connection.get_table_info(new_hand_id) - except Exception, err: + except Exception: log.error("db error: skipping %s" % new_hand_id) continue t1 = time.time() From 21396e101ef4eadb1e90cf9dc759d231deacaaba Mon Sep 17 00:00:00 2001 From: Eratosthenes Date: Sat, 20 Feb 2010 11:55:52 -0500 Subject: [PATCH 05/10] Create saveStarsHH option in import. --- pyfpdb/Configuration.py | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/pyfpdb/Configuration.py b/pyfpdb/Configuration.py index f7694e90..9112072e 100755 --- a/pyfpdb/Configuration.py +++ b/pyfpdb/Configuration.py @@ -414,6 +414,7 @@ class Import: self.hhArchiveBase = node.getAttribute("hhArchiveBase") self.saveActions = string_to_bool(node.getAttribute("saveActions"), default=True) self.fastStoreHudCache = string_to_bool(node.getAttribute("fastStoreHudCache"), default=False) + self.saveStarsHH = string_to_bool(node.getAttribute("saveStarsHH"), default=False) def __str__(self): return " interval = %s\n callFpdbHud = %s\n hhArchiveBase = %s\n saveActions = %s\n fastStoreHudCache = %s\n" \ @@ -808,8 +809,12 @@ class Config: try: imp['saveActions'] = self.imp.saveActions except: imp['saveActions'] = True + try: imp['saveStarsHH'] = self.imp.saveStarsHH + except: imp['saveStarsHH'] = False + try: imp['fastStoreHudCache'] = self.imp.fastStoreHudCache except: imp['fastStoreHudCache'] = True + return imp def get_default_paths(self, site = None): From da124770af5ccdb44794422f16290f72350bcc8a Mon Sep 17 00:00:00 2001 From: Eratosthenes Date: Mon, 22 Feb 2010 11:45:52 -0500 Subject: [PATCH 06/10] Add souce code locations for 3rd party libs + minor update. --- docs/readme.txt | 25 ++++++++++++++++++++----- 1 file changed, 20 insertions(+), 5 deletions(-) diff --git a/docs/readme.txt b/docs/readme.txt index 03e071d3..e3dbac23 100644 --- a/docs/readme.txt +++ b/docs/readme.txt @@ -1,5 +1,5 @@ README.txt -updated 26 March 2009, REB +updated 22 February 2010, REB fpdb - Free Poker Database @@ -29,7 +29,7 @@ fpdb supports: Omaha (incl Hi/low) 7 Card Stud (incl Hi/low) Razz - Draw support is under development + Triple Draw and Badugi Mixed Games -- HUD under development Operating Systems: @@ -38,23 +38,38 @@ fpdb supports: Mac OS/X -- no support for HUD Databases: + SQLite configured by default MySQL PostgreSQL - SQLite under development Downloads: Releases: http://sourceforge.net/project/showfiles.php?group_id=226872 Development code via git: http://www.assembla.com/spaces/free_poker_tools/trac_git_tool Developers: - At least 7 people have contributed code or patches. Others are welcome. + At least 10 people have contributed code or patches. Others are welcome. +Source Code: + If you received fpdb as the Windows compressed exe, then you did not +receive souce code for fpdb or the included libraries. If you wish, you can +obtain the source code here: + + fpdb: see Downloads, above. + python: http://python.org/ + gtk: http://www.gtk.org/download.html + pygtk: http://www.pygtk.org/downloads.html + psycopg2: http://initd.org/pub/software/psycopg/ + mysqldb: http://sourceforge.net/projects/mysql-python/files/ + sqlalchemy: http://www.sqlalchemy.org/download.html + numpy: http://www.scipy.org/Download + matplotlib: http://sourceforge.net/projects/matplotlib/files/ + License ======= Trademarks of third parties have been used under Fair Use or similar laws. Copyright 2008 Steffen Jobbagy-Felso -Copyright 2009 Ray E. Barker +Copyright 2009,2010 Ray E. Barker Permission is granted to copy, distribute and/or modify this document under the terms of the GNU Free Documentation License, Version 1.2 as published by the Free Software Foundation; with From 03880bbc63f7635821b5ff5ac75796d83ef6a94a Mon Sep 17 00:00:00 2001 From: Eratosthenes Date: Wed, 24 Feb 2010 10:28:12 -0500 Subject: [PATCH 07/10] Trivial refactor of get_stats_from_hand for readability. --- pyfpdb/Database.py | 43 ++++++++++++++++++++++++------------------- 1 file changed, 24 insertions(+), 19 deletions(-) diff --git a/pyfpdb/Database.py b/pyfpdb/Database.py index 0303aad2..76addf59 100644 --- a/pyfpdb/Database.py +++ b/pyfpdb/Database.py @@ -643,6 +643,29 @@ class Database: , hero_id = -1 , num_seats = 6 ): + + (hud_style, h_hud_style, query, subs) = self.prep_aggregation(hand, hud_params, hero_id, num_seats) + + c = self.connection.cursor() + +# now get the stats + stat_dict = {} + c.execute(self.sql.query[query], subs) + colnames = [desc[0] for desc in c.description] + for row in c.fetchall(): + playerid = row[0] + if (playerid == hero_id and h_hud_style != 'S') or (playerid != hero_id and hud_style != 'S'): + t_dict = {} + for name, val in zip(colnames, row): + t_dict[name.lower()] = val +# print t_dict + stat_dict[t_dict['player_id']] = t_dict + + return stat_dict + + def prep_aggregation(self, hand, hud_params, hero_id, num_seats): +# This sorts through the all the info having to do with aggregation +# and returns what get_stats needs. hud_style = hud_params['hud_style'] agg_bb_mult = hud_params['agg_bb_mult'] seats_style = hud_params['seats_style'] @@ -652,8 +675,6 @@ class Database: h_seats_style = hud_params['h_seats_style'] h_seats_cust_nums = hud_params['h_seats_cust_nums'] - stat_dict = {} - if seats_style == 'A': seats_min, seats_max = 0, 10 elif seats_style == 'C': @@ -715,23 +736,7 @@ class Database: subs = (hand ,hero_id, stylekey, agg_bb_mult, agg_bb_mult, seats_min, seats_max # hero params ,hero_id, h_stylekey, h_agg_bb_mult, h_agg_bb_mult, h_seats_min, h_seats_max) # villain params - - #print "get stats: hud style =", hud_style, "query =", query, "subs =", subs - c = self.connection.cursor() - -# now get the stats - c.execute(self.sql.query[query], subs) - colnames = [desc[0] for desc in c.description] - for row in c.fetchall(): - playerid = row[0] - if (playerid == hero_id and h_hud_style != 'S') or (playerid != hero_id and hud_style != 'S'): - t_dict = {} - for name, val in zip(colnames, row): - t_dict[name.lower()] = val -# print t_dict - stat_dict[t_dict['player_id']] = t_dict - - return stat_dict + return (hud_style, h_hud_style, query, subs) # uses query on handsplayers instead of hudcache to get stats on just this session def get_stats_from_hand_session(self, hand, stat_dict, hero_id From 04e8f117d5ebd47a29307328002d5f1bc49449ef Mon Sep 17 00:00:00 2001 From: Eratosthenes Date: Wed, 24 Feb 2010 17:06:36 -0500 Subject: [PATCH 08/10] Revert "Trivial refactor of get_stats_from_hand for readability." This reverts commit 03880bbc63f7635821b5ff5ac75796d83ef6a94a. --- pyfpdb/Database.py | 43 +++++++++++++++++++------------------------ 1 file changed, 19 insertions(+), 24 deletions(-) diff --git a/pyfpdb/Database.py b/pyfpdb/Database.py index 76addf59..0303aad2 100644 --- a/pyfpdb/Database.py +++ b/pyfpdb/Database.py @@ -643,29 +643,6 @@ class Database: , hero_id = -1 , num_seats = 6 ): - - (hud_style, h_hud_style, query, subs) = self.prep_aggregation(hand, hud_params, hero_id, num_seats) - - c = self.connection.cursor() - -# now get the stats - stat_dict = {} - c.execute(self.sql.query[query], subs) - colnames = [desc[0] for desc in c.description] - for row in c.fetchall(): - playerid = row[0] - if (playerid == hero_id and h_hud_style != 'S') or (playerid != hero_id and hud_style != 'S'): - t_dict = {} - for name, val in zip(colnames, row): - t_dict[name.lower()] = val -# print t_dict - stat_dict[t_dict['player_id']] = t_dict - - return stat_dict - - def prep_aggregation(self, hand, hud_params, hero_id, num_seats): -# This sorts through the all the info having to do with aggregation -# and returns what get_stats needs. hud_style = hud_params['hud_style'] agg_bb_mult = hud_params['agg_bb_mult'] seats_style = hud_params['seats_style'] @@ -675,6 +652,8 @@ class Database: h_seats_style = hud_params['h_seats_style'] h_seats_cust_nums = hud_params['h_seats_cust_nums'] + stat_dict = {} + if seats_style == 'A': seats_min, seats_max = 0, 10 elif seats_style == 'C': @@ -736,7 +715,23 @@ class Database: subs = (hand ,hero_id, stylekey, agg_bb_mult, agg_bb_mult, seats_min, seats_max # hero params ,hero_id, h_stylekey, h_agg_bb_mult, h_agg_bb_mult, h_seats_min, h_seats_max) # villain params - return (hud_style, h_hud_style, query, subs) + + #print "get stats: hud style =", hud_style, "query =", query, "subs =", subs + c = self.connection.cursor() + +# now get the stats + c.execute(self.sql.query[query], subs) + colnames = [desc[0] for desc in c.description] + for row in c.fetchall(): + playerid = row[0] + if (playerid == hero_id and h_hud_style != 'S') or (playerid != hero_id and hud_style != 'S'): + t_dict = {} + for name, val in zip(colnames, row): + t_dict[name.lower()] = val +# print t_dict + stat_dict[t_dict['player_id']] = t_dict + + return stat_dict # uses query on handsplayers instead of hudcache to get stats on just this session def get_stats_from_hand_session(self, hand, stat_dict, hero_id From 5c0e4cb0c2b623effbd8d91d6191d69ca9f8ab8d Mon Sep 17 00:00:00 2001 From: Eratosthenes Date: Thu, 25 Feb 2010 20:28:41 -0500 Subject: [PATCH 09/10] Use correct dirs for database and log. --- pyfpdb/Configuration.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/pyfpdb/Configuration.py b/pyfpdb/Configuration.py index d87014e6..d0f81a1b 100755 --- a/pyfpdb/Configuration.py +++ b/pyfpdb/Configuration.py @@ -470,7 +470,8 @@ class Config: self.file = file self.dir_self = get_exec_path() - self.dir_config = os.path.dirname(self.file) +# self.dir_config = os.path.dirname(self.file) + self.dir_config = get_default_config_path() self.dir_log = os.path.join(self.dir_config, 'log') self.dir_database = os.path.join(self.dir_config, 'database') self.log_file = os.path.join(self.dir_log, 'fpdb-log.txt') From aca5682daf4fe6a4402ef47592c77a01b3c7ae28 Mon Sep 17 00:00:00 2001 From: Eratosthenes Date: Thu, 25 Feb 2010 21:32:49 -0500 Subject: [PATCH 10/10] Get rid of erroneous error message. --- pyfpdb/XTables.py | 1 - 1 file changed, 1 deletion(-) diff --git a/pyfpdb/XTables.py b/pyfpdb/XTables.py index a14debc1..28737002 100644 --- a/pyfpdb/XTables.py +++ b/pyfpdb/XTables.py @@ -89,7 +89,6 @@ class Table(Table_Window): # break if window_number is None: - print "Window %s not found. Skipping." % search_string return None # my_geo = self.window.get_geometry()