Merge branch 'master' of git://git.assembla.com/fpdb.git

This commit is contained in:
Eric Blade 2011-03-19 18:57:37 -04:00
commit 368ec176f9
22 changed files with 591 additions and 67 deletions

View File

@ -370,6 +370,7 @@ class Site(object):
(10, 'Partouche', 'PA'), (10, 'Partouche', 'PA'),
(11, 'Carbon', 'CA'), (11, 'Carbon', 'CA'),
(12, 'PKR', 'PK'), (12, 'PKR', 'PK'),
(13, 'PacificPoker', 'P8'),
] ]
INITIAL_DATA_KEYS = ('id', 'name', 'code') INITIAL_DATA_KEYS = ('id', 'name', 'code')

View File

@ -78,7 +78,6 @@ def get_exec_path():
def get_config(file_name, fallback = True): def get_config(file_name, fallback = True):
"""Looks in cwd and in self.default_config_path for a config file.""" """Looks in cwd and in self.default_config_path for a config file."""
# look for example file even if not used here, path is returned to caller # look for example file even if not used here, path is returned to caller
config_found,example_found,example_copy = False,False,False config_found,example_found,example_copy = False,False,False
config_path, example_path = None,None config_path, example_path = None,None
@ -88,17 +87,17 @@ def get_config(file_name, fallback = True):
config_path = os.path.join(exec_dir, 'pyfpdb', file_name) config_path = os.path.join(exec_dir, 'pyfpdb', file_name)
else: else:
config_path = os.path.join(exec_dir, file_name) config_path = os.path.join(exec_dir, file_name)
# print "config_path=", config_path #print "config_path=", config_path
if os.path.exists(config_path): # there is a file in the cwd if os.path.exists(config_path): # there is a file in the cwd
config_found = True # so we use it config_found = True # so we use it
else: # no file in the cwd, look where it should be in the first place else: # no file in the cwd, look where it should be in the first place
default_dir = get_default_config_path() default_dir = get_default_config_path()
config_path = os.path.join(default_dir, file_name) config_path = os.path.join(default_dir, file_name)
# print "config path 2=", config_path #print "config path 2=", config_path
if os.path.exists(config_path): if os.path.exists(config_path):
config_found = True config_found = True
# Example configuration for debian package # Example configuration for debian package
if os.name == 'posix': if os.name == 'posix':
# If we're on linux, try to copy example from the place # If we're on linux, try to copy example from the place
# debian package puts it; get_default_config_path() creates # debian package puts it; get_default_config_path() creates
@ -111,6 +110,13 @@ def get_config(file_name, fallback = True):
example_copy = True example_copy = True
msg = _("Config file has been created at %s.\n") % config_path msg = _("Config file has been created at %s.\n") % config_path
logging.info(msg) logging.info(msg)
except IOError:
try:
example_path = file_name + '.example'
shutil.copyfile(example_path, config_path)
example_copy = True
msg = _("Config file has been created at %s.\n") % config_path
logging.info(msg)
except IOError: except IOError:
pass pass
@ -485,7 +491,6 @@ class Import:
self.node = node self.node = node
self.interval = node.getAttribute("interval") self.interval = node.getAttribute("interval")
self.callFpdbHud = node.getAttribute("callFpdbHud") self.callFpdbHud = node.getAttribute("callFpdbHud")
self.hhArchiveBase = node.getAttribute("hhArchiveBase")
self.ResultsDirectory = node.getAttribute("ResultsDirectory") self.ResultsDirectory = node.getAttribute("ResultsDirectory")
self.hhBulkPath = node.getAttribute("hhBulkPath") self.hhBulkPath = node.getAttribute("hhBulkPath")
self.saveActions = string_to_bool(node.getAttribute("saveActions"), default=False) self.saveActions = string_to_bool(node.getAttribute("saveActions"), default=False)
@ -495,8 +500,8 @@ class Import:
self.saveStarsHH = string_to_bool(node.getAttribute("saveStarsHH"), default=False) self.saveStarsHH = string_to_bool(node.getAttribute("saveStarsHH"), default=False)
def __str__(self): def __str__(self):
return " interval = %s\n callFpdbHud = %s\n hhArchiveBase = %s\n saveActions = %s\n fastStoreHudCache = %s\nResultsDirectory = %s" \ return " interval = %s\n callFpdbHud = %s\n saveActions = %s\n fastStoreHudCache = %s\nResultsDirectory = %s" \
% (self.interval, self.callFpdbHud, self.hhArchiveBase, self.saveActions, self.cacheSessions, self.sessionTimeout, self.fastStoreHudCache, self.ResultsDirectory) % (self.interval, self.callFpdbHud, self.saveActions, self.cacheSessions, self.sessionTimeout, self.fastStoreHudCache, self.ResultsDirectory)
class HudUI: class HudUI:
def __init__(self, node): def __init__(self, node):
@ -861,9 +866,6 @@ class Config:
return nodes_added return nodes_added
def set_hhArchiveBase(self, path):
self.imp.node.setAttribute("hhArchiveBase", path)
def find_default_conf(self): def find_default_conf(self):
if os.name == 'posix': if os.name == 'posix':
config_path = os.path.join(os.path.expanduser("~"), '.fpdb', 'default.conf') config_path = os.path.join(os.path.expanduser("~"), '.fpdb', 'default.conf')
@ -1261,10 +1263,6 @@ class Config:
try: imp['interval'] = self.imp.interval try: imp['interval'] = self.imp.interval
except: imp['interval'] = 10 except: imp['interval'] = 10
# hhArchiveBase is the temp store for part-processed hand histories - should be redundant eventually
try: imp['hhArchiveBase'] = self.imp.hhArchiveBase
except: imp['hhArchiveBase'] = "~/.fpdb/HandHistories/"
# ResultsDirectory is the local cache for downloaded results # ResultsDirectory is the local cache for downloaded results
# NOTE: try: except: doesn'tseem to be triggering # NOTE: try: except: doesn'tseem to be triggering
# using if instead # using if instead

