From 75dcf002f938753cd2d2f3aa9272c6c96970d1cb Mon Sep 17 00:00:00 2001 From: Matt Turnbull Date: Thu, 5 Mar 2009 01:12:15 +0000 Subject: [PATCH 1/4] Configuration: _getframe(0) so that GuiAutoImport can run standalone (stack not deep enough to go one deeper) fpdb_import: Everleaf plumbing back in place. GuiAutoImport.py: run standalone. --- pyfpdb/Configuration.py | 2 +- pyfpdb/GuiAutoImport.py | 55 ++++++++++++++++++++++++---------- pyfpdb/HandHistoryConverter.py | 10 +++++-- pyfpdb/fpdb_import.py | 12 ++++---- 4 files changed, 54 insertions(+), 25 deletions(-) diff --git a/pyfpdb/Configuration.py b/pyfpdb/Configuration.py index fb182f4b..65541004 100755 --- a/pyfpdb/Configuration.py +++ b/pyfpdb/Configuration.py @@ -609,7 +609,7 @@ class Config: def execution_path(self, filename): """Join the fpdb path to filename.""" - return os.path.join(os.path.dirname(inspect.getfile(sys._getframe(1))), filename) + return os.path.join(os.path.dirname(inspect.getfile(sys._getframe(0))), filename) if __name__== "__main__": c = Config() diff --git a/pyfpdb/GuiAutoImport.py b/pyfpdb/GuiAutoImport.py index eccba8cd..ab32e8eb 100644 --- a/pyfpdb/GuiAutoImport.py +++ b/pyfpdb/GuiAutoImport.py @@ -26,7 +26,8 @@ import os import sys import time import fpdb_import - +from optparse import OptionParser +import Configuration class GuiAutoImport (threading.Thread): def __init__(self, settings, config): @@ -134,7 +135,8 @@ class GuiAutoImport (threading.Thread): self.pipe_to_hud = subprocess.Popen(command, bufsize = bs, stdin = subprocess.PIPE, universal_newlines=True) else: - command = self.config.execution_path('HUD_main.py') +# command = os.path.join(os.getcwd(), 'HUD_main.py') # clearly doesn't work if you run from somewhere else. + command = self.config.execution_path('HUD_main.py') # Hi Ray. Sorry about this, kludging. bs = 1 self.pipe_to_hud = subprocess.Popen((command, self.database), bufsize = bs, stdin = subprocess.PIPE, universal_newlines=True) @@ -214,18 +216,39 @@ if __name__== "__main__": def destroy(*args): # call back for terminating the main eventloop gtk.main_quit() - settings = {} - settings['db-host'] = "192.168.1.100" - settings['db-user'] = "mythtv" - settings['db-password'] = "mythtv" - settings['db-databaseName'] = "fpdb" - settings['hud-defaultInterval'] = 10 - settings['hud-defaultPath'] = 'C:/Program Files/PokerStars/HandHistory/nutOmatic' - settings['callFpdbHud'] = True +# settings = {} +# settings['db-host'] = "192.168.1.100" +# settings['db-user'] = "mythtv" +# settings['db-password'] = "mythtv" +# settings['db-databaseName'] = "fpdb" +# settings['hud-defaultInterval'] = 10 +# settings['hud-defaultPath'] = 'C:/Program Files/PokerStars/HandHistory/nutOmatic' +# settings['callFpdbHud'] = True - i = GuiAutoImport(settings) - main_window = gtk.Window() - main_window.connect("destroy", destroy) - main_window.add(i.mainVBox) - main_window.show() - gtk.main() + parser = OptionParser() + parser.add_option("-q", "--quiet", action="store_false", dest="gui", default=True, help="don't start gui") + + (options, sys.argv) = parser.parse_args() + + config = Configuration.Config() +# db = fpdb_db.fpdb_db() + + settings = {} + if os.name == 'nt': settings['os'] = 'windows' + else: settings['os'] = 'linuxmac' + + settings.update(config.get_db_parameters('fpdb')) + settings.update(config.get_tv_parameters()) + settings.update(config.get_import_parameters()) + settings.update(config.get_default_paths()) + + if(options.gui == True): + i = GuiAutoImport(settings, config) + main_window = gtk.Window() + main_window.connect('destroy', destroy) + main_window.add(i.mainVBox) + main_window.show() + gtk.main() + else: + pass + diff --git a/pyfpdb/HandHistoryConverter.py b/pyfpdb/HandHistoryConverter.py index aedf3630..7c283c43 100644 --- a/pyfpdb/HandHistoryConverter.py +++ b/pyfpdb/HandHistoryConverter.py @@ -95,6 +95,7 @@ class HandHistoryConverter(threading.Thread): self.maxseats = 10 def __str__(self): + #TODO : I got rid of most of the hhdir stuff. tmp = "HandHistoryConverter: '%s'\n" % (self.sitename) tmp = tmp + "\thhbase: '%s'\n" % (self.hhbase) tmp = tmp + "\thhdir: '%s'\n" % (self.hhdir) @@ -143,13 +144,18 @@ class HandHistoryConverter(threading.Thread): if gametype is None: return + hand = None if gametype[1] in ("hold", "omaha"): hand = Hand.HoldemOmahaHand(self, self.sitename, gametype, handtext) elif gametype[1] in ("razz","stud","stud8"): hand = Hand.StudHand(self, self.sitename, gametype, handtext) - hand.writeHand(self.out_fh) - + if hand: + hand.writeHand(self.out_fh) + else: + logging.info("Unrecognised game type: %s" % gametype[1]) + # TODO: pity we don't know the HID at this stage. Log the entire hand? + # From the log we can deduce that it is the hand after the one before :) def processFile(self): diff --git a/pyfpdb/fpdb_import.py b/pyfpdb/fpdb_import.py index 7ff078dc..c664a0a8 100644 --- a/pyfpdb/fpdb_import.py +++ b/pyfpdb/fpdb_import.py @@ -118,7 +118,6 @@ class Importer: def addBulkImportImportFileOrDir(self, inputPath,filter = "passthrough"): """Add a file or directory for bulk import""" # Bulk import never monitors - # if directory, add all files in it. Otherwise add single file. # TODO: only add sane files? if os.path.isdir(inputPath): @@ -133,6 +132,7 @@ class Importer: #dirlist is a hash of lists: #dirlist{ 'PokerStars' => ["/path/to/import/", "filtername"] } def addImportDirectory(self,dir,monitor = False, site = "default", filter = "passthrough"): + #gets called by GuiAutoImport. #This should really be using os.walk #http://docs.python.org/library/os.html if os.path.isdir(dir): @@ -237,12 +237,12 @@ class Importer: hhbase = os.path.expanduser(hhbase) hhdir = os.path.join(hhbase,site) try: - ofile = os.path.join(hhdir, file.split(os.path.sep)[-2]+"-"+os.path.basename(file)) + out_path = os.path.join(hhdir, file.split(os.path.sep)[-2]+"-"+os.path.basename(file)) except: - ofile = os.path.join(hhdir, "x"+strftime("%d-%m-%y")+os.path.basename(file)) - out_fh = open(ofile, 'w') # TODO: seek to previous place in input and append output - in_fh = - conv = EverleafToFpdb.Everleaf(in_fh = file, out_fh = out_fh) + out_path = os.path.join(hhdir, "x"+strftime("%d-%m-%y")+os.path.basename(file)) + #out_fh = open(ofile, 'w') # TODO: seek to previous place in input and append output + conv = EverleafToFpdb.Everleaf(in_path = file, out_path = out_path) + conv.join() elif filter == "FulltiltToFpdb": print "converting ", file conv = FulltiltToFpdb.FullTilt(in_fh = file, out_fh = out_fh) From 1e047b69984cbebfa5cb39039200a6acf0c5d1aa Mon Sep 17 00:00:00 2001 From: Matt Turnbull Date: Thu, 5 Mar 2009 12:31:56 +0000 Subject: [PATCH 2/4] Don't error gruesomely when someone exports nonexistant graph sys.path[0] to get basepath of fpdb script --- pyfpdb/GuiAutoImport.py | 4 ++-- pyfpdb/GuiGraphViewer.py | 3 +++ 2 files changed, 5 insertions(+), 2 deletions(-) mode change 100644 => 100755 pyfpdb/GuiAutoImport.py diff --git a/pyfpdb/GuiAutoImport.py b/pyfpdb/GuiAutoImport.py old mode 100644 new mode 100755 index ab32e8eb..ee633d4f --- a/pyfpdb/GuiAutoImport.py +++ b/pyfpdb/GuiAutoImport.py @@ -135,8 +135,8 @@ class GuiAutoImport (threading.Thread): self.pipe_to_hud = subprocess.Popen(command, bufsize = bs, stdin = subprocess.PIPE, universal_newlines=True) else: -# command = os.path.join(os.getcwd(), 'HUD_main.py') # clearly doesn't work if you run from somewhere else. - command = self.config.execution_path('HUD_main.py') # Hi Ray. Sorry about this, kludging. + command = os.path.join(sys.path[0], 'HUD_main.py') + #command = self.config.execution_path('HUD_main.py') # Hi Ray. Sorry about this, kludging. bs = 1 self.pipe_to_hud = subprocess.Popen((command, self.database), bufsize = bs, stdin = subprocess.PIPE, universal_newlines=True) diff --git a/pyfpdb/GuiGraphViewer.py b/pyfpdb/GuiGraphViewer.py index 82f6d4fa..5c216ade 100644 --- a/pyfpdb/GuiGraphViewer.py +++ b/pyfpdb/GuiGraphViewer.py @@ -279,6 +279,8 @@ class GuiGraphViewer (threading.Thread): win.destroy() def exportGraph (self, widget, data): + if self.fig is None: + return # Might want to disable export button until something has been generated. dia_chooser = gtk.FileChooserDialog(title="Please choose the directory you wish to export to:", action=gtk.FILE_CHOOSER_ACTION_OPEN, buttons=(gtk.STOCK_CANCEL,gtk.RESPONSE_CANCEL,gtk.STOCK_OPEN,gtk.RESPONSE_OK)) @@ -359,6 +361,7 @@ class GuiGraphViewer (threading.Thread): graphButton.connect("clicked", self.generateGraph, "cliced data") graphButton.show() + self.fig = None self.exportButton=gtk.Button("Export to File") self.exportButton.connect("clicked", self.exportGraph, "show clicked") self.exportButton.show() From 426b5c2db53e1fa4bdb0aa07fb1b04ae8e719138 Mon Sep 17 00:00:00 2001 From: Matt Turnbull Date: Fri, 6 Mar 2009 01:24:38 +0000 Subject: [PATCH 3/4] had a go at PokerStars -> PokerStars conversion... fpt : bugfix hand : DrawHand class, moved discardCards there is 'studhi' = '7 Card Stud' in PokerStars string? was playing with Natalie HORSE file --- pyfpdb/EverleafToFpdb.py | 1 + pyfpdb/FulltiltToFpdb.py | 2 +- pyfpdb/Hand.py | 32 ++-- pyfpdb/PokerStarstoFpdb.py | 324 +++++++++++++++++++++++++++++++++++++ 4 files changed, 345 insertions(+), 14 deletions(-) create mode 100755 pyfpdb/PokerStarstoFpdb.py diff --git a/pyfpdb/EverleafToFpdb.py b/pyfpdb/EverleafToFpdb.py index efc8bc19..ec8bc410 100755 --- a/pyfpdb/EverleafToFpdb.py +++ b/pyfpdb/EverleafToFpdb.py @@ -46,6 +46,7 @@ follow : whether to tail -f the input""" self.filetype = "text" self.codepage = "cp1252" self.start() + # TODO: It's not clear that init should start the thread. def compilePlayerRegexs(self, players): if not players <= self.compiledPlayers: # x <= y means 'x is subset of y' diff --git a/pyfpdb/FulltiltToFpdb.py b/pyfpdb/FulltiltToFpdb.py index 251fd71e..1136effb 100755 --- a/pyfpdb/FulltiltToFpdb.py +++ b/pyfpdb/FulltiltToFpdb.py @@ -185,7 +185,7 @@ follow : whether to tail -f the input""" hand.hero = m.group('PNAME') # "2c, qh" -> set(["2c","qc"]) # Also works with Omaha hands. - cards = m.group('CARDS') + cards = m.group('NEWCARDS') cards = [c.strip() for c in cards.split(' ')] hand.addHoleCards(cards, m.group('PNAME')) diff --git a/pyfpdb/Hand.py b/pyfpdb/Hand.py index 85673478..86558e0d 100644 --- a/pyfpdb/Hand.py +++ b/pyfpdb/Hand.py @@ -84,6 +84,7 @@ seat (int) indicating the seat name (string) player name chips (string) the chips the player has at the start of the hand (can be None) If a player has None chips he won't be added.""" + logging.debug("addPlayer: %s %s (%s)" % (seat, name, chips)) if chips is not None: self.players.append([seat, name, chips]) self.stacks[name] = Decimal(chips) @@ -112,15 +113,7 @@ If a player has None chips he won't be added.""" print "checkPlayerExists", player, "fail" raise FpdbParseError - def discardHoleCards(self, cards, player): - try: - self.checkPlayerExists(player) - for card in cards: - self.holecards[player].remove(card) - except FpdbParseError, e: - pass - except ValueError: - print "[ERROR] discardHoleCard tried to discard a card %s didn't have" % (player,) + def setCommunityCards(self, street, cards): logging.debug("setCommunityCards %s %s" %(street, cards)) @@ -306,7 +299,7 @@ Map the tuple self.gametype onto the pokerstars string describing it "omahahi" : "Omaha", "omahahilo" : "FIXME", "razz" : "Razz", - "studhi" : "FIXME", + "studhi" : "7 Card Stud", "studhilo" : "FIXME", "fivedraw" : "5 Card Draw", "27_1draw" : "FIXME", @@ -444,7 +437,7 @@ Card ranks will be uppercased for player in [x for x in self.players if x[1] in players_who_act_preflop]: #Only print stacks of players who do something preflop - print >>fh, _("Seat %s: %s ($%s)" %(player[0], player[1], player[2])) + print >>fh, _("Seat %s: %s ($%s in chips) " %(player[0], player[1], player[2])) #May be more than 1 bb posting @@ -537,8 +530,21 @@ Card ranks will be uppercased print >>fh, _("Seat %d: %s mucked" % (seatnum, name)) print >>fh, "\n\n" - - + +class DrawHand(Hand): + def __init__(self, hhc, sitename, gametype, handText): + if gametype[1] not in ["badugi","5-card-draw"]: + pass # or indeed don't pass and complain instead + + def discardHoleCards(self, cards, player): + try: + self.checkPlayerExists(player) + for card in cards: + self.holecards[player].remove(card) + except FpdbParseError, e: + pass + except ValueError: + print "[ERROR] discardHoleCard tried to discard a card %s didn't have" % (player,) class StudHand(Hand): def __init__(self, hhc, sitename, gametype, handText): diff --git a/pyfpdb/PokerStarstoFpdb.py b/pyfpdb/PokerStarstoFpdb.py new file mode 100755 index 00000000..36157158 --- /dev/null +++ b/pyfpdb/PokerStarstoFpdb.py @@ -0,0 +1,324 @@ +#!/usr/bin/env python +# Copyright 2008, Carl Gherardi +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +######################################################################## + +import sys +from HandHistoryConverter import * + +# PokerStars HH Format + +#PokerStars Game #20461877044: Hold'em No Limit ($1/$2) - 2008/09/16 18:58:01 ET +#Table 'Gianfar IV' 6-max Seat #1 is the button +#Seat 1: ZeKGB ($224 in chips) +#Seat 2: quimboavida ($107.75 in chips) +#Seat 3: tropical100 ($190 in chips) +#Seat 4: jackhama33 ($54.95 in chips) +#Seat 5: Olubanu ($196 in chips) +#Seat 6: LSgambler ($205.35 in chips) +#quimboavida: posts small blind $1 +#tropical100: posts big blind $2 +#*** HOLE CARDS *** +#jackhama33: folds +#Olubanu: folds +#LSgambler: folds +#ZeKGB: folds +#quimboavida: calls $1 +#tropical100: raises $5 to $7 +#quimboavida: calls $5 +#*** FLOP *** [3d Qs Kd] +#quimboavida: bets $10 +#tropical100: calls $10 +#*** TURN *** [3d Qs Kd] [Ah] +#quimboavida: checks +#tropical100: checks +#*** RIVER *** [3d Qs Kd Ah] [7c] +#quimboavida: bets $30 +#tropical100: folds +#quimboavida collected $32.35 from pot +#*** SUMMARY *** +#Total pot $34 | Rake $1.65 +#Board [3d Qs Kd Ah 7c] +#Seat 1: ZeKGB (button) folded before Flop (didn't bet) +#Seat 2: quimboavida (small blind) collected ($32.35) +#Seat 3: tropical100 (big blind) folded on the River +#Seat 4: jackhama33 folded before Flop (didn't bet) +#Seat 5: Olubanu folded before Flop (didn't bet) +#Seat 6: LSgambler folded before Flop (didn't bet) + + +#PokerStars Game #25381215423: HORSE (Razz Limit, $0.10/$0.20) - 2009/02/26 15:20:19 ET +#Table 'Natalie V' 8-max + + +class PokerStars(HandHistoryConverter): + + # Static regexes + re_GameInfo = re.compile('PokerStars Game #(?P[0-9]+):\s+(HORSE)? \(?(?PHold\'em|Razz|7 Card Stud) (?PNo Limit|Limit|Pot Limit),? \(?\$?(?P[.0-9]+)/\$?(?P[.0-9]+)\) - (?P.*$)', re.MULTILINE) + re_SplitHands = re.compile('\n\n+') + re_HandInfo = re.compile("^Table \'(?P[- a-zA-Z]+)\'(?P.+?$)?", re.MULTILINE) + re_Button = re.compile('Seat #(?P
[ a-zA-Z]+) - \$?(?P[.0-9]+)/\$?(?P[.0-9]+) - (?P.*) - (?P
[0-9]+):(?P[0-9]+) ET - (?P[0-9]+)/(?P[0-9]+)/(?P[0-9]+)Table (?P
[ a-zA-Z]+)\nSeat (?P
[- a-zA-Z]+)") + re_GameInfo = re.compile(u"^(Blinds )?(?P\$| €|)(?P[.0-9]+)/(?:\$| €)?(?P[.0-9]+) (?PNL|PL|) (?P(Hold\'em|Omaha|7 Card Stud))", re.MULTILINE) + re_HandInfo = re.compile(u".*#(?P[0-9]+)\n.*\n(Blinds )?(?:\$| €|)(?P[.0-9]+)/(?:\$| €|)(?P[.0-9]+) (?P.*) - (?P\d\d\d\d/\d\d/\d\d - \d\d:\d\d:\d\d)\nTable (?P
[- a-zA-Z]+)") # re_GameInfo = re.compile(r".*Blinds \$?(?P[.0-9]+)/\$?(?P[.0-9]+) (?P(NL|PL)) (?P(Hold\'em|Omaha|7 Card Stud))") #re_HandInfo = re.compile(r".*#(?P[0-9]+)\n.*\nBlinds \$?(?P[.0-9]+)/\$?(?P[.0-9]+) (?P.*) - (?P\d\d\d\d/\d\d/\d\d - \d\d:\d\d:\d\d)\nTable (?P
[- a-zA-Z]+)", re.MULTILINE) re_Button = re.compile(r"^Seat (?P
[ a-zA-Z]+) - \$?(?P[.0-9]+)/\$?(?P[.0-9]+) - (?P.*) - (?P
[0-9]+):(?P[0-9]+) ET - (?P[0-9]+)/(?P[0-9]+)/(?P[0-9]+)Table (?P
[ a-zA-Z]+)\nSeat (?P