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

This commit is contained in:
Eratosthenes 2010-08-04 17:39:00 -04:00
commit edce06c5cb
35 changed files with 11377 additions and 1083 deletions

22
mit.txt Normal file
View File

@ -0,0 +1,22 @@
This license applies to the pytz files distributed with fpdb's Windows installer
Copyright (c) Stuart Bishop <stuart@stuartbishop.net>
Permission is hereby granted, free of charge, to any person obtaining
a copy of this software and associated documentation files (the
"Software"), to deal in the Software without restriction, including
without limitation the rights to use, copy, modify, merge, publish,
distribute, sublicense, and/or sell copies of the Software, and to
permit persons to whom the Software is furnished to do so, subject to
the following conditions:
The above copyright notice and this permission notice shall be
included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

View File

@ -1,3 +1,34 @@
free-poker-tools (0.20.902-1) unstable; urgency=low
* New snapshot release; .901 was broken for FTP
-- Mika Bostrom <bostik@iki.fi> Sat, 24 Jul 2010 09:05:57 +0300
free-poker-tools (0.20.901-1) unstable; urgency=low
* Snapshot release before oncoming 0.21
-- Mika Bostrom <bostik@iki.fi> Thu, 22 Jul 2010 23:32:47 +0300
free-poker-tools (0.20.1-1) unstable; urgency=low
* 0.20.1 release
-- Mika Bostrom <bostik@iki.fi> Thu, 22 Jul 2010 08:47:39 +0300
free-poker-tools (0.20-2) unstable; urgency=low
* Fix executable script shebangs: there is no /usr/bin/python2 (nor
/usr/bin/python3) symlink on Debian or Ubuntu
-- Mika Bostrom <bostik+fpdb@bostik.iki.fi> Thu, 08 Jul 2010 21:29:40 +0300
free-poker-tools (0.20-1) unstable; urgency=low
* 0.20 release
-- Mika Bostrom <bostik+fpdb@bostik.iki.fi> Thu, 08 Jul 2010 11:25:36 +0300
free-poker-tools (0.20~git20100630) unstable; urgency=low
* Snapshot release

View File