View File

@ -1519,6 +1519,7 @@ class Database:
c.execute("INSERT INTO Sites (name,code) VALUES ('Betfair', 'BF')") c.execute("INSERT INTO Sites (name,code) VALUES ('Betfair', 'BF')")
c.execute("INSERT INTO Sites (name,code) VALUES ('Absolute', 'AB')") c.execute("INSERT INTO Sites (name,code) VALUES ('Absolute', 'AB')")
c.execute("INSERT INTO Sites (name,code) VALUES ('PartyPoker', 'PP')") c.execute("INSERT INTO Sites (name,code) VALUES ('PartyPoker', 'PP')")
c.execute("INSERT INTO Sites (name,code) VALUES ('PacificPoker', 'P8')")
c.execute("INSERT INTO Sites (name,code) VALUES ('Partouche', 'PA')") c.execute("INSERT INTO Sites (name,code) VALUES ('Partouche', 'PA')")
c.execute("INSERT INTO Sites (name,code) VALUES ('Carbon', 'CA')") c.execute("INSERT INTO Sites (name,code) VALUES ('Carbon', 'CA')")
c.execute("INSERT INTO Sites (name,code) VALUES ('PKR', 'PK')") c.execute("INSERT INTO Sites (name,code) VALUES ('PKR', 'PK')")

View File

@ -2,7 +2,7 @@
<FreePokerToolsConfig xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="FreePokerToolsConfig.xsd"> <FreePokerToolsConfig xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="FreePokerToolsConfig.xsd">
<import callFpdbHud = "True" interval = "10" fastStoreHudCache="False" hhArchiveBase="~/.fpdb/HandHistories/" saveActions="True" cacheSessions="True" sessionTimeout="30"></import> <import callFpdbHud = "True" interval = "10" fastStoreHudCache="False" saveActions="True" cacheSessions="True" sessionTimeout="30"></import>
<!-- These values determine what stats are displayed in the HUD <!-- These values determine what stats are displayed in the HUD
@ -389,6 +389,49 @@ Left-Drag to Move"
</layout> </layout>
</site> </site>
<site enabled="True"
site_name="PacificPoker"
table_finder="poker.exe"
screen_name="Hero"
site_path="C:/Games/Poker/PacificPoker"
HH_path="C:/Users/rwielinga/AppData/Roaming/PacificPoker/HandHistory/Hero/"
decoder="everleaf_decode_table"
converter="PacificPokerToFpdb"
supported_games="holdem">
<layout fav_seat="0" height="547" max="8" width="794">
<location seat="1" x="640" y="64"> </location>
<location seat="2" x="650" y="230"> </location>
<location seat="3" x="650" y="385"> </location>
<location seat="4" x="588" y="425"> </location>
<location seat="5" x="92" y="425"> </location>
<location seat="6" x="0" y="373"> </location>
<location seat="7" x="0" y="223"> </location>
<location seat="8" x="25" y="50"> </location>
</layout>
<layout fav_seat="0" height="547" max="6" width="794">
<location seat="1" x="640" y="58"> </location>
<location seat="2" x="654" y="288"> </location>
<location seat="3" x="615" y="424"> </location>
<location seat="4" x="70" y="421"> </location>
<location seat="5" x="0" y="280"> </location>
<location seat="6" x="70" y="58"> </location>
</layout>
<layout fav_seat="0" height="547" max="2" width="794">
<location seat="1" x="651" y="288"> </location>
<location seat="2" x="10" y="288"> </location>
</layout>
<layout fav_seat="0" height="547" max="9" width="794">
<location seat="1" x="634" y="38"> </location>
<location seat="2" x="667" y="184"> </location>
<location seat="3" x="667" y="321"> </location>
<location seat="4" x="667" y="445"> </location>
<location seat="5" x="337" y="459"> </location>
<location seat="6" x="0" y="400"> </location>
<location seat="7" x="0" y="322"> </location>
<location seat="8" x="0" y="181"> </location>
<location seat="9" x="70" y="53"> </location>
</layout>
</site>
<site enabled="True" <site enabled="True"
site_name="Betfair" site_name="Betfair"
@ -754,6 +797,7 @@ Left-Drag to Move"
<hhc site="Win2day" converter="Win2dayToFpdb"/> <hhc site="Win2day" converter="Win2dayToFpdb"/>
<hhc site="Absolute" converter="AbsoluteToFpdb"/> <hhc site="Absolute" converter="AbsoluteToFpdb"/>
<hhc site="PartyPoker" converter="PartyPokerToFpdb"/> <hhc site="PartyPoker" converter="PartyPokerToFpdb"/>
<hhc site="PacificPoker" converter="PacificPokerToFpdb"/>
<hhc site="Betfair" converter="BetfairToFpdb"/> <hhc site="Betfair" converter="BetfairToFpdb"/>
<hhc site="OnGame" converter="OnGameToFpdb"/> <hhc site="OnGame" converter="OnGameToFpdb"/>
<hhc site="Carbon" converter="CarbonToFpdb"/> <hhc site="Carbon" converter="CarbonToFpdb"/>

View File

@ -12,7 +12,7 @@
config_difficulty="expert" config_difficulty="expert"
/> />
<import callFpdbHud = "True" interval = "10" fastStoreHudCache="False" hhArchiveBase="~/.fpdb/HandHistories/" saveActions="True" cacheSessions="False" sessionTimeout="30"></import> <import callFpdbHud = "True" interval = "10" fastStoreHudCache="False" saveActions="True" cacheSessions="False" sessionTimeout="30"></import>
<gui_cash_stats> <gui_cash_stats>
<col col_name="game" disp_all="True" disp_posn="True" col_title="Game" xalignment="0.0" field_format="%s" field_type="str" /> <col col_name="game" disp_all="True" disp_posn="True" col_title="Game" xalignment="0.0" field_format="%s" field_type="str" />

