From f84644990bf4ff1743e82db23c1d8562523ac3c5 Mon Sep 17 00:00:00 2001 From: Mika Bostrom Date: Sat, 22 Aug 2009 17:36:44 +0300 Subject: [PATCH 01/28] Debian packaging, step #1 * add setup.py for python distutils use * add packaging/debian/* Not ready yet, but at least seems to behave sanely --- packaging/debian/changelog | 5 +++++ packaging/debian/compat | 1 + packaging/debian/control | 24 ++++++++++++++++++++ packaging/debian/copyright | 7 ++++++ packaging/debian/links | 1 + packaging/debian/pyversions | 1 + packaging/debian/rules | 45 +++++++++++++++++++++++++++++++++++++ setup.py | 17 ++++++++++++++ 8 files changed, 101 insertions(+) create mode 100644 packaging/debian/changelog create mode 100644 packaging/debian/compat create mode 100644 packaging/debian/control create mode 100644 packaging/debian/copyright create mode 100644 packaging/debian/links create mode 100644 packaging/debian/pyversions create mode 100755 packaging/debian/rules create mode 100644 setup.py diff --git a/packaging/debian/changelog b/packaging/debian/changelog new file mode 100644 index 00000000..994884c6 --- /dev/null +++ b/packaging/debian/changelog @@ -0,0 +1,5 @@ +free-poker-tools (0.10.99) unstable; urgency=low + + * Initial packaging release. + + -- Mika Bostrom Thu, 20 Aug 2009 06:30:53 +0300 diff --git a/packaging/debian/compat b/packaging/debian/compat new file mode 100644 index 00000000..7f8f011e --- /dev/null +++ b/packaging/debian/compat @@ -0,0 +1 @@ +7 diff --git a/packaging/debian/control b/packaging/debian/control new file mode 100644 index 00000000..f557711a --- /dev/null +++ b/packaging/debian/control @@ -0,0 +1,24 @@ +Source: free-poker-tools +Maintainer: Mika Bostrom +Section: games +Priority: optional +Build-Depends: python, dpkg-dev, python-support +Standards-Version: 3.8.0 + +Package: python-fpdb +Architecture: any +Section: games +Priority: optional +Depends: ${python:Depends}, python-gtk2, python-matplotlib, + python-support, mysql-server | postgresql | python-pysqlite2, + python-psycopg2 | python-mysqldb +Suggests: wine +Description: free poker database with HUD + FPDB is a statistics tool for online poker. It supports most sites + and several games. Most prominent feature is its heads-up display + (HUD) which shows statistical details for players in real time. + . + Due to the fact that most online poker clients are Windows-only, + you may need to install wine. + . + FPDB is under heavy development. diff --git a/packaging/debian/copyright b/packaging/debian/copyright new file mode 100644 index 00000000..8796c11a --- /dev/null +++ b/packaging/debian/copyright @@ -0,0 +1,7 @@ +This package was debianised by Mika Bostrom + +Upstream authors: ... + +License: AGPL + +Copyright (C) 2008- The FPDB developers diff --git a/packaging/debian/links b/packaging/debian/links new file mode 100644 index 00000000..5a4601a7 --- /dev/null +++ b/packaging/debian/links @@ -0,0 +1 @@ +/usr/share/pyshared/fpdb/fpdb.py /usr/bin/fpdb diff --git a/packaging/debian/pyversions b/packaging/debian/pyversions new file mode 100644 index 00000000..8b253bc3 --- /dev/null +++ b/packaging/debian/pyversions @@ -0,0 +1 @@ +2.4- diff --git a/packaging/debian/rules b/packaging/debian/rules new file mode 100755 index 00000000..2ae2c776 --- /dev/null +++ b/packaging/debian/rules @@ -0,0 +1,45 @@ +#!/usr/bin/make -f +# -*- makefile -*- + +PACKAGE := python-fpdb + +build: build-stamp +build-stamp: + dh_testdir + python setup.py build + touch $@ + +clean: + dh_testdir + dh_testroot + python setup.py clean + rm -rf build + dh_clean build-stamp + +install: build + dh_testdir + dh_testroot + dh_prep || dh_clean -k + dh_installdirs + # + python setup.py install --root=debian/$(PACKAGE) --prefix=/usr --no-compile + +binary-indep: build install + dh_testdir + dh_testroot + dh_installchangelogs + dh_installdocs + dh_link + dh_compress + dh_fixperms + dh_pysupport + dh_installdeb + dh_gencontrol + dh_md5sums + dh_builddeb + +binary-arch: build install + +binary: binary-indep binary-arch +.PHONY: build clean binary-indep binary-arch binary install + diff --git a/setup.py b/setup.py new file mode 100644 index 00000000..668693cf --- /dev/null +++ b/setup.py @@ -0,0 +1,17 @@ +# setup.py +# Python packaging for fpdb + +from distutils.core import setup + +setup(name = 'fpdb', + description = 'Free Poker Database', + version = '0.10.999', + author = 'FPDB team', + author_email = 'fpdb-main@lists.sourceforge.net', + packages = ['fpdb'], + package_dir = { 'fpdb' : 'pyfpdb' }, + data_files = [ + ('/usr/share/doc/python-fpdb', + ['docs/readme.txt', 'docs/release-notes.txt', + 'docs/tabledesign.html', 'THANKS.txt'])] +) From ae0612370d229b886c212d390b47ea79dd65c67d Mon Sep 17 00:00:00 2001 From: Mika Bostrom Date: Sat, 22 Aug 2009 22:47:27 +0300 Subject: [PATCH 02/28] Packaging fixes * It seems that fpdb gets installed into /usr/share/python-support/ while many other packages end up in .../pyshared; fixed the symlink target * Fixed mail address in changelog, which now is the correct one * Added postinst script to make fpdb.py executable again. This hack is needed because dh_fixperms didn't allow to ignore the script's permissions and the file is located in .../fpdb/ along with all the other fpdb modules * Told package manager to create /usr/bin/fpdb symlink pointing to fpdb.py so we now have an application named "fpdb" in the system --- packaging/debian/changelog | 2 +- packaging/debian/links | 2 +- packaging/debian/python-fpdb.postinst | 5 +++++ 3 files changed, 7 insertions(+), 2 deletions(-) create mode 100644 packaging/debian/python-fpdb.postinst diff --git a/packaging/debian/changelog b/packaging/debian/changelog index 994884c6..84ecbce5 100644 --- a/packaging/debian/changelog +++ b/packaging/debian/changelog @@ -2,4 +2,4 @@ free-poker-tools (0.10.99) unstable; urgency=low * Initial packaging release. - -- Mika Bostrom Thu, 20 Aug 2009 06:30:53 +0300 + -- Mika Bostrom Thu, 20 Aug 2009 06:30:53 +0300 diff --git a/packaging/debian/links b/packaging/debian/links index 5a4601a7..01d1c490 100644 --- a/packaging/debian/links +++ b/packaging/debian/links @@ -1 +1 @@ -/usr/share/pyshared/fpdb/fpdb.py /usr/bin/fpdb +/usr/share/python-support/python-fpdb/fpdb/fpdb.py /usr/bin/fpdb diff --git a/packaging/debian/python-fpdb.postinst b/packaging/debian/python-fpdb.postinst new file mode 100644 index 00000000..1f618958 --- /dev/null +++ b/packaging/debian/python-fpdb.postinst @@ -0,0 +1,5 @@ +#!/bin/sh + +# When installed into .../fpdb/ the script gets mode 644 +# Note: "dh_fixperms -Xfpdb.py" did not work, hence this hack +chmod 755 /usr/bin/fpdb From d43954bc5f22b26b6dadb64ea01011d81f4133ca Mon Sep 17 00:00:00 2001 From: Mika Bostrom Date: Sat, 22 Aug 2009 23:05:18 +0300 Subject: [PATCH 03/28] Clean up debian/control Drop unneeded and already covered dependencies. Change package priority from optional to extra, which makes more sense. --- packaging/debian/control | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/packaging/debian/control b/packaging/debian/control index f557711a..93660791 100644 --- a/packaging/debian/control +++ b/packaging/debian/control @@ -1,14 +1,14 @@ Source: free-poker-tools Maintainer: Mika Bostrom Section: games -Priority: optional -Build-Depends: python, dpkg-dev, python-support +Priority: extra +Build-Depends: debhelper, python-support Standards-Version: 3.8.0 Package: python-fpdb Architecture: any Section: games -Priority: optional +Priority: extra Depends: ${python:Depends}, python-gtk2, python-matplotlib, python-support, mysql-server | postgresql | python-pysqlite2, python-psycopg2 | python-mysqldb From f4e6de744a877137b1f6ec93dd2581e197660e79 Mon Sep 17 00:00:00 2001 From: Mika Bostrom Date: Sun, 23 Aug 2009 10:18:06 +0300 Subject: [PATCH 04/28] Fix noop() prototype Hud's noop() is called from gtk event handler, which passes additional arguments. We don't care about them but we do want to prevent HUD-error.txt from being flooded with TypeError messages. --- pyfpdb/Hud.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pyfpdb/Hud.py b/pyfpdb/Hud.py index 41154c13..e0e14689 100644 --- a/pyfpdb/Hud.py +++ b/pyfpdb/Hud.py @@ -423,7 +423,7 @@ class Stat_Window: return True return False - def noop(self): # i'm going to try to connect the focus-in and focus-out events here, to see if that fixes any of the focus problems. + def noop(self, *args): # i'm going to try to connect the focus-in and focus-out events here, to see if that fixes any of the focus problems. return True def kill_popup(self, popup): From b0616a7d2c9e8bf961166ff4e6de19030d6fa9b8 Mon Sep 17 00:00:00 2001 From: Eric Blade Date: Sun, 13 Sep 2009 15:08:23 -0500 Subject: [PATCH 05/28] as soon as a stat window is clicked on, with any button, bring it forward. this seems to almost completely solve the insane focus-wobbling in windows --- pyfpdb/Hud.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pyfpdb/Hud.py b/pyfpdb/Hud.py index 43b8731b..392aa216 100644 --- a/pyfpdb/Hud.py +++ b/pyfpdb/Hud.py @@ -374,6 +374,7 @@ class Stat_Window: # This handles all callbacks from button presses on the event boxes in # the stat windows. There is a bit of an ugly kludge to separate single- # and double-clicks. + self.window.show_all() if event.button == 3: # right button event newpopup = Popup_window(self.window, self) @@ -388,7 +389,6 @@ class Stat_Window: if event.button == 1: # left button event # TODO: make position saving save sizes as well? - self.window.show_all() if event.state & gtk.gdk.SHIFT_MASK: self.window.begin_resize_drag(gtk.gdk.WINDOW_EDGE_SOUTH_EAST, event.button, int(event.x_root), int(event.y_root), event.time) else: From 4374b6c8108ef06b71bf4189326e193c8d544e88 Mon Sep 17 00:00:00 2001 From: Eric Blade Date: Tue, 15 Sep 2009 18:49:34 -0500 Subject: [PATCH 06/28] remove Database:__init__ parameters for db_name and game, as there was a comment right next to them # db_name and game not used anymore --- pyfpdb/Database.py | 2 +- pyfpdb/HUD_main.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/pyfpdb/Database.py b/pyfpdb/Database.py index f4de8169..de71da0c 100755 --- a/pyfpdb/Database.py +++ b/pyfpdb/Database.py @@ -181,7 +181,7 @@ class Database: # create index indexname on tablename (col); - def __init__(self, c, db_name = None, game = None, sql = None): # db_name and game not used any more + def __init__(self, c, sql = None): log.info("Creating Database instance, sql = %s" % sql) self.fdb = fpdb_db.fpdb_db() # sets self.fdb.db self.fdb.cursor and self.fdb.sql self.fdb.do_connect(c) diff --git a/pyfpdb/HUD_main.py b/pyfpdb/HUD_main.py index ecc96429..b1164b26 100755 --- a/pyfpdb/HUD_main.py +++ b/pyfpdb/HUD_main.py @@ -160,7 +160,7 @@ class HUD_main(object): # be passed to HUDs for use in the gui thread. HUD objects should not # need their own access to the database, but should open their own # if it is required. - self.db_connection = Database.Database(self.config, self.db_name, 'temp') + self.db_connection = Database.Database(self.config) self.db_connection.init_hud_stat_vars(hud_days) tourny_finder = re.compile('(\d+) (\d+)') From 8b19750b1f043475dabfe57df035dc3bb121109c Mon Sep 17 00:00:00 2001 From: Eric Blade Date: Tue, 15 Sep 2009 19:27:25 -0500 Subject: [PATCH 07/28] == None to is None (PEP 8, Style Guide for Python Code) --- pyfpdb/Database.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pyfpdb/Database.py b/pyfpdb/Database.py index de71da0c..011da193 100755 --- a/pyfpdb/Database.py +++ b/pyfpdb/Database.py @@ -201,7 +201,7 @@ class Database: # where possible avoid creating new SQL instance by using the global one passed in - if sql == None: + if sql is None: self.sql = SQL.Sql(type = self.type, db_server = db_params['db-server']) else: self.sql = sql From d6c5309aa3db51fc5d9145195152c0c1accf8286 Mon Sep 17 00:00:00 2001 From: Eric Blade Date: Tue, 15 Sep 2009 20:10:18 -0500 Subject: [PATCH 08/28] clean up some module import code in fpdb_import --- pyfpdb/fpdb_import.py | 16 +++++++--------- 1 file changed, 7 insertions(+), 9 deletions(-) diff --git a/pyfpdb/fpdb_import.py b/pyfpdb/fpdb_import.py index 2e299c5f..4e5febcc 100644 --- a/pyfpdb/fpdb_import.py +++ b/pyfpdb/fpdb_import.py @@ -49,22 +49,20 @@ log = logging.getLogger('importer') # database interface modules try: import MySQLdb - mysqlLibFound=True - log.debug("Import module: MySQLdb") except: - log.debug("Import module: MySQLdb not found") - + log.debug("Import database module: MySQLdb not found") +else: + mysqlLibFound = True + try: import psycopg2 - pgsqlLibFound=True +except: + log.debug("Import database module: psycopg2 not found") +else: import psycopg2.extensions psycopg2.extensions.register_type(psycopg2.extensions.UNICODE) - log.debug("Import module: psycopg2") -except: - log.debug("Import module: psycopg2 not found") class Importer: - def __init__(self, caller, settings, config, sql = None): """Constructor""" self.settings = settings From a1783a37cbd0b399a87f3049c62340e91de62a57 Mon Sep 17 00:00:00 2001 From: Eric Blade Date: Tue, 15 Sep 2009 21:04:00 -0500 Subject: [PATCH 09/28] reflow init_hud_stat_vars exception handling --- pyfpdb/Database.py | 17 +++++++---------- 1 file changed, 7 insertions(+), 10 deletions(-) diff --git a/pyfpdb/Database.py b/pyfpdb/Database.py index 011da193..32437d5f 100755 --- a/pyfpdb/Database.py +++ b/pyfpdb/Database.py @@ -370,23 +370,20 @@ class Database: def init_hud_stat_vars(self, hud_days): """Initialise variables used by Hud to fetch stats.""" + self.hand_1day_ago = 1 try: - # self.hand_1day_ago used to fetch stats for current session (i.e. if hud_style = 'S') - self.hand_1day_ago = 1 c = self.get_cursor() c.execute(self.sql.query['get_hand_1day_ago']) row = c.fetchone() + except: # TODO: what error is a database error?! + err = traceback.extract_tb(sys.exc_info()[2])[-1] + print "*** Error: " + err[2] + "(" + str(err[1]) + "): " + str(sys.exc_info()[1]) + else: if row and row[0]: - self.hand_1day_ago = row[0] - #print "hand 1day ago =", self.hand_1day_ago - - # self.date_ndays_ago used if hud_style = 'T' + self.hand_1_day_ago = row[0] d = timedelta(days=hud_days) now = datetime.utcnow() - d - self.date_ndays_ago = "d%02d%02d%02d" % (now.year-2000, now.month, now.day) - except: - err = traceback.extract_tb(sys.exc_info()[2])[-1] - print "***Error: "+err[2]+"("+str(err[1])+"): "+str(sys.exc_info()[1]) + self.date_ndays_ago = "d%02d%02d%02d" % (now.year - 2000, now.month, now.day) def init_player_hud_stat_vars(self, playerid): # not sure if this is workable, to be continued ... From e4772dcb743e85e0c452ffb52f57f496a375bc77 Mon Sep 17 00:00:00 2001 From: Eric Blade Date: Tue, 15 Sep 2009 21:06:43 -0500 Subject: [PATCH 10/28] init vars used in load_clicked, comment out the exception handler that was single handedly stopping virtually all errors in the import process from showing up --- pyfpdb/GuiBulkImport.py | 19 ++++++++++++------- 1 file changed, 12 insertions(+), 7 deletions(-) diff --git a/pyfpdb/GuiBulkImport.py b/pyfpdb/GuiBulkImport.py index c4f3105f..21f9e050 100755 --- a/pyfpdb/GuiBulkImport.py +++ b/pyfpdb/GuiBulkImport.py @@ -60,6 +60,11 @@ class GuiBulkImport(): return True def load_clicked(self, widget, data=None): + stored = None + dups = None + partial = None + errs = None + ttime = None # 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 @@ -101,13 +106,13 @@ class GuiBulkImport(): self.importer.addBulkImportImportFileOrDir(self.inputFile, site = sitename) self.importer.setCallHud(False) starttime = time() - try: - (stored, dups, partial, errs, ttime) = self.importer.runImport() - except: - print "*** EXCEPTION DURING BULKIMPORT!!!" - raise Exceptions.FpdbError - finally: - gobject.source_remove(self.timer) +# try: + (stored, dups, partial, errs, ttime) = self.importer.runImport() +# except: +# print "*** EXCEPTION DURING BULKIMPORT!!!" +# raise Exceptions.FpdbError +# finally: + gobject.source_remove(self.timer) ttime = time() - starttime if ttime == 0: From 2790a623afb73b12b0f0287870d1c59da28ebef0 Mon Sep 17 00:00:00 2001 From: Eric Blade Date: Tue, 15 Sep 2009 21:07:31 -0500 Subject: [PATCH 11/28] import, code, exception cleanups --- pyfpdb/fpdb_import.py | 4 +- pyfpdb/fpdb_parse_logic.py | 112 +++++++++++++++++++++++++------------ 2 files changed, 77 insertions(+), 39 deletions(-) diff --git a/pyfpdb/fpdb_import.py b/pyfpdb/fpdb_import.py index 4e5febcc..4fb4789d 100644 --- a/pyfpdb/fpdb_import.py +++ b/pyfpdb/fpdb_import.py @@ -49,14 +49,14 @@ log = logging.getLogger('importer') # database interface modules try: import MySQLdb -except: +except ImportError: log.debug("Import database module: MySQLdb not found") else: mysqlLibFound = True try: import psycopg2 -except: +except ImportError: log.debug("Import database module: psycopg2 not found") else: import psycopg2.extensions diff --git a/pyfpdb/fpdb_parse_logic.py b/pyfpdb/fpdb_parse_logic.py index da6f644d..4ce1f678 100644 --- a/pyfpdb/fpdb_parse_logic.py +++ b/pyfpdb/fpdb_parse_logic.py @@ -18,46 +18,63 @@ #parses an in-memory fpdb hand history and calls db routine to store it import sys - -import fpdb_simple -import Database from time import time, strftime from Exceptions import * +import fpdb_simple +import Database -#parses a holdem hand def mainParser(settings, siteID, category, hand, config, db = None, writeq = None): - + """ mainParser for Holdem Hands """ t0 = time() - #print "mainparser" backend = settings['db-backend'] - # Ideally db connection is passed in, if not use sql list if passed in, otherwise start from scratch + # Ideally db connection is passed in, if not use sql list if passed in, + # otherwise start from scratch if db == None: db = Database.Database(c = config, sql = None) category = fpdb_simple.recogniseCategory(hand[0]) - base = "hold" if category == "holdem" or category == "omahahi" or category == "omahahilo" else "stud" + base = "hold" if (category == "holdem" or category == "omahahi" or + category == "omahahilo") else "stud" #part 0: create the empty arrays - lineTypes = [] #char, valid values: header, name, cards, action, win, rake, ignore - lineStreets = [] #char, valid values: (predeal, preflop, flop, turn, river) - - cardValues, cardSuits, boardValues, boardSuits, antes, actionTypes, allIns, actionAmounts, actionNos, actionTypeByNo, seatLines, winnings, rakes=[],[],[],[],[],[],[],[],[],[],[],[],[] + # lineTypes valid values: header, name, cards, action, win, rake, ignore + # lineStreets valid values: predeal, preflop, flop, turn, river + lineTypes = [] + lineStreets = [] + cardValues = [] + cardSuits = [] + boardValues = [] + boardSuits = [] + antes = [] + allIns = [] + actionAmounts = [] + actionNos = [] + actionTypes = [] + actionTypeByNo = [] + seatLines = [] + winnings = [] + rakes = [] #part 1: read hand no and check for duplicate siteHandNo = fpdb_simple.parseSiteHandNo(hand[0]) - #print "siteHandNo =", siteHandNo - handStartTime = fpdb_simple.parseHandStartTime(hand[0]) - + handStartTime = fpdb_simple.parseHandStartTime(hand[0]) isTourney = fpdb_simple.isTourney(hand[0]) - smallBlindLine = 0 + + smallBlindLine = None for i, line in enumerate(hand): if 'posts small blind' in line or 'posts the small blind' in line: if line[-2:] == "$0": continue smallBlindLine = i break + else: + smallBlindLine = 0 + # If we did not find a small blind line, what happens? + # if we leave it at None, it errors two lines down. - gametypeID = fpdb_simple.recogniseGametypeID(backend, db, db.get_cursor(), hand[0], hand[smallBlindLine], siteID, category, isTourney) + gametypeID = fpdb_simple.recogniseGametypeID(backend, db, db.get_cursor(), + hand[0], hand[smallBlindLine], + siteID, category, isTourney) if isTourney: siteTourneyNo = fpdb_simple.parseTourneyNo(hand[0]) buyin = fpdb_simple.parseBuyin(hand[0]) @@ -68,8 +85,14 @@ def mainParser(settings, siteID, category, hand, config, db = None, writeq = Non tourneyStartTime= handStartTime #todo: read tourney start time rebuyOrAddon = fpdb_simple.isRebuyOrAddon(hand[0]) - ## The tourney site id has to be searched because it may already be in db with a TourneyTypeId which is different from the one automatically calculated (Summary import first) - tourneyTypeId = fpdb_simple.recogniseTourneyTypeId(db, siteID, siteTourneyNo, buyin, fee, knockout, rebuyOrAddon) + # The tourney site id has to be searched because it may already be in + # db with a TourneyTypeId which is different from the one automatically + # calculated (Summary import first) + tourneyTypeId = fpdb_simple.recogniseTourneyTypeId(db, siteID, + siteTourneyNo, + buyin, fee, + knockout, + rebuyOrAddon) else: siteTourneyNo = -1 buyin = -1 @@ -100,7 +123,9 @@ def mainParser(settings, siteID, category, hand, config, db = None, writeq = Non startCashes = tmp['startCashes'] seatNos = tmp['seatNos'] - fpdb_simple.createArrays(category, len(names), cardValues, cardSuits, antes, winnings, rakes, actionTypes, allIns, actionAmounts, actionNos, actionTypeByNo) + fpdb_simple.createArrays(category, len(names), cardValues, cardSuits, antes, + winnings, rakes, actionTypes, allIns, + actionAmounts, actionNos, actionTypeByNo) #3b read positions if base == "hold": @@ -109,27 +134,32 @@ def mainParser(settings, siteID, category, hand, config, db = None, writeq = Non #part 4: take appropriate action for each line based on linetype for i, line in enumerate(hand): if lineTypes[i] == "cards": - fpdb_simple.parseCardLine(category, lineStreets[i], line, names, cardValues, cardSuits, boardValues, boardSuits) + fpdb_simple.parseCardLine(category, lineStreets[i], line, names, + cardValues, cardSuits, boardValues, + boardSuits) #if category=="studhilo": # print "hand[i]:", hand[i] # print "cardValues:", cardValues # print "cardSuits:", cardSuits elif lineTypes[i] == "action": - fpdb_simple.parseActionLine(base, isTourney, line, lineStreets[i], playerIDs, names, actionTypes, allIns, actionAmounts, actionNos, actionTypeByNo) + fpdb_simple.parseActionLine(base, isTourney, line, lineStreets[i], + playerIDs, names, actionTypes, allIns, + actionAmounts, actionNos, actionTypeByNo) elif lineTypes[i] == "win": fpdb_simple.parseWinLine(line, names, winnings, isTourney) elif lineTypes[i] == "rake": totalRake = 0 if isTourney else fpdb_simple.parseRake(line) fpdb_simple.splitRake(winnings, rakes, totalRake) - elif lineTypes[i]=="header" or lineTypes[i]=="rake" or lineTypes[i]=="name" or lineTypes[i]=="ignore": + elif (lineTypes[i] == "header" or lineTypes[i] == "rake" or + lineTypes[i] == "name" or lineTypes[i] == "ignore"): pass - elif lineTypes[i]=="ante": + elif lineTypes[i] == "ante": fpdb_simple.parseAnteLine(line, isTourney, names, antes) - elif lineTypes[i]=="table": + elif lineTypes[i] == "table": tableResult=fpdb_simple.parseTableLine(base, line) else: - raise FpdbError("unrecognised lineType:"+lineTypes[i]) - + raise FpdbError("unrecognised lineType:" + lineTypes[i]) + maxSeats = tableResult['maxSeats'] tableName = tableResult['tableName'] #print "before part5, antes:", antes @@ -152,26 +182,34 @@ def mainParser(settings, siteID, category, hand, config, db = None, writeq = Non # if hold'em, use positions and not antes, if stud do not use positions, use antes # this is used for handsplayers inserts, so still needed even if hudcache update is being skipped if base == "hold": - hudImportData = fpdb_simple.generateHudCacheData(playerIDs, base, category, actionTypes - , allIns, actionTypeByNo, winnings, totalWinnings, positions - , actionTypes, actionAmounts, None) + hudImportData = fpdb_simple.generateHudCacheData(playerIDs, base, + category, actionTypes, + allIns, actionTypeByNo, + winnings, + totalWinnings, + positions, actionTypes, + actionAmounts, None) else: - hudImportData = fpdb_simple.generateHudCacheData(playerIDs, base, category, actionTypes - , allIns, actionTypeByNo, winnings, totalWinnings, None - , actionTypes, actionAmounts, antes) + hudImportData = fpdb_simple.generateHudCacheData(playerIDs, base, + category, actionTypes, + allIns, actionTypeByNo, + winnings, + totalWinnings, None, + actionTypes, + actionAmounts, antes) - #print "parse: hand data prepared" # only reads up to here apart from inserting new players try: db.commit() # need to commit new players as different db connection used # for other writes. maybe this will change maybe not ... - except: + except: # TODO: this really needs to be narrowed down print "parse: error during commit: " + str(sys.exc_value) # HERE's an ugly kludge to keep from failing when positions is undef # We'll fix this by getting rid of the legacy importer. REB try: - if positions: pass - except: + if positions: + pass + except NameError: positions = [0, 0, 0, 0, 0, 0, 0, 0, 0, 0] # save data structures in a HandToWrite instance and then insert into database: htw = Database.HandToWrite() From 23acfbd6427e8bde1f1e0e16fd459c253e215aaa Mon Sep 17 00:00:00 2001 From: Eric Blade Date: Tue, 15 Sep 2009 21:25:26 -0500 Subject: [PATCH 12/28] deal with KeyErrors in update() in a vaguely intelligent fashion --- pyfpdb/Hud.py | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/pyfpdb/Hud.py b/pyfpdb/Hud.py index 392aa216..77143d79 100644 --- a/pyfpdb/Hud.py +++ b/pyfpdb/Hud.py @@ -334,11 +334,16 @@ class Hud: self.update_table_position() for s in self.stat_dict: - statd = self.stat_dict[s] + try: + statd = self.stat_dict[s] + except KeyError: + print "KeyError at the start of the for loop in update in hud_main. How this can possibly happen is totally beyond my comprehension. Your HUD may be about to get really weird. -Eric" + print "(btw, the key was ", s, " and statd is...", statd + continue try: self.stat_windows[statd['seat']].player_id = statd['player_id'] #self.stat_windows[self.stat_dict[s]['seat']].player_id = self.stat_dict[s]['player_id'] - except: # omg, we have more seats than stat windows .. damn poker sites with incorrect max seating info .. let's force 10 here + except KeyError: # omg, we have more seats than stat windows .. damn poker sites with incorrect max seating info .. let's force 10 here self.max = 10 self.create(hand, config, self.stat_dict, self.cards) self.stat_windows[statd['seat']].player_id = statd['player_id'] From a566d52b9a76a6bf278b46a9064fedce1071f0cd Mon Sep 17 00:00:00 2001 From: Eric Blade Date: Tue, 15 Sep 2009 21:26:10 -0500 Subject: [PATCH 13/28] cleaning cleaning cleaning.. keep them coders cleaning.. cleaning cleaning cleaning.. --- pyfpdb/fpdb_simple.py | 46 +++++++++++++++++++++---------------------- 1 file changed, 23 insertions(+), 23 deletions(-) diff --git a/pyfpdb/fpdb_simple.py b/pyfpdb/fpdb_simple.py index 3c5f6bca..02e5cd45 100644 --- a/pyfpdb/fpdb_simple.py +++ b/pyfpdb/fpdb_simple.py @@ -53,8 +53,9 @@ def checkPositions(positions): ### RHH modified to allow for "position 9" here (pos==9 is when you're a dead hand before the BB ### eric - position 8 could be valid - if only one blind is posted, but there's still 10 people, ie a sitout is present, and the small is dead... -#classifies each line for further processing in later code. Manipulates the passed arrays. def classifyLines(hand, category, lineTypes, lineStreets): + """ makes a list of classifications for each line for further processing + manipulates passed arrays """ currentStreet = "predeal" done = False #set this to true once we reach the last relevant line (the summary, except rake, is all repeats) for i, line in enumerate(hand): @@ -114,61 +115,59 @@ def classifyLines(hand, category, lineTypes, lineStreets): else: raise FpdbError("unrecognised linetype in:"+hand[i]) lineStreets.append(currentStreet) -#end def classifyLines def convert3B4B(category, limit_type, actionTypes, actionAmounts): """calculates the actual bet amounts in the given amount array and changes it accordingly.""" for i in xrange(len(actionTypes)): for j in xrange(len(actionTypes[i])): - bets=[] + bets = [] for k in xrange(len(actionTypes[i][j])): - if (actionTypes[i][j][k]=="bet"): + if (actionTypes[i][j][k] == "bet"): bets.append((i,j,k)) if (len(bets)>=2): #print "len(bets) 2 or higher, need to correct it. bets:",bets,"len:",len(bets) for betNo in reversed(xrange (1,len(bets))): - amount2=actionAmounts[bets[betNo][0]][bets[betNo][1]][bets[betNo][2]] - amount1=actionAmounts[bets[betNo-1][0]][bets[betNo-1][1]][bets[betNo-1][2]] - actionAmounts[bets[betNo][0]][bets[betNo][1]][bets[betNo][2]]=amount2-amount1 - #print "actionAmounts postConvert",actionAmounts -#end def convert3B4B(actionTypes, actionAmounts) + amount2 = actionAmounts[bets[betNo][0]][bets[betNo][1]][bets[betNo][2]] + amount1 = actionAmounts[bets[betNo-1][0]][bets[betNo-1][1]][bets[betNo-1][2]] + actionAmounts[bets[betNo][0]][bets[betNo][1]][bets[betNo][2]] = amount2 - amount1 -#Corrects the bet amount if the player had to pay blinds def convertBlindBet(actionTypes, actionAmounts): - i=0#setting street to pre-flop + """ Corrects the bet amount if the player had to pay blinds """ + i = 0#setting street to pre-flop for j in xrange(len(actionTypes[i])):#playerloop - blinds=[] - bets=[] + blinds = [] + bets = [] for k in xrange(len(actionTypes[i][j])): if actionTypes[i][j][k] == "blind": blinds.append((i,j,k)) if blinds and actionTypes[i][j][k] == "bet": -# if (len(blinds)>0 and actionTypes[i][j][k]=="bet"): bets.append((i,j,k)) if len(bets) == 1: blind_amount=actionAmounts[blinds[0][0]][blinds[0][1]][blinds[0][2]] bet_amount=actionAmounts[bets[0][0]][bets[0][1]][bets[0][2]] - actionAmounts[bets[0][0]][bets[0][1]][bets[0][2]]=bet_amount-blind_amount -#end def convertBlindBet + actionAmounts[bets[0][0]][bets[0][1]][bets[0][2]] = bet_amount - blind_amount #converts the strings in the given array to ints (changes the passed array, no returning). see table design for conversion details #todo: make this use convertCardValuesBoard def convertCardValues(arr): map(convertCardValuesBoard, arr) -#end def convertCardValues # a 0-card is one in a stud game that we did not see or was not shown -card_map = { 0: 0, "2": 2, "3" : 3, "4" : 4, "5" : 5, "6" : 6, "7" : 7, "8" : 8, "9" : 9, "T" : 10, "J" : 11, "Q" : 12, "K" : 13, "A" : 14} +card_map = { 0: 0, "2": 2, "3" : 3, "4" : 4, "5" : 5, "6" : 6, "7" : 7, "8" : 8, + "9" : 9, "T" : 10, "J" : 11, "Q" : 12, "K" : 13, "A" : 14} -#converts the strings in the given array to ints (changes the passed array, no returning). see table design for conversion details def convertCardValuesBoard(arr): + """ converts the strings in the given array to ints + (changes the passed array, no returning). see table design for + conversion details """ for i in xrange(len(arr)): arr[i] = card_map[arr[i]] -#end def convertCardValuesBoard -#this creates the 2D/3D arrays. manipulates the passed arrays instead of returning. -def createArrays(category, seats, card_values, card_suits, antes, winnings, rakes, action_types, allIns, action_amounts, actionNos, actionTypeByNo): +def createArrays(category, seats, card_values, card_suits, antes, winnings, + rakes, action_types, allIns, action_amounts, actionNos, + actionTypeByNo): + """ this creates the 2D/3D arrays. manipulates the passed arrays instead of returning. """ for i in xrange(seats):#create second dimension arrays card_values.append( [] ) card_suits.append( [] ) @@ -176,7 +175,8 @@ def createArrays(category, seats, card_values, card_suits, antes, winnings, rake winnings.append(0) rakes.append(0) - streetCount = 4 if category == "holdem" or category == "omahahi" or category == "omahahilo" else 5 + streetCount = 4 if (category == "holdem" or category == "omahahi" or + category == "omahahilo") else 5 for i in xrange(streetCount): #build the first dimension array, for streets action_types.append([]) From ba663c231c1011afce6bae9cc96d95474cbf5313 Mon Sep 17 00:00:00 2001 From: Eric Blade Date: Tue, 15 Sep 2009 22:04:37 -0500 Subject: [PATCH 14/28] cleanups --- pyfpdb/fpdb_simple.py | 223 ++++++++++++++++++------------------------ 1 file changed, 96 insertions(+), 127 deletions(-) diff --git a/pyfpdb/fpdb_simple.py b/pyfpdb/fpdb_simple.py index 02e5cd45..084949d6 100644 --- a/pyfpdb/fpdb_simple.py +++ b/pyfpdb/fpdb_simple.py @@ -184,14 +184,14 @@ def createArrays(category, seats, card_values, card_suits, antes, winnings, action_amounts.append([]) actionNos.append([]) actionTypeByNo.append([]) - for j in xrange (seats): #second dimension arrays: players + for j in xrange(seats): # second dimension arrays: players action_types[i].append([]) allIns[i].append([]) action_amounts[i].append([]) actionNos[i].append([]) # if (category=="holdem" or category=="omahahi" or category=="omahahilo"): # pass - if category=="razz" or category=="studhi" or category=="studhilo":#need to fill card arrays. + if category == "razz" or category == "studhi" or category == "studhilo": #need to fill card arrays. for i in xrange(seats): for j in xrange(7): card_values[i].append(0) @@ -201,25 +201,24 @@ def createArrays(category, seats, card_values, card_suits, antes, winnings, #end def createArrays def fill_board_cards(board_values, board_suits): -#fill up the two board card arrays - while (len(board_values)<5): + """ fill up the two board card arrays """ + while len(board_values) < 5: board_values.append(0) board_suits.append("x") -#end def fill_board_cards def fillCardArrays(player_count, base, category, card_values, card_suits): """fills up the two card arrays""" - if (category=="holdem"): + if category == "holdem": cardCount = 2 - elif (category=="omahahi" or category=="omahahilo"): + elif category == "omahahi" or category == "omahahilo": cardCount = 4 - elif base=="stud": + elif base == "stud": cardCount = 7 else: raise FpdbError("invalid category:", category) for i in xrange(player_count): - while (len(card_values[i]) < cardCount): + while len(card_values[i]) < cardCount: card_values[i].append(0) card_suits[i].append("x") #end def fillCardArrays @@ -230,12 +229,12 @@ def filterAnteBlindFold(hand): #todo: this'll only get rid of one ante folder, not multiple ones #todo: in tourneys this should not be removed but #print "start of filterAnteBlindFold" - pre3rd=[] + pre3rd = [] for i, line in enumerate(hand): if line.startswith("*** 3") or line.startswith("*** HOLE"): pre3rd = hand[0:i] - foldeeName=None + foldeeName = None for line in pre3rd: if line.endswith("folds") or line.endswith("is sitting out") or line.endswith(" stands up"): #found ante fold or timeout pos = line.find(" folds") @@ -251,26 +250,25 @@ def filterAnteBlindFold(hand): pos2 = line.find(" (") foldeeName = line[pos1:pos2] - if foldeeName!=None: + if foldeeName is not None: #print "filterAnteBlindFold, foldeeName:",foldeeName for i, line in enumerate(hand): if foldeeName in line: hand[i] = None return [line for line in hand if line] -#end def filterAnteFold def stripEOLspaces(str): return str.rstrip() -#removes useless lines as well as trailing spaces def filterCrap(hand, isTourney): - #remove two trailing spaces at end of line + """ removes useless lines as well as trailing spaces """ + + #remove trailing spaces at end of line hand = [line.rstrip() for line in hand] - #print "hand after trailing space removal in filterCrap:",hand #general variable position word filter/string filter - for i in xrange (len(hand)): + for i in xrange(len(hand)): if hand[i].startswith("Board ["): hand[i] = False elif hand[i].find(" out of hand ")!=-1: @@ -347,15 +345,16 @@ def filterCrap(hand, isTourney): hand[i] = False elif (hand[i].endswith(" is sitting out")): hand[i] = False - - hand = [line for line in hand if line] # python docs say this is identical to filter(None, list) + # python docs say this is identical to filter(None, list) + # which removes all false items from the passed list (hand) + hand = [line for line in hand if line] - #print "done with filterCrap, hand:", hand return hand -#end filterCrap -#takes a poker float (including , for thousand seperator and converts it to an int def float2int(string): + """ takes a poker float (including , for thousand seperator) and + converts it to an int """ + # Note that this automagically assumes US style currency formatters pos = string.find(",") if pos != -1: #remove , the thousand seperator string = "%s%s" % (string[0:pos], string[pos+1:]) @@ -368,56 +367,46 @@ def float2int(string): if pos == -1: #no decimal point - was in full dollars - need to multiply with 100 result *= 100 return result -#end def float2int -ActionLines = ( "calls $", ": calls ", "brings in for", "completes it to", "posts small blind", - "posts the small blind", "posts big blind", "posts the big blind", - "posts small & big blinds", "posts $", "posts a dead", "bets $", - ": bets ", " raises") +ActionLines = ( "calls $", ": calls ", "brings in for", "completes it to", + "posts small blind", "posts the small blind", "posts big blind", + "posts the big blind", "posts small & big blinds", "posts $", + "posts a dead", "bets $", ": bets ", " raises") -#returns boolean whether the passed line is an action line def isActionLine(line): - if (line.endswith("folds")): + if line.endswith("folds"): return True - elif (line.endswith("checks")): + elif line.endswith("checks"): return True - elif (line.startswith("Uncalled bet")): + elif line.startswith("Uncalled bet"): return True - + + # searches for each member of ActionLines being in line, returns true + # on first match .. neat func return any(x for x in ActionLines if x in line) -# return bool([ x for x in ActionLines if x in line]) -# ret = any(True for searchstr in ActionLines if searchstr in line) -# ret = len( [ x for x in ActionLines if line.find(x) > -1] ) > 0 -# ret = any(searchstr in line for searchstr in ActionLines) -#end def isActionLine -#returns whether this is a duplicate def isAlreadyInDB(db, gametypeID, siteHandNo): - #print "isAlreadyInDB gtid,shand:",gametypeID, siteHandNo c = db.get_cursor() - c.execute( db.sql.query['isAlreadyInDB'], (gametypeID, siteHandNo)) + c.execute(db.sql.query['isAlreadyInDB'], (gametypeID, siteHandNo)) result = c.fetchall() - if (len(result)>=1): + if len(result) >= 1: raise DuplicateError ("dupl") -#end isAlreadyInDB def isRebuyOrAddon(topline): """isRebuyOrAddon not implemented yet""" return False -#end def isRebuyOrAddon #returns whether the passed topline indicates a tournament or not def isTourney(topline): return "Tournament" in topline -#end def isTourney WinLines = ( "wins the pot", "ties for the ", "wins side pot", "wins the low main pot", "wins the high main pot", "wins the low", "wins the high pot", "wins the high side pot", "wins the main pot", "wins the side pot", "collected" ) -#returns boolean whether the passed line is a win line + def isWinLine(line): + """ returns boolean whether the passed line is a win line """ return any(x for x in WinLines if x in line) -#end def isWinLine #returns the amount of cash/chips put into the put in the given action line def parseActionAmount(line, atype, isTourney): @@ -426,7 +415,8 @@ def parseActionAmount(line, atype, isTourney): #elif (line.endswith(", and is all in")): # line=line[:-15] - if line.endswith(", and is capped"):#ideally we should recognise this as an all-in if category is capXl + #ideally we should recognise this as an all-in if category is capXl + if line.endswith(", and is capped"): line=line[:-15] if line.endswith(" and is capped"): line=line[:-14] @@ -439,9 +429,9 @@ def parseActionAmount(line, atype, isTourney): pos1 = line.find("(") + 1 pos2 = line.find(")") amount = float2int(line[pos1:pos2]) - elif atype == "bet" and line.find(": raises $")!=-1 and line.find("to $")!=-1: - pos=line.find("to $")+4 - amount=float2int(line[pos:]) + elif atype == "bet" and ": raises $" in line and "to $" in line: + pos = line.find("to $")+4 + amount = float2int(line[pos:]) else: if not isTourney: pos = line.rfind("$")+1 @@ -489,7 +479,6 @@ def parseActionLine(base, isTourney, line, street, playerIDs, names, action_type actionNos[street][playerno].append(nextActionNo) tmp=(playerIDs[playerno], atype) actionTypeByNo[street].append(tmp) -#end def parseActionLine def goesAllInOnThisLine(line): """returns whether the player went all-in on this line and removes the all-in text from the line.""" @@ -501,7 +490,6 @@ def goesAllInOnThisLine(line): line = line[:-15] isAllIn = True return (line, isAllIn) -#end def goesAllInOnThisLine #returns the action type code (see table design) of the given action line ActionTypes = { 'brings in for' :"blind", @@ -530,7 +518,6 @@ def parseActionType(line): if x in line: return ActionTypes[x] raise FpdbError ("failed to recognise actiontype in parseActionLine in: "+line) -#end def parseActionType #parses the ante out of the given line and checks which player paid it, updates antes accordingly. def parseAnteLine(line, isTourney, names, antes): @@ -547,15 +534,12 @@ def parseAnteLine(line, isTourney, names, antes): pos1 = line.rfind("ante") + 5 pos2 = line.find(" ", pos1) antes[i] += int(line[pos1:pos2]) - #print "parseAnteLine line: ", line, "antes[i]", antes[i], "antes", antes -#end def parseAntes #returns the buyin of a tourney in cents def parseBuyin(topline): pos1 = topline.find("$")+1 pos2 = topline.find("+") return float2int(topline[pos1:pos2]) -#end def parseBuyin #parses a card line and changes the passed arrays accordingly #todo: reorganise this messy method @@ -568,8 +552,9 @@ def parseCardLine(category, street, line, names, cardValues, cardSuits, boardVal for i in (pos, pos+3): cardValues[playerNo].append(line[i:i+1]) cardSuits[playerNo].append(line[i+1:i+2]) - if len(cardValues[playerNo]) !=2: - if cardValues[playerNo][0]==cardValues[playerNo][2] and cardSuits[playerNo][1]==cardSuits[playerNo][3]: #two tests will do + if len(cardValues[playerNo]) != 2: + if (cardValues[playerNo][0] == cardValues[playerNo][2] and + cardSuits[playerNo][1] == cardSuits[playerNo][3]): cardValues[playerNo]=cardValues[playerNo][0:2] cardSuits[playerNo]=cardSuits[playerNo][0:2] else: @@ -580,13 +565,14 @@ def parseCardLine(category, street, line, names, cardValues, cardSuits, boardVal cardValues[playerNo].append(line[i:i+1]) cardSuits[playerNo].append(line[i+1:i+2]) if (len(cardValues[playerNo])!=4): - if cardValues[playerNo][0]==cardValues[playerNo][4] and cardSuits[playerNo][3]==cardSuits[playerNo][7]: #two tests will do - cardValues[playerNo]=cardValues[playerNo][0:4] - cardSuits[playerNo]=cardSuits[playerNo][0:4] + if (cardValues[playerNo][0] == cardValues[playerNo][4] and + cardSuits[playerNo][3] == cardSuits[playerNo][7]): #two tests will do + cardValues[playerNo] = cardValues[playerNo][0:4] + cardSuits[playerNo] = cardSuits[playerNo][0:4] else: print "line:",line,"cardValues[playerNo]:",cardValues[playerNo] raise FpdbError("read too many/too few holecards in parseCardLine") - elif category=="razz" or category=="studhi" or category=="studhilo": + elif category == "razz" or category == "studhi" or category == "studhilo": if "shows" not in line and "mucked" not in line: #print "parseCardLine(in stud if), street:", street if line[pos+2]=="]": #-> not (hero and 3rd street) @@ -631,7 +617,6 @@ def parseCardLine(category, street, line, names, cardValues, cardSuits, boardVal #print boardValues else: raise FpdbError ("unrecognised line:"+line) -#end def parseCardLine def parseCashesAndSeatNos(lines): """parses the startCashes and seatNos of each player out of the given lines and returns them as a dictionary of two arrays""" @@ -647,7 +632,6 @@ def parseCashesAndSeatNos(lines): pos2=lines[i].find(" in chips") cashes.append(float2int(lines[i][pos1:pos2])) return {'startCashes':cashes, 'seatNos':seatNos} -#end def parseCashesAndSeatNos #returns the buyin of a tourney in cents def parseFee(topline): @@ -655,7 +639,6 @@ def parseFee(topline): pos1=topline.find("$",pos1)+1 pos2=topline.find(" ", pos1) return float2int(topline[pos1:pos2]) -#end def parsefee #returns a datetime object with the starttime indicated in the given topline def parseHandStartTime(topline): @@ -688,10 +671,9 @@ def parseHandStartTime(topline): result = datetime.datetime(int(m.group('YEAR')), int(m.group('MON')), int(m.group('DAY')), int(m.group('HR')), int(m.group('MIN')), int(m.group('SEC'))) if not isUTC: #these use US ET - result+=datetime.timedelta(hours=5) + result += datetime.timedelta(hours=5) return result -#end def parseHandStartTime #parses the names out of the given lines and returns them as an array def findName(line): @@ -701,13 +683,11 @@ def findName(line): def parseNames(lines): return [findName(line) for line in lines] -#end def parseNames def parsePositions(hand, names): positions = [-1 for i in names] sb, bb = -1, -1 - #find blinds for line in hand: if sb == -1 and "small blind" in line and "dead small blind" not in line: sb = line @@ -735,10 +715,7 @@ def parsePositions(hand, names): positions[bb]="B" #fill up rest of array - if sbExists: - arraypos = sb-1 - else: - arraypos = bb-1 + arraypos = sb - 1 if sbExists else bb - 1 distFromBtn=0 while arraypos >= 0 and arraypos != bb: @@ -753,21 +730,19 @@ def parsePositions(hand, names): while positions[i] < 0 and i != sb: positions[i] = 9 i -= 1 - ### RHH - Changed to set the null seats before BB to "9" - if sbExists: - i = sb-1 - else: - i = bb-1 + ### RHH - Changed to set the null seats before BB to "9" + i = sb - 1 if sbExists else bb - 1 + while positions[i] < 0: positions[i]=9 i-=1 arraypos=len(names)-1 if (bb!=0 or (bb==0 and sbExists==False) or (bb == 1 and sb != arraypos) ): - while (arraypos>bb and arraypos > sb): - positions[arraypos]=distFromBtn - arraypos-=1 - distFromBtn+=1 + while (arraypos > bb and arraypos > sb): + positions[arraypos] = distFromBtn + arraypos -= 1 + distFromBtn += 1 if any(p == -1 for p in positions): print "parsePositions names:",names @@ -775,21 +750,18 @@ def parsePositions(hand, names): raise FpdbError ("failed to read positions") # print str(positions), "\n" return positions -#end def parsePositions #simply parses the rake amount and returns it as an int def parseRake(line): - pos=line.find("Rake")+6 - rake=float2int(line[pos:]) + pos = line.find("Rake")+6 + rake = float2int(line[pos:]) return rake -#end def parseRake def parseSiteHandNo(topline): """returns the hand no assigned by the poker site""" - pos1=topline.find("#")+1 - pos2=topline.find(":") + pos1 = topline.find("#")+1 + pos2 = topline.find(":") return topline[pos1:pos2] -#end def parseSiteHandNo def parseTableLine(base, line): """returns a dictionary with maxSeats and tableName""" @@ -804,11 +776,10 @@ def parseTableLine(base, line): #returns the hand no assigned by the poker site def parseTourneyNo(topline): - pos1=topline.find("Tournament #")+12 - pos2=topline.find(",", pos1) + pos1 = topline.find("Tournament #")+12 + pos2 = topline.find(",", pos1) #print "parseTourneyNo pos1:",pos1," pos2:",pos2, " result:",topline[pos1:pos2] return topline[pos1:pos2] -#end def parseTourneyNo #parses a win/collect line. manipulates the passed array winnings, no explicit return def parseWinLine(line, names, winnings, isTourney): @@ -819,12 +790,11 @@ def parseWinLine(line, names, winnings, isTourney): if isTourney: pos1 = line.rfind("collected ") + 10 pos2 = line.find(" ", pos1) - winnings[i]+=int(line[pos1:pos2]) + winnings[i] += int(line[pos1:pos2]) else: pos1 = line.rfind("$") + 1 pos2 = line.find(" ", pos1) winnings[i] += float2int(line[pos1:pos2]) -#end def parseWinLine #returns the category (as per database) string for the given line def recogniseCategory(line): @@ -844,7 +814,6 @@ def recogniseCategory(line): return "studhilo" else: raise FpdbError("failed to recognise category, line:"+line) -#end def recogniseCategory #returns the int for the gametype_id for the given line def recogniseGametypeID(backend, db, cursor, topline, smallBlindLine, site_id, category, isTourney):#todo: this method is messy @@ -853,50 +822,50 @@ def recogniseGametypeID(backend, db, cursor, topline, smallBlindLine, site_id, c #note: the below variable names small_bet and big_bet are misleading, in NL/PL they mean small/big blind if isTourney: - type="tour" - pos1=topline.find("(")+1 - if (topline[pos1]=="H" or topline[pos1]=="O" or topline[pos1]=="R" or topline[pos1]=="S" or topline[pos1+2]=="C"): - pos1=topline.find("(", pos1)+1 - pos2=topline.find("/", pos1) - small_bet=int(topline[pos1:pos2]) + type = "tour" + pos1 = topline.find("(")+1 + if(topline[pos1] == "H" or topline[pos1] == "O" or + topline[pos1] == "R" or topline[pos1]=="S" or + topline[pos1+2] == "C"): + pos1 = topline.find("(", pos1)+1 + pos2 = topline.find("/", pos1) + small_bet = int(topline[pos1:pos2]) else: - type="ring" - pos1=topline.find("$")+1 - pos2=topline.find("/$") - small_bet=float2int(topline[pos1:pos2]) + type = "ring" + pos1 = topline.find("$")+1 + pos2 = topline.find("/$") + small_bet = float2int(topline[pos1:pos2]) - pos1=pos2+2 + pos1 = pos2+2 if isTourney: - pos1-=1 - pos2=topline.find(")") + pos1 -= 1 + pos2 = topline.find(")") - if pos2<=pos1: - pos2=topline.find(")", pos1) + if pos2 <= pos1: + pos2 = topline.find(")", pos1) if isTourney: - big_bet=int(topline[pos1:pos2]) + big_bet = int(topline[pos1:pos2]) else: - big_bet=float2int(topline[pos1:pos2]) + big_bet = float2int(topline[pos1:pos2]) - if (topline.find("No Limit")!=-1): - limit_type="nl" - if (topline.find("Cap No")!=-1): - limit_type="cn" - elif (topline.find("Pot Limit")!=-1): - limit_type="pl" - if (topline.find("Cap Pot")!=-1): - limit_type="cp" + if 'No Limit' in topline: + limit_type = "nl" if 'Cap No' not in topline else "cn" + elif 'Pot Limit' in topline: + limit_type = "pl" if 'Cap Pot' not in topline else "cp" else: - limit_type="fl" + limit_type = "fl" #print "recogniseGametypeID small_bet/blind:",small_bet,"big bet/blind:", big_bet,"limit type:",limit_type - if (limit_type=="fl"): - cursor.execute ( db.sql.query['getGametypeFL'] - , (site_id, type, category, limit_type, small_bet, big_bet)) + if limit_type == "fl": + cursor.execute(db.sql.query['getGametypeFL'], (site_id, type, category, + limit_type, small_bet, + big_bet)) else: - cursor.execute ( db.sql.query['getGametypeNL'] - , (site_id, type, category, limit_type, small_bet, big_bet)) - result=cursor.fetchone() + cursor.execute(db.sql.query['getGametypeNL'], (site_id, type, category, + limit_type, small_bet, + big_bet)) + result = cursor.fetchone() #print "recgt1 result=",result #ret=result[0] #print "recgt1 ret=",ret From bcecf643f2e108e36c5eb7a6ec6b349848460ec8 Mon Sep 17 00:00:00 2001 From: Eric Blade Date: Tue, 15 Sep 2009 22:10:37 -0500 Subject: [PATCH 15/28] cleanup imports section and spacing in fpdb_db --- pyfpdb/fpdb_db.py | 33 ++++++++++++++++----------------- 1 file changed, 16 insertions(+), 17 deletions(-) diff --git a/pyfpdb/fpdb_db.py b/pyfpdb/fpdb_db.py index 1e74865e..2b73a40e 100644 --- a/pyfpdb/fpdb_db.py +++ b/pyfpdb/fpdb_db.py @@ -21,19 +21,18 @@ import re import sys import logging from time import time, strftime +from Exceptions import * -use_pool = False try: import sqlalchemy.pool as pool use_pool = True -except: +except ImportError: logging.info("Not using sqlalchemy connection pool.") + use_pool = False import fpdb_simple import FpdbSQLQueries -from Exceptions import * - class fpdb_db: MYSQL_INNODB = 2 @@ -67,12 +66,12 @@ class fpdb_db: """Connects a database with the given parameters""" if backend is None: raise FpdbError('Database backend not defined') - self.backend=backend - self.host=host - self.user=user - self.password=password - self.database=database - if backend==fpdb_db.MYSQL_INNODB: + self.backend = backend + self.host = host + self.user = user + self.password = password + self.database = database + if backend == fpdb_db.MYSQL_INNODB: import MySQLdb if use_pool: MySQLdb = pool.manage(MySQLdb, pool_size=5) @@ -113,7 +112,7 @@ class fpdb_db: msg = "PostgreSQL connection to database (%s) user (%s) failed." % (database, user) print msg raise FpdbError(msg) - elif backend==fpdb_db.SQLITE: + elif backend == fpdb_db.SQLITE: logging.info("Connecting to SQLite:%(database)s" % {'database':database}) import sqlite3 if use_pool: @@ -125,20 +124,20 @@ class fpdb_db: sqlite3.register_adapter(bool, lambda x: "1" if x else "0") else: raise FpdbError("unrecognised database backend:"+backend) - self.cursor=self.db.cursor() + self.cursor = self.db.cursor() # Set up query dictionary as early in the connection process as we can. self.sql = FpdbSQLQueries.FpdbSQLQueries(self.get_backend_name()) self.cursor.execute(self.sql.query['set tx level']) - self.wrongDbVersion=False + self.wrongDbVersion = False try: self.cursor.execute("SELECT * FROM Settings") - settings=self.cursor.fetchone() - if settings[0]!=118: + settings = self.cursor.fetchone() + if settings[0] != 118: print "outdated or too new database version - please recreate tables" - self.wrongDbVersion=True + self.wrongDbVersion = True except:# _mysql_exceptions.ProgrammingError: if database != ":memory:": print "failed to read settings table - please recreate tables" - self.wrongDbVersion=True + self.wrongDbVersion = True #end def connect def disconnect(self, due_to_error=False): From ba1513847b2c043a5bff74a3e7d73a38b0c19a1d Mon Sep 17 00:00:00 2001 From: Eric Blade Date: Tue, 15 Sep 2009 23:30:59 -0500 Subject: [PATCH 16/28] clean up exception handling in Configuration and imports in GuiGraphViewer --- pyfpdb/Configuration.py | 15 +++++++++------ pyfpdb/GuiGraphViewer.py | 2 +- 2 files changed, 10 insertions(+), 7 deletions(-) diff --git a/pyfpdb/Configuration.py b/pyfpdb/Configuration.py index e6361fb0..1b2f47b4 100755 --- a/pyfpdb/Configuration.py +++ b/pyfpdb/Configuration.py @@ -316,8 +316,8 @@ class Config: # Parse even if there was no real config file found and we are using the example # If using the example, we'll edit it later + log.info("Reading configuration file %s" % file) try: - log.info("Reading configuration file %s" % (file)) doc = xml.dom.minidom.parse(file) except: log.error("Error parsing %s. See error log file." % (file)) @@ -353,20 +353,22 @@ class Config: for db_node in doc.getElementsByTagName("database"): try: db = Database(node = db_node) + except: + raise FpdbError("Unable to create database object") + else: if db.db_name in self.supported_databases: raise FpdbError("Database names must be unique") - # If there is only one Database node, or none are marked default, the first is selected - if len(self.supported_databases) == 0: + # If there is only one Database node, or none are marked + # default, use first + if not self.supported_databases: self.db_selected = db.db_name self.supported_databases[db.db_name] = db if db.db_selected: self.db_selected = db.db_name - except: - raise + if dbname and dbname in self.supported_databases: self.db_selected = dbname - # s_dbs = doc.getElementsByTagName("mucked_windows") for aw_node in doc.getElementsByTagName("aw"): aw = Aux_window(node = aw_node) @@ -535,6 +537,7 @@ class Config: def get_db_parameters(self): db = {} name = self.db_selected + # TODO: What's up with all the exception handling here?! try: db['db-databaseName'] = name except: pass diff --git a/pyfpdb/GuiGraphViewer.py b/pyfpdb/GuiGraphViewer.py index 645896b4..f5beadcf 100644 --- a/pyfpdb/GuiGraphViewer.py +++ b/pyfpdb/GuiGraphViewer.py @@ -32,7 +32,7 @@ try: from matplotlib.backends.backend_gtkagg import NavigationToolbar2GTKAgg as NavigationToolbar from numpy import arange, cumsum from pylab import * -except: +except ImportError: print """Failed to load libs for graphing, graphing will not function. Please in stall numpy and matplotlib if you want to use graphs.""" print """This is of no consequence for other parts of the program, e.g. import From 0938afb8829d45cea7d3b0dca0fdc8957c8b287a Mon Sep 17 00:00:00 2001 From: Eric Blade Date: Tue, 15 Sep 2009 23:32:23 -0500 Subject: [PATCH 17/28] FTtoFPDB: readBlinds: cleanup exception handler also deal with finishPositions not being accurate, by printing a message to that effect, instead of crashing an import --- pyfpdb/FulltiltToFpdb.py | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/pyfpdb/FulltiltToFpdb.py b/pyfpdb/FulltiltToFpdb.py index d24c7bdd..ea17c21a 100755 --- a/pyfpdb/FulltiltToFpdb.py +++ b/pyfpdb/FulltiltToFpdb.py @@ -289,11 +289,12 @@ class Fulltilt(HandHistoryConverter): def readBlinds(self, hand): + m = self.re_PostBB.search(hand.handText) try: - m = self.re_PostSB.search(hand.handText) hand.addBlind(m.group('PNAME'), 'small blind', m.group('SB')) - except: # no small blind + except IndexError: # no small blind found hand.addBlind(None, None, None) + for a in self.re_PostBB.finditer(hand.handText): hand.addBlind(a.group('PNAME'), 'big blind', a.group('BB')) for a in self.re_PostBoth.finditer(hand.handText): @@ -656,7 +657,9 @@ class Fulltilt(HandHistoryConverter): heroName = n.group('HERO_NAME') tourney.hero = heroName # Is this really useful ? - if (tourney.finishPositions[heroName] != Decimal(n.group('HERO_FINISHING_POS'))): + if heroName not in tourney.finishPositions: + print heroName, "not found in tourney.finishPositions ..." + elif (tourney.finishPositions[heroName] != Decimal(n.group('HERO_FINISHING_POS'))): print "Bad parsing : finish position incoherent : %s / %s" % (tourney.finishPositions[heroName], n.group('HERO_FINISHING_POS')) return True From 2095f3c89908e1c4072564344f778a18b413b9e5 Mon Sep 17 00:00:00 2001 From: Eric Blade Date: Wed, 16 Sep 2009 00:13:42 -0500 Subject: [PATCH 18/28] use with..as for file reading/writing, as we don't need 2.4 compat anyway right? --- pyfpdb/Configuration.py | 22 ++++++++++------------ 1 file changed, 10 insertions(+), 12 deletions(-) diff --git a/pyfpdb/Configuration.py b/pyfpdb/Configuration.py index 1b2f47b4..61308641 100755 --- a/pyfpdb/Configuration.py +++ b/pyfpdb/Configuration.py @@ -24,6 +24,7 @@ Handles HUD configuration files. ######################################################################## # Standard Library modules +from __future__ import with_statement import os import sys import inspect @@ -444,12 +445,11 @@ class Config: def read_default_conf(self, file): parms = {} - fh = open(file, "r") - for line in fh: - line = string.strip(line) - (key, value) = line.split('=') - parms[key] = value - fh.close + with open(file, "r") as fh: + for line in fh: + line = string.strip(line) + (key, value) = line.split('=') + parms[key] = value return parms def find_example_config(self): @@ -498,14 +498,12 @@ class Config: def save(self, file = None): if file != None: - f = open(file, 'w') - self.doc.writexml(f) - f.close() + with open(file, 'w') as f: + self.doc.writexml(f) else: shutil.move(self.file, self.file+".backup") - f = open(self.file, 'w') - self.doc.writexml(f) - f.close + with open(self.file, 'w'): + self.doc.writexml(f) def edit_layout(self, site_name, max, width = None, height = None, fav_seat = None, locations = None): From ded05cb290bf7a0c4da71240e5a840c13a7941e8 Mon Sep 17 00:00:00 2001 From: Eric Blade Date: Wed, 16 Sep 2009 00:54:29 -0500 Subject: [PATCH 19/28] put the regex search back into the try: in FT readBlinds() because it broke FL games somehow --- pyfpdb/FulltiltToFpdb.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pyfpdb/FulltiltToFpdb.py b/pyfpdb/FulltiltToFpdb.py index ea17c21a..e9c07e20 100755 --- a/pyfpdb/FulltiltToFpdb.py +++ b/pyfpdb/FulltiltToFpdb.py @@ -289,8 +289,8 @@ class Fulltilt(HandHistoryConverter): def readBlinds(self, hand): - m = self.re_PostBB.search(hand.handText) try: + m = self.re_PostBB.search(hand.handText) hand.addBlind(m.group('PNAME'), 'small blind', m.group('SB')) except IndexError: # no small blind found hand.addBlind(None, None, None) From 7ed5d0972e52b9cfc0caedcba61774106f655543 Mon Sep 17 00:00:00 2001 From: Eric Blade Date: Wed, 16 Sep 2009 00:13:42 -0500 Subject: [PATCH 20/28] use with..as for file reading/writing, as we don't need 2.4 compat anyway right? --- pyfpdb/Configuration.py | 22 ++++++++++------------ 1 file changed, 10 insertions(+), 12 deletions(-) diff --git a/pyfpdb/Configuration.py b/pyfpdb/Configuration.py index 1b2f47b4..61308641 100755 --- a/pyfpdb/Configuration.py +++ b/pyfpdb/Configuration.py @@ -24,6 +24,7 @@ Handles HUD configuration files. ######################################################################## # Standard Library modules +from __future__ import with_statement import os import sys import inspect @@ -444,12 +445,11 @@ class Config: def read_default_conf(self, file): parms = {} - fh = open(file, "r") - for line in fh: - line = string.strip(line) - (key, value) = line.split('=') - parms[key] = value - fh.close + with open(file, "r") as fh: + for line in fh: + line = string.strip(line) + (key, value) = line.split('=') + parms[key] = value return parms def find_example_config(self): @@ -498,14 +498,12 @@ class Config: def save(self, file = None): if file != None: - f = open(file, 'w') - self.doc.writexml(f) - f.close() + with open(file, 'w') as f: + self.doc.writexml(f) else: shutil.move(self.file, self.file+".backup") - f = open(self.file, 'w') - self.doc.writexml(f) - f.close + with open(self.file, 'w'): + self.doc.writexml(f) def edit_layout(self, site_name, max, width = None, height = None, fav_seat = None, locations = None): From fbceb6d7afb6692dddafc002147711dcbe90377e Mon Sep 17 00:00:00 2001 From: Eric Blade Date: Wed, 16 Sep 2009 01:28:28 -0500 Subject: [PATCH 21/28] bypass the changes made in readBlinds which somehow broke the hell out of stuff --- pyfpdb/FulltiltToFpdb.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/pyfpdb/FulltiltToFpdb.py b/pyfpdb/FulltiltToFpdb.py index d24c7bdd..a74d71d3 100755 --- a/pyfpdb/FulltiltToFpdb.py +++ b/pyfpdb/FulltiltToFpdb.py @@ -656,7 +656,9 @@ class Fulltilt(HandHistoryConverter): heroName = n.group('HERO_NAME') tourney.hero = heroName # Is this really useful ? - if (tourney.finishPositions[heroName] != Decimal(n.group('HERO_FINISHING_POS'))): + if heroName not in tourney.finishPositions: + print heroName, "not found in tourney.finishPositions ..." + elif (tourney.finishPositions[heroName] != Decimal(n.group('HERO_FINISHING_POS'))): print "Bad parsing : finish position incoherent : %s / %s" % (tourney.finishPositions[heroName], n.group('HERO_FINISHING_POS')) return True From 226153f15fd14cd2bee294b3fb995186003fc86e Mon Sep 17 00:00:00 2001 From: Eric Blade Date: Wed, 16 Sep 2009 01:40:43 -0500 Subject: [PATCH 22/28] Revert "FTtoFPDB: readBlinds: cleanup exception handler" This reverts commit 0938afb8829d45cea7d3b0dca0fdc8957c8b287a. Conflicts: pyfpdb/FulltiltToFpdb.py --- pyfpdb/FulltiltToFpdb.py | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/pyfpdb/FulltiltToFpdb.py b/pyfpdb/FulltiltToFpdb.py index ab5eac4a..a74d71d3 100644 --- a/pyfpdb/FulltiltToFpdb.py +++ b/pyfpdb/FulltiltToFpdb.py @@ -290,11 +290,10 @@ class Fulltilt(HandHistoryConverter): def readBlinds(self, hand): try: - m = self.re_PostBB.search(hand.handText) + m = self.re_PostSB.search(hand.handText) hand.addBlind(m.group('PNAME'), 'small blind', m.group('SB')) - except IndexError: # no small blind found + except: # no small blind hand.addBlind(None, None, None) - for a in self.re_PostBB.finditer(hand.handText): hand.addBlind(a.group('PNAME'), 'big blind', a.group('BB')) for a in self.re_PostBoth.finditer(hand.handText): From 3f0ede67eec4dd2ca2d5ea84f5ba97b1130c5999 Mon Sep 17 00:00:00 2001 From: Eric Blade Date: Thu, 17 Sep 2009 05:26:06 -0500 Subject: [PATCH 23/28] fix a small error that caused deletion of your hud_config when saving.. oopsie --- pyfpdb/Configuration.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pyfpdb/Configuration.py b/pyfpdb/Configuration.py index 61308641..b8022a45 100755 --- a/pyfpdb/Configuration.py +++ b/pyfpdb/Configuration.py @@ -502,7 +502,7 @@ class Config: self.doc.writexml(f) else: shutil.move(self.file, self.file+".backup") - with open(self.file, 'w'): + with open(self.file, 'w') as f: self.doc.writexml(f) def edit_layout(self, site_name, max, width = None, height = None, From 84dc9652dfed22acd5d93f31793043d53e6733dd Mon Sep 17 00:00:00 2001 From: Mika Bostrom Date: Sat, 19 Sep 2009 11:10:07 +0300 Subject: [PATCH 24/28] Fix table creation for Postgres PostgreSQL does not have an UNSIGNED specifier in its language. Mysql's "TINYINT UNSIGNED" is postgreSQL's "SMALLINT" which is a bit inconvenient but apart from annoying, not a problem. --- pyfpdb/SQL.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pyfpdb/SQL.py b/pyfpdb/SQL.py index c8639fbc..986f9762 100644 --- a/pyfpdb/SQL.py +++ b/pyfpdb/SQL.py @@ -400,7 +400,7 @@ class Sql: endTime timestamp without time zone, buyinChips INT, tourneyName varchar(40), - matrixIdProcessed SMALLINT UNSIGNED DEFAULT 0, /* Mask use : 1=Positionnal Winnings|2=Match1|4=Match2|...|pow(2,n)=Matchn */ + matrixIdProcessed SMALLINT DEFAULT 0, /* Mask use : 1=Positionnal Winnings|2=Match1|4=Match2|...|pow(2,n)=Matchn */ rebuyChips INT DEFAULT 0, addonChips INT DEFAULT 0, rebuyAmount INT DEFAULT 0, From e54c45b7d1b8bbb59526cc7d99e8700e58f81bbb Mon Sep 17 00:00:00 2001 From: Mika Bostrom Date: Sat, 19 Sep 2009 11:44:06 +0300 Subject: [PATCH 25/28] Fix database creation with Postgres * Database.py : fillDefaultData() PostgreSQL has a rather annoying (mis)feature when dealing with boolean data types: raw 1/0 input as integer is not automatically cast to boolean values. Instead, one must use one of several other ways of signifying true/false. http://www.postgresql.org/docs/8.4/static/datatype-boolean.html documents the available and understood formatting. Fix by special-casing PostgreSQL and making all boolean values fed as strings, '1' for true and '0' for false. --- pyfpdb/Database.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/pyfpdb/Database.py b/pyfpdb/Database.py index f4de8169..53e2a10e 100755 --- a/pyfpdb/Database.py +++ b/pyfpdb/Database.py @@ -1014,6 +1014,8 @@ class Database: c.execute("INSERT INTO Sites (name,currency) VALUES ('PartyPoker', 'USD')") if self.backend == self.SQLITE: c.execute("INSERT INTO TourneyTypes (id, siteId, buyin, fee) VALUES (NULL, 1, 0, 0);") + elif self.backend == self.PGSQL: + c.execute("insert into TourneyTypes values (0,1,0,0,0,'0','0',null,'0','0','0');") else: c.execute("insert into TourneyTypes values (0,1,0,0,0,0,0,null,0,0,0);") From 577beed94239f2cd422e9f45e92f0678266a9665 Mon Sep 17 00:00:00 2001 From: Worros Date: Sat, 19 Sep 2009 19:24:07 +0800 Subject: [PATCH 26/28] Prep new function - commented out for the moment --- pyfpdb/Database.py | 107 +++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 107 insertions(+) diff --git a/pyfpdb/Database.py b/pyfpdb/Database.py index f4de8169..82001344 100755 --- a/pyfpdb/Database.py +++ b/pyfpdb/Database.py @@ -1183,6 +1183,10 @@ class Database: return result #end def store_the_hand +########################### +# NEWIMPORT CODE +########################### + def storeHand(self, p): #stores into table hands: q = """INSERT INTO Hands ( @@ -1258,6 +1262,109 @@ class Database: #return getLastInsertId(backend, conn, cursor) # def storeHand + def storeHandsPlayers(self, p): + #def store_hands_players_holdem_omaha(self, backend, category, hands_id, player_ids, start_cashes + # ,positions, card_values, card_suits, winnings, rakes, seatNos, hudCache): + # result=[] + # + # # postgres (and others?) needs the booleans converted to ints before saving: + # # (or we could just save them as boolean ... but then we can't sum them so easily in sql ???) + # # NO - storing booleans for now so don't need this + # #hudCacheInt = {} + # #for k,v in hudCache.iteritems(): + # # if k in ('wonWhenSeenStreet1', 'wonAtSD', 'totalProfit'): + # # hudCacheInt[k] = v + # # else: + # # hudCacheInt[k] = map(lambda x: 1 if x else 0, v) + # + # try: + # inserts = [] + # for i in xrange(len(player_ids)): + # card1 = Card.cardFromValueSuit(card_values[i][0], card_suits[i][0]) + # card2 = Card.cardFromValueSuit(card_values[i][1], card_suits[i][1]) + # + # if (category=="holdem"): + # startCards = Card.twoStartCards(card_values[i][0], card_suits[i][0], card_values[i][1], card_suits[i][1]) + # card3 = None + # card4 = None + # elif (category=="omahahi" or category=="omahahilo"): + # startCards = Card.fourStartCards(card_values[i][0], card_suits[i][0], card_values[i][1], card_suits[i][1] + # ,card_values[i][2], card_suits[i][2], card_values[i][3], card_suits[i][3]) + # card3 = Card.cardFromValueSuit(card_values[i][2], card_suits[i][2]) + # card4 = Card.cardFromValueSuit(card_values[i][3], card_suits[i][3]) + # else: + # raise FpdbError("invalid category") + # + # inserts.append( ( + # hands_id, player_ids[i], start_cashes[i], positions[i], 1, # tourneytypeid - needed for hudcache + # card1, card2, card3, card4, startCards, + # winnings[i], rakes[i], seatNos[i], hudCache['totalProfit'][i], + # hudCache['street0VPI'][i], hudCache['street0Aggr'][i], + # hudCache['street0_3BChance'][i], hudCache['street0_3BDone'][i], + # hudCache['street1Seen'][i], hudCache['street2Seen'][i], hudCache['street3Seen'][i], + # hudCache['street4Seen'][i], hudCache['sawShowdown'][i], + # hudCache['street1Aggr'][i], hudCache['street2Aggr'][i], hudCache['street3Aggr'][i], hudCache['street4Aggr'][i], + # hudCache['otherRaisedStreet1'][i], hudCache['otherRaisedStreet2'][i], + # hudCache['otherRaisedStreet3'][i], hudCache['otherRaisedStreet4'][i], + # hudCache['foldToOtherRaisedStreet1'][i], hudCache['foldToOtherRaisedStreet2'][i], + # hudCache['foldToOtherRaisedStreet3'][i], hudCache['foldToOtherRaisedStreet4'][i], + # hudCache['wonWhenSeenStreet1'][i], hudCache['wonAtSD'][i], + # hudCache['stealAttemptChance'][i], hudCache['stealAttempted'][i], hudCache['foldBbToStealChance'][i], + # hudCache['foldedBbToSteal'][i], hudCache['foldSbToStealChance'][i], hudCache['foldedSbToSteal'][i], + # hudCache['street1CBChance'][i], hudCache['street1CBDone'][i], hudCache['street2CBChance'][i], hudCache['street2CBDone'][i], + # hudCache['street3CBChance'][i], hudCache['street3CBDone'][i], hudCache['street4CBChance'][i], hudCache['street4CBDone'][i], + # hudCache['foldToStreet1CBChance'][i], hudCache['foldToStreet1CBDone'][i], + # hudCache['foldToStreet2CBChance'][i], hudCache['foldToStreet2CBDone'][i], + # hudCache['foldToStreet3CBChance'][i], hudCache['foldToStreet3CBDone'][i], + # hudCache['foldToStreet4CBChance'][i], hudCache['foldToStreet4CBDone'][i], + # hudCache['street1CheckCallRaiseChance'][i], hudCache['street1CheckCallRaiseDone'][i], + # hudCache['street2CheckCallRaiseChance'][i], hudCache['street2CheckCallRaiseDone'][i], + # hudCache['street3CheckCallRaiseChance'][i], hudCache['street3CheckCallRaiseDone'][i], + # hudCache['street4CheckCallRaiseChance'][i], hudCache['street4CheckCallRaiseDone'][i], + # hudCache['street0Calls'][i], hudCache['street1Calls'][i], hudCache['street2Calls'][i], hudCache['street3Calls'][i], hudCache['street4Calls'][i], + # hudCache['street0Bets'][i], hudCache['street1Bets'][i], hudCache['street2Bets'][i], hudCache['street3Bets'][i], hudCache['street4Bets'][i] + # ) ) + # c = self.get_cursor() + # c.executemany (""" + # INSERT INTO HandsPlayers + # (handId, playerId, startCash, position, tourneyTypeId, + # card1, card2, card3, card4, startCards, winnings, rake, seatNo, totalProfit, + # 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, foldBbToStealChance, foldedBbToSteal, foldSbToStealChance, foldedSbToSteal, + # street1CBChance, street1CBDone, street2CBChance, street2CBDone, + # street3CBChance, street3CBDone, street4CBChance, street4CBDone, + # foldToStreet1CBChance, foldToStreet1CBDone, foldToStreet2CBChance, foldToStreet2CBDone, + # foldToStreet3CBChance, foldToStreet3CBDone, foldToStreet4CBChance, foldToStreet4CBDone, + # street1CheckCallRaiseChance, street1CheckCallRaiseDone, street2CheckCallRaiseChance, street2CheckCallRaiseDone, + # street3CheckCallRaiseChance, street3CheckCallRaiseDone, street4CheckCallRaiseChance, street4CheckCallRaiseDone, + # street0Calls, street1Calls, street2Calls, street3Calls, street4Calls, + # street0Bets, street1Bets, street2Bets, street3Bets, street4Bets + # ) + # VALUES (%s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, + # %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, + # %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, + # %s, %s, %s, %s, %s, %s, %s, %s, %s, %s)""".replace('%s', self.sql.query['placeholder']) + # ,inserts ) + # result.append( self.get_last_insert_id(c) ) # wrong? not used currently + # except: + # raise FpdbError( "store_hands_players_holdem_omaha error: " + str(sys.exc_value) ) + # + # return result + + pass + + +################################# +# Finish of NEWIMPORT CODE +################################# + + + def storeHands(self, backend, site_hand_no, gametype_id ,hand_start_time, names, tableName, maxSeats, hudCache ,board_values, board_suits): From 1351cd6dd9bb412a06e8d95ba2406b41c09e4f1b Mon Sep 17 00:00:00 2001 From: Mika Bostrom Date: Mon, 21 Sep 2009 15:31:19 +0300 Subject: [PATCH 27/28] Use cleaner syntax in fillDefaultData --- pyfpdb/Database.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pyfpdb/Database.py b/pyfpdb/Database.py index 53e2a10e..c9247b3c 100755 --- a/pyfpdb/Database.py +++ b/pyfpdb/Database.py @@ -1015,7 +1015,7 @@ class Database: if self.backend == self.SQLITE: c.execute("INSERT INTO TourneyTypes (id, siteId, buyin, fee) VALUES (NULL, 1, 0, 0);") elif self.backend == self.PGSQL: - c.execute("insert into TourneyTypes values (0,1,0,0,0,'0','0',null,'0','0','0');") + c.execute("insert into TourneyTypes values (0,1,0,0,0,False,False,null,False,False,False);") else: c.execute("insert into TourneyTypes values (0,1,0,0,0,0,0,null,0,0,0);") From a67830d92e36a83b4ae9aa3b81918fe2287691ab Mon Sep 17 00:00:00 2001 From: sqlcoder Date: Wed, 23 Sep 2009 23:03:34 +0100 Subject: [PATCH 28/28] 2 changes: move recognisePlayerIDs from fpdb_simple into Database, and make index on siteTourneyNo on Tourneys table unique and refine store_tourneys function to handle this --- pyfpdb/Database.py | 111 +++++++++++++++++++++++++++++-------- pyfpdb/SQL.py | 6 +- pyfpdb/fpdb_parse_logic.py | 2 +- pyfpdb/fpdb_simple.py | 62 --------------------- 4 files changed, 91 insertions(+), 90 deletions(-) diff --git a/pyfpdb/Database.py b/pyfpdb/Database.py index 341a1434..b3adde0c 100755 --- a/pyfpdb/Database.py +++ b/pyfpdb/Database.py @@ -77,7 +77,7 @@ class Database: , {'tab':'HandsPlayers', 'col':'playerId', 'drop':0} # not needed, handled by fk , {'tab':'HandsPlayers', 'col':'tourneyTypeId', 'drop':0} , {'tab':'HandsPlayers', 'col':'tourneysPlayersId', 'drop':0} - , {'tab':'Tourneys', 'col':'siteTourneyNo', 'drop':0} + #, {'tab':'Tourneys', 'col':'siteTourneyNo', 'drop':0} created elsewhere - needs to be unique ] , [ # indexes for postgres (list index 3) {'tab':'Gametypes', 'col':'siteId', 'drop':0} @@ -93,7 +93,7 @@ class Database: , {'tab':'Players', 'col':'siteId', 'drop':1} , {'tab':'Players', 'col':'name', 'drop':0} , {'tab':'Tourneys', 'col':'tourneyTypeId', 'drop':1} - , {'tab':'Tourneys', 'col':'siteTourneyNo', 'drop':0} + #, {'tab':'Tourneys', 'col':'siteTourneyNo', 'drop':0} created elsewhere - needs to be unique , {'tab':'TourneysPlayers', 'col':'playerId', 'drop':0} , {'tab':'TourneysPlayers', 'col':'tourneyId', 'drop':0} , {'tab':'TourneyTypes', 'col':'siteId', 'drop':0} @@ -106,7 +106,7 @@ class Database: , {'tab':'HandsPlayers', 'col':'playerId', 'drop':0} , {'tab':'HandsPlayers', 'col':'tourneyTypeId', 'drop':0} , {'tab':'HandsPlayers', 'col':'tourneysPlayersId', 'drop':0} - , {'tab':'Tourneys', 'col':'siteTourneyNo', 'drop':0} + #, {'tab':'Tourneys', 'col':'siteTourneyNo', 'drop':0} created elsewhere - needs to be unique ] ] @@ -491,6 +491,69 @@ class Database: else: return None + #returns the SQL ids of the names given in an array + # TODO: if someone gets industrious, they should make the parts that use the output of this function deal with a dict + # { playername: id } instead of depending on it's relation to the positions list + # then this can be reduced in complexity a bit + + #def recognisePlayerIDs(cursor, names, site_id): + # result = [] + # for i in xrange(len(names)): + # cursor.execute ("SELECT id FROM Players WHERE name=%s", (names[i],)) + # tmp=cursor.fetchall() + # if (len(tmp)==0): #new player + # cursor.execute ("INSERT INTO Players (name, siteId) VALUES (%s, %s)", (names[i], site_id)) + # #print "Number of players rows inserted: %d" % cursor.rowcount + # cursor.execute ("SELECT id FROM Players WHERE name=%s", (names[i],)) + # tmp=cursor.fetchall() + # #print "recognisePlayerIDs, names[i]:",names[i],"tmp:",tmp + # result.append(tmp[0][0]) + # return result + + def recognisePlayerIDs(self, names, site_id): + c = self.get_cursor() + q = "SELECT name,id FROM Players WHERE siteid=%d and (name=%s)" %(site_id, " OR name=".join([self.sql.query['placeholder'] for n in names])) + c.execute(q, names) # get all playerids by the names passed in + ids = dict(c.fetchall()) # convert to dict + if len(ids) != len(names): + notfound = [n for n in names if n not in ids] # make list of names not in database + if notfound: # insert them into database + q_ins = "INSERT INTO Players (name, siteId) VALUES (%s, "+str(site_id)+")" + q_ins = q_ins.replace('%s', self.sql.query['placeholder']) + c.executemany(q_ins, [(n,) for n in notfound]) + q2 = "SELECT name,id FROM Players WHERE siteid=%d and (name=%s)" % (site_id, " OR name=".join(["%s" for n in notfound])) + q2 = q2.replace('%s', self.sql.query['placeholder']) + c.execute(q2, notfound) # get their new ids + tmp = c.fetchall() + for n,id in tmp: # put them all into the same dict + ids[n] = id + # return them in the SAME ORDER that they came in in the names argument, rather than the order they came out of the DB + return [ids[n] for n in names] + #end def recognisePlayerIDs + + # Here's a version that would work if it wasn't for the fact that it needs to have the output in the same order as input + # this version could also be improved upon using list comprehensions, etc + + #def recognisePlayerIDs(cursor, names, site_id): + # result = [] + # notfound = [] + # cursor.execute("SELECT name,id FROM Players WHERE name='%s'" % "' OR name='".join(names)) + # tmp = dict(cursor.fetchall()) + # for n in names: + # if n not in tmp: + # notfound.append(n) + # else: + # result.append(tmp[n]) + # if notfound: + # cursor.executemany("INSERT INTO Players (name, siteId) VALUES (%s, "+str(site_id)+")", (notfound)) + # cursor.execute("SELECT id FROM Players WHERE name='%s'" % "' OR name='".join(notfound)) + # tmp = cursor.fetchall() + # for n in tmp: + # result.append(n[0]) + # + # return result + + def get_site_id(self, site): c = self.get_cursor() c.execute(self.sql.query['getSiteId'], (site,)) @@ -867,7 +930,7 @@ class Database: c.execute(self.sql.query['createHandsPlayersTable']) c.execute(self.sql.query['createHandsActionsTable']) c.execute(self.sql.query['createHudCacheTable']) - #c.execute(self.sql.query['addTourneyIndex']) + c.execute(self.sql.query['addTourneyIndex']) #c.execute(self.sql.query['addHandsIndex']) #c.execute(self.sql.query['addPlayersIndex']) self.fillDefaultData() @@ -1858,26 +1921,26 @@ class Database: def store_tourneys(self, tourneyTypeId, siteTourneyNo, entries, prizepool, startTime): try: - cursor = self.get_cursor() - cursor.execute("SELECT id FROM Tourneys WHERE siteTourneyNo=%s AND tourneyTypeId+0=%s".replace('%s', self.sql.query['placeholder']) - , (siteTourneyNo, tourneyTypeId)) - tmp=cursor.fetchone() - #print "tried SELECTing tourneys.id, result:",tmp - - try: - len(tmp) - except TypeError:#means we have to create new one - cursor.execute("""INSERT INTO Tourneys - (tourneyTypeId, siteTourneyNo, entries, prizepool, startTime) - VALUES (%s, %s, %s, %s, %s)""".replace('%s', self.sql.query['placeholder']) - ,(tourneyTypeId, siteTourneyNo, entries, prizepool, startTime)) - cursor.execute("SELECT id FROM Tourneys WHERE siteTourneyNo=%s AND tourneyTypeId+0=%s", (siteTourneyNo, tourneyTypeId)) - tmp=cursor.fetchone() - #print "created new tourneys.id:",tmp + # try and create tourney record, fetch id if it already exists + # avoids race condition when doing the select first + cursor.execute("""INSERT INTO Tourneys + (tourneyTypeId, siteTourneyNo, entries, prizepool, startTime) + VALUES (%s, %s, %s, %s, %s)""".replace('%s', self.sql.query['placeholder']) + ,(tourneyTypeId, siteTourneyNo, entries, prizepool, startTime)) + tmp = self.get_last_insert_id(cursor) + #cursor.execute("SELECT id FROM Tourneys WHERE siteTourneyNo=%s AND tourneyTypeId+0=%s", (siteTourneyNo, tourneyTypeId)) + #tmp=cursor.fetchone() + #print "created new tourneys.id:",tmp except: - raise FpdbError( "store_tourneys error: " + str(sys.exc_value) ) + #if str(sys.exc_value) .... not unique index error: + # raise FpdbError( "store_tourneys error: " + str(sys.exc_value) ) + #else: + cursor = self.get_cursor() + cursor.execute( "SELECT id FROM Tourneys WHERE siteTourneyNo=%s AND tourneyTypeId+0=%s".replace('%s', self.sql.query['placeholder']) + , (siteTourneyNo, tourneyTypeId) ) + tmp = cursor.fetchone()[0] - return tmp[0] + return tmp #end def store_tourneys def store_tourneys_players(self, tourney_id, player_ids, payin_amounts, ranks, winnings): @@ -2132,10 +2195,10 @@ class Database: def tStoreTourneyPlayers(self, tourney, dbTourneyId): logging.debug("Database.tStoreTourneyPlayers") # First, get playerids for the players and specifically the one for hero : - playersIds = fpdb_simple.recognisePlayerIDs(self, tourney.players, tourney.siteId) + playersIds = self.recognisePlayerIDs(tourney.players, tourney.siteId) # hero may be None for matrix tourneys summaries # hero = [ tourney.hero ] -# heroId = fpdb_simple.recognisePlayerIDs(self, hero , tourney.siteId) +# heroId = self.recognisePlayerIDs(hero , tourney.siteId) # logging.debug("hero Id = %s - playersId = %s" % (heroId , playersIds)) tourneyPlayersIds=[] diff --git a/pyfpdb/SQL.py b/pyfpdb/SQL.py index 986f9762..af9af079 100644 --- a/pyfpdb/SQL.py +++ b/pyfpdb/SQL.py @@ -1160,11 +1160,11 @@ class Sql: if db_server == 'mysql': - self.query['addTourneyIndex'] = """ALTER TABLE Tourneys ADD INDEX siteTourneyNo(siteTourneyNo)""" + self.query['addTourneyIndex'] = """ALTER TABLE Tourneys ADD UNIQUE INDEX siteTourneyNo(siteTourneyNo)""" elif db_server == 'postgresql': - self.query['addTourneyIndex'] = """CREATE INDEX siteTourneyNo ON Tourneys (siteTourneyNo)""" + self.query['addTourneyIndex'] = """CREATE UNIQUE INDEX siteTourneyNo ON Tourneys (siteTourneyNo)""" elif db_server == 'sqlite': - self.query['addHandsIndex'] = """ """ + self.query['addTourneyIndex'] = """CREATE UNIQUE INDEX siteTourneyNo ON Tourneys (siteTourneyNo)""" if db_server == 'mysql': self.query['addHandsIndex'] = """ALTER TABLE Hands ADD INDEX siteHandNo(siteHandNo)""" diff --git a/pyfpdb/fpdb_parse_logic.py b/pyfpdb/fpdb_parse_logic.py index 4ce1f678..1334a8ac 100644 --- a/pyfpdb/fpdb_parse_logic.py +++ b/pyfpdb/fpdb_parse_logic.py @@ -118,7 +118,7 @@ def mainParser(settings, siteID, category, hand, config, db = None, writeq = Non seatLines.append(line) names = fpdb_simple.parseNames(seatLines) - playerIDs = fpdb_simple.recognisePlayerIDs(db, names, siteID) # inserts players as needed + playerIDs = db.recognisePlayerIDs(names, siteID) # inserts players as needed tmp = fpdb_simple.parseCashesAndSeatNos(seatLines) startCashes = tmp['startCashes'] seatNos = tmp['seatNos'] diff --git a/pyfpdb/fpdb_simple.py b/pyfpdb/fpdb_simple.py index 084949d6..40204ee9 100644 --- a/pyfpdb/fpdb_simple.py +++ b/pyfpdb/fpdb_simple.py @@ -937,68 +937,6 @@ def recogniseTourneyTypeId(db, siteId, tourneySiteId, buyin, fee, knockout, rebu return result[0] #end def recogniseTourneyTypeId -#returns the SQL ids of the names given in an array -# TODO: if someone gets industrious, they should make the parts that use the output of this function deal with a dict -# { playername: id } instead of depending on it's relation to the positions list -# then this can be reduced in complexity a bit - -#def recognisePlayerIDs(cursor, names, site_id): -# result = [] -# for i in xrange(len(names)): -# cursor.execute ("SELECT id FROM Players WHERE name=%s", (names[i],)) -# tmp=cursor.fetchall() -# if (len(tmp)==0): #new player -# cursor.execute ("INSERT INTO Players (name, siteId) VALUES (%s, %s)", (names[i], site_id)) -# #print "Number of players rows inserted: %d" % cursor.rowcount -# cursor.execute ("SELECT id FROM Players WHERE name=%s", (names[i],)) -# tmp=cursor.fetchall() -# #print "recognisePlayerIDs, names[i]:",names[i],"tmp:",tmp -# result.append(tmp[0][0]) -# return result - -def recognisePlayerIDs(db, names, site_id): - c = db.get_cursor() - q = "SELECT name,id FROM Players WHERE siteid=%d and (name=%s)" %(site_id, " OR name=".join([db.sql.query['placeholder'] for n in names])) - c.execute(q, names) # get all playerids by the names passed in - ids = dict(c.fetchall()) # convert to dict - if len(ids) != len(names): - notfound = [n for n in names if n not in ids] # make list of names not in database - if notfound: # insert them into database - q_ins = "INSERT INTO Players (name, siteId) VALUES (%s, "+str(site_id)+")" - q_ins = q_ins.replace('%s', db.sql.query['placeholder']) - c.executemany(q_ins, [(n,) for n in notfound]) - q2 = "SELECT name,id FROM Players WHERE siteid=%d and (name=%s)" % (site_id, " OR name=".join(["%s" for n in notfound])) - q2 = q2.replace('%s', db.sql.query['placeholder']) - c.execute(q2, notfound) # get their new ids - tmp = c.fetchall() - for n,id in tmp: # put them all into the same dict - ids[n] = id - # return them in the SAME ORDER that they came in in the names argument, rather than the order they came out of the DB - return [ids[n] for n in names] -#end def recognisePlayerIDs - - -# Here's a version that would work if it wasn't for the fact that it needs to have the output in the same order as input -# this version could also be improved upon using list comprehensions, etc - -#def recognisePlayerIDs(cursor, names, site_id): -# result = [] -# notfound = [] -# cursor.execute("SELECT name,id FROM Players WHERE name='%s'" % "' OR name='".join(names)) -# tmp = dict(cursor.fetchall()) -# for n in names: -# if n not in tmp: -# notfound.append(n) -# else: -# result.append(tmp[n]) -# if notfound: -# cursor.executemany("INSERT INTO Players (name, siteId) VALUES (%s, "+str(site_id)+")", (notfound)) -# cursor.execute("SELECT id FROM Players WHERE name='%s'" % "' OR name='".join(notfound)) -# tmp = cursor.fetchall() -# for n in tmp: -# result.append(n[0]) -# -# return result #recognises the name in the given line and returns its array position in the given array def recognisePlayerNo(line, names, atype):