@ -10,7 +10,7 @@ NEED_PYTHON=2.5
DESCRIPTION="A free/open source tracker/HUD for use with online poker"
HOMEPAGE="http://fpdb.wiki.sourceforge.net/"
SRC_URI="mirror://sourceforge/${PN}/${PV}/${P}.tar.gz"
SRC_URI="mirror://sourceforge/${PN}/${PV}/${P}.tar.bz2"
LICENSE="AGPL-3"
SLOT="0"
@ -29,7 +29,8 @@ RDEPEND="
dev-python/pygtk
graph? ( dev-python/numpy
dev-python/matplotlib[gtk] )
dev-python/python-xlib"
dev-python/python-xlib
dev-python/pytz"
DEPEND="${RDEPEND}"
src_install() {
@ -53,9 +54,7 @@ src_install() {
pkg_postinst() {
games_pkg_postinst
echo
elog "Note that if you really want to use mysql or postgresql you will have to create"
elog "the database and user yourself and enter it into the fpdb config."
elog "Note that if you really want to use mysql or postgresql you will have to create"
elog "the database and user yourself and enter it into the fpdb config."
elog "You can find the instructions on the project's website."
echo
}

View File

@ -2,19 +2,22 @@
# Distributed under the terms of the GNU General Public License v2
# created by Steffen Schaumburg, steffen@schaumburger.info
inherit eutils
inherit games
EAPI="2"
NEED_PYTHON=2.5
DESCRIPTION="Fpdb is a free/open source tracker/HUD for use with online poker"
DESCRIPTION="A free/open source tracker/HUD for use with online poker"
HOMEPAGE="http://fpdb.wiki.sourceforge.net/"
SRC_URI="mirror://sourceforge/${PN}/${PV}/${P}.tar.gz"
SRC_URI="mirror://sourceforge/${PN}/Snapshots/${P}.tar.bz2"
LICENSE="AGPL-3"
SLOT="0"
KEYWORDS="~amd64 ~x86"
#note: this should work on other architectures too, please send me your experiences
IUSE="graphing mysql postgres sqlite"
IUSE="graph mysql postgres sqlite"
RDEPEND="
mysql? ( virtual/mysql
dev-python/mysql-python )
@ -24,36 +27,34 @@ RDEPEND="
dev-python/numpy )
>=x11-libs/gtk+-2.10
dev-python/pygtk
graphing? ( dev-python/numpy
graph? ( dev-python/numpy
dev-python/matplotlib[gtk] )
dev-python/python-xlib"
dev-python/python-xlib
dev-python/pytz"
DEPEND="${RDEPEND}"
src_install() {
dodir /usr/share/games/fpdb
exeinto /usr/share/games/fpdb
doexe run_fpdb.py
dosym /usr/share/games/fpdb/run_fpdb.py /usr/bin/fpdb
insinto /usr/share/games/fpdb
insinto "${GAMES_DATADIR}"/${PN}
doins -r gfx
doins -r pyfpdb
doins readme.txt
insinto /usr/share/games/fpdb/files
doins files/*
exeinto "${GAMES_DATADIR}"/${PN}
doexe run_fpdb.py
insinto /usr/share/games/fpdb/gfx
doins gfx/*
insinto /usr/share/games/fpdb/pyfpdb
doins pyfpdb/*
# pyfpdb/regression-test-files dir is missing for now; cp -r ??
dodir "${GAMES_BINDIR}"
dosym "${GAMES_DATADIR}"/${PN}/run_fpdb.py "${GAMES_BINDIR}"/${PN}
newicon gfx/fpdb-icon.png ${PN}.png
make_desktop_entry ${PN}
prepgamesdirs
fperms +x "${GAMES_DATADIR}"/${PN}/pyfpdb/*.pyw
}
pkg_postinst() {
elog "Note that if you really want to use mysql or postgresql you will have to create"
elog "the database and user yourself and enter it into the fpdb config."
games_pkg_postinst
elog "Note that if you really want to use mysql or postgresql you will have to create"
elog "the database and user yourself and enter it into the fpdb config."
elog "You can find the instructions on the project's website."
}

View File

@ -1,57 +0,0 @@
# Copyright 1999-2010 Gentoo Foundation
# Distributed under the terms of the GNU General Public License v2
# created by Steffen Schaumburg, steffen@schaumburger.info
EAPI="2"
NEED_PYTHON=2.5
#inherit distutils
DESCRIPTION="A database program to track your online poker games"
HOMEPAGE="http://fpdb.sourceforge.net/"
#SRC_URI="mirror://sourceforge/fpdb/${MY_P}.tar.bz2"
LICENSE="AGPL-3"
SLOT="0"
KEYWORDS="~amd64 ~x86"
#note: this should work on other architectures too, please send me your experiences
IUSE="graphing mysql postgres sqlite"
RDEPEND="
mysql? ( virtual/mysql
dev-python/mysql-python )
postgres? ( dev-db/postgresql-server
dev-python/psycopg )
sqlite? ( dev-lang/python[sqlite]
dev-python/numpy )
>=x11-libs/gtk+-2.10
dev-python/pygtk
graphing? ( dev-python/numpy
dev-python/matplotlib[gtk] )
dev-python/python-xlib"
DEPEND="${RDEPEND}"
#src_install() {
# DIRINST="${D}usr/share/games/fpdb/"
# mkdir -p "${DIRINST}"
# cp -R * "${DIRINST}" || die
#
# DIRBIN="${D}usr/games/bin/"
# mkdir -p "${DIRBIN}"
# #echo "pathes"
# #echo "${DIRINST}pyfpdb/fpdb.py"
# #echo "${DIRBIN}fpdb.py"
# #echo
# echo "cd /usr/share/games/fpdb/pyfpdb/ && python fpdb.py" > "${DIRBIN}fpdb" || die
# chmod 755 "${DIRBIN}fpdb" || die
#}
#src_test() {
#}
pkg_postinst() {
elog "Fpdb's dependencies have been installed. Please visit fpdb.sourceforge.net"
elog "and download and unpack the archive.You can then start fpdb by running run_fpdb.py."
elog "Note that if you really want to use mysql or postgresql you will have to create"
elog "the database and user yourself and enter it into the fpdb config."
}

View File

@ -0,0 +1,5 @@
If you want to run a stable version please use current_stable.ebuild
If you want to run a testing version please use current_testing.ebuild
To use the ebuild please simply copy it into your local portage tree and rename it to fpdb-version.ebuild, for example fpdb-0.20.1.ebuild or fpdb-0.20.902.ebuild.
Here's a little howto on how to utilise 3rd party ebuilds such as this one: http://www.gentoo-wiki.info/HOWTO_Installing_3rd_Party_Ebuilds

View File

@ -30,15 +30,41 @@ py2exe 0.6.9 ... http://sourceforge.net/projects/py2exe/files/py2exe/0.6.9/py2ex
psycopg2 ... http://www.stickpeople.com/projects/python/win-psycopg/psycopg2-2.2.1.win32-py2.6-pg8.4.3-release.exe
(Note: stickpeople is the offical repository, not a community build)
1.2/ MySQL
MySQL-python-1.2.3.win32-py2.6-fpdb0.20.exe ... http://www.mediafire.com/file/iodnnnznmj1/MySQL-python-1.2.3.win32-py2.6-fpdb0.20.exe
This is an intaller built from source by gimick. There are no official mysql-python2.6 build for windows.
This is an intaller built from source by gimick. There are no official mysql-python2.6 builds for windows.
Community builds are also available from some developers. see www.codegood.com for example.
1.3/ pytz fixup to work in an executable package
pytz needs runtime access to timezone definition files. pytz is hard-coded to search in the directory from which the pytz .py modules are being run.
In a py2exe package, this directory is actually a library.zip container file, so windows cannot find the timezone definitions, and will crash the app.
We need to make a one-line change to pytz to search in the current working directory (which is not a container), and not the application directory.
The py2exe script copies the timezone datafiles into the package folder pyfpdb/zoneinfo.
Thanks to Jeff Peck <peck.jeff <at> gmail.com> on the py2exe mailing list for documenting this problem and solution.
1.3.1/ Navigate to C:\Python26\Lib\site-packages\pytz
1.3.2/ Edit __init__.py
1.3.3/ At line 55 replace the following line(s):
filename = os.path.join(os.path.dirname(__file__),
'zoneinfo', *name_parts)
with this line:
filename = os.path.join(os.getcwd(), 'zoneinfo', *name_parts)
1.3.4/ Save and exit
Step 2 Setup GTK
-----------------
@ -196,7 +222,7 @@ pyfpdb/share/man
Step 12 rename folder
---------------------
Rename the folder to something meaningful to the community. If you have built for NoSSE, append noSSE to the directory name.
Rename the folder to something meaningful to the community. If you have built for NoSSE, append anyCPU to the directory name.
Step 13 Compress to executable archive

View File

@ -42,10 +42,10 @@ class Absolute(HandHistoryConverter):
#Seat 6 - FETS63 ($0.75 in chips)
#Board [10s 5d Kh Qh 8c]
re_GameInfo = re.compile(ur"^Stage #([0-9]+): (?P<GAME>Holdem|HORSE)(?: \(1 on 1\)|)? ?(?P<LIMIT>No Limit|Pot Limit|Normal|)? ?(?P<CURRENCY>\$| €|)(?P<SB>[.0-9]+)/?(?:\$| €|)(?P<BB>[.0-9]+)?", re.MULTILINE)
re_GameInfo = re.compile(ur"^Stage #(C?[0-9]+): (?P<GAME>Holdem|HORSE)(?: \(1 on 1\)|)? ?(?P<LIMIT>No Limit|Pot Limit|Normal|)? ?(?P<CURRENCY>\$| €|)(?P<SB>[.0-9]+)/?(?:\$| €|)(?P<BB>[.0-9]+)?", re.MULTILINE)
re_HorseGameInfo = re.compile(ur"^Game Type: (?P<LIMIT>Limit) (?P<GAME>Holdem)", re.MULTILINE)
# TODO: can set max seats via (1 on 1) to a known 2 ..
re_HandInfo = re.compile(ur"^Stage #(?P<HID>[0-9]+): .*(?P<DATETIME>\d\d\d\d-\d\d-\d\d \d\d:\d\d:\d\d).*\n(Table: (?P<TABLE>.*) \(Real Money\))?", re.MULTILINE)
re_HandInfo = re.compile(ur"^Stage #C?(?P<HID>[0-9]+): .*(?P<DATETIME>\d\d\d\d-\d\d-\d\d \d\d:\d\d:\d\d).*\n(Table: (?P<TABLE>.*) \(Real Money\))?", re.MULTILINE)
re_TableFromFilename = re.compile(ur".*IHH([0-9]+) (?P<TABLE>.*) -") # on HORSE STUD games, the table name isn't in the hand info!
re_Button = re.compile(ur"Seat #(?P<BUTTON>[0-9]) is the ?[dead]* dealer$", re.MULTILINE) # TODO: that's not the right way to match for "dead" dealer is it?
re_PlayerInfo = re.compile(ur"^Seat (?P<SEAT>[0-9]) - (?P<PNAME>.*) \((?:\$| €|)(?P<CASH>[0-9]*[.0-9]+) in chips\)", re.MULTILINE)
@ -96,17 +96,18 @@ class Absolute(HandHistoryConverter):
def determineGameType(self, handText):
"""return dict with keys/values:
'type' in ('ring', 'tour')
'limitType' in ('nl', 'cn', 'pl', 'cp', 'fl')
'base' in ('hold', 'stud', 'draw')
'category' in ('holdem', 'omahahi', omahahilo', 'razz', 'studhi', 'studhilo', 'fivedraw', '27_1draw', '27_3draw', 'badugi')
'hilo' in ('h','l','s')
'smallBlind' int?
'bigBlind' int?
'smallBet'
'bigBet'
'currency' in ('USD', 'EUR', 'T$', <countrycode>)
or None if we fail to get the info """
'type' in ('ring', 'tour')
'limitType' in ('nl', 'cn', 'pl', 'cp', 'fl')
'base' in ('hold', 'stud', 'draw')
'category' in ('holdem', 'omahahi', omahahilo', 'razz', 'studhi', 'studhilo', 'fivedraw', '27_1draw', '27_3draw', 'badugi')
'hilo' in ('h','l','s')
'smallBlind' int?
'bigBlind' int?
'smallBet'
'bigBet'
'currency' in ('USD', 'EUR', 'T$', <countrycode>)
or None if we fail to get the info """
info = {'type':'ring'}
m = self.re_GameInfo.search(handText)
@ -329,6 +330,9 @@ def validCard(card):
return card
if __name__ == "__main__":
import Configuration
config = Configuration.Config(None)
parser = OptionParser()
parser.add_option("-i", "--input", dest="ipath", help="parse input hand history", default="-")
parser.add_option("-o", "--output", dest="opath", help="output translation to", default="-")
@ -345,5 +349,5 @@ if __name__ == "__main__":
LOG_FILENAME = './logging.out'
logging.basicConfig(filename=LOG_FILENAME,level=options.verbosity)
e = Absolute(in_path = options.ipath, out_path = options.opath, follow = options.follow, autostart=True, debugging=True)
e = Absolute(config, in_path = options.ipath, out_path = options.opath, follow = options.follow, autostart=True)

View File

@ -52,8 +52,13 @@ def get_default_config_path():
if os.name == 'posix':
config_path = os.path.join(os.path.expanduser("~"), '.fpdb')
elif os.name == 'nt':
config_path = os.path.join(os.environ["APPDATA"], 'fpdb')
config_path = os.path.join(unicode(os.environ[u"APPDATA"], "latin-1"), u"fpdb")
#print u"path after joining in get_default_config_path:",config_path
else: config_path = False
try: os.mkdir(config_path)
except: pass
return config_path
def get_exec_path():
@ -110,7 +115,7 @@ def get_logger(file_name, config = "config", fallback = False, log_dir=None, log
(conf_file,copied) = get_config(file_name, fallback = fallback)
if log_dir is None:
log_dir = os.path.join(get_exec_path(), 'log')
log_dir = os.path.join(get_exec_path(), u'log')
#print "\nget_logger: checking log_dir:", log_dir
check_dir(log_dir)
if log_file is None:
@ -147,7 +152,7 @@ def check_dir(path, create = True):
msg = "Creating directory: '%s'" % (path)
print msg
log.info(msg)
os.mkdir(path)
os.mkdir(path)#, "utf-8"))
else:
return False
@ -357,6 +362,7 @@ class Game:
class Database:
def __init__(self, node):
self.db_name = node.getAttribute("db_name")
self.db_desc = node.getAttribute("db_desc")
self.db_server = node.getAttribute("db_server").lower()
self.db_ip = node.getAttribute("db_ip")
self.db_user = node.getAttribute("db_user")
@ -499,6 +505,41 @@ class General(dict):
s = s + " %s = %s\n" % (k, self[k])
return(s)
class GUICashStats(list):
"""<gui_cash_stats>
<col col_name="game" col_title="Game" disp_all="True" disp_posn="True" field_format="%s" field_type="str" xalignment="0.0" />
...
</gui_cash_stats>
"""
def __init__(self):
super(GUICashStats, self).__init__()
def add_elements(self, node):
# is this needed?
for child in node.childNodes:
if child.nodeType == child.ELEMENT_NODE:
col_name, col_title, disp_all, disp_posn, field_format, field_type, xalignment=None, None, True, True, "%s", "str", 0.0
if child.hasAttribute('col_name'): col_name = child.getAttribute('col_name')
if child.hasAttribute('col_title'): col_title = child.getAttribute('col_title')
if child.hasAttribute('disp_all'): disp_all = string_to_bool(child.getAttribute('disp_all'))
if child.hasAttribute('disp_posn'): disp_posn = string_to_bool(child.getAttribute('disp_posn'))
if child.hasAttribute('field_format'): field_format = child.getAttribute('field_format')
if child.hasAttribute('field_type'): field_type = child.getAttribute('field_type')
try:
if child.hasAttribute('xalignment'): xalignment = float(child.getAttribute('xalignment'))
except ValueError:
print "bad number in xalignment was ignored"
log.info("bad number in xalignment was ignored")
self.append( [col_name, col_title, disp_all, disp_posn, field_format, field_type, xalignment] )
# def __str__(self):
# s = ""
# for l in self:
# s = s + " %s = %s\n" % (k, self[k])
# return(s)
class Config:
def __init__(self, file = None, dbname = ''):
# "file" is a path to an xml file with the fpdb/HUD configuration
@ -519,9 +560,9 @@ class Config:
self.dir_self = get_exec_path()
# self.dir_config = os.path.dirname(self.file)
self.dir_config = get_default_config_path()
self.dir_log = os.path.join(self.dir_config, 'log')
self.dir_database = os.path.join(self.dir_config, 'database')
self.log_file = os.path.join(self.dir_log, 'fpdb-log.txt')
self.dir_log = os.path.join(self.dir_config, u'log')
self.dir_database = os.path.join(self.dir_config, u'database')
self.log_file = os.path.join(self.dir_log, u'fpdb-log.txt')
log = get_logger("logging.conf", "config", log_dir=self.dir_log)
# Parse even if there was no real config file found and we are using the example
@ -554,10 +595,14 @@ class Config:
self.db_selected = None # database the user would like to use
self.tv = None
self.general = General()
self.gui_cash_stats = GUICashStats()
for gen_node in doc.getElementsByTagName("general"):
self.general.add_elements(node=gen_node) # add/overwrite elements in self.general
for gcs_node in doc.getElementsByTagName("gui_cash_stats"):
self.gui_cash_stats.add_elements(node=gcs_node) # add/overwrite elements in self.gui_cash_stats
# s_sites = doc.getElementsByTagName("supported_sites")
for site_node in doc.getElementsByTagName("site"):
site = Site(node = site_node)
@ -817,6 +862,9 @@ class Config:
try: db['db-databaseName'] = name
except: pass
try: db['db-desc'] = self.supported_databases[name].db_desc
except: pass
try: db['db-host'] = self.supported_databases[name].db_ip
except: pass
@ -834,20 +882,29 @@ class Config:
return db
def set_db_parameters(self, db_name = 'fpdb', db_ip = None, db_user = None,
db_pass = None, db_server = None):
db_pass = None, db_desc = None, db_server = None,
default = "False"):
db_node = self.get_db_node(db_name)
default = default.lower()
defaultb = string_to_bool(default, False)
if db_node != None:
if db_desc is not None: db_node.setAttribute("db_desc", db_desc)
if db_ip is not None: db_node.setAttribute("db_ip", db_ip)
if db_user is not None: db_node.setAttribute("db_user", db_user)
if db_pass is not None: db_node.setAttribute("db_pass", db_pass)
if db_server is not None: db_node.setAttribute("db_server", db_server)
if db_type is not None: db_node.setAttribute("db_type", db_type)
if defaultb: db_node.setAttribute("default", default)
elif db_node.hasAttribute("default"):
db_node.removeAttribute("default")
if self.supported_databases.has_key(db_name):
if db_desc is not None: self.supported_databases[db_name].dp_desc = db_desc
if db_ip is not None: self.supported_databases[db_name].dp_ip = db_ip
if db_user is not None: self.supported_databases[db_name].dp_user = db_user
if db_pass is not None: self.supported_databases[db_name].dp_pass = db_pass
if db_server is not None: self.supported_databases[db_name].dp_server = db_server
if db_type is not None: self.supported_databases[db_name].dp_type = db_type
self.supported_databases[db_name].db_selected = defaultb
if defaultb:
self.db_selected = db_name
return
def get_backend(self, name):
@ -1133,6 +1190,9 @@ class Config:
def get_general_params(self):
return( self.general )
def get_gui_cash_stat_params(self):
return( self.gui_cash_stats )
if __name__== "__main__":
c = Config()
@ -1206,6 +1266,8 @@ if __name__== "__main__":
print "start up path = ", c.execution_path("")
print "gui_cash_stats =", c.gui_cash_stats
try:
from xml.dom.ext import PrettyPrint
for site_node in c.doc.getElementsByTagName("site"):

View File

@ -74,7 +74,7 @@ except ImportError:
use_numpy = False
DB_VERSION = 136
DB_VERSION = 139
# Variance created as sqlite has a bunch of undefined aggregate functions.
@ -147,7 +147,6 @@ class Database:
{'tab':'Hands', 'col':'gametypeId', 'drop':0}
, {'tab':'HandsPlayers', 'col':'handId', 'drop':0}
, {'tab':'HandsPlayers', 'col':'playerId', 'drop':0}
, {'tab':'HandsPlayers', 'col':'tourneyTypeId', 'drop':0}
, {'tab':'HandsPlayers', 'col':'tourneysPlayersId', 'drop':0}
, {'tab':'HudCache', 'col':'gametypeId', 'drop':1}
, {'tab':'HudCache', 'col':'playerId', 'drop':0}
@ -168,7 +167,6 @@ class Database:
{'fktab':'Hands', 'fkcol':'gametypeId', 'rtab':'Gametypes', 'rcol':'id', 'drop':1}
, {'fktab':'HandsPlayers', 'fkcol':'handId', 'rtab':'Hands', 'rcol':'id', 'drop':1}
, {'fktab':'HandsPlayers', 'fkcol':'playerId', 'rtab':'Players', 'rcol':'id', 'drop':1}
, {'fktab':'HandsPlayers', 'fkcol':'tourneyTypeId', 'rtab':'TourneyTypes', 'rcol':'id', 'drop':1}
, {'fktab':'HandsPlayers', 'fkcol':'tourneysPlayersId','rtab':'TourneysPlayers','rcol':'id', 'drop':1}
, {'fktab':'HandsActions', 'fkcol':'handsPlayerId', 'rtab':'HandsPlayers', 'rcol':'id', 'drop':1}
, {'fktab':'HudCache', 'fkcol':'gametypeId', 'rtab':'Gametypes', 'rcol':'id', 'drop':1}
@ -953,6 +951,7 @@ class Database:
# hmmm, tested by commenting out rollback in grapher. lock seems to work but
# then drop still hangs :-( does work in some tests though??
# will leave code here for now pending further tests/enhancement ...
c.execute("BEGIN TRANSACTION")
c.execute( "lock table %s in exclusive mode nowait" % (fk['fktab'],) )
#print "after lock, status:", c.statusmessage
#print "alter table %s drop constraint %s_%s_fkey" % (fk['fktab'], fk['fktab'], fk['fkcol'])
@ -963,6 +962,7 @@ class Database:
if "does not exist" not in str(sys.exc_value):
print "warning: drop pg fk %s_%s_fkey failed: %s, continuing ..." \
% (fk['fktab'], fk['fkcol'], str(sys.exc_value).rstrip('\n') )
c.execute("END TRANSACTION")
except:
print "warning: constraint %s_%s_fkey not dropped: %s, continuing ..." \
% (fk['fktab'],fk['fkcol'], str(sys.exc_value).rstrip('\n'))
@ -986,6 +986,7 @@ class Database:
print "dropping pg index ", idx['tab'], idx['col']
try:
# try to lock table to see if index drop will work:
c.execute("BEGIN TRANSACTION")
c.execute( "lock table %s in exclusive mode nowait" % (idx['tab'],) )
#print "after lock, status:", c.statusmessage
try:
@ -997,6 +998,7 @@ class Database:
if "does not exist" not in str(sys.exc_value):
print "warning: drop index %s_%s_idx failed: %s, continuing ..." \
% (idx['tab'],idx['col'], str(sys.exc_value).rstrip('\n'))
c.execute("END TRANSACTION")
except:
print "warning: index %s_%s_idx not dropped %s, continuing ..." \
% (idx['tab'],idx['col'], str(sys.exc_value).rstrip('\n'))
@ -1369,6 +1371,7 @@ class Database:
# hmmm, tested by commenting out rollback in grapher. lock seems to work but
# then drop still hangs :-( does work in some tests though??
# will leave code here for now pending further tests/enhancement ...
c.execute("BEGIN TRANSACTION")
c.execute( "lock table %s in exclusive mode nowait" % (fk['fktab'],) )
#print "after lock, status:", c.statusmessage
#print "alter table %s drop constraint %s_%s_fkey" % (fk['fktab'], fk['fktab'], fk['fkcol'])
@ -1379,6 +1382,7 @@ class Database:
if "does not exist" not in str(sys.exc_value):
print "warning: drop pg fk %s_%s_fkey failed: %s, continuing ..." \
% (fk['fktab'], fk['fkcol'], str(sys.exc_value).rstrip('\n') )
c.execute("END TRANSACTION")
except:
print "warning: constraint %s_%s_fkey not dropped: %s, continuing ..." \
% (fk['fktab'],fk['fkcol'], str(sys.exc_value).rstrip('\n'))
@ -1641,7 +1645,6 @@ class Database:
pdata[p]['street3Bets'],
pdata[p]['street4Bets'],
pdata[p]['position'],
pdata[p]['tourneyTypeId'],
pdata[p]['tourneysPlayersIds'],
pdata[p]['startCards'],
pdata[p]['street0_3BChance'],
@ -1654,8 +1657,8 @@ class Database:
pdata[p]['foldToOtherRaisedStreet2'],
pdata[p]['foldToOtherRaisedStreet3'],
pdata[p]['foldToOtherRaisedStreet4'],
pdata[p]['stealAttemptChance'],
pdata[p]['stealAttempted'],
pdata[p]['raiseFirstInChance'],
pdata[p]['raisedFirstIn'],
pdata[p]['foldBbToStealChance'],
pdata[p]['foldedBbToSteal'],
pdata[p]['foldSbToStealChance'],
@ -1735,8 +1738,8 @@ class Database:
if pdata[p]['foldToOtherRaisedStreet4']: line[21] = 1
line[22] = pdata[p]['wonWhenSeenStreet1']
line[23] = pdata[p]['wonAtSD']
if pdata[p]['stealAttemptChance']: line[24] = 1
if pdata[p]['stealAttempted']: line[25] = 1
if pdata[p]['raiseFirstInChance']: line[24] = 1
if pdata[p]['raisedFirstIn']: line[25] = 1
if pdata[p]['foldBbToStealChance']: line[26] = 1
if pdata[p]['foldedBbToSteal']: line[27] = 1
if pdata[p]['foldSbToStealChance']: line[28] = 1
@ -1825,7 +1828,7 @@ class Database:
def getGameTypeId(self, siteid, game):
c = self.get_cursor()
#FIXME: Fixed for NL at the moment
c.execute(self.sql.query['getGametypeNL'], (siteid, game['type'], game['category'], game['limitType'],
c.execute(self.sql.query['getGametypeNL'], (siteid, game['type'], game['category'], game['limitType'], game['currency'],
int(Decimal(game['sb'])*100), int(Decimal(game['bb'])*100)))
tmp = c.fetchone()
if (tmp == None):
@ -1834,7 +1837,7 @@ class Database:
hilo = "s"
elif game['category'] in ['razz','27_3draw','badugi']:
hilo = "l"
tmp = self.insertGameTypes( (siteid, 'USD', game['type'], game['base'], game['category'], game['limitType'], hilo,
tmp = self.insertGameTypes( (siteid, game['currency'], game['type'], game['base'], game['category'], game['limitType'], hilo,
int(Decimal(game['sb'])*100), int(Decimal(game['bb'])*100), 0, 0) )
#FIXME: recognise currency
return tmp[0]
@ -1983,26 +1986,27 @@ class Database:
(hand.tourNo, hand.siteId)
)
result=cursor.fetchone()
print "result of fetching TT by number and site:",result
#print "result of fetching TT by number and site:",result
if result:
tourneyTypeId = result[0]
else:
# Check for an existing TTypeId that matches tourney info, if not found create it
print "info that we use to get TT by detail:", hand.siteId, hand.buyinCurrency, hand.buyin, hand.fee, hand.gametype['category'], hand.gametype['limitType'], hand.buyInChips, hand.isKO, hand.isRebuy, hand.isAddOn, hand.speed, hand.isShootout, hand.isMatrix, hand.added, hand.addedCurrency
#print "info that we use to get TT by detail:", hand.siteId, hand.buyinCurrency, hand.buyin, hand.fee, hand.gametype['category'], hand.gametype['limitType'], hand.isKO, hand.isRebuy, hand.isAddOn, hand.speed, hand.isShootout, hand.isMatrix
#print "the query:",self.sql.query['getTourneyTypeId'].replace('%s', self.sql.query['placeholder'])
cursor.execute (self.sql.query['getTourneyTypeId'].replace('%s', self.sql.query['placeholder']),
(hand.siteId, hand.buyinCurrency, hand.buyin, hand.fee, hand.gametype['category'], hand.gametype['limitType'], hand.buyInChips, hand.isKO,
hand.isRebuy, hand.isAddOn, hand.speed, hand.isShootout, hand.isMatrix, hand.added, hand.addedCurrency)
(hand.siteId, hand.buyinCurrency, hand.buyin, hand.fee, hand.gametype['category'], hand.gametype['limitType'], hand.isKO,
hand.isRebuy, hand.isAddOn, hand.speed, hand.isShootout, hand.isMatrix) #TODO: add koamount
)
result=cursor.fetchone()
print "result of fetching TT by details:",result
#print "result of fetching TT by details:",result
try:
tourneyTypeId = result[0]
except TypeError: #this means we need to create a new entry
cursor.execute (self.sql.query['insertTourneyType'].replace('%s', self.sql.query['placeholder']),
(hand.siteId, hand.buyinCurrency, hand.buyin, hand.fee, hand.gametype['category'], hand.gametype['limitType'], hand.buyInChips,
hand.isKO, hand.isRebuy,
(hand.siteId, hand.buyinCurrency, hand.buyin, hand.fee, hand.gametype['category'], hand.gametype['limitType'],
hand.buyInChips, hand.isKO, hand.koBounty, hand.isRebuy,
hand.isAddOn, hand.speed, hand.isShootout, hand.isMatrix, hand.added, hand.addedCurrency)
)
tourneyTypeId = self.get_last_insert_id(cursor)

View File

@ -53,8 +53,8 @@ class DerivedStats():
self.handsplayers[player[1]]['street0_3BDone'] = False
self.handsplayers[player[1]]['street0_4BChance'] = False
self.handsplayers[player[1]]['street0_4BDone'] = False
self.handsplayers[player[1]]['stealAttemptChance'] = False
self.handsplayers[player[1]]['stealAttempted'] = False
self.handsplayers[player[1]]['raiseFirstInChance'] = False
self.handsplayers[player[1]]['raisedFirstIn'] = False
self.handsplayers[player[1]]['foldBbToStealChance'] = False
self.handsplayers[player[1]]['foldSbToStealChance'] = False
self.handsplayers[player[1]]['foldedSbToSteal'] = False
@ -290,7 +290,10 @@ class DerivedStats():
# print "p_actions:", self.pfba(actions), "p_folds:", self.pfba(actions, l=('folds',)), "alliners:", alliners
# pas = set.union(self.pfba(actions) - self.pfba(actions, l=('folds',)), alliners)
p_in = set(x[1] for x in hand.players)
# hand.players includes people that are sitting out on some sites.
# Those that posted an ante should have been deal cards.
p_in = set([x[0] for x in hand.actions['BLINDSANTES']] + [x[0] for x in hand.actions['PREFLOP']])
for (i, street) in enumerate(hand.actionStreets):
actions = hand.actions[street]
p_in = p_in - self.pfba(actions, l=('folds',))
@ -315,13 +318,14 @@ class DerivedStats():
self.hands['street%dRaises' % i] = len(filter( lambda action: action[1] in ('raises','bets'), hand.actions[street]))
def calcSteals(self, hand):
"""Fills stealAttempt(Chance|ed, fold(Bb|Sb)ToSteal(Chance|)
"""Fills raiseFirstInChance|raisedFirstIn, fold(Bb|Sb)ToSteal(Chance|)
Steal attempt - open raise on positions 1 0 S - i.e. MP3, CO, BU, SB
Steal attempt - open raise on positions 1 0 S - i.e. CO, BU, SB
(note: I don't think PT2 counts SB steals in HU hands, maybe we shouldn't?)
Fold to steal - folding blind after steal attemp wo any other callers or raisers
"""
steal_attempt = False
raised = False
steal_positions = (1, 0, 'S')
if hand.gametype['base'] == 'stud':
steal_positions = (2, 1, 0)
@ -341,11 +345,13 @@ class DerivedStats():
if steal_attempt and act != 'folds':
break
if posn in steal_positions and not steal_attempt:
self.handsplayers[pname]['stealAttemptChance'] = True
if not steal_attempt and not raised: # if posn in steal_positions and not steal_attempt:
self.handsplayers[pname]['raiseFirstInChance'] = True
if act in ('bets', 'raises'):
self.handsplayers[pname]['stealAttempted'] = True
steal_attempt = True
self.handsplayers[pname]['raisedFirstIn'] = True
raised = True
if posn in steal_positions:
steal_attempt = True
if act == 'calls':
break

View File

@ -34,11 +34,11 @@ class Everleaf(HandHistoryConverter):
# Static regexes
re_SplitHands = re.compile(r"\n\n\n+")
re_TailSplitHands = re.compile(r"(\n\n\n+)")
re_GameInfo = re.compile(ur"^(Blinds )?(?P<CURRENCY>\$| €|)(?P<SB>[.0-9]+)/(?:\$| €)?(?P<BB>[.0-9]+) (?P<LIMIT>NL|PL|) ?(?P<GAME>(Hold\'em|Omaha|7 Card Stud))", re.MULTILINE)
#re.compile(ur"^(Blinds )?(?P<CURRENCY>\$| €|)(?P<SB>[.0-9]+)/(?:\$| €)?(?P<BB>[.0-9]+) (?P<LIMIT>NL|PL|) (?P<GAME>(Hold\'em|Omaha|7 Card Stud))", re.MULTILINE)
re_HandInfo = re.compile(ur".*#(?P<HID>[0-9]+)\n.*\n(Blinds )?(?:\$| €|)(?P<SB>[.0-9]+)/(?:\$| €|)(?P<BB>[.0-9]+) (?P<GAMETYPE>.*) - (?P<DATETIME>\d\d\d\d/\d\d/\d\d - \d\d:\d\d:\d\d)\nTable (?P<TABLE>.+$)", re.MULTILINE)
re_Button = re.compile(ur"^Seat (?P<BUTTON>\d+) is the button", re.MULTILINE)
re_PlayerInfo = re.compile(ur"^Seat (?P<SEAT>[0-9]+): (?P<PNAME>.*) \(\s+((?:\$| €|) (?P<CASH>[.0-9]+) (USD|EURO|Chips)|new player|All-in) \)", re.MULTILINE)
re_GameInfo = re.compile(ur"^(Blinds )?(?P<CURRENCY>[$€]?)(?P<SB>[.0-9]+)/[$€]?(?P<BB>[.0-9]+) (?P<LIMIT>NL|PL|) ?(?P<GAME>(Hold\'em|Omaha|7 Card Stud))", re.MULTILINE)
#re.compile(ur"^(Blinds )?(?P<CURRENCY>\$| €|)(?P<SB>[.0-9]+)/(?:\$| €)?(?P<BB>[.0-9]+) (?P<LIMIT>NL|PL|) ?(?P<GAME>(Hold\'em|Omaha|7 Card Stud))", re.MULTILINE)
re_HandInfo = re.compile(ur".*#(?P<HID>[0-9]+)\n.*\n(Blinds )?(?P<CURRENCY>[$€])?(?P<SB>[.0-9]+)/(?:[$€])?(?P<BB>[.0-9]+) (?P<GAMETYPE>.*) - (?P<DATETIME>\d\d\d\d/\d\d/\d\d - \d\d:\d\d:\d\d)\nTable (?P<TABLE>.+$)", re.MULTILINE)
re_Button = re.compile(ur"^Seat (?P<BUTTON>\d+) is the button$", re.MULTILINE)
re_PlayerInfo = re.compile(ur"^Seat (?P<SEAT>[0-9]+): (?P<PNAME>.*) \(\s+([$€]? (?P<CASH>[.0-9]+) (USD|EURO|Chips)|new player|All-in) \)$", re.MULTILINE)
re_Board = re.compile(ur"\[ (?P<CARDS>.+) \]")
re_TourneyInfoFromFilename = re.compile(ur".*TID_(?P<TOURNO>[0-9]+)-(?P<TABLE>[0-9]+)\.txt")
@ -50,16 +50,16 @@ class Everleaf(HandHistoryConverter):
self.compiledPlayers = players
player_re = "(?P<PNAME>" + "|".join(map(re.escape, players)) + ")"
logging.debug("player_re: "+ player_re)
self.re_PostSB = re.compile(ur"^%s: posts small blind \[(?:\$| €|) (?P<SB>[.0-9]+)" % player_re, re.MULTILINE)
self.re_PostBB = re.compile(ur"^%s: posts big blind \[(?:\$| €|) (?P<BB>[.0-9]+)" % player_re, re.MULTILINE)
self.re_PostBoth = re.compile(ur"^%s: posts both blinds \[(?:\$| €|) (?P<SBBB>[.0-9]+)" % player_re, re.MULTILINE)
self.re_Antes = re.compile(ur"^%s: posts ante \[(?:\$| €|) (?P<ANTE>[.0-9]+)" % player_re, re.MULTILINE)
self.re_BringIn = re.compile(ur"^%s posts bring-in (?:\$| €|)(?P<BRINGIN>[.0-9]+)\." % player_re, re.MULTILINE)
self.re_HeroCards = re.compile(ur"^Dealt to %s \[ (?P<CARDS>.*) \]" % player_re, re.MULTILINE)
self.re_Action = re.compile(ur"^%s(?P<ATYPE>: bets| checks| raises| calls| folds)(\s\[(?:\$| €|) (?P<BET>[.,\d]+) (USD|EURO|Chips)\])?" % player_re, re.MULTILINE)
#self.re_Action = re.compile(ur"^%s(?P<ATYPE>: bets| checks| raises| calls| folds| complete to)(\s\[?(?:\$| €|) ?(?P<BET>\d+\.?\d*)\.?\s?(USD|EUR|)\]?)?" % player_re, re.MULTILINE)
self.re_PostSB = re.compile(ur"^%s: posts small blind \[[$€]? (?P<SB>[.0-9]+)\s.*\]$" % player_re, re.MULTILINE)
self.re_PostBB = re.compile(ur"^%s: posts big blind \[[$€]? (?P<BB>[.0-9]+)\s.*\]$" % player_re, re.MULTILINE)
self.re_PostBoth = re.compile(ur"^%s: posts both blinds \[[$€]? (?P<SBBB>[.0-9]+)\s.*\]$" % player_re, re.MULTILINE)
self.re_Antes = re.compile(ur"^%s: posts ante \[[$€]? (?P<ANTE>[.0-9]+)\s.*\]$" % player_re, re.MULTILINE)
self.re_BringIn = re.compile(ur"^%s posts bring-in [$€]? (?P<BRINGIN>[.0-9]+)\." % player_re, re.MULTILINE)
self.re_HeroCards = re.compile(ur"^Dealt to %s \[ (?P<CARDS>.*) \]$" % player_re, re.MULTILINE)
# ^%s(?P<ATYPE>: bets| checks| raises| calls| folds)(\s\[(?:\$| €|) (?P<BET>[.,\d]+) (USD|EURO|Chips)\])?
self.re_Action = re.compile(ur"^%s(?P<ATYPE>: bets| checks| raises| calls| folds)(\s\[(?:[$€]?) (?P<BET>[.,\d]+)\s?(USD|EURO|Chips|)\])?" % player_re, re.MULTILINE)
self.re_ShowdownAction = re.compile(ur"^%s shows \[ (?P<CARDS>.*) \]" % player_re, re.MULTILINE)
self.re_CollectPot = re.compile(ur"^%s wins (?:\$| €|) (?P<POT>[.\d]+) (USD|EURO|chips)(.*?\[ (?P<CARDS>.*?) \])?" % player_re, re.MULTILINE)
self.re_CollectPot = re.compile(ur"^%s wins (?:[$€]?)\s?(?P<POT>[.\d]+) (USD|EURO|chips)(.*?\[ (?P<CARDS>.*?) \])?" % player_re, re.MULTILINE)
self.re_SitsOut = re.compile(ur"^%s sits out" % player_re, re.MULTILINE)
def readSupportedGames(self):
@ -112,7 +112,7 @@ or None if we fail to get the info """
'Razz' : ('stud','razz'),
'7 Card Stud' : ('stud','studhi')
}
currencies = { u' ':'EUR', '$':'USD', '':'T$' }
currencies = { u'':'EUR', '$':'USD', '':'T$'}
if 'LIMIT' in mg:
info['limitType'] = limits[mg['LIMIT']]
if 'GAME' in mg:
@ -140,19 +140,25 @@ or None if we fail to get the info """
hand.handid = m.group('HID')
hand.tablename = m.group('TABLE')
hand.maxseats = 6 # assume 6-max unless we have proof it's a larger/smaller game, since everleaf doesn't give seat max info
currencies = { u'':'EUR', '$':'USD', '':'T$', None:'T$' }
mg = m.groupdict()
hand.gametype['currency'] = currencies[mg['CURRENCY']]
t = self.re_TourneyInfoFromFilename.search(self.in_path)
if t:
tourno = t.group('TOURNO')
hand.tourNo = tourno
hand.tablename = t.group('TABLE')
#TODO we should fetch info including buyincurrency, buyin and fee from URL:
# https://www.poker4ever.com/tourney/%TOURNEY_NUMBER%
# Believe Everleaf time is GMT/UTC, no transation necessary
# Stars format (Nov 10 2008): 2008/11/07 12:38:49 CET [2008/11/07 7:38:49 ET]
# or : 2008/11/07 12:38:49 ET
# Not getting it in my HH files yet, so using
# 2008/11/10 3:58:52 ET
#TODO: Do conversion from GMT to ET
#TODO: Need some date functions to convert to different timezones (Date::Manip for perl rocked for this)
hand.startTime = datetime.datetime.strptime(m.group('DATETIME'), "%Y/%m/%d - %H:%M:%S")
return

View File

@ -229,12 +229,21 @@ class Filters(threading.Thread):
return self.numHands
#end def getNumHands
def getNumTourneys(self):
return self.numTourneys
#end def getNumTourneys
def getSites(self):
return self.sites
#end def getSites
def getTourneyTypes(self):
return self.tourneyTypes
#end def getTourneyTypes
def getGames(self):
return self.games
#end def getGames
def getSiteIds(self):
return self.siteid
@ -316,6 +325,7 @@ class Filters(threading.Thread):
liststore.append(_nt)
self.__set_hero_name(pname, site)
#end def createPlayerLine
def __set_hero_name(self, w, site):
_name = w.get_text()
@ -338,6 +348,20 @@ class Filters(threading.Thread):
cb.connect('clicked', self.__set_site_select, site)
cb.set_active(True)
hbox.pack_start(cb, False, False, 0)
#end def createSiteLine
def __set_tourney_type_select(self, w, tourneyType):
#print w.get_active()
self.tourneyTypes[tourneyType] = w.get_active()
log.debug("self.tourney_types[%s] set to %s" %(tourneyType, self.tourneyTypes[tourneyType]))
#end def __set_tourney_type_select
def createTourneyTypeLine(self, hbox, tourneyType):
cb = gtk.CheckButton(str(tourneyType))
cb.connect('clicked', self.__set_tourney_type_select, tourneyType)
hbox.pack_start(cb, False, False, 0)
cb.set_active(True)
#end def createTourneyTypeLine
def createGameLine(self, hbox, game):
cb = gtk.CheckButton(game)
@ -357,6 +381,7 @@ class Filters(threading.Thread):
#print w.get_active()
self.sites[site] = w.get_active()
log.debug("self.sites[%s] set to %s" %(site, self.sites[site]))
#end def __set_site_select
def __set_game_select(self, w, game):
#print w.get_active()
@ -505,6 +530,7 @@ class Filters(threading.Thread):
#print "__set_seat_select: seat =", seat, "active =", w.get_active()
self.seats[seat] = w.get_active()
log.debug( "self.seats[%s] set to %s" %(seat, self.seats[seat]) )
#end def __set_seat_select
def __set_group_select(self, w, group):
#print "__set_seat_select: seat =", seat, "active =", w.get_active()
@ -552,6 +578,7 @@ class Filters(threading.Thread):
hbox.pack_start(phands, False, False, 0)
phands.connect("changed", self.__set_num_hands, site)
top_hbox.pack_start(showb, expand=False, padding=1)
#end def fillPlayerFrame
def fillSitesFrame(self, vbox):
top_hbox = gtk.HBox(False, 0)
@ -583,6 +610,33 @@ class Filters(threading.Thread):
# self.siteid[site] = result[0][0]
#else:
# print "Either 0 or more than one site matched - EEK"
#end def fillSitesFrame
def fillTourneyTypesFrame(self, vbox):
top_hbox = gtk.HBox(False, 0)
vbox.pack_start(top_hbox, False, False, 0)
lbl_title = gtk.Label(self.filterText['tourneyTypesTitle'])
lbl_title.set_alignment(xalign=0.0, yalign=0.5)
top_hbox.pack_start(lbl_title, expand=True, padding=3)
showb = gtk.Button(label="hide", stock=None, use_underline=True)
showb.set_alignment(xalign=1.0, yalign=0.5)
showb.connect('clicked', self.__toggle_box, 'tourneyTypes')
top_hbox.pack_start(showb, expand=False, padding=1)
vbox1 = gtk.VBox(False, 0)
vbox.pack_start(vbox1, False, False, 0)
self.boxes['tourneyTypes'] = vbox1
result = self.db.getTourneyTypesIds()
if len(result) >= 1:
for line in result:
hbox = gtk.HBox(False, 0)
vbox1.pack_start(hbox, False, True, 0)
self.createTourneyTypeLine(hbox, line[0])
else:
print "INFO: No tourney types returned from database"
log.info("No tourney types returned from database")
#end def fillTourneyTypesFrame
def fillGamesFrame(self, vbox):
top_hbox = gtk.HBox(False, 0)
@ -859,6 +913,7 @@ class Filters(threading.Thread):
for w in self.mainVBox.get_children():
w.destroy()
self.make_filter()
#end def __refresh
def __toggle_box(self, widget, entry):
if self.boxes[entry].props.visible:

View File

@ -54,7 +54,7 @@ class Fulltilt(HandHistoryConverter):
\$?(?P<SB>[.0-9]+)/\$?(?P<BB>[.0-9]+)\s(Ante\s\$?(?P<ANTE>[.0-9]+)\s)?-\s
\$?(?P<CAP>[.0-9]+\sCap\s)?
(?P<GAMETYPE>[a-zA-Z\/\'\s]+)\s-\s
(?P<DATETIME>\d+:\d+:\d+\s\w+\s-\s\d+/\d+/\d+|\d+:\d+\s\w+\s-\s\w+\,\s\w+\s\d+\,\s\d+)
(?P<DATETIME>\d+:\d+:\d+\s(?P<TZ1>\w+)\s-\s\d+/\d+/\d+|\d+:\d+\s(?P<TZ2>\w+)\s-\s\w+\,\s\w+\s\d+\,\s\d+)
(?P<PARTIAL>\(partial\))?\n
(?:.*?\n(?P<CANCELLED>Hand\s\#(?P=HID)\shas\sbeen\scanceled))?
''', re.VERBOSE|re.DOTALL)
@ -201,13 +201,18 @@ class Fulltilt(HandHistoryConverter):
return None
hand.handid = m.group('HID')
hand.tablename = m.group('TABLE')
try:
hand.startTime = datetime.datetime.strptime(m.group('DATETIME'), "%H:%M:%S ET - %Y/%m/%d")
except:
hand.startTime = datetime.datetime.strptime(m.group('DATETIME'), "%H:%M ET - %a, %B %d, %Y")
hand.startTime = HandHistoryConverter.changeTimezone(hand.startTime, "ET", "UTC")
timezone = "ET"
if m.group('TZ1') == "CET" or m.group('TZ2') == "CET":
timezone = "CET"
try:
stringformat = "%H:%M:%S " + m.group('TZ1') + " - %Y/%m/%d"
hand.startTime = datetime.datetime.strptime(m.group('DATETIME'), stringformat)
except:
stringformat = "%H:%M " + m.group('TZ2') + " - %a, %B %d, %Y"
hand.startTime = datetime.datetime.strptime(m.group('DATETIME'), stringformat)
hand.startTime = HandHistoryConverter.changeTimezone(hand.startTime, timezone, "UTC")
if m.group("CANCELLED") or m.group("PARTIAL"):
raise FpdbParseError(hid=m.group('HID'))

View File

@ -33,17 +33,32 @@ log = logging.getLogger("maintdbs")
import Exceptions
import Database
import SQL
class GuiDatabase:
# columns in liststore:
MODEL_DBMS = 0
MODEL_NAME = 1
MODEL_DESC = 2
MODEL_USER = 3
MODEL_PASS = 4
MODEL_HOST = 5
MODEL_DFLT = 6
MODEL_DFLTIC = 7
MODEL_STATUS = 8
MODEL_STATIC = 9
# columns in listview:
COL_DBMS = 0
COL_NAME = 1
COL_DESC = 2
COL_USER = 3
COL_PASS = 4
COL_HOST = 5
COL_ICON = 6
COL_DFLT = 6
COL_ICON = 7
def __init__(self, config, mainwin, dia):
self.config = config
@ -56,9 +71,9 @@ class GuiDatabase:
#gtk.Widget.set_size_request(self.vbox, 700, 400);
# list of databases in self.config.supported_databases:
self.liststore = gtk.ListStore(str, str, str, str
,str, str, str, str) #object, gtk.gdk.Pixbuf)
# dbms, name, comment, user, pass, ip, status(, icon?)
self.liststore = gtk.ListStore(str, str, str, str, str
,str, str, str, str, str)
# dbms, name, comment, user, passwd, host, "", default_icon, status, icon
# this is how to add a filter:
#
# # Creation of the filter, from the model
@ -70,11 +85,12 @@ class GuiDatabase:
self.listview = gtk.TreeView(model=self.liststore)
self.listview.set_grid_lines(gtk.TREE_VIEW_GRID_LINES_NONE)
self.listcols = []
self.changes = False
scrolledwindow = gtk.ScrolledWindow()
scrolledwindow.set_policy(gtk.POLICY_AUTOMATIC, gtk.POLICY_AUTOMATIC)
scrolledwindow.add(self.listview)
self.vbox.pack_start(scrolledwindow, expand=True, fill=True, padding=0)
self.scrolledwindow = gtk.ScrolledWindow()
self.scrolledwindow.set_policy(gtk.POLICY_AUTOMATIC, gtk.POLICY_AUTOMATIC)
self.scrolledwindow.add(self.listview)
self.vbox.pack_start(self.scrolledwindow, expand=True, fill=True, padding=0)
refreshbutton = gtk.Button("Refresh")
refreshbutton.connect("clicked", self.refresh, None)
@ -87,18 +103,28 @@ class GuiDatabase:
col = self.addTextColumn("Username", 3, True)
col = self.addTextColumn("Password", 4, True)
col = self.addTextColumn("Host", 5, True)
col = self.addTextObjColumn("", 6)
col = self.addTextObjColumn("Default", 6, 6)
col = self.addTextObjColumn("Status", 7, 8)
#self.listview.get_selection().set_mode(gtk.SELECTION_SINGLE)
#self.listview.get_selection().connect("changed", self.on_selection_changed)
self.listview.add_events(gtk.gdk.BUTTON_PRESS_MASK)
self.listview.connect('button_press_event', self.selectTest)
self.loadDbs()
self.dia.connect('response', self.dialog_response_cb)
#self.dia.connect('response', self.dialog_response_cb)
except:
err = traceback.extract_tb(sys.exc_info()[2])[-1]
print 'guidbmaint: '+ err[2] + "(" + str(err[1]) + "): " + str(sys.exc_info()[1])
def dialog_response_cb(self, dialog, response_id):
# this is called whether close button is pressed or window is closed
log.info('dialog_response_cb: response_id='+str(response_id))
#if self.changes:
# self.config.save()
dialog.destroy()
return(response_id)
def get_dialog(self):
@ -125,6 +151,7 @@ class GuiDatabase:
def edited_cb(self, cell, path, new_text, user_data):
liststore, col = user_data
log.info('edited_cb: col = '+str(col))
valid = True
name = self.liststore[path][self.COL_NAME]
@ -138,10 +165,11 @@ class GuiDatabase:
self.config.set_db_parameters( db_server = self.liststore[path][self.COL_DBMS]
, db_name = name
, db_desc = self.liststore[path][self.COL_DESC]
, db_ip = self.liststore[path][self.COL_HOST]
, db_user = self.liststore[path][self.COL_USER]
, db_pass = self.liststore[path][self.COL_PASS] )
self.changes = True
return
def check_new_name(self, path, new_text):
@ -152,38 +180,73 @@ class GuiDatabase:
#TODO: popup an error message telling user names must be unique
return name_ok
def addTextObjColumn(self, title, n):
def addTextObjColumn(self, title, viewcol, storecol, editable=False):
col = gtk.TreeViewColumn(title)
self.listview.append_column(col)
cRenderT = gtk.CellRendererText()
cRenderT.set_property("wrap-mode", pango.WRAP_WORD_CHAR)
col.pack_start(cRenderT, False)
col.add_attribute(cRenderT, 'text', n)
col.add_attribute(cRenderT, 'text', storecol)
cRenderP = gtk.CellRendererPixbuf()
col.pack_start(cRenderP, False)
col.add_attribute(cRenderP, 'stock-id', n+1)
col.pack_start(cRenderP, True)
col.add_attribute(cRenderP, 'stock-id', storecol+1)
col.set_max_width(1000)
col.set_spacing(0) # no effect
self.listcols.append(col)
#col.set_clickable(True)
#col.connect("clicked", self.sortCols, p)
col.set_clickable(True)
col.connect("clicked", self.sortCols, viewcol)
return(col)
def selectTest(self, widget, event):
if event.button == 1: # and event.type == gtk.gdk._2BUTTON_PRESS:
pthinfo = self.listview.get_path_at_pos( int(event.x), int(event.y) )
if pthinfo is not None:
path, col, cellx, celly = pthinfo
row = path[0]
if col == self.listcols[self.COL_DFLT]:
if self.liststore[row][self.MODEL_STATUS] == 'ok' and self.liststore[row][self.MODEL_DFLTIC] is None:
self.setDefaultDB(row)
def setDefaultDB(self, row):
print "set new defaultdb:", row, self.liststore[row][self.MODEL_NAME]
for r in xrange(len(self.liststore)):
if r == row:
self.liststore[r][self.MODEL_DFLTIC] = gtk.STOCK_APPLY
default = "True"
else:
self.liststore[r][self.MODEL_DFLTIC] = None
default = "False"
self.config.set_db_parameters( db_server = self.liststore[r][self.COL_DBMS]
, db_name = self.liststore[r][self.COL_NAME]
, db_desc = self.liststore[r][self.COL_DESC]
, db_ip = self.liststore[r][self.COL_HOST]
, db_user = self.liststore[r][self.COL_USER]
, db_pass = self.liststore[r][self.COL_PASS]
, default = default
)
self.changes = True
return
def loadDbs(self):
self.liststore.clear()
self.listcols = []
self.dbs = [] # list of tuples: (dbms, name, comment, user, passwd, host, status, icon)
#self.listcols = []
dia = self.info_box2(None, 'Testing database connections ... ', "", False, False)
while gtk.events_pending():
gtk.mainiteration()
try:
# want to fill: dbms, name, comment, user, passwd, host, status(, icon?)
# want to fill: dbms, name, comment, user, passwd, host, default, status, icon
for name in self.config.supported_databases: #db_ip/db_user/db_pass/db_server
dbms = self.config.supported_databases[name].db_server # mysql/postgresql/sqlite
dbms_num = self.config.get_backend(dbms) # 2 / 3 / 4
comment = ""
comment = self.config.supported_databases[name].db_desc
if dbms == 'sqlite':
user = ""
passwd = ""
@ -191,22 +254,30 @@ class GuiDatabase:
user = self.config.supported_databases[name].db_user
passwd = self.config.supported_databases[name].db_pass
host = self.config.supported_databases[name].db_ip
default = (name == self.config.db_selected)
default_icon = None
if default: default_icon = gtk.STOCK_APPLY
status = ""
icon = None
err_msg = ""
db = Database.Database(self.config, sql = None, autoconnect = False)
sql = SQL.Sql(db_server=dbms)
db = Database.Database(self.config, sql = sql, autoconnect = False)
# try to connect to db, set status and err_msg if it fails
try:
# is creating empty db for sqlite ... mod db.py further?
# add noDbTables flag to db.py?
log.debug("loaddbs: trying to connect to: %s/%s, %s, %s/%s" % (str(dbms_num),dbms,name,user,passwd))
db.connect(backend=dbms_num, host=host, database=name, user=user, password=passwd, create=False)
if db.connected:
log.debug(" connected ok")
status = 'ok'
icon = gtk.STOCK_APPLY
if db.wrongDbVersion:
status = 'old'
icon = gtk.STOCK_INFO
else:
log.debug(" not connected but no exception")
except Exceptions.FpdbMySQLAccessDenied:
err_msg = "MySQL Server reports: Access denied. Are your permissions set correctly?"
status = "failed"
@ -230,13 +301,17 @@ class GuiDatabase:
+ err[2] + "(" + str(err[1]) + "): " + str(sys.exc_info()[1]) )
status = "failed"
icon = gtk.STOCK_CANCEL
if err_msg:
log.info( 'db connection to '+str(dbms_num)+','+host+','+name+','+user+','+passwd+' failed: '
+ err_msg )
b = gtk.Button(name)
b.show()
iter = self.liststore.append( (dbms, name, comment, user, passwd, host, status, icon) )
iter = self.liststore.append( (dbms, name, comment, user, passwd, host, "", default_icon, status, icon) )
self.info_box2(dia[0], "finished.", "", False, True)
self.listview.show()
scrolledwindow.show()
self.scrolledwindow.show()
self.vbox.show()
self.dia.set_focus(self.listview)
@ -249,13 +324,16 @@ class GuiDatabase:
def sortCols(self, col, n):
try:
log.info('sortcols n='+str(n))
if not col.get_sort_indicator() or col.get_sort_order() == gtk.SORT_ASCENDING:
col.set_sort_order(gtk.SORT_DESCENDING)
else:
col.set_sort_order(gtk.SORT_ASCENDING)
self.liststore.set_sort_column_id(n, col.get_sort_order())
#self.liststore.set_sort_func(n, self.sortnums, (n,grid))
log.info('sortcols len(listcols)='+str(len(self.listcols)))
for i in xrange(len(self.listcols)):
log.info('sortcols i='+str(i))
self.listcols[i].set_sort_indicator(False)
self.listcols[n].set_sort_indicator(True)
# use this listcols[col].set_sort_indicator(True)
@ -264,10 +342,69 @@ class GuiDatabase:
err = traceback.extract_tb(sys.exc_info()[2])
print "***sortCols error: " + str(sys.exc_info()[1])
print "\n".join( [e[0]+':'+str(e[1])+" "+e[2] for e in err] )
log.info('sortCols error: ' + str(sys.exc_info()) )
def refresh(self, widget, data):
self.loadDbs()
def info_box(self, dia, str1, str2, run, destroy):
if dia is None:
#if run:
btns = gtk.BUTTONS_NONE
btns = gtk.BUTTONS_OK
dia = gtk.MessageDialog( parent=self.main_window, flags=gtk.DIALOG_DESTROY_WITH_PARENT
, type=gtk.MESSAGE_INFO, buttons=(btns), message_format=str1 )
# try to remove buttons!
# (main message is in inverse video if no buttons, so try removing them after
# creating dialog)
# NO! message just goes back to inverse video :-( use info_box2 instead
for c in dia.vbox.get_children():
if isinstance(c, gtk.HButtonBox):
for d in c.get_children():
log.info('child: '+str(d)+' is a '+str(d.__class__))
if isinstance(d, gtk.Button):
log.info('removing button '+str(d))
c.remove(d)
if str2:
dia.format_secondary_text(str2)
else:
dia.set_markup(str1)
if str2:
dia.format_secondary_text(str2)
dia.show()
response = None
if run: response = dia.run()
if destroy: dia.destroy()
return (dia, response)
def info_box2(self, dia, str1, str2, run, destroy):
if dia is None:
# create dialog and add icon and label
btns = (gtk.BUTTONS_OK)
btns = None
# messagedialog puts text in inverse colors if no buttons are displayed??
#dia = gtk.MessageDialog( parent=self.main_window, flags=gtk.DIALOG_DESTROY_WITH_PARENT
# , type=gtk.MESSAGE_INFO, buttons=(btns), message_format=str1 )
dia = gtk.Dialog( parent=self.main_window, flags=gtk.DIALOG_DESTROY_WITH_PARENT
, title="" ) # , buttons=btns
vbox = dia.vbox
h = gtk.HBox(False, 2)
i = gtk.Image()
i.set_from_stock(gtk.STOCK_DIALOG_INFO, gtk.ICON_SIZE_DIALOG)
l = gtk.Label(str1)
h.pack_start(i, padding=5)
h.pack_start(l, padding=5)
vbox.pack_start(h)
else:
# add extra label
vbox = dia.vbox
vbox.pack_start( gtk.Label(str1) )
dia.show_all()
response = None
if run: response = dia.run()
if destroy: dia.destroy()
return (dia, response)
if __name__=="__main__":

View File

@ -26,6 +26,20 @@ import gobject
import Configuration
rewrite = { 'general' : 'General', 'supported_databases' : 'Databases'
, 'import' : 'Import', 'hud_ui' : 'HUD'
, 'supported_sites' : 'Sites', 'supported_games' : 'Games'
, 'popup_windows' : 'Popup Windows', 'pu' : 'Window'
, 'pu_name' : 'Popup Name', 'pu_stat' : 'Stat'
, 'pu_stat_name' : 'Stat Name'
, 'aux_windows' : 'Auxiliary Windows', 'aw stud_mucked' : 'stud_mucked'
, 'aw mucked' : 'mucked', 'hhcs' : 'Hand History Converters'
, 'gui_cash_stats' : 'Ring Player Stats', 'field_type' : 'Field Type'
, 'col_title' : 'Column Heading', 'xalignment' : 'Left/Right Align'
, 'disp_all' : 'Show in Summaries', 'disp_posn' : 'Show in Position Stats'
, 'col_name' : 'Stat Name', 'field_format' : 'Format'
}
class GuiPrefs:
def __init__(self, config, mainwin, dia, parentwin):
@ -78,6 +92,13 @@ class GuiPrefs:
self.tree_box.show()
self.dialog.show()
def rewriteText(self, s):
upd = False
if s in rewrite:
s = rewrite[s]
upd = True
return( (s,upd) )
def addTreeRows(self, parent, node):
if (node.nodeType == node.ELEMENT_NODE):
(setting, value) = (node.nodeName, None)
@ -94,11 +115,15 @@ class GuiPrefs:
iter = self.configStore.append( parent, [node, setting, value] )
if node.hasAttributes():
for i in xrange(node.attributes.length):
self.configStore.append( iter, [node, node.attributes.item(i).localName, node.attributes.item(i).value] )
if node.attributes.item(i).localName in ('site_name', 'game_name', 'stat_name', 'name', 'db_server', 'site'):
localName,updated = self.rewriteText( node.attributes.item(i).localName )
self.configStore.append( iter, [node, localName, node.attributes.item(i).value] )
if node.attributes.item(i).localName in ('site_name', 'game_name', 'stat_name', 'name', 'db_server', 'site', 'col_name'):
name = " " + node.attributes.item(i).value
if name != "":
self.configStore.set_value(iter, 1, setting+name)
label,updated = self.rewriteText(setting+name)
if name != "" or updated:
self.configStore.set_value(iter, 1, label)
if node.hasChildNodes():
for elem in node.childNodes:
self.addTreeRows(iter, elem)

View File

@ -31,7 +31,9 @@ import Filters
import Charset
import GuiPlayerStats
colalias,colshow,colheading,colxalign,colformat,coltype = 0,1,2,3,4,5
#colalias,colshowsumm,colshowposn,colheading,colxalign,colformat,coltype = 0,1,2,3,4,5,6
#new order in config file:
colalias,colheading,colshowsumm,colshowposn,colformat,coltype,colxalign = 0,1,2,3,4,5,6
ranks = {'x':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}
class GuiRingPlayerStats (GuiPlayerStats.GuiPlayerStats):
@ -88,34 +90,36 @@ class GuiRingPlayerStats (GuiPlayerStats.GuiPlayerStats):
# ToDo: store in config
# ToDo: create popup to adjust column config
# columns to display, keys match column name returned by sql, values in tuple are:
# is column displayed, column heading, xalignment, formatting, celltype
self.columns = [ ["game", True, "Game", 0.0, "%s", "str"]
, ["hand", False, "Hand", 0.0, "%s", "str"] # true not allowed for this line
, ["plposition", False, "Posn", 1.0, "%s", "str"] # true not allowed for this line (set in code)
, ["pname", False, "Name", 0.0, "%s", "str"] # true not allowed for this line (set in code)
, ["n", True, "Hds", 1.0, "%1.0f", "str"]
, ["avgseats", False, "Seats", 1.0, "%3.1f", "str"]
, ["vpip", True, "VPIP", 1.0, "%3.1f", "str"]
, ["pfr", True, "PFR", 1.0, "%3.1f", "str"]
, ["pf3", True, "PF3", 1.0, "%3.1f", "str"]
, ["aggfac", True, "AggFac", 1.0, "%2.2f", "str"]
, ["aggfrq", True, "AggFreq", 1.0, "%3.1f", "str"]
, ["conbet", True, "ContBet", 1.0, "%3.1f", "str"]
, ["steals", True, "Steals", 1.0, "%3.1f", "str"]
, ["saw_f", True, "Saw_F", 1.0, "%3.1f", "str"]
, ["sawsd", True, "SawSD", 1.0, "%3.1f", "str"]
, ["wtsdwsf", True, "WtSDwsF", 1.0, "%3.1f", "str"]
, ["wmsd", True, "W$SD", 1.0, "%3.1f", "str"]
, ["flafq", True, "FlAFq", 1.0, "%3.1f", "str"]
, ["tuafq", True, "TuAFq", 1.0, "%3.1f", "str"]
, ["rvafq", True, "RvAFq", 1.0, "%3.1f", "str"]
, ["pofafq", False, "PoFAFq", 1.0, "%3.1f", "str"]
, ["net", True, "Net($)", 1.0, "%6.2f", "cash"]
, ["bbper100", True, "bb/100", 1.0, "%4.2f", "str"]
, ["rake", True, "Rake($)", 1.0, "%6.2f", "cash"]
, ["bb100xr", True, "bbxr/100", 1.0, "%4.2f", "str"]
, ["variance", True, "Variance", 1.0, "%5.2f", "str"]
]
# is column displayed(summary then position), column heading, xalignment, formatting, celltype
self.columns = self.conf.get_gui_cash_stat_params()
# self.columns = [ ["game", True, True, "Game", 0.0, "%s", "str"]
# , ["hand", False, False, "Hand", 0.0, "%s", "str"] # initial setting ignored for this line (set in code)
# , ["plposition", False, False, "Posn", 1.0, "%s", "str"] # initial setting ignored for this line (set in code)
# , ["pname", False, False, "Name", 0.0, "%s", "str"] # initial setting ignored for this line (set in code)
# , ["n", True, True, "Hds", 1.0, "%1.0f", "str"]
# , ["avgseats", False, False, "Seats", 1.0, "%3.1f", "str"]
# , ["vpip", True, True, "VPIP", 1.0, "%3.1f", "str"]
# , ["pfr", True, True, "PFR", 1.0, "%3.1f", "str"]
# , ["pf3", True, True, "PF3", 1.0, "%3.1f", "str"]
# , ["aggfac", True, True, "AggFac", 1.0, "%2.2f", "str"]
# , ["aggfrq", True, True, "AggFreq", 1.0, "%3.1f", "str"]
# , ["conbet", True, True, "ContBet", 1.0, "%3.1f", "str"]
# , ["rfi", True, True, "RFI", 1.0, "%3.1f", "str"]
# , ["steals", True, True, "Steals", 1.0, "%3.1f", "str"]
# , ["saw_f", True, True, "Saw_F", 1.0, "%3.1f", "str"]
# , ["sawsd", True, True, "SawSD", 1.0, "%3.1f", "str"]
# , ["wtsdwsf", True, True, "WtSDwsF", 1.0, "%3.1f", "str"]
# , ["wmsd", True, True, "W$SD", 1.0, "%3.1f", "str"]
# , ["flafq", True, True, "FlAFq", 1.0, "%3.1f", "str"]
# , ["tuafq", True, True, "TuAFq", 1.0, "%3.1f", "str"]
# , ["rvafq", True, True, "RvAFq", 1.0, "%3.1f", "str"]
# , ["pofafq", False, False, "PoFAFq", 1.0, "%3.1f", "str"]
# , ["net", True, True, "Net($)", 1.0, "%6.2f", "cash"]
# , ["bbper100", True, True, "bb/100", 1.0, "%4.2f", "str"]
# , ["rake", True, True, "Rake($)", 1.0, "%6.2f", "cash"]
# , ["bb100xr", True, True, "bbxr/100", 1.0, "%4.2f", "str"]
# , ["variance", True, True, "Variance", 1.0, "%5.2f", "str"]
# ]
# Detail filters: This holds the data used in the popup window, extra values are
# added at the end of these lists during processing
@ -149,6 +153,8 @@ class GuiRingPlayerStats (GuiPlayerStats.GuiPlayerStats):
self.stats_vbox = gtk.VPaned()
self.stats_vbox.show()
self.stats_frame.add(self.stats_vbox)
self.top_pane_height = 0
self.height_inc = None
# self.fillStatsFrame(self.stats_vbox)
#self.main_hbox.pack_start(self.filters.get_vbox())
@ -158,7 +164,17 @@ class GuiRingPlayerStats (GuiPlayerStats.GuiPlayerStats):
self.main_hbox.show()
# make sure Hand column is not displayed
[x for x in self.columns if x[0] == 'hand'][0][1] = False
[x for x in self.columns if x[0] == 'hand'][0][colshowsumm] = False
[x for x in self.columns if x[0] == 'hand'][0][colshowposn] = False
# if rfi and steal both on for summaries, turn rfi off
if ( [x for x in self.columns if x[0] == 'rfi'][0][colshowsumm]
and [x for x in self.columns if x[0] == 'steals'][0][colshowsumm]):
[x for x in self.columns if x[0] == 'rfi'][0][colshowsumm] = False
# if rfi and steal both on for position breakdowns, turn steals off:
if ( [x for x in self.columns if x[0] == 'rfi'][0][colshowposn]
and [x for x in self.columns if x[0] == 'steals'][0][colshowposn]):
[x for x in self.columns if x[0] == 'steals'][0][colshowposn] = False
self.last_pos = -1
@ -168,18 +184,33 @@ class GuiRingPlayerStats (GuiPlayerStats.GuiPlayerStats):
#end def get_vbox
def refreshStats(self, widget, data):
self.last_pos = self.stats_vbox.get_position()
#self.last_pos = self.stats_vbox.get_position()
self.height_inc = None
#old_len = 0
#if self.liststore:
# old_len = len(self.liststore[0])
try: self.stats_vbox.destroy()
except AttributeError: pass
self.liststore = []
self.listcols = []
#self.stats_vbox = gtk.VBox(False, 0)
self.stats_vbox = gtk.VPaned()
self.stats_vbox.show()
self.stats_frame.add(self.stats_vbox)
self.fillStatsFrame(self.stats_vbox)
if self.last_pos > 0:
self.stats_vbox.set_position(self.last_pos)
# set height of top pane
# (tried 2 ways, guesstimate using ratio of old to new number of rows and sum of
# heights of parts)
new_len = 0
if self.liststore:
#new_len = len(self.liststore[0])
#print "setting to", self.top_pane_height + self.height_inc
self.stats_vbox.set_position(self.top_pane_height + self.height_inc)
#if self.last_pos > 0:
# if old_len > 0 and new_len > 0 and new_len <= 10:
# self.stats_vbox.set_position(self.last_pos * (new_len+1.9)/(old_len+1.9))
# else:
# self.stats_vbox.set_position(self.last_pos)
#end def refreshStats
def fillStatsFrame(self, vbox):
@ -225,8 +256,8 @@ class GuiRingPlayerStats (GuiPlayerStats.GuiPlayerStats):
# Scrolled window for summary table
swin = gtk.ScrolledWindow(hadjustment=None, vadjustment=None)
swin.set_policy(gtk.POLICY_AUTOMATIC, gtk.POLICY_AUTOMATIC)
swin.show()
vbox.pack1(swin)
vbox.pack1(swin) #, resize=True) don't use resize, self.height_inc relies on initial
# height of pane being correct for one row
# Display summary table at top of page
# 3rd parameter passes extra flags, currently includes:
@ -236,6 +267,7 @@ class GuiRingPlayerStats (GuiPlayerStats.GuiPlayerStats):
flags = [False, self.filters.getNumHands(), 0]
self.addGrid(swin, 'playerDetailedStats', flags, playerids
,sitenos, limits, type, seats, groups, dates, games)
swin.show()
if 'allplayers' in groups and groups['allplayers']:
# can't currently do this combination so skip detailed table
@ -249,19 +281,32 @@ class GuiRingPlayerStats (GuiPlayerStats.GuiPlayerStats):
vbox2.pack_start(heading, expand=False, padding=3)
# Scrolled window for detailed table (display by hand)
swin = gtk.ScrolledWindow(hadjustment=None, vadjustment=None)
swin.set_policy(gtk.POLICY_AUTOMATIC, gtk.POLICY_AUTOMATIC)
swin.show()
vbox2.pack_start(swin, expand=True, padding=3)
swin2 = gtk.ScrolledWindow(hadjustment=None, vadjustment=None)
swin2.set_policy(gtk.POLICY_AUTOMATIC, gtk.POLICY_AUTOMATIC)
swin2.show()
vbox2.pack_start(swin2, expand=True, padding=3)
vbox.pack2(vbox2)
vbox2.show()
# Detailed table
flags[0] = True
flags[2] = 1
self.addGrid(swin, 'playerDetailedStats', flags, playerids
self.addGrid(swin2, 'playerDetailedStats', flags, playerids
,sitenos, limits, type, seats, groups, dates, games)
if self.height_inc is None:
self.height_inc = 0
# need this to check whether scrollbar is visible:
while gtk.events_pending(): # see http://faq.pygtk.org/index.py?req=index for more hints (3.7)
gtk.main_iteration(False)
hs = swin.get_hscrollbar()
if hs is not None:
#print "hs vis", hs.get_property('visible'), hs.get_property('visible').__class__
if hs.get_property('visible'):
self.height_inc = hs.size_request()[1] + swin.style_get_property('scrollbar-spacing')
#print "hh set to", self.height_inc
self.stats_vbox.set_position(self.top_pane_height + self.height_inc)
self.db.rollback()
print "Stats page displayed in %4.2f seconds" % (time() - startTime)
#end def createStatsTable
@ -350,6 +395,8 @@ class GuiRingPlayerStats (GuiPlayerStats.GuiPlayerStats):
colnames = [desc[0].lower() for desc in self.cursor.description]
# pre-fetch some constant values:
colshow = colshowsumm
if groups['posn']: colshow = colshowposn
self.cols_to_show = [x for x in self.columns if x[colshow]]
hgametypeid_idx = colnames.index('hgametypeid')
@ -445,6 +492,11 @@ class GuiRingPlayerStats (GuiPlayerStats.GuiPlayerStats):
sqlrow += 1
row += 1
vbox.show_all()
view.show()
if len(self.liststore) == 1:
#print "view hieght is ", view.get_allocation().height, view.size_request(), view.get_visible_rect().height, view.get_vadjustment().get_value()
self.top_pane_height = view.size_request()[1]
#print "saved ", self.top_pane_height
#end def addGrid
def refineQuery(self, query, flags, playerids, sitenos, limits, type, seats, groups, dates, games):
@ -455,20 +507,22 @@ class GuiRingPlayerStats (GuiPlayerStats.GuiPlayerStats):
else:
holecards = flags[0]
numhands = flags[1]
colshow = colshowsumm
if groups['posn']: colshow = colshowposn
if 'allplayers' in groups and groups['allplayers']:
nametest = "(hp.playerId)"
if holecards or groups['posn']:
pname = "'all players'"
# set flag in self.columns to not show player name column
[x for x in self.columns if x[0] == 'pname'][0][1] = False
[x for x in self.columns if x[0] == 'pname'][0][colshow] = False
# can't do this yet (re-write doing more maths in python instead of sql?)
if numhands:
nametest = "(-1)"
else:
pname = "p.name"
# set flag in self.columns to show player name column
[x for x in self.columns if x[0] == 'pname'][0][1] = True
[x for x in self.columns if x[0] == 'pname'][0][colshow] = True
if numhands:
having = ' and count(1) > %d ' % (numhands,)
else:
@ -480,7 +534,7 @@ class GuiRingPlayerStats (GuiPlayerStats.GuiPlayerStats):
nametest = "1 = 2"
pname = "p.name"
# set flag in self.columns to not show player name column
[x for x in self.columns if x[0] == 'pname'][0][1] = False
[x for x in self.columns if x[0] == 'pname'][0][colshow] = False
query = query.replace("<player_test>", nametest)
query = query.replace("<playerName>", pname)
query = query.replace("<havingclause>", having)
@ -603,11 +657,11 @@ class GuiRingPlayerStats (GuiPlayerStats.GuiPlayerStats):
#query = query.replace("<position>", "case hp.position when '0' then 'Btn' else hp.position end")
query = query.replace("<position>", "hp.position")
# set flag in self.columns to show posn column
[x for x in self.columns if x[0] == 'plposition'][0][1] = True
[x for x in self.columns if x[0] == 'plposition'][0][colshow] = True
else:
query = query.replace("<position>", "gt.base")
# unset flag in self.columns to hide posn column
[x for x in self.columns if x[0] == 'plposition'][0][1] = False
[x for x in self.columns if x[0] == 'plposition'][0][colshow] = False
#print "query =\n", query
return(query)

View File

@ -1,290 +0,0 @@
#!/usr/bin/python
# -*- coding: utf-8 -*-
#Copyright 2008-2010 Steffen Schaumburg
#This program is free software: you can redistribute it and/or modify
#it under the terms of the GNU Affero General Public License as published by
#the Free Software Foundation, version 3 of the License.
#
#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 Affero General Public License
#along with this program. If not, see <http://www.gnu.org/licenses/>.
#In the "official" distribution you can find the license in agpl-3.0.txt.
import threading
import pygtk
pygtk.require('2.0')
import gtk
import os
import fpdb_import
from Exceptions import *
class GuiTableViewer (threading.Thread):
def hudDivide (self, a, b):
if b==0:
return "n/a"
else:
return str(int((a/float(b))*100))+"%"
#end def hudDivide
def browse_clicked(self, widget, data):
"""runs when user clicks browse on tv tab"""
#print "start of table_viewer.browser_clicked"
current_path=self.filename_tbuffer.get_text(self.filename_tbuffer.get_start_iter(), self.filename_tbuffer.get_end_iter())
dia_chooser = gtk.FileChooserDialog(title="Please choose the file for which you want to open the Table Viewer",
action=gtk.FILE_CHOOSER_ACTION_OPEN,
buttons=(gtk.STOCK_CANCEL,gtk.RESPONSE_CANCEL,gtk.STOCK_OPEN,gtk.RESPONSE_OK))
#dia_chooser.set_current_folder(pathname)
dia_chooser.set_filename(current_path)
#dia_chooser.set_select_multiple(select_multiple) #not in tv, but want this in bulk import
response = dia_chooser.run()
if response == gtk.RESPONSE_OK:
#print dia_chooser.get_filename(), 'selected'
self.filename_tbuffer.set_text(dia_chooser.get_filename())
elif response == gtk.RESPONSE_CANCEL:
print 'Closed, no files selected'
dia_chooser.destroy()
#end def table_viewer.browse_clicked
def prepare_data(self):
"""prepares the data for display by refresh_clicked, returns a 2D array"""
#print "start of prepare_data"
arr=[]
#first prepare the header row
if (self.category=="holdem" or self.category=="omahahi" or self.category=="omahahilo"):
tmp=("Name", "HDs", "VPIP", "PFR", "PF3B", "ST")
tmp+=("FS", "FB")
tmp+=("CB", )
tmp+=("2B", "3B")
tmp+=("AF", "FF", "AT", "FT", "AR", "FR")
tmp+=("WtSD", "W$wsF", "W$SD")
else:
raise FpdbError("reimplement stud")
arr.append(tmp)
#then the data rows
for player in range(len(self.player_names)):
tmp=[]
p_name = Charset.to_gui(self.player_names[player][0])
tmp.append(p_name)
seatCount=len(self.player_names)
if seatCount>=8:
minSeats,maxSeats=7,10
elif seatCount==7:
minSeats,maxSeats=6,10
elif seatCount==6 or seatCount==5:
minSeats,maxSeats=seatCount-1,seatCount+1
elif seatCount==4:
minSeats,maxSeats=4,5
elif seatCount==2 or seatCount==3:
minSeats,maxSeats=seatCount,seatCount
else:
FpdbError("invalid seatCount")
self.cursor.execute("SELECT * FROM HudCache WHERE gametypeId=%s AND playerId=%s AND activeSeats>=%s AND activeSeats<=%s", (self.gametype_id, self.player_ids[player][0], minSeats, maxSeats))
rows=self.cursor.fetchall()
row=[]
for field_no in range(len(rows[0])):
row.append(rows[0][field_no])
for row_no in range(len(rows)):
if row_no==0:
pass
else:
for field_no in range(len(rows[row_no])):
if field_no<=3:
pass
else:
#print "in prep data, row_no:",row_no,"field_no:",field_no
row[field_no]+=rows[row_no][field_no]
tmp.append(str(row[6]))#Hands
tmp.append(self.hudDivide(row[7],row[6])) #VPIP
tmp.append(self.hudDivide(row[8],row[6])) #PFR
tmp.append(self.hudDivide(row[10],row[9])+" ("+str(row[9])+")") #PF3B
tmp.append(self.hudDivide(row[31],row[30])+" ("+str(row[30])+")") #ST
tmp.append(self.hudDivide(row[35],row[34])+" ("+str(row[34])+")") #FS
tmp.append(self.hudDivide(row[33],row[32])+" ("+str(row[32])+")") #FB
tmp.append(self.hudDivide(row[37],row[36])+" ("+str(row[36])+")") #CB
tmp.append(self.hudDivide(row[39],row[38])+" ("+str(row[38])+")") #2B
tmp.append(self.hudDivide(row[41],row[40])+" ("+str(row[40])+")") #3B
tmp.append(self.hudDivide(row[16],row[11])+" ("+str(row[11])+")") #AF
tmp.append(self.hudDivide(row[24],row[20])+" ("+str(row[20])+")") #FF
tmp.append(self.hudDivide(row[17],row[12])+" ("+str(row[12])+")") #AT
tmp.append(self.hudDivide(row[25],row[21])+" ("+str(row[21])+")") #FT
tmp.append(self.hudDivide(row[18],row[13])+" ("+str(row[13])+")") #AR
tmp.append(self.hudDivide(row[26],row[22])+" ("+str(row[22])+")") #FR
tmp.append(self.hudDivide(row[15],row[11])) #WtSD
tmp.append(self.hudDivide(row[28],row[11])) #W$wSF
tmp.append(self.hudDivide(row[29],row[15])+" ("+str(row[15])+")") #W$@SD
arr.append(tmp)
return arr
#end def table_viewer.prepare_data
def refresh_clicked(self, widget, data):
"""runs when user clicks refresh"""
#print "start of table_viewer.refresh_clicked"
arr=self.prepare_data()
try: self.data_table.destroy()
except AttributeError: pass
self.data_table=gtk.Table(rows=len(arr), columns=len(arr[0]), homogeneous=False)
self.main_vbox.pack_start(self.data_table)
self.data_table.show()
for row in range(len(arr)):
for column in range (len(arr[row])):
eventBox=gtk.EventBox()
new_label=gtk.Label(arr[row][column])
if row%2==0: #
bg_col="white"
if column==0 or (column>=5 and column<=10):
bg_col="lightgrey"
else:
bg_col="lightgrey"
if column==0 or (column>=5 and column<=10):
bg_col="grey"
#style = eventBox.get_style()
#style.font.height=8
#eventBox.set_style(style)
eventBox.modify_bg(gtk.STATE_NORMAL, gtk.gdk.color_parse(bg_col))
eventBox.add(new_label)
self.data_table.attach(child=eventBox, left_attach=column, right_attach=column+1, top_attach=row, bottom_attach=row+1)
eventBox.show()
new_label.show()
#end def table_viewer.refresh_clicked
def read_names_clicked(self, widget, data):
"""runs when user clicks read names"""
#print "start of table_viewer.read_names_clicked"
self.db.reconnect()
self.cursor=self.db.get_cursor()
#self.hands_id=self.last_read_hand_id
self.cursor.execute("SELECT gametypeId FROM Hands WHERE id=%s", (self.hands_id, ))
self.gametype_id=self.cursor.fetchone()[0]
self.cursor.execute("SELECT category FROM Gametypes WHERE id=%s", (self.gametype_id, ))
self.category=self.cursor.fetchone()[0]
#print "self.gametype_id", self.gametype_id," category:", self.category, " self.hands_id:", self.hands_id
self.cursor.execute("""SELECT DISTINCT Players.id FROM HandsPlayers
INNER JOIN Players ON HandsPlayers.playerId=Players.id
WHERE handId=%s""", (self.hands_id, ))
self.player_ids=self.cursor.fetchall()
#print "self.player_ids:",self.player_ids
self.cursor.execute("""SELECT DISTINCT Players.name FROM HandsPlayers
INNER JOIN Players ON HandsPlayers.playerId=Players.id
WHERE handId=%s""", (self.hands_id, ))
self.player_names=self.cursor.fetchall()
#print "self.player_names:",self.player_names
#end def table_viewer.read_names_clicked
def import_clicked(self, widget, data):
"""runs when user clicks import"""
#print "start of table_viewer.import_clicked"
self.inputFile=self.filename_tbuffer.get_text(self.filename_tbuffer.get_start_iter(), self.filename_tbuffer.get_end_iter())
self.importer = fpdb_import.Importer(self, self.settings, self.config)
self.importer.setMinPrint(0)
self.importer.setQuiet(False)
self.importer.setFailOnError(False)
self.importer.setHandCount(0)
self.importer.addImportFile(self.inputFile)
self.importer.runImport()
self.hands_id=self.importer.handsId
#end def table_viewer.import_clicked
def all_clicked(self, widget, data):
"""runs when user clicks all"""
#print "start of table_viewer.all_clicked"
self.import_clicked(widget, data)
self.read_names_clicked(widget, data)
self.refresh_clicked(widget, data)
#end def table_viewer.all_clicked
def get_vbox(self):
"""returns the vbox of this thread"""
return self.main_vbox
#end def get_vbox
def __init__(self, db, settings, config=None, debug=True):
"""Constructor for table_viewer"""
self.debug=debug
#print "start of table_viewer constructor"
self.db = db
self.cursor = db.get_cursor()
self.settings = settings
self.config = config
self.main_vbox = gtk.VBox(False, 0)
self.main_vbox.show()
self.settings_hbox = gtk.HBox(False, 0)
self.main_vbox.pack_end(self.settings_hbox, False, True, 0)
self.settings_hbox.show()
self.filename_label = gtk.Label("Path of history file")
self.settings_hbox.pack_start(self.filename_label, False, False)
self.filename_label.show()
self.filename_tbuffer=gtk.TextBuffer()
self.filename_tbuffer.set_text(self.settings['hud-defaultPath'])
self.filename_tview=gtk.TextView(self.filename_tbuffer)
self.settings_hbox.pack_start(self.filename_tview, True, True, padding=5)
self.filename_tview.show()
self.browse_button=gtk.Button("Browse...")
self.browse_button.connect("clicked", self.browse_clicked, "Browse clicked")
self.settings_hbox.pack_start(self.browse_button, False, False)
self.browse_button.show()
self.button_hbox = gtk.HBox(False, 0)
self.main_vbox.pack_end(self.button_hbox, False, True, 0)
self.button_hbox.show()
#self.import_button = gtk.Button("Import")
#self.import_button.connect("clicked", self.import_clicked, "Import clicked")
#self.button_hbox.add(self.import_button)
#self.import_button.show()
#self.read_names_button = gtk.Button("Read Names")
#self.read_names_button.connect("clicked", self.read_names_clicked, "Read clicked")
#self.button_hbox.add(self.read_names_button)
#self.read_names_button.show()
#self.refresh_button = gtk.Button("Show/Refresh data")
#self.refresh_button.connect("clicked", self.refresh_clicked, "Refresh clicked")
#self.button_hbox.add(self.refresh_button)
#self.refresh_button.show()
self.all_button = gtk.Button("Import&Read&Refresh")
self.all_button.connect("clicked", self.all_clicked, "All clicked")
self.button_hbox.add(self.all_button)
self.all_button.show()
#end of table_viewer.__init__

View File

@ -556,22 +556,26 @@ Left-Drag to Move"
<popup_windows>
<pu pu_name="default">
<pu_stat pu_stat_name="playername"> </pu_stat>
<pu_stat pu_stat_name="totalprofit"> </pu_stat>
<pu_stat pu_stat_name="profit100"> </pu_stat>
<pu_stat pu_stat_name="n"> </pu_stat>
<pu_stat pu_stat_name="vpip"> </pu_stat>
<pu_stat pu_stat_name="pfr"> </pu_stat>
<pu_stat pu_stat_name="three_B_0"> </pu_stat>
<pu_stat pu_stat_name="steal"> </pu_stat>
<pu_stat pu_stat_name="f_steal"> </pu_stat>
<pu_stat pu_stat_name="f_BB_steal"> </pu_stat>
<pu_stat pu_stat_name="f_SB_steal"> </pu_stat>
<pu_stat pu_stat_name="wmsd"> </pu_stat>
<pu_stat pu_stat_name="wtsd"> </pu_stat>
<pu_stat pu_stat_name="WMsF"> </pu_stat>
<pu_stat pu_stat_name="agg_fact"> </pu_stat>
<pu_stat pu_stat_name="a_freq1"> </pu_stat>
<pu_stat pu_stat_name="a_freq2"> </pu_stat>
<pu_stat pu_stat_name="a_freq3"> </pu_stat>
<pu_stat pu_stat_name="a_freq4"> </pu_stat>
<pu_stat pu_stat_name="agg_freq"> </pu_stat>
<pu_stat pu_stat_name="agg_fact"> </pu_stat>
<pu_stat pu_stat_name="cbet"> </pu_stat>
<pu_stat pu_stat_name="cb1"> </pu_stat>
<pu_stat pu_stat_name="cb2"> </pu_stat>

View File

@ -79,12 +79,13 @@ class Hand(object):
self.fee = None # the Database code is looking for this one .. ?
self.level = None
self.mixed = None
self.speed = "Normal"
self.isRebuy = False
self.isAddOn = False
self.isKO = False
self.isMatrix = False
self.isShootout = False
self.speed = None
self.isRebuy = None
self.isAddOn = None
self.isKO = None
self.koBounty = None
self.isMatrix = None
self.isShootout = None
self.added = None
self.addedCurrency = None
self.tourneyComment = None
@ -168,6 +169,7 @@ class Hand(object):
("IS REBUY", self.isRebuy),
("IS ADDON", self.isAddOn),
("IS KO", self.isKO),
("KO BOUNTY", self.koBounty),
("IS MATRIX", self.isMatrix),
("IS SHOOTOUT", self.isShootout),
("TOURNEY COMMENT", self.tourneyComment),

View File

@ -26,8 +26,11 @@ import codecs
from decimal import Decimal
import operator
from xml.dom.minidom import Node
import time
import datetime
from pytz import timezone
import pytz
import logging
# logging has been set up in fpdb.py or HUD_main.py, use their settings:
@ -430,9 +433,9 @@ or None if we fail to get the info """
try:
in_fh = codecs.open(self.in_path, 'r', kodec)
whole_file = in_fh.read()
in_fh.close()
self.obs = whole_file[self.index:]
self.index = len(whole_file)
in_fh.close()
break
except:
pass
@ -497,19 +500,68 @@ or None if we fail to get the info """
@staticmethod
def changeTimezone(time, givenTimezone, wantedTimezone):
if givenTimezone=="ET" and wantedTimezone=="UTC":
# approximate rules for ET daylight savings time:
if ( time.month == 12 # all of Dec
or (time.month == 11 and time.day > 4) # and most of November
or time.month < 3 # and all of Jan/Feb
or (time.month == 3 and time.day < 11) ): # and 1st 10 days of March
offset = datetime.timedelta(hours=5) # are EST: assume 5 hour offset (ET without daylight saving)
else:
offset = datetime.timedelta(hours=4) # rest is EDT: assume 4 hour offset (ET with daylight saving)
# adjust time into UTC:
time = time + offset
#print " tz = %s start = %s" % (tz, str(hand.starttime))
return time
#print "raw time:",time, "given TZ:", givenTimezone
if wantedTimezone=="UTC":
wantedTimezone = pytz.utc
else:
raise Error #TODO raise appropriate error
if givenTimezone=="ET":
givenTimezone = timezone('US/Eastern')
elif givenTimezone=="CET":
givenTimezone = timezone('Europe/Berlin')
#Note: Daylight Saving Time is standardised across the EU so this should be fine
elif givenTimezone == 'HST': # Hawaiian Standard Time
pass
elif givenTimezone == 'AKT': # Alaska Time
pass
elif givenTimezone == 'PT': # Pacific Time
pass
elif givenTimezone == 'MT': # Mountain Time
pass
elif givenTimezone == 'CT': # Central Time
pass
elif givenTimezone == 'AT': # Atlantic Time
pass
elif givenTimezone == 'NT': # Newfoundland Time
pass
elif givenTimezone == 'ART': # Argentinian Time
pass
elif givenTimezone == 'BRT': # Brasilia Time
pass
elif givenTimezone == 'AKT': # Alaska Time
pass
elif givenTimezone == 'WET': # Western European Time
pass
elif givenTimezone == 'EET': # Eastern European Time
pass
elif givenTimezone == 'MSK': # Moscow Standard Time
pass
elif givenTimezone == 'IST': # India Standard Time
pass
elif givenTimezone == 'CCT': # China Coast Time
pass
elif givenTimezone == 'JST': # Japan Standard Time
pass
elif givenTimezone == 'AWST': # Australian Western Standard Time
givenTimezone = timezone('Australia/West')
elif givenTimezone == 'ACST': # Australian Central Standard Time
givenTimezone = timezone('Australia/Darwin')
elif givenTimezone == 'AEST': # Australian Eastern Standard Time
# Each State on the East Coast has different DSTs.
# Melbournce is out because I don't like AFL, Queensland doesn't have DST
# ACT is full of politicians and Tasmania will never notice.
# Using Sydney.
givenTimezone = timezone('Australia/Sydney')
elif givenTimezone == 'NZT': # New Zealand Time
pass
else:
raise Error #TODO raise appropriate error
localisedTime = givenTimezone.localize(time)
utcTime = localisedTime.astimezone(wantedTimezone)
#print "utcTime:",utcTime
return utcTime
#end @staticmethod def changeTimezone
@staticmethod

View File

@ -469,6 +469,9 @@ class Hud:
# While we're at it, fix the positions of mucked cards too
for aux in self.aux_windows:
aux.update_card_positions()
self.reposition_windows()
# call reposition_windows, which apparently moves even hidden windows, where this function does not, even though they do the same thing, afaict
return True

View File

@ -72,7 +72,7 @@ class PokerStars(HandHistoryConverter):
(Tournament\s\# # open paren of tournament info
(?P<TOURNO>\d+),\s
# here's how I plan to use LS
(?P<BUYIN>([%(LS)s\+\d\.]+\s?(?P<TOUR_ISO>%(LEGAL_ISO)s)?)|Freeroll)\s+)?
(?P<BUYIN>(?P<BIAMT>[%(LS)s\d\.]+)?\+?(?P<BIRAKE>[%(LS)s\d\.]+)?\+?(?P<BOUNTY>[%(LS)s\d\.]+)?\s?(?P<TOUR_ISO>%(LEGAL_ISO)s)?|Freeroll)\s+)?
# close paren of tournament info
(?P<MIXED>HORSE|8\-Game|HOSE)?\s?\(?
(?P<GAME>Hold\'em|Razz|RAZZ|7\sCard\sStud|7\sCard\sStud\sHi/Lo|Omaha|Omaha\sHi/Lo|Badugi|Triple\sDraw\s2\-7\sLowball|5\sCard\sDraw)\s
@ -206,24 +206,20 @@ class PokerStars(HandHistoryConverter):
m = self.re_HandInfo.search(hand.handText,re.DOTALL)
if m:
info.update(m.groupdict())
# hand.maxseats = int(m2.group(1))
else:
pass # throw an exception here, eh?
m = self.re_GameInfo.search(hand.handText)
if m:
info.update(m.groupdict())
# m = self.re_Button.search(hand.handText)
# if m: info.update(m.groupdict())
# TODO : I rather like the idea of just having this dict as hand.info
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/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])
# m2 = re.search("(?P<Y>[0-9]{4})\/(?P<M>[0-9]{2})\/(?P<D>[0-9]{2})[\- ]+(?P<H>[0-9]+):(?P<MIN>[0-9]+):(?P<S>[0-9]+)", info[key])
datetimestr = "2000/01/01 00:00:00" # default used if time not found (stops import crashing, but startTime will be wrong)
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??
@ -236,12 +232,15 @@ class PokerStars(HandHistoryConverter):
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:
#print "info[key]:",info[key]
if info[key].find("$")!=-1:
hand.buyinCurrency="USD"
elif info[key].find(u"")!=-1:
@ -249,15 +248,29 @@ class PokerStars(HandHistoryConverter):
elif info[key].find("FPP")!=-1:
hand.buyinCurrency="PSFP"
else:
raise FpdbParseError("failed to detect currency") #FIXME: handle other currencies, FPP, play money
#FIXME: handle other currencies, FPP, play money
raise FpdbParseError("failed to detect currency")
info['BIAMT'] = info['BIAMT'].strip(u'$€FPP')
if hand.buyinCurrency=="USD" or hand.buyinCurrency=="EUR":
info[key]=info[key][:-4]
middle=info[key].find("+")
hand.buyin = int(100*Decimal(info[key][1:middle]))
hand.fee = int(100*Decimal(info[key][middle+2:]))
elif hand.buyinCurrency=="PSFP":
hand.buyin = int(Decimal(info[key][0:-3]))
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]

View File

@ -146,8 +146,8 @@ class Sql:
id BIGSERIAL, PRIMARY KEY (id),
tourneysPlayerId INT NOT NULL, FOREIGN KEY (tourneysPlayerId) REFERENCES TourneysPlayers(id),
playerId INT NOT NULL, FOREIGN KEY (playerId) REFERENCES Players(id),
buyInPercentage FLOAT UNSIGNED NOT NULL,
payOffPercentage FLOAT UNSIGNED NOT NULL)"""
buyInPercentage FLOAT NOT NULL,
payOffPercentage FLOAT NOT NULL)"""
elif db_server == 'sqlite':
self.query['createBackingsTable'] = """CREATE TABLE Backings (
id INTEGER PRIMARY KEY,
@ -392,9 +392,9 @@ class Sql:
self.query['createTourneyTypesTable'] = """CREATE TABLE TourneyTypes (
id SMALLINT UNSIGNED AUTO_INCREMENT NOT NULL, PRIMARY KEY (id),
siteId SMALLINT UNSIGNED NOT NULL, FOREIGN KEY (siteId) REFERENCES Sites(id),
currency varchar(4) NOT NULL,
buyIn INT NOT NULL,
fee INT NOT NULL,
currency varchar(4),
buyIn INT,
fee INT,
category varchar(9) NOT NULL,
limitType char(2) NOT NULL,
buyInChips INT,
@ -423,9 +423,9 @@ class Sql:
self.query['createTourneyTypesTable'] = """CREATE TABLE TourneyTypes (
id SERIAL, PRIMARY KEY (id),
siteId INT NOT NULL, FOREIGN KEY (siteId) REFERENCES Sites(id),
currency varchar(4) NOT NULL,
buyin INT NOT NULL,
fee INT NOT NULL,
currency varchar(4),
buyin INT,
fee INT,
category varchar(9),
limitType char(2),
buyInChips INT,
@ -453,9 +453,9 @@ class Sql:
self.query['createTourneyTypesTable'] = """CREATE TABLE TourneyTypes (
id INTEGER PRIMARY KEY,
siteId INT NOT NULL,
currency VARCHAR(4) NOT NULL,
buyin INT NOT NULL,
fee INT NOT NULL,
currency VARCHAR(4),
buyin INT,
fee INT,
category TEXT,
limitType TEXT,
buyInChips INT,
@ -560,7 +560,6 @@ class Sql:
comment text,
commentTs DATETIME,
tourneysPlayersId BIGINT UNSIGNED, FOREIGN KEY (tourneysPlayersId) REFERENCES TourneysPlayers(id),
tourneyTypeId SMALLINT UNSIGNED, FOREIGN KEY (tourneyTypeId) REFERENCES TourneyTypes(id),
wonWhenSeenStreet1 FLOAT,
wonWhenSeenStreet2 FLOAT,
@ -599,8 +598,8 @@ class Sql:
foldToOtherRaisedStreet3 BOOLEAN,
foldToOtherRaisedStreet4 BOOLEAN,
stealAttemptChance BOOLEAN,
stealAttempted BOOLEAN,
raiseFirstInChance BOOLEAN,
raisedFirstIn BOOLEAN,
foldBbToStealChance BOOLEAN,
foldedBbToSteal BOOLEAN,
foldSbToStealChance BOOLEAN,
@ -677,7 +676,6 @@ class Sql:
comment text,
commentTs timestamp without time zone,
tourneysPlayersId BIGINT, FOREIGN KEY (tourneysPlayersId) REFERENCES TourneysPlayers(id),
tourneyTypeId INT, FOREIGN KEY (tourneyTypeId) REFERENCES TourneyTypes(id),
wonWhenSeenStreet1 FLOAT,
wonWhenSeenStreet2 FLOAT,
@ -716,8 +714,8 @@ class Sql:
foldToOtherRaisedStreet3 BOOLEAN,
foldToOtherRaisedStreet4 BOOLEAN,
stealAttemptChance BOOLEAN,
stealAttempted BOOLEAN,
raiseFirstInChance BOOLEAN,
raisedFirstIn BOOLEAN,
foldBbToStealChance BOOLEAN,
foldedBbToSteal BOOLEAN,
foldSbToStealChance BOOLEAN,
@ -793,7 +791,6 @@ class Sql:
comment TEXT,
commentTs REAL,
tourneysPlayersId INT,
tourneyTypeId INT,
wonWhenSeenStreet1 REAL,
wonWhenSeenStreet2 REAL,
@ -832,8 +829,8 @@ class Sql:
foldToOtherRaisedStreet3 INT,
foldToOtherRaisedStreet4 INT,
stealAttemptChance INT,
stealAttempted INT,
raiseFirstInChance INT,
raisedFirstIn INT,
foldBbToStealChance INT,
foldedBbToSteal INT,
foldSbToStealChance INT,
@ -1028,8 +1025,8 @@ class Sql:
foldToOtherRaisedStreet3 INT,
foldToOtherRaisedStreet4 INT,
stealAttemptChance INT,
stealAttempted INT,
raiseFirstInChance INT,
raisedFirstIn INT,
foldBbToStealChance INT,
foldedBbToSteal INT,
foldSbToStealChance INT,
@ -1128,8 +1125,8 @@ class Sql:
foldToOtherRaisedStreet3 INT,
foldToOtherRaisedStreet4 INT,
stealAttemptChance INT,
stealAttempted INT,
raiseFirstInChance INT,
raisedFirstIn INT,
foldBbToStealChance INT,
foldedBbToSteal INT,
foldSbToStealChance INT,
@ -1227,8 +1224,8 @@ class Sql:
foldToOtherRaisedStreet3 INT,
foldToOtherRaisedStreet4 INT,
stealAttemptChance INT,
stealAttempted INT,
raiseFirstInChance INT,
raisedFirstIn INT,
foldBbToStealChance INT,
foldedBbToSteal INT,
foldSbToStealChance INT,
@ -1367,8 +1364,18 @@ class Sql:
sum(hc.foldToOtherRaisedStreet4) AS f_freq_4,
sum(hc.wonWhenSeenStreet1) AS w_w_s_1,
sum(hc.wonAtSD) AS wmsd,
sum(hc.stealAttemptChance) AS steal_opp,
sum(hc.stealAttempted) AS steal,
sum(case hc.position
when 'S' then hc.raiseFirstInChance
when '0' then hc.raiseFirstInChance
when '1' then hc.raiseFirstInChance
else 0
) AS steal_opp,
sum(case hc.position
when 'S' then hc.raisedFirstIn
when '0' then hc.raisedFirstIn
when '1' then hc.raisedFirstIn
else 0
) AS steal,
sum(hc.foldSbToStealChance) AS SBstolen,
sum(hc.foldedSbToSteal) AS SBnotDef,
sum(hc.foldBbToStealChance) AS BBstolen,
@ -1466,8 +1473,8 @@ class Sql:
sum(hc.foldToOtherRaisedStreet4) AS f_freq_4,
sum(hc.wonWhenSeenStreet1) AS w_w_s_1,
sum(hc.wonAtSD) AS wmsd,
sum(hc.stealAttemptChance) AS steal_opp,
sum(hc.stealAttempted) AS steal,
sum(hc.raiseFirstInChance) AS steal_opp,
sum(hc.raisedFirstIn) AS steal,
sum(hc.foldSbToStealChance) AS SBstolen,
sum(hc.foldedSbToSteal) AS SBnotDef,
sum(hc.foldBbToStealChance) AS BBstolen,
@ -1592,8 +1599,8 @@ class Sql:
cast(hp2.foldToOtherRaisedStreet4 as <signed>integer) AS f_freq_4,
cast(hp2.wonWhenSeenStreet1 as <signed>integer) AS w_w_s_1,
cast(hp2.wonAtSD as <signed>integer) AS wmsd,
cast(hp2.stealAttemptChance as <signed>integer) AS steal_opp,
cast(hp2.stealAttempted as <signed>integer) AS steal,
cast(hp2.raiseFirstInChance as <signed>integer) AS steal_opp,
cast(hp2.raisedFirstIn as <signed>integer) AS steal,
cast(hp2.foldSbToStealChance as <signed>integer) AS SBstolen,
cast(hp2.foldedSbToSteal as <signed>integer) AS SBnotDef,
cast(hp2.foldBbToStealChance as <signed>integer) AS BBstolen,
@ -1694,8 +1701,8 @@ class Sql:
cast(hp2.foldToOtherRaisedStreet4 as <signed>integer) AS f_freq_4,
cast(hp2.wonWhenSeenStreet1 as <signed>integer) AS w_w_s_1,
cast(hp2.wonAtSD as <signed>integer) AS wmsd,
cast(hp2.stealAttemptChance as <signed>integer) AS steal_opp,
cast(hp2.stealAttempted as <signed>integer) AS steal,
cast(hp2.raiseFirstInChance as <signed>integer) AS steal_opp,
cast(hp2.raisedFirstIn as <signed>integer) AS steal,
cast(hp2.foldSbToStealChance as <signed>integer) AS SBstolen,
cast(hp2.foldedSbToSteal as <signed>integer) AS SBnotDef,
cast(hp2.foldBbToStealChance as <signed>integer) AS BBstolen,
@ -1797,8 +1804,8 @@ class Sql:
cast(hp2.foldToOtherRaisedStreet4 as <signed>integer) AS f_freq_4,
cast(hp2.wonWhenSeenStreet1 as <signed>integer) AS w_w_s_1,
cast(hp2.wonAtSD as <signed>integer) AS wmsd,
cast(hp2.stealAttemptChance as <signed>integer) AS steal_opp,
cast(hp2.stealAttempted as <signed>integer) AS steal,
cast(hp2.raiseFirstInChance as <signed>integer) AS steal_opp,
cast(hp2.raisedFirstIn as <signed>integer) AS steal,
cast(hp2.foldSbToStealChance as <signed>integer) AS SBstolen,
cast(hp2.foldedSbToSteal as <signed>integer) AS SBnotDef,
cast(hp2.foldBbToStealChance as <signed>integer) AS BBstolen,
@ -2029,11 +2036,35 @@ class Sql:
,case when sum(cast(hp.street0_3Bchance as <signed>integer)) = 0 then -999
else 100.0*sum(cast(hp.street0_3Bdone as <signed>integer))/sum(cast(hp.street0_3Bchance as <signed>integer))
end AS pf3
,case when sum(cast(hp.stealattemptchance as <signed>integer)) = 0 then -999
else 100.0*sum(cast(hp.stealattempted as <signed>integer))/sum(cast(hp.stealattemptchance as <signed>integer))
,case when sum(cast(hp.raiseFirstInChance as <signed>integer)) = 0 then -999
else 100.0 * sum(cast(hp.raisedFirstIn as <signed>integer)) /
sum(cast(hp.raiseFirstInChance as <signed>integer))
end AS rfi
,case when sum(case hp.position
when 'S' then cast(hp.raiseFirstInChance as <signed>integer)
when '0' then cast(hp.raiseFirstInChance as <signed>integer)
when '1' then cast(hp.raiseFirstInChance as <signed>integer)
else 0
end
) = 0 then -999
else 100.0 *
sum(case hp.position
when 'S' then cast(hp.raisedFirstIn as <signed>integer)
when '0' then cast(hp.raisedFirstIn as <signed>integer)
when '1' then cast(hp.raisedFirstIn as <signed>integer)
else 0
end
) /
sum(case hp.position
when 'S' then cast(hp.raiseFirstInChance as <signed>integer)
when '0' then cast(hp.raiseFirstInChance as <signed>integer)
when '1' then cast(hp.raiseFirstInChance as <signed>integer)
else 0
end
)
end AS steals
,100.0*sum(cast(hp.street1Seen as <signed>integer))/count(1) AS saw_f
,100.0*sum(cast(hp.sawShowdown as <signed>integer))/count(1) AS sawsd
,100.0*sum(cast(hp.street1Seen as <signed>integer))/count(1) AS saw_f
,100.0*sum(cast(hp.sawShowdown as <signed>integer))/count(1) AS sawsd
,case when sum(cast(hp.street1Seen as <signed>integer)) = 0 then -999
else 100.0*sum(cast(hp.sawShowdown as <signed>integer))/sum(cast(hp.street1Seen as <signed>integer))
end AS wtsdwsf
@ -2126,8 +2157,32 @@ class Sql:
,case when sum(cast(hp.street0_3Bchance as <signed>integer)) = 0 then -999
else 100.0*sum(cast(hp.street0_3Bdone as <signed>integer))/sum(cast(hp.street0_3Bchance as <signed>integer))
end AS pf3
,case when sum(cast(hp.stealattemptchance as <signed>integer)) = 0 then -999
else 100.0*sum(cast(hp.stealattempted as <signed>integer))/sum(cast(hp.stealattemptchance as <signed>integer))
,case when sum(cast(hp.raiseFirstInChance as <signed>integer)) = 0 then -999
else 100.0 * sum(cast(hp.raisedFirstIn as <signed>integer)) /
sum(cast(hp.raiseFirstInChance as <signed>integer))
end AS rfi
,case when sum(case hp.position
when 'S' then cast(hp.raiseFirstInChance as <signed>integer)
when '0' then cast(hp.raiseFirstInChance as <signed>integer)
when '1' then cast(hp.raiseFirstInChance as <signed>integer)
else 0
end
) = 0 then -999
else 100.0 *
sum(case hp.position
when 'S' then cast(hp.raisedFirstIn as <signed>integer)
when '0' then cast(hp.raisedFirstIn as <signed>integer)
when '1' then cast(hp.raisedFirstIn as <signed>integer)
else 0
end
) /
sum(case hp.position
when 'S' then cast(hp.raiseFirstInChance as <signed>integer)
when '0' then cast(hp.raiseFirstInChance as <signed>integer)
when '1' then cast(hp.raiseFirstInChance as <signed>integer)
else 0
end
)
end AS steals
,100.0*sum(cast(hp.street1Seen as <signed>integer))/count(1) AS saw_f
,100.0*sum(cast(hp.sawShowdown as <signed>integer))/count(1) AS sawsd
@ -2224,8 +2279,32 @@ class Sql:
,case when sum(cast(hp.street0_3Bchance as <signed>integer)) = 0 then -999
else 100.0*sum(cast(hp.street0_3Bdone as <signed>integer))/sum(cast(hp.street0_3Bchance as <signed>integer))
end AS pf3
,case when sum(cast(hp.stealattemptchance as <signed>integer)) = 0 then -999
else 100.0*sum(cast(hp.stealattempted as <signed>integer))/sum(cast(hp.stealattemptchance as <signed>integer))
,case when sum(cast(hp.raiseFirstInChance as <signed>integer)) = 0 then -999
else 100.0 * sum(cast(hp.raisedFirstIn as <signed>integer)) /
sum(cast(hp.raiseFirstInChance as <signed>integer))
end AS rfi
,case when sum(case hp.position
when 'S' then cast(hp.raiseFirstInChance as <signed>integer)
when '0' then cast(hp.raiseFirstInChance as <signed>integer)
when '1' then cast(hp.raiseFirstInChance as <signed>integer)
else 0
end
) = 0 then -999
else 100.0 *
sum(case hp.position
when 'S' then cast(hp.raisedFirstIn as <signed>integer)
when '0' then cast(hp.raisedFirstIn as <signed>integer)
when '1' then cast(hp.raisedFirstIn as <signed>integer)
else 0
end
) /
sum(case hp.position
when 'S' then cast(hp.raiseFirstInChance as <signed>integer)
when '0' then cast(hp.raiseFirstInChance as <signed>integer)
when '1' then cast(hp.raiseFirstInChance as <signed>integer)
else 0
end
)
end AS steals
,100.0*sum(cast(hp.street1Seen as <signed>integer))/count(1) AS saw_f
,100.0*sum(cast(hp.sawShowdown as <signed>integer))/count(1) AS sawsd
@ -2383,8 +2462,8 @@ class Sql:
,case when sum(street0_3Bchance) = 0 then '0'
else format(100.0*sum(street0_3Bdone)/sum(street0_3Bchance),1)
end AS pf3
,case when sum(stealattemptchance) = 0 then '-'
else format(100.0*sum(stealattempted)/sum(stealattemptchance),1)
,case when sum(raiseFirstInChance) = 0 then '-'
else format(100.0*sum(raisedFirstIn)/sum(raiseFirstInChance),1)
end AS steals
,format(100.0*sum(street1Seen)/sum(HDs),1) AS saw_f
,format(100.0*sum(sawShowdown)/sum(HDs),1) AS sawsd
@ -2447,6 +2526,8 @@ class Sql:
) hprof2
on hprof2.gtId = stats.gtId
order by stats.category, stats.limittype, stats.bigBlindDesc desc <orderbyseats>"""
#elif db_server == 'sqlite': #TODO
# self.query['playerStats'] = """ """
else: # assume postgres
self.query['playerStats'] = """
SELECT upper(stats.limitType) || ' '
@ -2486,8 +2567,8 @@ class Sql:
,case when sum(street0_3Bchance) = 0 then '0'
else to_char(100.0*sum(street0_3Bdone)/sum(street0_3Bchance),'90D0')
end AS pf3
,case when sum(stealattemptchance) = 0 then '-'
else to_char(100.0*sum(stealattempted)/sum(stealattemptchance),'90D0')
,case when sum(raiseFirstInChance) = 0 then '-'
else to_char(100.0*sum(raisedFirstIn)/sum(raiseFirstInChance),'90D0')
end AS steals
,to_char(100.0*sum(street1Seen)/sum(HDs),'90D0') AS saw_f
,to_char(100.0*sum(sawShowdown)/sum(HDs),'90D0') AS sawsd
@ -2550,8 +2631,6 @@ class Sql:
) hprof2
on hprof2.gtId = stats.gtId
order by stats.base, stats.limittype, stats.bigBlindDesc desc <orderbyseats>"""
#elif db_server == 'sqlite':
# self.query['playerStats'] = """ """
if db_server == 'mysql':
self.query['playerStatsByPosition'] = """
@ -2611,8 +2690,8 @@ class Sql:
,case when sum(street0_3Bchance) = 0 then '0'
else format(100.0*sum(street0_3Bdone)/sum(street0_3Bchance),1)
end AS pf3
,case when sum(stealattemptchance) = 0 then '-'
else format(100.0*sum(stealattempted)/sum(stealattemptchance),1)
,case when sum(raiseFirstInChance) = 0 then '-'
else format(100.0*sum(raisedFirstIn)/sum(raiseFirstInChance),1)
end AS steals
,format(100.0*sum(street1Seen)/sum(HDs),1) AS saw_f
,format(100.0*sum(sawShowdown)/sum(HDs),1) AS sawsd
@ -2745,8 +2824,8 @@ class Sql:
,case when sum(street0_3Bchance) = 0 then '0'
else to_char(100.0*sum(street0_3Bdone)/sum(street0_3Bchance),'90D0')
end AS pf3
,case when sum(stealattemptchance) = 0 then '-'
else to_char(100.0*sum(stealattempted)/sum(stealattemptchance),'90D0')
,case when sum(raiseFirstInChance) = 0 then '-'
else to_char(100.0*sum(raisedFirstIn)/sum(raiseFirstInChance),'90D0')
end AS steals
,to_char(round(100.0*sum(street1Seen)/sum(HDs)),'90D0') AS saw_f
,to_char(round(100.0*sum(sawShowdown)/sum(HDs)),'90D0') AS sawsd
@ -2925,8 +3004,8 @@ class Sql:
,foldToOtherRaisedStreet2
,foldToOtherRaisedStreet3
,foldToOtherRaisedStreet4
,stealAttemptChance
,stealAttempted
,raiseFirstInChance
,raisedFirstIn
,foldBbToStealChance
,foldedBbToSteal
,foldSbToStealChance
@ -2989,7 +3068,7 @@ class Sql:
when hp.position = '9' then 'E'
else 'E'
end AS hc_position
,hp.tourneyTypeId
,t.tourneyTypeId
,date_format(h.startTime, 'd%y%m%d')
,count(1)
,sum(wonWhenSeenStreet1)
@ -3015,8 +3094,8 @@ class Sql:
,sum(foldToOtherRaisedStreet2)
,sum(foldToOtherRaisedStreet3)
,sum(foldToOtherRaisedStreet4)
,sum(stealAttemptChance)
,sum(stealAttempted)
,sum(raiseFirstInChance)
,sum(raisedFirstIn)
,sum(foldBbToStealChance)
,sum(foldedBbToSteal)
,sum(foldSbToStealChance)
@ -3063,12 +3142,14 @@ class Sql:
,sum(hp.street4Raises)
FROM HandsPlayers hp
INNER JOIN Hands h ON (h.id = hp.handId)
INNER JOIN TourneysPlayers tp ON (tp.id = hp.tourneysPlayersId)
INNER JOIN Tourneys t ON (t.id = tp.tourneyId)
<where_clause>
GROUP BY h.gametypeId
,hp.playerId
,h.seats
,hc_position
,hp.tourneyTypeId
,t.tourneyTypeId
,date_format(h.startTime, 'd%y%m%d')
"""
elif db_server == 'postgresql':
@ -3104,8 +3185,8 @@ class Sql:
,foldToOtherRaisedStreet2
,foldToOtherRaisedStreet3
,foldToOtherRaisedStreet4
,stealAttemptChance
,stealAttempted
,raiseFirstInChance
,raisedFirstIn
,foldBbToStealChance
,foldedBbToSteal
,foldSbToStealChance
@ -3168,7 +3249,7 @@ class Sql:
when hp.position = '9' then 'E'
else 'E'
end AS hc_position
,hp.tourneyTypeId
,t.tourneyTypeId
,'d' || to_char(h.startTime, 'YYMMDD')
,count(1)
,sum(wonWhenSeenStreet1)
@ -3194,8 +3275,8 @@ class Sql:
,sum(CAST(foldToOtherRaisedStreet2 as integer))
,sum(CAST(foldToOtherRaisedStreet3 as integer))
,sum(CAST(foldToOtherRaisedStreet4 as integer))
,sum(CAST(stealAttemptChance as integer))
,sum(CAST(stealAttempted as integer))
,sum(CAST(raiseFirstInChance as integer))
,sum(CAST(raisedFirstIn as integer))
,sum(CAST(foldBbToStealChance as integer))
,sum(CAST(foldedBbToSteal as integer))
,sum(CAST(foldSbToStealChance as integer))
@ -3242,12 +3323,14 @@ class Sql:
,sum(CAST(hp.street4Raises as integer))
FROM HandsPlayers hp
INNER JOIN Hands h ON (h.id = hp.handId)
INNER JOIN TourneysPlayers tp ON (tp.id = hp.tourneysPlayersId)
INNER JOIN Tourneys t ON (t.id = tp.tourneyId)
<where_clause>
GROUP BY h.gametypeId
,hp.playerId
,h.seats
,hc_position
,hp.tourneyTypeId
,t.tourneyTypeId
,to_char(h.startTime, 'YYMMDD')
"""
else: # assume sqlite
@ -3283,8 +3366,8 @@ class Sql:
,foldToOtherRaisedStreet2
,foldToOtherRaisedStreet3
,foldToOtherRaisedStreet4
,stealAttemptChance
,stealAttempted
,raiseFirstInChance
,raisedFirstIn
,foldBbToStealChance
,foldedBbToSteal
,foldSbToStealChance
@ -3347,7 +3430,7 @@ class Sql:
when hp.position = '9' then 'E'
else 'E'
end AS hc_position
,hp.tourneyTypeId
,t.tourneyTypeId
,'d' || substr(strftime('%Y%m%d', h.startTime),3,7)
,count(1)
,sum(wonWhenSeenStreet1)
@ -3373,8 +3456,8 @@ class Sql:
,sum(CAST(foldToOtherRaisedStreet2 as integer))
,sum(CAST(foldToOtherRaisedStreet3 as integer))
,sum(CAST(foldToOtherRaisedStreet4 as integer))
,sum(CAST(stealAttemptChance as integer))
,sum(CAST(stealAttempted as integer))
,sum(CAST(raiseFirstInChance as integer))
,sum(CAST(raisedFirstIn as integer))
,sum(CAST(foldBbToStealChance as integer))
,sum(CAST(foldedBbToSteal as integer))
,sum(CAST(foldSbToStealChance as integer))
@ -3421,12 +3504,14 @@ class Sql:
,sum(CAST(hp.street4Raises as integer))
FROM HandsPlayers hp
INNER JOIN Hands h ON (h.id = hp.handId)
INNER JOIN TourneysPlayers tp ON (tp.id = hp.tourneysPlayersId)
INNER JOIN Tourneys t ON (t.id = tp.tourneyId)
<where_clause>
GROUP BY h.gametypeId
,hp.playerId
,h.seats
,hc_position
,hp.tourneyTypeId
,t.tourneyTypeId
,'d' || substr(strftime('%Y%m%d', h.startTime),3,7)
"""
@ -3462,8 +3547,8 @@ class Sql:
foldToOtherRaisedStreet4,
wonWhenSeenStreet1,
wonAtSD,
stealAttemptChance,
stealAttempted,
raiseFirstInChance,
raisedFirstIn,
foldBbToStealChance,
foldedBbToSteal,
foldSbToStealChance,
@ -3551,8 +3636,8 @@ class Sql:
foldToOtherRaisedStreet4=foldToOtherRaisedStreet4+%s,
wonWhenSeenStreet1=wonWhenSeenStreet1+%s,
wonAtSD=wonAtSD+%s,
stealAttemptChance=stealAttemptChance+%s,
stealAttempted=stealAttempted+%s,
raiseFirstInChance=raiseFirstInChance+%s,
raisedFirstIn=raisedFirstIn+%s,
foldBbToStealChance=foldBbToStealChance+%s,
foldedBbToSteal=foldedBbToSteal+%s,
foldSbToStealChance=foldSbToStealChance+%s,
@ -3656,6 +3741,7 @@ class Sql:
AND type=%s
AND category=%s
AND limitType=%s
AND currency=%s
AND smallBlind=%s
AND bigBlind=%s
"""
@ -3692,21 +3778,18 @@ class Sql:
AND fee=%s
AND category=%s
AND limitType=%s
AND buyInChips=%s
AND knockout=%s
AND rebuy=%s
AND addOn=%s
AND speed=%s
AND shootout=%s
AND matrix=%s
AND added=%s
AND addedCurrency=%s
"""
self.query['insertTourneyType'] = """INSERT INTO TourneyTypes
(siteId, currency, buyin, fee, category, limitType, buyInChips, knockout, rebuy,
(siteId, currency, buyin, fee, category, limitType, buyInChips, knockout, koBounty, rebuy,
addOn ,speed, shootout, matrix, added, addedCurrency)
VALUES (%s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s)
VALUES (%s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s)
"""
self.query['getTourneyByTourneyNo'] = """SELECT t.*
@ -3861,7 +3944,6 @@ class Sql:
street3Bets,
street4Bets,
position,
tourneyTypeId,
tourneysPlayersId,
startCards,
street0_3BChance,
@ -3874,8 +3956,8 @@ class Sql:
foldToOtherRaisedStreet2,
foldToOtherRaisedStreet3,
foldToOtherRaisedStreet4,
stealAttemptChance,
stealAttempted,
raiseFirstInChance,
raisedFirstIn,
foldBbToStealChance,
foldedBbToSteal,
foldSbToStealChance,
@ -3920,7 +4002,7 @@ class Sql:
%s, %s, %s, %s, %s,
%s, %s, %s, %s, %s,
%s, %s, %s, %s, %s,
%s, %s
%s
)"""
################################

View File

@ -350,6 +350,29 @@ def f_BB_steal(stat_dict, player):
'fBB_s=NA',
'(0/0)',
'% folded BB to steal')
def f_steal(stat_dict, player):
""" Folded blind to steal."""
stat = 0.0
try:
folded_blind = stat_dict[player]['sbnotdef'] + stat_dict[player]['bbnotdef']
blind_stolen = stat_dict[player]['sbstolen'] + stat_dict[player]['bbstolen']
stat = float(folded_blind)/float(blind_stolen)
return (stat,
'%3.1f' % (100*stat) + '%',
'fB=%3.1f' % (100*stat) + '%',
'fB_s=%3.1f' % (100*stat) + '%',
'(%d/%d)' % (folded_blind, blind_stolen),
'% folded blind to steal'
)
except:
return (stat,
'NA',
'fB=NA',
'fB_s=NA',
'(0/0)',
'% folded blind to steal')
def three_B(stat_dict, player):
""" Three bet preflop/3rd."""
@ -566,8 +589,8 @@ def agg_fact(stat_dict, player):
def cbet(stat_dict, player):
""" Flop continuation bet."""
""" Continuation bet % = (times made a continuation bet on the flop) * 100 / (number of opportunities to make a continuation bet on the flop) """
""" Total continuation bet."""
""" Continuation bet % = (times made a continuation bet on any street) * 100 / (number of opportunities to make a continuation bet on any street) """
stat = 0.0
try:
@ -777,6 +800,7 @@ if __name__== "__main__":
#print "player = ", player, do_stat(stat_dict, player = player, stat = 'steal')
#print "player = ", player, do_stat(stat_dict, player = player, stat = 'f_SB_steal')
#print "player = ", player, do_stat(stat_dict, player = player, stat = 'f_BB_steal')
#print "player = ", player, do_stat(stat_dict, player = player, stat = 'f_steal')
#print "player = ", player, do_stat(stat_dict, player = player, stat = 'three_B')
#print "player = ", player, do_stat(stat_dict, player = player, stat = 'WMsF')
#print "player = ", player, do_stat(stat_dict, player = player, stat = 'a_freq1')

View File

@ -63,68 +63,12 @@ class TourneyFilters(Filters.Filters):
self.make_filter()
#end def __init__
def __calendar_dialog(self, widget, entry):
d = gtk.Window(gtk.WINDOW_TOPLEVEL)
d.set_title('Pick a date')
vb = gtk.VBox()
cal = gtk.Calendar()
vb.pack_start(cal, expand=False, padding=0)
btn = gtk.Button('Done')
btn.connect('clicked', self.__get_date, cal, entry, d)
vb.pack_start(btn, expand=False, padding=4)
d.add(vb)
d.set_position(gtk.WIN_POS_MOUSE)
d.show_all()
#end def __calendar_dialog
def __clear_dates(self, w):
self.start_date.set_text('')
self.end_date.set_text('')
#end def __clear_dates
def __get_dates(self):
# self.day_start gives user's start of day in hours
offset = int(self.day_start * 3600) # calc day_start in seconds
t1 = self.start_date.get_text()
t2 = self.end_date.get_text()
if t1 == '':
t1 = '1970-01-02'
if t2 == '':
t2 = '2020-12-12'
s1 = strptime(t1, "%Y-%m-%d") # make time_struct
s2 = strptime(t2, "%Y-%m-%d")
e1 = mktime(s1) + offset # s1 is localtime, but returned time since epoch is UTC, then add the
e2 = mktime(s2) + offset # s2 is localtime, but returned time since epoch is UTC
e2 = e2 + 24 * 3600 - 1 # date test is inclusive, so add 23h 59m 59s to e2
adj_t1 = strftime("%Y-%m-%d %H:%M:%S", gmtime(e1)) # make adjusted string including time
adj_t2 = strftime("%Y-%m-%d %H:%M:%S", gmtime(e2))
log.info("t1="+t1+" adj_t1="+adj_t1+'.')
return (adj_t1, adj_t2)
#end def __get_dates
def __refresh(self, widget, entry):
def __refresh(self, widget, entry): #identical with Filters
for w in self.mainVBox.get_children():
w.destroy()
self.make_filter()
#end def __refresh
def __set_hero_name(self, w, site):
_name = w.get_text()
# get_text() returns a str but we want internal variables to be unicode:
_guiname = unicode(_name)
self.heroes[site] = _guiname
#log.debug("setting heroes[%s]: %s"%(site, self.heroes[site]))
#end def __set_hero_name
def __set_num_tourneys(self, w, val):
try:
self.numTourneys = int(w.get_text())
@ -133,25 +77,7 @@ class TourneyFilters(Filters.Filters):
print "setting numTourneys:", self.numTourneys
#end def __set_num_tourneys
def __set_seat_select(self, w, seat):
#print "__set_seat_select: seat =", seat, "active =", w.get_active()
self.seats[seat] = w.get_active()
log.debug( "self.seats[%s] set to %s" %(seat, self.seats[seat]) )
#end def __set_seat_select
def __set_site_select(self, w, site):
#print w.get_active()
self.sites[site] = w.get_active()
log.debug("self.sites[%s] set to %s" %(site, self.sites[site]))
#end def __set_site_select
def __set_tourney_type_select(self, w, tourneyType):
#print w.get_active()
self.tourneyTypes[tourneyType] = w.get_active()
log.debug("self.tourney_types[%s] set to %s" %(tourneyType, self.tourneyTypes[tourneyType]))
#end def __set_tourney_type_select
def __toggle_box(self, widget, entry):
def __toggle_box(self, widget, entry): #identical with Filters
if self.boxes[entry].props.visible:
self.boxes[entry].hide()
widget.set_label("show")
@ -160,259 +86,6 @@ class TourneyFilters(Filters.Filters):
widget.set_label("hide")
#end def __toggle_box
def createPlayerLine(self, hbox, site, player):
log.debug('add:"%s"' % player)
label = gtk.Label(site +" id:")
hbox.pack_start(label, False, False, 3)
pname = gtk.Entry()
pname.set_text(player)
pname.set_width_chars(20)
hbox.pack_start(pname, False, True, 0)
#pname.connect("changed", self.__set_hero_name, site)
# Added EntryCompletion but maybe comboBoxEntry is more flexible? (e.g. multiple choices)
completion = gtk.EntryCompletion()
pname.set_completion(completion)
liststore = gtk.ListStore(gobject.TYPE_STRING)
completion.set_model(liststore)
completion.set_text_column(0)
names = self.db.get_player_names(self.conf, self.siteid[site]) # (config=self.conf, site_id=None, like_player_name="%")
for n in names: # list of single-element "tuples"
_n = Charset.to_gui(n[0])
_nt = (_n, )
liststore.append(_nt)
self.__set_hero_name(pname, site)
#end def createPlayerLine
def createSiteLine(self, hbox, site):
cb = gtk.CheckButton(site)
cb.connect('clicked', self.__set_site_select, site)
cb.set_active(True)
hbox.pack_start(cb, False, False, 0)
#end def createSiteLine
def createTourneyTypeLine(self, hbox, tourneyType):
cb = gtk.CheckButton(str(tourneyType))
cb.connect('clicked', self.__set_tourney_type_select, tourneyType)
hbox.pack_start(cb, False, False, 0)
cb.set_active(True)
#end def createTourneyTypeLine
def fillDateFrame(self, vbox):
# Hat tip to Mika Bostrom - calendar code comes from PokerStats
top_hbox = gtk.HBox(False, 0)
vbox.pack_start(top_hbox, False, False, 0)
lbl_title = gtk.Label(self.filterText['datestitle'])
lbl_title.set_alignment(xalign=0.0, yalign=0.5)
top_hbox.pack_start(lbl_title, expand=True, padding=3)
showb = gtk.Button(label="hide", stock=None, use_underline=True)
showb.set_alignment(xalign=1.0, yalign=0.5)
showb.connect('clicked', self.__toggle_box, 'dates')
top_hbox.pack_start(showb, expand=False, padding=1)
vbox1 = gtk.VBox(False, 0)
vbox.pack_start(vbox1, False, False, 0)
self.boxes['dates'] = vbox1
hbox = gtk.HBox()
vbox1.pack_start(hbox, False, True, 0)
lbl_start = gtk.Label('From:')
btn_start = gtk.Button()
btn_start.set_image(gtk.image_new_from_stock(gtk.STOCK_INDEX, gtk.ICON_SIZE_BUTTON))
btn_start.connect('clicked', self.__calendar_dialog, self.start_date)
hbox.pack_start(lbl_start, expand=False, padding=3)
hbox.pack_start(btn_start, expand=False, padding=3)
hbox.pack_start(self.start_date, expand=False, padding=2)
#New row for end date
hbox = gtk.HBox()
vbox1.pack_start(hbox, False, True, 0)
lbl_end = gtk.Label(' To:')
btn_end = gtk.Button()
btn_end.set_image(gtk.image_new_from_stock(gtk.STOCK_INDEX, gtk.ICON_SIZE_BUTTON))
btn_end.connect('clicked', self.__calendar_dialog, self.end_date)
btn_clear = gtk.Button(label=' Clear Dates ')
btn_clear.connect('clicked', self.__clear_dates)
hbox.pack_start(lbl_end, expand=False, padding=3)
hbox.pack_start(btn_end, expand=False, padding=3)
hbox.pack_start(self.end_date, expand=False, padding=2)
hbox.pack_start(btn_clear, expand=False, padding=15)
#end def fillDateFrame
def fillPlayerFrame(self, vbox, display):
top_hbox = gtk.HBox(False, 0)
vbox.pack_start(top_hbox, False, False, 0)
lbl_title = gtk.Label(self.filterText['playerstitle'])
lbl_title.set_alignment(xalign=0.0, yalign=0.5)
top_hbox.pack_start(lbl_title, expand=True, padding=3)
showb = gtk.Button(label="refresh", stock=None, use_underline=True)
showb.set_alignment(xalign=1.0, yalign=0.5)
showb.connect('clicked', self.__refresh, 'players')
vbox1 = gtk.VBox(False, 0)
vbox.pack_start(vbox1, False, False, 0)
self.boxes['players'] = vbox1
for site in self.conf.get_supported_sites():
hBox = gtk.HBox(False, 0)
vbox1.pack_start(hBox, False, True, 0)
player = self.conf.supported_sites[site].screen_name
_pname = Charset.to_gui(player)
self.createPlayerLine(hBox, site, _pname)
hbox = gtk.HBox(False, 0)
vbox1.pack_start(hbox, False, False, 0)
#cb = gtk.CheckButton(self.filterText['groupsall'])
#cb.connect('clicked', self.__set_group_select, 'allplayers')
#hbox.pack_start(cb, False, False, 0)
#self.sbGroups['allplayers'] = cb
#self.groups['allplayers'] = False
#lbl = gtk.Label('Min # Hands:')
#lbl.set_alignment(xalign=1.0, yalign=0.5)
#hbox.pack_start(lbl, expand=True, padding=3)
#phands = gtk.Entry()
#phands.set_text('0')
#phands.set_width_chars(8)
#hbox.pack_start(phands, False, False, 0)
#phands.connect("changed", self.__set_num_hands, site)
top_hbox.pack_start(showb, expand=False, padding=1)
#end def fillPlayerFrame
def fillSeatsFrame(self, vbox, display):
hbox = gtk.HBox(False, 0)
vbox.pack_start(hbox, False, False, 0)
lbl_title = gtk.Label(self.filterText['seatstitle'])
lbl_title.set_alignment(xalign=0.0, yalign=0.5)
hbox.pack_start(lbl_title, expand=True, padding=3)
showb = gtk.Button(label="hide", stock=None, use_underline=True)
showb.set_alignment(xalign=1.0, yalign=0.5)
showb.connect('clicked', self.__toggle_box, 'seats')
hbox.pack_start(showb, expand=False, padding=1)
vbox1 = gtk.VBox(False, 0)
vbox.pack_start(vbox1, False, False, 0)
self.boxes['seats'] = vbox1
hbox = gtk.HBox(False, 0)
vbox1.pack_start(hbox, False, True, 0)
lbl_from = gtk.Label(self.filterText['seatsbetween'])
lbl_to = gtk.Label(self.filterText['seatsand'])
adj1 = gtk.Adjustment(value=2, lower=2, upper=10, step_incr=1, page_incr=1, page_size=0)
sb1 = gtk.SpinButton(adjustment=adj1, climb_rate=0.0, digits=0)
adj2 = gtk.Adjustment(value=10, lower=2, upper=10, step_incr=1, page_incr=1, page_size=0)
sb2 = gtk.SpinButton(adjustment=adj2, climb_rate=0.0, digits=0)
hbox.pack_start(lbl_from, expand=False, padding=3)
hbox.pack_start(sb1, False, False, 0)
hbox.pack_start(lbl_to, expand=False, padding=3)
hbox.pack_start(sb2, False, False, 0)
self.sbSeats['from'] = sb1
self.sbSeats['to'] = sb2
#end def fillSeatsFrame
def fillSitesFrame(self, vbox):
top_hbox = gtk.HBox(False, 0)
top_hbox.show()
vbox.pack_start(top_hbox, False, False, 0)
lbl_title = gtk.Label(self.filterText['sitestitle'])
lbl_title.set_alignment(xalign=0.0, yalign=0.5)
top_hbox.pack_start(lbl_title, expand=True, padding=3)
showb = gtk.Button(label="hide", stock=None, use_underline=True)
showb.set_alignment(xalign=1.0, yalign=0.5)
showb.connect('clicked', self.__toggle_box, 'sites')
showb.show()
top_hbox.pack_start(showb, expand=False, padding=1)
vbox1 = gtk.VBox(False, 0)
self.boxes['sites'] = vbox1
vbox.pack_start(vbox1, False, False, 0)
for site in self.conf.get_supported_sites():
hbox = gtk.HBox(False, 0)
vbox1.pack_start(hbox, False, True, 0)
self.createSiteLine(hbox, site)
#end def fillSitesFrame
def fillTourneyTypesFrame(self, vbox):
top_hbox = gtk.HBox(False, 0)
vbox.pack_start(top_hbox, False, False, 0)
lbl_title = gtk.Label(self.filterText['tourneyTypesTitle'])
lbl_title.set_alignment(xalign=0.0, yalign=0.5)
top_hbox.pack_start(lbl_title, expand=True, padding=3)
showb = gtk.Button(label="hide", stock=None, use_underline=True)
showb.set_alignment(xalign=1.0, yalign=0.5)
showb.connect('clicked', self.__toggle_box, 'tourneyTypes')
top_hbox.pack_start(showb, expand=False, padding=1)
vbox1 = gtk.VBox(False, 0)
vbox.pack_start(vbox1, False, False, 0)
self.boxes['tourneyTypes'] = vbox1
result = self.db.getTourneyTypesIds()
if len(result) >= 1:
for line in result:
hbox = gtk.HBox(False, 0)
vbox1.pack_start(hbox, False, True, 0)
self.createTourneyTypeLine(hbox, line[0])
else:
print "INFO: No tourney types returned from database"
log.info("No tourney types returned from database")
#end def fillTourneyTypesFrame
def getDates(self):
return self.__get_dates()
#end def getDates
def getHeroes(self):
return self.heroes
#end def getHeroes
def getNumTourneys(self):
return self.numTourneys
#end def getNumTourneys
def getSeats(self):
if 'from' in self.sbSeats:
self.seats['from'] = self.sbSeats['from'].get_value_as_int()
if 'to' in self.sbSeats:
self.seats['to'] = self.sbSeats['to'].get_value_as_int()
return self.seats
#end def getSeats
def getSiteIds(self):
return self.siteid
#end def getSiteIds
def getSites(self):
return self.sites
#end def getSites
def getTourneyTypes(self):
return self.tourneyTypes
#end def getTourneyTypes
def get_vbox(self):
"""returns the vbox of this thread"""
return self.mainVBox
#end def get_vbox
def make_filter(self):
self.tourneyTypes = {}
#self.tourneys = {}
@ -526,15 +199,4 @@ class TourneyFilters(Filters.Filters):
# make sure any locks on db are released:
self.db.rollback()
#end def make_filter
def registerButton2Name(self, title):
self.Button2.set_label(title)
self.label['button2'] = title
#end def registerButton2Name
def registerButton2Callback(self, callback):
self.Button2.connect("clicked", callback, "clicked")
self.Button2.set_sensitive(True)
self.callback['button2'] = callback
#end def registerButton2Callback
#end class TourneyFilters

View File

@ -70,7 +70,7 @@ class Table(Table_Window):
for listing in os.popen('xwininfo -root -tree').readlines():
if re.search(search_string, listing):
# print listing
mo = re.match('\s+([\dxabcdef]+) (.+):\s\(\"([a-zA-Z.]+)\".+ (\d+)x(\d+)\+\d+\+\d+ \+(\d+)\+(\d+)', listing)
mo = re.match('\s+([\dxabcdef]+) (.+):\s\(\"([a-zA-Z0-9\-.]+)\".+ (\d+)x(\d+)\+\d+\+\d+ \+(\d+)\+(\d+)', listing)
self.number = int( mo.group(1), 0)
self.width = int( mo.group(4) )
self.height = int( mo.group(5) )

View File

@ -107,7 +107,6 @@ import ImapFetcher
import GuiRingPlayerStats
import GuiTourneyPlayerStats
import GuiPositionalStats
import GuiTableViewer
import GuiAutoImport
import GuiGraphViewer
import GuiSessionViewer
@ -117,7 +116,7 @@ import Configuration
import Exceptions
import Stats
VERSION = "0.20.1 plus git"
VERSION = "0.20.903 plus git"
class fpdb:
@ -229,13 +228,12 @@ class fpdb:
self.quit(widget)
def dia_about(self, widget, data=None):
#self.warning_box("About FPDB:\n\nFPDB was originally created by a guy named Steffen, sometime in 2008, \nand is mostly worked on these days by people named Eratosthenes, s0rrow, _mt, EricBlade, sqlcoder, and other strange people.\n\n", "ABOUT FPDB")
dia = gtk.AboutDialog()
dia.set_name("Free Poker Database (FPDB)")
dia.set_version(VERSION)
dia.set_copyright("Copyright 2008-2010, Steffen, Eratosthenes, Carl Gherardi, Eric Blade, _mt, sqlcoder, Bostik, and others")
dia.set_comments("")
dia.set_license("This program is licensed under the AGPL3, see agpl-3.0.txt in the fpdb installation directory")
dia.set_comments("You are free to change and distribute original or changed versions of fpdb within the rules set out by the license")
dia.set_license("Please see fpdb's start screen for license information")
dia.set_website("http://fpdb.sourceforge.net/")
dia.set_authors(['Steffen', 'Eratosthenes', 'Carl Gherardi',
@ -306,8 +304,8 @@ class fpdb:
dia.destroy()
def dia_maintain_dbs(self, widget, data=None):
self.warning_box("Unimplemented: Maintain Databases")
return
#self.warning_box("Unimplemented: Maintain Databases")
#return
if len(self.tab_names) == 1:
if self.obtain_global_lock("dia_maintain_dbs"): # returns true if successful
# only main tab has been opened, open dialog
@ -321,8 +319,14 @@ class fpdb:
prefs = GuiDatabase.GuiDatabase(self.config, self.window, dia)
response = dia.run()
if response == gtk.RESPONSE_ACCEPT:
log.info('saving updated db data')
# save updated config
self.config.save()
self.load_profile()
for name in self.config.supported_databases: #db_ip/db_user/db_pass/db_server
log.info('fpdb: name,desc='+name+','+self.config.supported_databases[name].db_desc)
else:
log.info('guidb response was '+str(response))
self.release_global_lock()
@ -547,23 +551,14 @@ class fpdb:
# self.release_global_lock()
# lock_released = True
self.db.recreate_tables()
# find any guibulkimport windows and clear player cache:
# find any guibulkimport/guiautoimport windows and clear player cache:
for t in self.threads:
if isinstance(t, GuiBulkImport.GuiBulkImport):
if isinstance(t, GuiBulkImport.GuiBulkImport) or isinstance(t, GuiAutoImport.GuiAutoImport):
t.importer.database.resetPlayerIDs()
self.release_global_lock()
#else:
# for other dbs use same connection as holds global lock
# self.fdb_lock.fdb.recreate_tables()
# TODO: figure out why this seems to be necessary
dia_restart = gtk.MessageDialog(parent=self.window, flags=0, type=gtk.MESSAGE_WARNING,
buttons=(gtk.BUTTONS_OK), message_format="Restart fpdb")
diastring = "Fpdb now needs to close. Please restart it."
dia_restart.format_secondary_text(diastring)
dia_restart.run()
dia_restart.destroy()
self.quit(None, None)
elif response == gtk.RESPONSE_NO:
self.release_global_lock()
print 'User cancelled recreating tables'
@ -801,7 +796,6 @@ class fpdb:
<menuitem action="tourneyplayerstats"/>
<menuitem action="posnstats"/>
<menuitem action="sessionstats"/>
<menuitem action="tableviewer"/>
</menu>
<menu action="database">
<menuitem action="maintaindbs"/>
@ -815,7 +809,6 @@ class fpdb:
<menuitem action="Logs"/>
<separator/>
<menuitem action="About"/>
<menuitem action="License"/>
</menu>
</menubar>
</ui>"""
@ -839,12 +832,11 @@ class fpdb:
('hudConfigurator', None, '_HUD Configurator', '<control>H', 'HUD Configurator', self.diaHudConfigurator),
('graphs', None, '_Graphs', '<control>G', 'Graphs', self.tabGraphViewer),
('ringplayerstats', None, 'Ring _Player Stats (tabulated view)', '<control>P', 'Ring Player Stats (tabulated view)', self.tab_ring_player_stats),
('tourneyplayerstats', None, '_Tourney Player Stats (tabulated view)', '<control>T', 'Tourney Player Stats (tabulated view)', self.tab_tourney_player_stats),
('tourneyplayerstats', None, '_Tourney Player Stats (tabulated view, mysql only)', '<control>T', 'Tourney Player Stats (tabulated view, mysql only)', self.tab_tourney_player_stats),
('posnstats', None, 'P_ositional Stats (tabulated view)', '<control>O', 'Positional Stats (tabulated view)', self.tab_positional_stats),
('sessionstats', None, 'Session Stats', None, 'Session Stats', self.tab_session_stats),
('tableviewer', None, 'Poker_table Viewer (mostly obselete)', None, 'Poker_table Viewer (mostly obselete)', self.tab_table_viewer),
('database', None, '_Database'),
('maintaindbs', None, '_Maintain Databases (todo)', None, 'Maintain Databases', self.dia_maintain_dbs),
('maintaindbs', None, '_Maintain Databases', None, 'Maintain Databases', self.dia_maintain_dbs),
('createtabs', None, 'Create or Recreate _Tables', None, 'Create or Recreate Tables ', self.dia_recreate_tables),
('rebuildhudcache', None, 'Rebuild HUD Cache', None, 'Rebuild HUD Cache', self.dia_recreate_hudcache),
('rebuildindexes', None, 'Rebuild DB Indexes', None, 'Rebuild DB Indexes', self.dia_rebuild_indexes),
@ -852,8 +844,7 @@ class fpdb:
('dumptofile', None, 'Dump Database to Textfile (takes ALOT of time)', None, 'Dump Database to Textfile (takes ALOT of time)', self.dia_dump_db),
('help', None, '_Help'),
('Logs', None, '_Log Messages', None, 'Log and Debug Messages', self.dia_logs),
('About', None, 'A_bout', None, 'About the program', self.dia_about),
('License', None, '_License and Copying (todo)', None, 'License and Copying', self.dia_licensing),
('About', None, 'A_bout, License, Copying', None, 'About the program', self.dia_about),
])
actiongroup.get_action('Quit').set_property('short-label', '_Quit')
@ -1068,16 +1059,10 @@ If you need help click on Contact - Get Help on our website.
Please note that default.conf is no longer needed nor used, all configuration now happens in HUD_config.xml.
This program is free/libre open source software licensed partially under the AGPL3, and partially under GPL2 or later.
You can find the full license texts in agpl-3.0.txt, gpl-2.0.txt and gpl-3.0.txt in the fpdb installation directory.""")
The Windows installer package includes code licensed under the MIT license.
You can find the full license texts in agpl-3.0.txt, gpl-2.0.txt, gpl-3.0.txt and mit.txt in the fpdb installation directory.""")
self.add_and_display_tab(mh_tab, "Help")
def tab_table_viewer(self, widget, data=None):
"""opens a table viewer tab"""
new_tv_thread = GuiTableViewer.GuiTableViewer(self.db, self.settings, self.config)
self.threads.append(new_tv_thread)
tv_tab = new_tv_thread.get_vbox()
self.add_and_display_tab(tv_tab, "Table Viewer")
def tabGraphViewer(self, widget, data=None):
"""opens a graph viewer tab"""
new_gv_thread = GuiGraphViewer.GuiGraphViewer(self.sql, self.config, self.window)

View File

@ -464,8 +464,11 @@ class Importer:
#pipe the Hands.id out to the HUD
for hid in to_hud:
print "fpdb_import: sending hand to hud", hand.dbid_hands, "pipe =", self.caller.pipe_to_hud
self.caller.pipe_to_hud.stdin.write("%s" % (hid) + os.linesep)
try:
print "fpdb_import: sending hand to hud", hand.dbid_hands, "pipe =", self.caller.pipe_to_hud
self.caller.pipe_to_hud.stdin.write("%s" % (hid) + os.linesep)
except IOError, e:
log.error("Failed to send hand to HUD: %s" % e)
errors = getattr(hhc, 'numErrors')
stored = getattr(hhc, 'numHands')

View File

@ -1,5 +1,5 @@
[loggers]
keys=root,fpdb,logview,parser,importer,config,db,hud,filter
keys=root,fpdb,logview,parser,importer,config,db,hud,filter,maintdbs
[handlers]
keys=consoleHandler,rotatingFileHandler
@ -17,6 +17,12 @@ handlers=consoleHandler,rotatingFileHandler
qualname=fpdb
propagate=0
[logger_maintdbs]
level=INFO
handlers=consoleHandler,rotatingFileHandler
qualname=maintdbs
propagate=0
[logger_logview]
level=INFO
handlers=consoleHandler,rotatingFileHandler

View File

@ -1 +0,0 @@
python makeexe.py py2exe

View File

@ -1,27 +0,0 @@
#!/usr/bin/env python
# -*- coding: utf-8 -*-
#Copyright 2009-2010 Eric Blade
#This program is free software: you can redistribute it and/or modify
#it under the terms of the GNU Affero General Public License as published by
#the Free Software Foundation, version 3 of the License.
#
#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 Affero General Public License
#along with this program. If not, see <http://www.gnu.org/licenses/>.
#In the "official" distribution you can find the license in agpl-3.0.txt.
from distutils.core import setup
import py2exe
opts = {
'py2exe': {
'includes': "pango,atk,gobject",
}
}
setup(name='Free Poker Database', version='0.12', console=[{"script":"fpdb.py"}])

View File

@ -72,6 +72,14 @@ Py2exe script for fpdb.
import os
import sys
# get out now if parameter not passed
try:
sys.argv[1] <> ""
except:
print "A parameter is required, quitting now"
quit()
from distutils.core import setup
import py2exe
import glob
@ -82,7 +90,6 @@ from datetime import date
origIsSystemDLL = py2exe.build_exe.isSystemDLL
def isSystemDLL(pathname):
#VisC++ runtime msvcp71.dll removed; py2.6 needs msvcp90.dll which will not be distributed.
#dwmapi appears to be vista-specific file, not XP
if os.path.basename(pathname).lower() in ("dwmapi.dll"):
return 0
@ -97,7 +104,7 @@ def remove_tree(top):
# could delete all your disk files.
# sc: Nicked this from somewhere, added the if statement to try
# make it a bit safer
if top in ('build','dist','gfx') and os.path.basename(os.getcwd()) == 'pyfpdb':
if top in ('build','dist','pyfpdb',dist_dirname) and os.path.basename(os.getcwd()) == 'pyfpdb':
#print "removing directory '"+top+"' ..."
for root, dirs, files in os.walk(top, topdown=False):
for name in files:
@ -114,12 +121,6 @@ def test_and_remove(top):
print "Unexpected file '"+top+"' found. Exiting."
exit()
# remove build and dist dirs if they exist
test_and_remove('dist')
test_and_remove('build')
#test_and_remove('gfx')
today = date.today().strftime('%Y%m%d')
print "\n" + r"Output will be created in \pyfpdb\ and \fpdb_"+today+'\\'
#print "Enter value for XXX (any length): ", # the comma means no newline
@ -128,12 +129,18 @@ dist_dirname = r'fpdb-' + today + '-exe'
dist_dir = r'..\fpdb-' + today + '-exe'
print
test_and_remove(dist_dir)
# remove build and dist dirs if they exist
test_and_remove('dist')
test_and_remove('build')
test_and_remove('pyfpdb')
test_and_remove(dist_dirname)
setup(
name = 'fpdb',
description = 'Free Poker DataBase',
version = '0.20',
version = '0.20.903',
windows = [ {'script': 'fpdb.pyw', "icon_resources": [(1, "../gfx/fpdb_large_icon.ico")]},
{'script': 'HUD_main.pyw', },
@ -142,7 +149,7 @@ setup(
options = {'py2exe': {
'packages' : ['encodings', 'matplotlib'],
'includes' : ['gio', 'cairo', 'pango', 'pangocairo', 'atk', 'gobject'
'includes' : ['gio', 'cairo', 'pango', 'pangocairo', 'atk', 'gobject'
,'matplotlib.numerix.random_array'
,'AbsoluteToFpdb', 'BetfairToFpdb'
,'CarbonToFpdb', 'EverleafToFpdb'
@ -151,14 +158,14 @@ setup(
,'UltimateBetToFpdb', 'Win2dayToFpdb'
],
'excludes' : ['_tkagg', '_agg2', 'cocoaagg', 'fltkagg'], # surely we need this? '_gtkagg'
'dll_excludes': ['libglade-2.0-0.dll', 'libgdk-win32-2.0-0.dll'
,'libgobject-2.0-0.dll', 'msvcr90.dll', 'MSVCP90.dll', 'MSVCR90.dll','msvcr90.dll'],
'dll_excludes': ['libglade-2.0-0.dll', 'libgdk-win32-2.0-0.dll', 'libgobject-2.0-0.dll'
, 'msvcr90.dll', 'MSVCP90.dll', 'MSVCR90.dll','msvcr90.dll'], # these are vis c / c++ runtimes, and must not be redistributed
}
},
# files in 2nd value in tuple are moved to dir named in 1st value
#data_files updated for new locations of licences + readme nolonger exists
data_files = [('', ['HUD_config.xml.example', 'Cards01.png', 'logging.conf', '../agpl-3.0.txt', '../fdl-1.2.txt', '../THANKS.txt', '../readme.txt'])
data_files = [('', ['HUD_config.xml.example', 'Cards01.png', 'logging.conf', '../agpl-3.0.txt', '../fdl-1.2.txt', '../gpl-3.0.txt', '../gpl-2.0.txt', '../mit.txt', '../readme.txt'])
,(dist_dir, [r'..\run_fpdb.bat'])
,( dist_dir + r'\gfx', glob.glob(r'..\gfx\*.*') )
# line below has problem with fonts subdir ('not a regular file')
@ -166,25 +173,28 @@ setup(
] + matplotlib.get_py2exe_datafiles()
)
# rename completed output package as pyfpdb
os.rename('dist', 'pyfpdb')
# these instructions no longer needed:
#print '\n' + 'If py2exe was successful add the \\etc \\lib and \\share dirs '
#print 'from your gtk dir to \\%s\\pyfpdb\\\n' % dist_dirname
#print 'Also copy libgobject-2.0-0.dll and libgdk-win32-2.0-0.dll from <gtk_dir>\\bin'
#print 'into there'
# pull pytz zoneinfo into pyfpdb package folder
src_dir = r'c:\python26\Lib\site-packages\pytz\zoneinfo'
src_dir = src_dir.replace('\\', '\\\\')
dest_dir = os.path.join(r'pyfpdb', 'zoneinfo')
shutil.copytree( src_dir, dest_dir )
# shunt pyfpdb package over to the distribution folder
dest = os.path.join(dist_dirname, 'pyfpdb')
#print "try renaming pyfpdb to", dest
# print "try renaming pyfpdb to", dest
dest = dest.replace('\\', '\\\\')
#print "dest is now", dest
# print "dest is now", dest
os.rename( 'pyfpdb', dest )
# prompt for gtk location
print "Enter directory name for GTK (e.g. c:\code\gtk_2.14.7-20090119)\n: ", # the comma means no newline
gtk_dir = sys.stdin.readline().rstrip()
gtk_dir = ""
while not os.path.exists(gtk_dir):
print "Enter directory name for GTK (e.g. c:\code\gtk_2.14.7-20090119)\n: ", # the comma means no newline
gtk_dir = sys.stdin.readline().rstrip()
print "\ncopying files and dirs from ", gtk_dir, "to", dest.replace('\\\\', '\\'), "..."
src = os.path.join(gtk_dir, 'bin', 'libgdk-win32-2.0-0.dll')
@ -195,7 +205,6 @@ src = os.path.join(gtk_dir, 'bin', 'libgobject-2.0-0.dll')
src = src.replace('\\', '\\\\')
shutil.copy( src, dest )
src_dir = os.path.join(gtk_dir, 'etc')
src_dir = src_dir.replace('\\', '\\\\')
dest_dir = os.path.join(dest, 'etc')

File diff suppressed because it is too large Load Diff

View File

@ -13,14 +13,12 @@ from distutils.core import setup
setup(name = 'fpdb',
description = 'Free Poker Database',
version = '0.12',
version = '0.20',
author = 'FPDB team',
author_email = 'fpdb-main@lists.sourceforge.net',
packages = ['fpdb'],
package_dir = { 'fpdb' : 'pyfpdb' },
data_files = [
('/usr/share/doc/python-fpdb',
['THANKS.txt']),
('/usr/share/pixmaps',
['gfx/fpdb-icon.png', 'gfx/fpdb-icon2.png',
'gfx/fpdb-cards.png'