View File

@ -460,24 +460,8 @@ or None if we fail to get the info """
def sanityCheck(self): def sanityCheck(self):
"""Check we aren't going to do some stupid things""" """Check we aren't going to do some stupid things"""
#TODO: the hhbase stuff needs to be in fpdb_import
sane = False sane = False
base_w = False base_w = False
#~ #Check if hhbase exists and is writable
#~ #Note: Will not try to create the base HH directory
#~ if not (os.access(self.hhbase, os.W_OK) and os.path.isdir(self.hhbase)):
#~ print "HH Sanity Check: Directory hhbase '" + self.hhbase + "' doesn't exist or is not writable"
#~ else:
#~ #Check if hhdir exists and is writable
#~ if not os.path.isdir(self.hhdir):
#~ # In first pass, dir may not exist. Attempt to create dir
#~ print "Creating directory: '%s'" % (self.hhdir)
#~ os.mkdir(self.hhdir)
#~ sane = True
#~ elif os.access(self.hhdir, os.W_OK):
#~ sane = True
#~ else:
#~ print "HH Sanity Check: Directory hhdir '" + self.hhdir + "' or its parent directory are not writable"
# Make sure input and output files are different or we'll overwrite the source file # Make sure input and output files are different or we'll overwrite the source file
if True: # basically.. I don't know if True: # basically.. I don't know

View File

@ -83,6 +83,7 @@ def site_alias(alias):
"""Function for converting various site aliases to the FPDB name""" """Function for converting various site aliases to the FPDB name"""
tmp = alias tmp = alias
aliases = { aliases = {
"PacificPoker" : "PacificPoker",
"PokerStars" : "PokerStars", "PokerStars" : "PokerStars",
"Full Tilt Poker": "Full Tilt Poker", "Full Tilt Poker": "Full Tilt Poker",
"PartyPoker" : "PartyPoker", "PartyPoker" : "PartyPoker",

View File

@ -0,0 +1,467 @@
#!/usr/bin/env python
# -*- coding: utf-8 -*-
#
# Copyright 2008-2010, 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 L10n
_ = L10n.get_translation()
# TODO: straighten out discards for draw games
import sys
from HandHistoryConverter import *
from decimal_wrapper import Decimal
# PacificPoker HH Format
class PacificPoker(HandHistoryConverter):
# Class Variables
sitename = "PacificPoker"
filetype = "text"
codepage = ("utf8", "cp1252")
siteId = 13 # Needs to match id entry in Sites database
mixes = { 'HORSE': 'horse', '8-Game': '8game', 'HOSE': 'hose'} # Legal mixed games
sym = {'USD': "\$", 'CAD': "\$", 'T$': "", "EUR": "\xe2\x82\xac", "GBP": "\xa3", "play": ""} # ADD Euro, Sterling, etc HERE
substitutions = {
'LEGAL_ISO' : "USD|EUR|GBP|CAD|FPP", # legal ISO currency codes
'LS' : "\$|\xe2\x82\xac|" # legal currency symbols - Euro(cp1252, utf-8)
}
# translations from captured groups to fpdb info strings
# :: TODO 0.02 limit does not seem right
Lim_Blinds = { '0.02': ('0.01', '0.02'), '0.04': ('0.01', '0.02'),
'0.10': ('0.02', '0.05'), '0.20': ('0.05', '0.10'),
'0.40': ('0.10', '0.20'), '0.50': ('0.10', '0.25'),
'1.00': ('0.25', '0.50'), '1': ('0.25', '0.50'),
'2.00': ('0.50', '1.00'), '2': ('0.50', '1.00'),
'4.00': ('1.00', '2.00'), '4': ('1.00', '2.00'),
'6.00': ('1.00', '3.00'), '6': ('1.00', '3.00'),
'8.00': ('2.00', '4.00'), '8': ('2.00', '4.00'),
'10.00': ('2.00', '5.00'), '10': ('2.00', '5.00'),
'20.00': ('5.00', '10.00'), '20': ('5.00', '10.00'),
'30.00': ('10.00', '15.00'), '30': ('10.00', '15.00'),
'40.00': ('10.00', '20.00'), '40': ('10.00', '20.00'),
'60.00': ('15.00', '30.00'), '60': ('15.00', '30.00'),
'80.00': ('20.00', '40.00'), '80': ('20.00', '40.00'),
'100.00': ('25.00', '50.00'), '100': ('25.00', '50.00'),
'200.00': ('50.00', '100.00'), '200': ('50.00', '100.00'),
'400.00': ('100.00', '200.00'), '400': ('100.00', '200.00'),
'800.00': ('200.00', '400.00'), '800': ('200.00', '400.00'),
'1000.00': ('250.00', '500.00'),'1000': ('250.00', '500.00')
}
limits = { 'No Limit':'nl', 'Pot Limit':'pl', 'Limit':'fl', 'LIMIT':'fl', 'Fix Limit':'fl' }
games = { # base, category
"Holdem" : ('hold','holdem'),
'Omaha' : ('hold','omahahi'),
'Omaha Hi/Lo' : ('hold','omahahilo'),
'OmahaHL' : ('hold','omahahilo'),
'Razz' : ('stud','razz'),
'RAZZ' : ('stud','razz'),
'7 Card Stud' : ('stud','studhi'),
'7 Card Stud Hi/Lo' : ('stud','studhilo'),
'Badugi' : ('draw','badugi'),
'Triple Draw 2-7 Lowball' : ('draw','27_3draw'),
'Single Draw 2-7 Lowball' : ('draw','27_1draw'),
'5 Card Draw' : ('draw','fivedraw')
}
currencies = { u'':'EUR', '$':'USD', '':'T$' }
# Static regexes
re_GameInfo = re.compile(u"""
\#Game\sNo\s:\s(?P<HID>[0-9]+)\\n
\*\*\*\*\*\sCassava\sHand\sHistory\sfor\sGame\s[0-9]+\s\*\*\*\*\*\\n
(?P<CURRENCY>%(LS)s)?(?P<SB>[.,0-9]+)/(%(LS)s)?(?P<BB>[.,0-9]+)\sBlinds\s
(?P<LIMIT>No\sLimit|Fix\sLimit|Pot\sLimit)\s
(?P<GAME>Holdem|Omaha|OmahaHL)
\s-\s\*\*\*\s
(?P<DATETIME>.*$)
""" % substitutions, re.MULTILINE|re.VERBOSE)
re_PlayerInfo = re.compile(u"""
^Seat\s(?P<SEAT>[0-9]+):\s
(?P<PNAME>.*)\s
\(\s(%(LS)s)?(?P<CASH>[.,0-9]+)\s\)""" % substitutions,
re.MULTILINE|re.VERBOSE)
re_HandInfo = re.compile("""
^Table\s(?P<TABLE>[-\ \#a-zA-Z\d]+)\s
(\(Real\sMoney\))?
(?P<PLAY>\(Practice\sPlay\))?
\\n
Seat\s(?P<BUTTON>[0-9]+)\sis\sthe\sbutton
""", re.MULTILINE|re.VERBOSE)
re_SplitHands = re.compile('\n\n+')
re_TailSplitHands = re.compile('(\n\n\n+)')
re_Button = re.compile('Seat (?P<BUTTON>\d+) is the button', re.MULTILINE)
re_Board = re.compile(r"\[\s(?P<CARDS>.+)\s\]")
re_DateTime = re.compile("""(?P<D>[0-9]{2})\s(?P<M>[0-9]{2})\s(?P<Y>[0-9]{4})[\- ]+(?P<H>[0-9]+):(?P<MIN>[0-9]+):(?P<S>[0-9]+)""", re.MULTILINE)
# These used to be compiled per player, but regression tests say
# we don't have to, and it makes life faster.
short_subst = {'PLYR': r'(?P<PNAME>.+?)', 'CUR': '\$?'}
re_PostSB = re.compile(r"^%(PLYR)s posts small blind \[%(CUR)s(?P<SB>[.,0-9]+)\]" % short_subst, re.MULTILINE)
re_PostBB = re.compile(r"^%(PLYR)s posts big blind \[%(CUR)s(?P<BB>[.,0-9]+)\]" % short_subst, re.MULTILINE)
re_Antes = re.compile(r"^%(PLYR)s posts the ante \[%(CUR)s(?P<ANTE>[.,0-9]+)\]" % short_subst, re.MULTILINE)
re_BringIn = re.compile(r"^%(PLYR)s: brings[- ]in( low|) for %(CUR)s(?P<BRINGIN>[.,0-9]+)" % short_subst, re.MULTILINE)
re_PostBoth = re.compile(r"^%(PLYR)s posts dead blind \[%(CUR)s(?P<SBBB>[.,0-9]+)\s\+\s%(CUR)s[.,0-9]+\]" % short_subst, re.MULTILINE)
re_HeroCards = re.compile(r"^Dealt to %(PLYR)s( \[\s(?P<NEWCARDS>.+?)\s\])" % short_subst, re.MULTILINE)
re_Action = re.compile(r"""
^%(PLYR)s(?P<ATYPE>\sbets|\schecks|\sraises|\scalls|\sfolds|\sdiscards|\sstands\spat)
(\s\[(%(CUR)s)?(?P<BET>[.,0-9]+)\])?
(\s*and\sis\sall.in)?
(\s*and\shas\sreached\sthe\s[%(CUR)s\d\.]+\scap)?
(\s*cards?(\s\[(?P<DISCARDED>.+?)\])?)?\s*$"""
% short_subst, re.MULTILINE|re.VERBOSE)
re_ShowdownAction = re.compile(r"^%s shows \[(?P<CARDS>.*)\]" % short_subst['PLYR'], re.MULTILINE)
re_sitsOut = re.compile("^%s sits out" % short_subst['PLYR'], re.MULTILINE)
re_ShownCards = re.compile("^%s ?(?P<SHOWED>shows|mucks) \[ (?P<CARDS>.*) \]$" % short_subst['PLYR'], re.MULTILINE)
re_CollectPot = re.compile(r"^%(PLYR)s collected \[ %(CUR)s(?P<POT>[.,0-9]+) \]$" % short_subst, re.MULTILINE)
def compilePlayerRegexs(self, hand):
pass
def readSupportedGames(self):
return [["ring", "hold", "nl"],
["ring", "hold", "pl"],
["ring", "hold", "fl"],
["ring", "stud", "fl"],
["ring", "draw", "fl"],
["ring", "draw", "pl"],
["ring", "draw", "nl"],
["tour", "hold", "nl"],
["tour", "hold", "pl"],
["tour", "hold", "fl"],
["tour", "stud", "fl"],
["tour", "draw", "fl"],
["tour", "draw", "pl"],
["tour", "draw", "nl"],
]
def determineGameType(self, handText):
info = {}
m = self.re_GameInfo.search(handText)
if not m:
tmp = handText[0:120]
log.error(_("Unable to recognise gametype from: '%s'") % tmp)
log.error(_("determineGameType: Raising FpdbParseError"))
raise FpdbParseError(_("Unable to recognise gametype from: '%s'") % tmp)
mg = m.groupdict()
if 'LIMIT' in mg:
#print "DEBUG: re_GameInfo[LIMIT] \'", mg['LIMIT'], "\'"
info['limitType'] = self.limits[mg['LIMIT']]
if 'GAME' in mg:
#print "DEBUG: re_GameInfo[GAME] \'", mg['GAME'], "\'"
(info['base'], info['category']) = self.games[mg['GAME']]
if 'SB' in mg:
#print "DEBUG: re_GameInfo[SB] \'", mg['SB'], "\'"
info['sb'] = mg['SB']
if 'BB' in mg:
#print "DEBUG: re_GameInfo[BB] \'", mg['BB'], "\'"
info['bb'] = mg['BB']
if 'CURRENCY' in mg:
#print "DEBUG: re_GameInfo[CURRENCY] \'", mg['CURRENCY'], "\'"
info['currency'] = self.currencies[mg['CURRENCY']]
if 'TOURNO' in mg and mg['TOURNO'] is not None:
info['type'] = 'tour'
else:
info['type'] = 'ring'
if info['limitType'] == 'fl' and info['bb'] is not None and info['type'] == 'ring' and info['base'] != 'stud':
try:
info['sb'] = self.Lim_Blinds[mg['BB']][0]
info['bb'] = self.Lim_Blinds[mg['BB']][1]
except KeyError:
log.error(_("Lim_Blinds has no lookup for '%s'") % mg['BB'])
log.error(_("determineGameType: Raising FpdbParseError"))
raise FpdbParseError(_("Lim_Blinds has no lookup for '%s'") % mg['BB'])
return info
def readHandInfo(self, hand):
info = {}
m = self.re_HandInfo.search(hand.handText,re.DOTALL)
m2 = self.re_GameInfo.search(hand.handText)
if m is None or m2 is None:
log.error(_("No match in readHandInfo: '%s'") % hand.handText[0:100])
raise FpdbParseError(_("No match in readHandInfo: '%s'") % hand.handText[0:100])
info.update(m.groupdict())
info.update(m2.groupdict())
log.debug("readHandInfo: %s" % info)
for key in info:
if key == 'DATETIME':
#2008/11/12 10:00:48 CET [2008/11/12 4:00:48 ET] # (both dates are parsed so ET date overrides the other)
#2008/08/17 - 01:14:43 (ET)
#2008/09/07 06:23:14 ET
m1 = self.re_DateTime.finditer(info[key])
datetimestr = "2000/01/01 00:00:00" # default used if time not found
for a in m1:
datetimestr = "%s/%s/%s %s:%s:%s" % (a.group('Y'), a.group('M'),a.group('D'),a.group('H'),a.group('MIN'),a.group('S'))
#tz = a.group('TZ') # just assume ET??
#print " tz = ", tz, " datetime =", datetimestr
hand.startTime = datetime.datetime.strptime(datetimestr, "%Y/%m/%d %H:%M:%S") # also timezone at end, e.g. " ET"
hand.startTime = HandHistoryConverter.changeTimezone(hand.startTime, "ET", "UTC")
if key == 'HID':
hand.handid = info[key]
if key == 'TOURNO':
hand.tourNo = info[key]
if key == 'BUYIN':
if hand.tourNo!=None:
#print "DEBUG: info['BUYIN']: %s" % info['BUYIN']
#print "DEBUG: info['BIAMT']: %s" % info['BIAMT']
#print "DEBUG: info['BIRAKE']: %s" % info['BIRAKE']
#print "DEBUG: info['BOUNTY']: %s" % info['BOUNTY']
if info[key] == 'Freeroll':
hand.buyin = 0
hand.fee = 0
hand.buyinCurrency = "FREE"
else:
if info[key].find("$")!=-1:
hand.buyinCurrency="USD"
elif info[key].find(u"")!=-1:
hand.buyinCurrency="EUR"
elif info[key].find("FPP")!=-1:
hand.buyinCurrency="PSFP"
else:
#FIXME: handle other currencies, FPP, play money
raise FpdbParseError(_("Failed to detect currency. Hand ID: %s: '%s'") % (hand.handid, info[key]))
info['BIAMT'] = info['BIAMT'].strip(u'$€FPP')
if hand.buyinCurrency!="PSFP":
if info['BOUNTY'] != None:
# There is a bounty, Which means we need to switch BOUNTY and BIRAKE values
tmp = info['BOUNTY']
info['BOUNTY'] = info['BIRAKE']
info['BIRAKE'] = tmp
info['BOUNTY'] = info['BOUNTY'].strip(u'$€') # Strip here where it isn't 'None'
hand.koBounty = int(100*Decimal(info['BOUNTY']))
hand.isKO = True
else:
hand.isKO = False
info['BIRAKE'] = info['BIRAKE'].strip(u'$€')
hand.buyin = int(100*Decimal(info['BIAMT']))
hand.fee = int(100*Decimal(info['BIRAKE']))
else:
hand.buyin = int(Decimal(info['BIAMT']))
hand.fee = 0
if key == 'LEVEL':
hand.level = info[key]
if key == 'TABLE':
if hand.tourNo != None:
hand.tablename = re.split(" ", info[key])[1]
else:
hand.tablename = info[key]
if key == 'BUTTON':
hand.buttonpos = info[key]
if key == 'MAX' and info[key] != None:
hand.maxseats = int(info[key])
if key == 'MIXED':
hand.mixed = self.mixes[info[key]] if info[key] is not None else None
if key == 'PLAY' and info['PLAY'] is not None:
# hand.currency = 'play' # overrides previously set value
hand.gametype['currency'] = 'play'
def readButton(self, hand):
m = self.re_Button.search(hand.handText)
if m:
hand.buttonpos = int(m.group('BUTTON'))
else:
log.info(_('readButton: not found'))
def readPlayerStacks(self, hand):
log.debug("readPlayerStacks")
m = self.re_PlayerInfo.finditer(hand.handText)
for a in m:
#print "DEBUG: Seat[", a.group('SEAT'), "]; PNAME[", a.group('PNAME'), "]; CASH[", a.group('CASH'), "]"
hand.addPlayer(int(a.group('SEAT')), a.group('PNAME'), a.group('CASH'))
def markStreets(self, hand):
# PREFLOP = ** Dealing down cards **
# This re fails if, say, river is missing; then we don't get the ** that starts the river.
if hand.gametype['base'] in ("hold"):
m = re.search(r"\*\* Dealing down cards \*\*(?P<PREFLOP>.+(?=\*\* Dealing flop \*\*)|.+)"
r"(\*\* Dealing flop \*\* (?P<FLOP>\[ \S\S, \S\S, \S\S \].+(?=\*\* Dealing turn \*\*)|.+))?"
r"(\*\* Dealing turn \*\* (?P<TURN>\[ \S\S \].+(?=\*\* Dealing river \*\*)|.+))?"
r"(\*\* Dealing river \*\* (?P<RIVER>\[ \S\S \].+))?"
, hand.handText,re.DOTALL)
if m is None:
log.error("Didn't match markStreets")
raise FpdbParseError(_("No match in markStreets"))
else:
#print "DEBUG: Matched markStreets"
mg = m.groupdict()
# if 'PREFLOP' in mg:
# print "DEBUG: PREFLOP: ", [mg['PREFLOP']]
# if 'FLOP' in mg:
# print "DEBUG: FLOP: ", [mg['FLOP']]
# if 'TURN' in mg:
# print "DEBUG: TURN: ", [mg['TURN']]
# if 'RIVER' in mg:
# print "DEBUG: RIVER: ", [mg['RIVER']]
hand.addStreets(m)
def readCommunityCards(self, hand, street): # street has been matched by markStreets, so exists in this hand
if street in ('FLOP','TURN','RIVER'): # a list of streets which get dealt community cards (i.e. all but PREFLOP)
#print "DEBUG readCommunityCards:", street, hand.streets.group(street)
m = self.re_Board.search(hand.streets[street])
hand.setCommunityCards(street, m.group('CARDS').split(', '))
def readAntes(self, hand):
log.debug(_("reading antes"))
m = self.re_Antes.finditer(hand.handText)
for player in m:
#~ logging.debug("hand.addAnte(%s,%s)" %(player.group('PNAME'), player.group('ANTE')))
hand.addAnte(player.group('PNAME'), player.group('ANTE'))
def readBringIn(self, hand):
m = self.re_BringIn.search(hand.handText,re.DOTALL)
if m:
#~ logging.debug("readBringIn: %s for %s" %(m.group('PNAME'), m.group('BRINGIN')))
hand.addBringIn(m.group('PNAME'), m.group('BRINGIN'))
def readBlinds(self, hand):
liveBlind = True
for a in self.re_PostSB.finditer(hand.handText):
if liveBlind:
hand.addBlind(a.group('PNAME'), 'small blind', a.group('SB'))
liveBlind = False
else:
# Post dead blinds as ante
hand.addBlind(a.group('PNAME'), 'secondsb', a.group('SB'))
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):
hand.addBlind(a.group('PNAME'), 'both', a.group('SBBB'))
def readHeroCards(self, hand):
# streets PREFLOP, PREDRAW, and THIRD are special cases beacause
# we need to grab hero's cards
for street in ('PREFLOP', 'DEAL'):
if street in hand.streets.keys():
m = self.re_HeroCards.finditer(hand.streets[street])
for found in m:
# if m == None:
# hand.involved = False
# else:
hand.hero = found.group('PNAME')
newcards = found.group('NEWCARDS').split(', ')
hand.addHoleCards(street, hand.hero, closed=newcards, shown=False, mucked=False, dealt=True)
for street, text in hand.streets.iteritems():
if not text or street in ('PREFLOP', 'DEAL'): continue # already done these
m = self.re_HeroCards.finditer(hand.streets[street])
for found in m:
player = found.group('PNAME')
if found.group('NEWCARDS') is None:
newcards = []
else:
newcards = found.group('NEWCARDS').split(', ')
if found.group('OLDCARDS') is None:
oldcards = []
else:
oldcards = found.group('OLDCARDS').split(', ')
if street == 'THIRD' and len(newcards) == 3: # hero in stud game
hand.hero = player
hand.dealt.add(player) # need this for stud??
hand.addHoleCards(street, player, closed=newcards[0:2], open=[newcards[2]], shown=False, mucked=False, dealt=False)
else:
hand.addHoleCards(street, player, open=newcards, closed=oldcards, shown=False, mucked=False, dealt=False)
def readAction(self, hand, street):
m = self.re_Action.finditer(hand.streets[street])
for action in m:
acts = action.groupdict()
#print "DEBUG: acts: %s" %acts
if action.group('ATYPE') == ' raises':
hand.addRaiseBy( street, action.group('PNAME'), action.group('BET').replace(',','') )
elif action.group('ATYPE') == ' calls':
hand.addCall( street, action.group('PNAME'), action.group('BET').replace(',','') )
elif action.group('ATYPE') == ' bets':
hand.addBet( street, action.group('PNAME'), action.group('BET').replace(',','') )
elif action.group('ATYPE') == ' folds':
hand.addFold( street, action.group('PNAME'))
elif action.group('ATYPE') == ' checks':
hand.addCheck( street, action.group('PNAME'))
elif action.group('ATYPE') == ' discards':
hand.addDiscard(street, action.group('PNAME'), action.group('BET').replace(',',''), action.group('DISCARDED'))
elif action.group('ATYPE') == ' stands pat':
hand.addStandsPat( street, action.group('PNAME'))
else:
print _("DEBUG: unimplemented readAction: '%s' '%s'") %(action.group('PNAME'),action.group('ATYPE'),)
def readShowdownActions(self, hand):
# TODO: pick up mucks also??
for shows in self.re_ShowdownAction.finditer(hand.handText):
cards = shows.group('CARDS').split(', ')
hand.addShownCards(cards, shows.group('PNAME'))
def readCollectPot(self,hand):
for m in self.re_CollectPot.finditer(hand.handText):
#print "DEBUG: hand.addCollectPot(player=", m.group('PNAME'), ", pot=", m.group('POT'), ")"
hand.addCollectPot(player=m.group('PNAME'),pot=m.group('POT').replace(',',''))
def readShownCards(self,hand):
for m in self.re_ShownCards.finditer(hand.handText):
if m.group('CARDS') is not None:
cards = m.group('CARDS')
cards = cards.split(', ') # needs to be a list, not a set--stud needs the order
(shown, mucked) = (False, False)
if m.group('SHOWED') == "showed": shown = True
elif m.group('SHOWED') == "mucked": mucked = True
#print "DEBUG: hand.addShownCards(%s, %s, %s, %s)" %(cards, m.group('PNAME'), shown, mucked)
hand.addShownCards(cards=cards, player=m.group('PNAME'), shown=shown, mucked=mucked)
if __name__ == "__main__":
parser = OptionParser()
parser.add_option("-i", "--input", dest="ipath", help=_("parse input hand history"), default="regression-test-files/stars/horse/HH20090226 Natalie V - $0.10-$0.20 - HORSE.txt")
parser.add_option("-o", "--output", dest="opath", help=_("output translation to"), default="-")
parser.add_option("-f", "--follow", dest="follow", help=_("follow (tail -f) the input"), action="store_true", default=False)
#parser.add_option("-q", "--quiet", action="store_const", const=logging.CRITICAL, dest="verbosity", default=logging.INFO)
#parser.add_option("-v", "--verbose", action="store_const", const=logging.INFO, dest="verbosity")
#parser.add_option("--vv", action="store_const", const=logging.DEBUG, dest="verbosity")
(options, args) = parser.parse_args()
e = PacificPoker(in_path = options.ipath, out_path = options.opath, follow = options.follow)

View File

@ -172,6 +172,8 @@ def compare(leaf, importer, errors, site):
# Test if this is a hand history file # Test if this is a hand history file
if filename.endswith('.txt'): if filename.endswith('.txt'):
# test if there is a .hp version of the file # test if there is a .hp version of the file
print "Site: %s" % site
print "Filename: %s" % filename
importer.addBulkImportImportFileOrDir(filename, site=site) importer.addBulkImportImportFileOrDir(filename, site=site)
(stored, dups, partial, errs, ttime) = importer.runImport() (stored, dups, partial, errs, ttime) = importer.runImport()
@ -213,7 +215,7 @@ def usage():
print "Run tests for a sinlge site:" print "Run tests for a sinlge site:"
print "\t./TestHandsPlayers -s <Sitename>" print "\t./TestHandsPlayers -s <Sitename>"
print "Run tests for a sinlge file in a site:" print "Run tests for a sinlge file in a site:"
print "\t./TestHandsPlayers -s <Sitename> -f <filname>" print "\t./TestHandsPlayers -s <Sitename> -f <filename>"
sys.exit(0) sys.exit(0)
def main(argv=None): def main(argv=None):
@ -255,6 +257,7 @@ def main(argv=None):
importer.setCallHud(False) importer.setCallHud(False)
importer.setFakeCacheHHC(True) importer.setFakeCacheHHC(True)
PacificPokerErrors= FpdbError('PacificPoker')
PokerStarsErrors = FpdbError('PokerStars') PokerStarsErrors = FpdbError('PokerStars')
FTPErrors = FpdbError('Full Tilt Poker') FTPErrors = FpdbError('Full Tilt Poker')
PartyPokerErrors = FpdbError('Party Poker') PartyPokerErrors = FpdbError('Party Poker')
@ -271,7 +274,7 @@ def main(argv=None):
WinamaxErrors = FpdbError('Winamax') WinamaxErrors = FpdbError('Winamax')
ErrorsList = [ ErrorsList = [
PokerStarsErrors, FTPErrors, PartyPokerErrors, PacificPokerErrors, PokerStarsErrors, FTPErrors, PartyPokerErrors,
BetfairErrors, OnGameErrors, AbsoluteErrors, BetfairErrors, OnGameErrors, AbsoluteErrors,
EverleafErrors, CarbonErrors, PKRErrors, EverleafErrors, CarbonErrors, PKRErrors,
iPokerErrors, WinamaxErrors, UltimateBetErrors, iPokerErrors, WinamaxErrors, UltimateBetErrors,
@ -279,6 +282,7 @@ def main(argv=None):
] ]
sites = { sites = {
'PacificPoker' : False,
'PokerStars' : False, 'PokerStars' : False,
'Full Tilt Poker' : False, 'Full Tilt Poker' : False,
'PartyPoker' : False, 'PartyPoker' : False,
@ -301,6 +305,11 @@ def main(argv=None):
else: else:
sites[options.sitename] = True sites[options.sitename] = True
if sites['PacificPoker'] == True and not single_file_test:
walk_testfiles("regression-test-files/cash/PacificPoker/", compare, importer, PacificPokerErrors, "PacificPoker")
elif sites['PacificPoker'] == True and single_file_test:
walk_testfiles(options.filename, compare, importer, PacificPokerErrors, "PacificPoker")
if sites['PokerStars'] == True and not single_file_test: if sites['PokerStars'] == True and not single_file_test:
walk_testfiles("regression-test-files/cash/Stars/", compare, importer, PokerStarsErrors, "PokerStars") walk_testfiles("regression-test-files/cash/Stars/", compare, importer, PokerStarsErrors, "PokerStars")
walk_testfiles("regression-test-files/tour/Stars/", compare, importer, PokerStarsErrors, "PokerStars") walk_testfiles("regression-test-files/tour/Stars/", compare, importer, PokerStarsErrors, "PokerStars")

View File

@ -80,7 +80,7 @@ class Table(Table_Window):
try: try:
if self.window == None: if self.window == None:
log.error(_("Window %s not found. Skipping." % self.search_string)) log.error(_("Window %s not found. Skipping.") % self.search_string)
return None return None
except AttributeError: except AttributeError:
log.error(_("self.window doesn't exist? why?")) log.error(_("self.window doesn't exist? why?"))

View File

@ -1328,26 +1328,6 @@ You can find the full license texts in agpl-3.0.txt, gpl-2.0.txt, gpl-3.0.txt an
return response return response
def validate_config(self): def validate_config(self):
# can this be removed now?
if self.config.get_import_parameters().get('saveStarsHH'):
hhbase = self.config.get_import_parameters().get("hhArchiveBase")
hhbase = os.path.expanduser(hhbase)
#hhdir = os.path.join(hhbase,site)
hhdir = hhbase
if not os.path.isdir(hhdir):
diapath = gtk.MessageDialog(parent=None, flags=0, type=gtk.MESSAGE_WARNING, buttons=(gtk.BUTTONS_YES_NO), message_format="Setup hh dir")
diastring = _("WARNING: Unable to find output hand history directory %s\n\n Press YES to create this directory, or NO to select a new one.") % hhdir
diapath.format_secondary_text(diastring)
response = diapath.run()
diapath.destroy()
if response == gtk.RESPONSE_YES:
try:
os.makedirs(hhdir)
except:
self.warning_box(_("WARNING: Unable to create hand output directory. Importing is not likely to work until this is fixed."))
elif response == gtk.RESPONSE_NO:
self.select_hhArchiveBase()
# check if sites in config file are in DB # check if sites in config file are in DB
for site in self.config.get_supported_sites(True): # get site names from config file for site in self.config.get_supported_sites(True): # get site names from config file
try: try:

View File

@ -444,13 +444,6 @@ class Importer:
log.info((_("Converting %s") % file) + " (" + str(q.qsize()) + ")") log.info((_("Converting %s") % file) + " (" + str(q.qsize()) + ")")
else: else:
log.info(_("Converting %s") % file) log.info(_("Converting %s") % file)
hhbase = self.config.get_import_parameters().get("hhArchiveBase")
hhbase = os.path.expanduser(hhbase)
hhdir = os.path.join(hhbase,site)
try:
out_path = os.path.join(hhdir, file.split(os.path.sep)[-2]+"-"+os.path.basename(file))
except:
out_path = os.path.join(hhdir, "x"+strftime("%d-%m-%y")+os.path.basename(file))
filter_name = filter.replace("ToFpdb", "") filter_name = filter.replace("ToFpdb", "")
@ -462,9 +455,7 @@ class Importer:
idx = self.pos_in_file[file] idx = self.pos_in_file[file]
else: else:
self.pos_in_file[file] = 0 self.pos_in_file[file] = 0
hhc = obj( self.config, in_path = file, out_path = out_path, index = idx hhc = obj( self.config, in_path = file, index = idx, starsArchive = self.settings['starsArchive'], ftpArchive = self.settings['ftpArchive'], sitename = site )
, starsArchive = self.settings['starsArchive'], ftpArchive = self.settings['ftpArchive'],
sitename = site )
if hhc.getStatus(): if hhc.getStatus():
handlist = hhc.getProcessedHands() handlist = hhc.getProcessedHands()
self.pos_in_file[file] = hhc.getLastCharacterRead() self.pos_in_file[file] = hhc.getLastCharacterRead()

View File

@ -0,0 +1,48 @@
#Game No : 172275663
***** Cassava Hand History for Game 172275663 *****
$0.01/$0.02 Blinds No Limit Holdem - *** 04 02 2011 11:27:06
Table Huelva (Real Money)
Seat 10 is the button
Total number of players : 8
Seat 1: Aussie_No.1 ( $2.58 )
Seat 2: loffelj ( $4.14 )
Seat 3: campdog14 ( $1.37 )
Seat 5: Mendya. ( $2 )
Seat 6: Borr_09 ( $0.22 )
Seat 7: roughvan ( $1.23 )
Seat 9: border360 ( $2.34 )
Seat 10: guerrillero7 ( $1.97 )
Aussie_No.1 posts small blind [$0.01]
loffelj posts big blind [$0.02]
campdog14 posts dead blind [$0.01 + $0.02]
Mendya. posts dead blind [$0.01 + $0.02]
** Dealing down cards **
Dealt to Borr_09 [ Ad, 5c ]
campdog14 checks
Mendya. checks
Borr_09 folds
roughvan folds
border360 folds
guerrillero7 folds
Aussie_No.1 calls [$0.01]
loffelj checks
** Dealing flop ** [ 4s, Ac, 7h ]
Aussie_No.1 checks
loffelj checks
campdog14 checks
Mendya. bets [$0.06]
Aussie_No.1 folds
loffelj folds
campdog14 calls [$0.06]
** Dealing turn ** [ 4h ]
campdog14 checks
Mendya. checks
** Dealing river ** [ 4c ]
campdog14 checks
Mendya. bets [$0.15]
campdog14 calls [$0.15]
** Summary **
Mendya. shows [ Kd, 7c ]
campdog14 shows [ 7s, 5s ]
campdog14 collected [ $0.24 ]
Mendya. collected [ $1,024.24 ]