Merge branch 'master' of git://git.assembla.com/fpdb
Conflicts: pyfpdb/PartyPokerToFpdb.py
This commit is contained in:
commit
d09aa716f4
2
.gitattributes
vendored
Normal file
2
.gitattributes
vendored
Normal file
|
|
@ -0,0 +1,2 @@
|
|||
pyfpdb/HUD_config.xml.example -crlf
|
||||
|
||||
BIN
gfx/Table.png
Normal file
BIN
gfx/Table.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 9.3 KiB |
32
packaging/announce-0.20.905.txt
Normal file
32
packaging/announce-0.20.905.txt
Normal file
|
|
@ -0,0 +1,32 @@
|
|||
Hello everyone,
|
||||
The new snapshot 0.20.905 is now available for download as source or as packages/installers for Debian, Gentoo, Ubuntu and Windows.
|
||||
This version brings many improvements and bugfixes, updating is recommended for users of previous snapshots. If you're using a stable version like 0.20 or 0.20.1 please consider trying this version and report any bugs, and in particular regressions, so we can fix them. This snapshot will hopefully be the last, next step is one or more release candidates, and then the next stable release.
|
||||
|
||||
We are still looking for translators! You can find some information about what languages we are still missing here: http://sourceforge.net/apps/mediawiki/fpdb/index.php?title=Translation
|
||||
|
||||
188 changesets (excl. merges) have gone in since 0.20.904.
|
||||
Please note that you will have to either recreate your database or use a new one if you're updating from 0.20.904 or older.
|
||||
Config files from 0.20 and later should work. Please report if you have problems with config files from that version or later.
|
||||
|
||||
What's changed:
|
||||
- Fpdb now supports running in languages other than English, Erki supplied a translation for Hungarian. French, Spanish and Italian are in progress by new contributors. Fpdb will use the system-configured language, a configuration option will be added before the next stable release. Note that this is about the user interface language, non-English history file parsing is a seperate topic.
|
||||
- Much improved testing to improve the recording of data, especially corner cases and non-trivial stats
|
||||
- OnGame network (which now includes Betfair) is now properly supported
|
||||
- FTP.fr importing now works. We don't know if the HUD works yet, give it a go and let us know
|
||||
- We noticed that fpdb already supports PS.fr
|
||||
- PokerStars should support all limits now
|
||||
- The Debian package now handles a missing config file properly
|
||||
- Many minor improvements to the Gentoo ebuilds for the upcoming submission to the sunrise overlay
|
||||
- We changed how email import is configured. Either delete your old config or see the HUD_config.xml.example file for how to add the section to the right place
|
||||
- fpdb should now be able to run with any config file from 0.20 or later, including all 0.20.9* snapshots
|
||||
- Some more fixes to window visibility and the minimise to tray icon feature
|
||||
- Various other small cleanups, fixes and improvements. See the git changelog for full details
|
||||
|
||||
To download:
|
||||
- Debian/Ubuntu Linux: http://sourceforge.net/projects/fpdb/files/fpdb/Snapshots/python-fpdb_0.20.905-1_all.deb/download
|
||||
- Gentoo Linux: http://sourceforge.net/projects/fpdb/files/fpdb/Snapshots/fpdb-0.20.905.ebuild/download
|
||||
- Windows: http://sourceforge.net/projects/fpdb/files/fpdb/Snapshots/fpdb-0.20.905anyCPU.exe/download
|
||||
- Source version for those who installed the dependencies manually: http://sourceforge.net/projects/fpdb/files/fpdb/Snapshots/fpdb-0.20.905.tar.bz2/download
|
||||
|
||||
Thanks to everyone who contributed code, translations, testing and bug reports!
|
||||
The fpdb team
|
||||
|
|
@ -1,3 +1,34 @@
|
|||
free-poker-tools (0.20.906-1) unstable; urgency=low
|
||||
|
||||
* New snapshot
|
||||
|
||||
-- Mika Bostrom <bostik@iki.fi> Fri, 27 Aug 2010 08:26:05 +0300
|
||||
|
||||
free-poker-tools (0.20.905-1) unstable; urgency=low
|
||||
|
||||
* New snapshot
|
||||
* Hungarian translation
|
||||
|
||||
-- Mika Bostrom <bostik@iki.fi> Wed, 25 Aug 2010 10:05:36 +0300
|
||||
|
||||
free-poker-tools (0.20.904-2) unstable; urgency=low
|
||||
|
||||
* On fpdb start, copy example HUD_config.xml in place if none is present
|
||||
|
||||
-- Mika Bostrom <bostik@iki.fi> Tue, 17 Aug 2010 08:23:31 +0300
|
||||
|
||||
free-poker-tools (0.20.904-1) unstable; urgency=low
|
||||
|
||||
* .904 snapshot release
|
||||
|
||||
-- Mika Bostrom <bostik@iki.fi> Sat, 14 Aug 2010 09:24:25 +0300
|
||||
|
||||
free-poker-tools (0.20.903-1) unstable; urgency=low
|
||||
|
||||
* .903 snapshot release
|
||||
|
||||
-- Mika Bostrom <bostik@iki.fi> Tue, 03 Aug 2010 17:47:41 +0300
|
||||
|
||||
free-poker-tools (0.20.902-1) unstable; urgency=low
|
||||
|
||||
* New snapshot release; .901 was broken for FTP
|
||||
|
|
|
|||
|
|
@ -26,9 +26,7 @@ install: build
|
|||
# Copy *.pyw manually in packaging tree
|
||||
cp pyfpdb/*.pyw debian/$(PACKAGE)/usr/lib/python2.6/site-packages/fpdb/
|
||||
# Remove scripts that are only useful in win32
|
||||
rm debian/$(PACKAGE)/usr/lib/python2.6/site-packages/fpdb//windows_make_bats.py
|
||||
rm debian/$(PACKAGE)/usr/lib/python2.6/site-packages/fpdb/makeexe.py
|
||||
rm debian/$(PACKAGE)/usr/lib/python2.6/site-packages/fpdb/py2exe_setup.py
|
||||
rm debian/$(PACKAGE)/usr/lib/python2.6/site-packages/fpdb/windows_make_bats.py
|
||||
|
||||
|
||||
binary-indep: build install
|
||||
|
|
|
|||
23
packaging/gentoo/ChangeLog
Normal file
23
packaging/gentoo/ChangeLog
Normal file
|
|
@ -0,0 +1,23 @@
|
|||
# Copyright 1999-2010 Gentoo Foundation
|
||||
# Distributed under the terms of the GNU General Public License v2
|
||||
# created by Steffen Schaumburg, steffen@schaumburger.info
|
||||
|
||||
29 Aug 2010; Erki Ferenc <erkiferenc@gmail.com>
|
||||
fpdb-0.20.906.ebuild, fpdb-9999.ebuild:
|
||||
improve l10n handling
|
||||
|
||||
29 Aug 2010; Steffen Schaumburg <steffen@schaumburger.info>
|
||||
fpdb-0.20.1.ebuild, fpdb-0.20.906.ebuild, fpdb-9999.ebuild:
|
||||
change required python version to 2.6
|
||||
|
||||
*fpdb-0.20.906 (29 Aug 2010)
|
||||
29 Aug 2010; Steffen Schaumburg <steffen@schaumburger.info>
|
||||
+fpdb-0.20.906.ebuild -fpdb-0.20.904.ebuild:
|
||||
Bump version
|
||||
|
||||
*fpdb-0.20.1 fpdb-0.20.904 fpdb-9999 (17 Aug 2010)
|
||||
|
||||
17 Aug 2010; Steffen Schaumburg <steffen@schaumburger.info>
|
||||
+fpdb-0.20.1.ebuild, +fpdb-0.20.904.ebuild, +fpdb-9999.ebuild, +metadata.xml:
|
||||
Initial changelog for repoman.
|
||||
|
||||
7
packaging/gentoo/Manifest
Normal file
7
packaging/gentoo/Manifest
Normal file
|
|
@ -0,0 +1,7 @@
|
|||
DIST fpdb-0.20.1.tar.bz2 662807 RMD160 b5f22a684c605ddbba7d2154005a822b02a19490 SHA1 e4cc40de5849d3ae33a680d917b340ab37c6448b SHA256 46eff0625f300c070ce88c519ae6019f6e1c98a7725733c5e16b50a058247fe3
|
||||
DIST fpdb-0.20.906.tar.bz2 702558 RMD160 bc5d01ef4899502aea33f286ac4274ef7ef498ef SHA1 9791680d53de1b276dc0297ac43a0e11758d3e19 SHA256 9ae706d5e9c2a2ee031d2b222ba46e088993cc892fc08b5276bbfd5e44a0436b
|
||||
EBUILD fpdb-0.20.1.ebuild 1508 RMD160 7585cd1de73172649e182782d427a476afed4036 SHA1 3c92d6dbb868b8b4c26b75539771641087742761 SHA256 9a7d302016e4c4d6cc18af14514bd5112d18aeb7dc6390a3413e3e4cc71da6bd
|
||||
EBUILD fpdb-0.20.906.ebuild 1643 RMD160 ed44ee49d715458b54edbbe054eb5c9775c6ac7a SHA1 ebd8ea291ace0671d4eb264754dfb0616373a51a SHA256 a9bdad768a0ab5ef065f3e6e2e1bd89dded6e0d3b64c4771944c4aae7d163efd
|
||||
EBUILD fpdb-9999.ebuild 1685 RMD160 f06457ead33dca99c0acf830f26bbf2f8ca12cd1 SHA1 70444fa4a88439955472407ec0b072970993631a SHA256 2df59120b376bb4e5966f8a719bc881c756b3210b7a30d394ee1753efbfd706e
|
||||
MISC ChangeLog 831 RMD160 efd32886d09b0750e680716030c0034c3a280a25 SHA1 82f3eda3cd83cbba3e45d4b75593e74f3dd4f568 SHA256 d74efef05cf51ef3840ef043218c8a30c1bcccfa9d9d2e4ca1b7198ed1c91f29
|
||||
MISC metadata.xml 550 RMD160 a6fa8799f644c0882f832a12cc9e6a0f4f09ae7f SHA1 3a40c442cadb1f532e0299040c2da79e9721dd4f SHA256 b5a1c538de3786446a87479b1023cdb4f084085feb7290959619739969ce7d3b
|
||||
|
|
@ -1,12 +1,10 @@
|
|||
# Copyright 1999-2010 Gentoo Foundation
|
||||
# Distributed under the terms of the GNU General Public License v2
|
||||
# created by Steffen Schaumburg, steffen@schaumburger.info
|
||||
|
||||
inherit eutils
|
||||
inherit games
|
||||
# $Header: $
|
||||
|
||||
EAPI="2"
|
||||
NEED_PYTHON=2.5
|
||||
|
||||
inherit eutils games
|
||||
|
||||
DESCRIPTION="A free/open source tracker/HUD for use with online poker"
|
||||
HOMEPAGE="http://fpdb.wiki.sourceforge.net/"
|
||||
|
|
@ -19,18 +17,18 @@ KEYWORDS="~amd64 ~x86"
|
|||
|
||||
IUSE="graph 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
|
||||
graph? ( dev-python/numpy
|
||||
dev-python/matplotlib[gtk] )
|
||||
dev-python/python-xlib
|
||||
dev-python/pytz"
|
||||
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
|
||||
graph? ( dev-python/numpy
|
||||
dev-python/matplotlib[gtk] )
|
||||
dev-python/python-xlib
|
||||
dev-python/pytz"
|
||||
DEPEND="${RDEPEND}"
|
||||
|
||||
src_install() {
|
||||
|
|
@ -48,13 +46,13 @@ src_install() {
|
|||
newicon gfx/fpdb-icon.png ${PN}.png
|
||||
make_desktop_entry ${PN}
|
||||
|
||||
prepgamesdirs
|
||||
fperms +x "${GAMES_DATADIR}"/${PN}/pyfpdb/*.pyw
|
||||
prepgamesdirs
|
||||
}
|
||||
|
||||
pkg_postinst() {
|
||||
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 "the database and user yourself and enter it into the fpdb config."
|
||||
elog "You can find the instructions on the project's website."
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,12 +1,10 @@
|
|||
# Copyright 1999-2010 Gentoo Foundation
|
||||
# Distributed under the terms of the GNU General Public License v2
|
||||
# created by Steffen Schaumburg, steffen@schaumburger.info
|
||||
|
||||
inherit eutils
|
||||
inherit games
|
||||
# $Header: $
|
||||
|
||||
EAPI="2"
|
||||
NEED_PYTHON=2.5
|
||||
|
||||
inherit eutils games
|
||||
|
||||
DESCRIPTION="A free/open source tracker/HUD for use with online poker"
|
||||
HOMEPAGE="http://fpdb.wiki.sourceforge.net/"
|
||||
|
|
@ -17,44 +15,51 @@ SLOT="0"
|
|||
KEYWORDS="~amd64 ~x86"
|
||||
#note: this should work on other architectures too, please send me your experiences
|
||||
|
||||
IUSE="graph mysql postgres sqlite"
|
||||
IUSE="graph mysql postgres sqlite linguas_hu"
|
||||
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
|
||||
graph? ( dev-python/numpy
|
||||
dev-python/matplotlib[gtk] )
|
||||
dev-python/python-xlib
|
||||
dev-python/pytz"
|
||||
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
|
||||
graph? ( dev-python/numpy
|
||||
dev-python/matplotlib[gtk] )
|
||||
dev-python/python-xlib
|
||||
dev-python/pytz"
|
||||
DEPEND="${RDEPEND}"
|
||||
|
||||
src_install() {
|
||||
insinto "${GAMES_DATADIR}"/${PN}
|
||||
doins -r gfx
|
||||
doins -r pyfpdb
|
||||
doins readme.txt
|
||||
doins -r gfx || die "failed to install gfx directory"
|
||||
doins -r pyfpdb || die "failed to install pyfpdb directory"
|
||||
|
||||
if use linguas_hu; then
|
||||
msgfmt pyfpdb/locale/fpdb-hu_HU.po -o pyfpdb/locale/hu.mo || die "failed to create hungarian mo file"
|
||||
fi
|
||||
|
||||
domo pyfpdb/locale/*.mo || die "failed to install mo files"
|
||||
|
||||
doins readme.txt || die "failed to install readme.txt file"
|
||||
|
||||
exeinto "${GAMES_DATADIR}"/${PN}
|
||||
doexe run_fpdb.py
|
||||
doexe run_fpdb.py || die "failed to install executable run_fpdb.py"
|
||||
|
||||
dodir "${GAMES_BINDIR}"
|
||||
dosym "${GAMES_DATADIR}"/${PN}/run_fpdb.py "${GAMES_BINDIR}"/${PN}
|
||||
dosym "${GAMES_DATADIR}"/${PN}/run_fpdb.py "${GAMES_BINDIR}"/${PN} || die "failed to create symlink for starting fpdb"
|
||||
|
||||
newicon gfx/fpdb-icon.png ${PN}.png
|
||||
make_desktop_entry ${PN}
|
||||
newicon gfx/fpdb-icon.png ${PN}.png || die "failed to install fpdb icon"
|
||||
make_desktop_entry ${PN} || die "failed to create desktop entry"
|
||||
|
||||
prepgamesdirs
|
||||
fperms +x "${GAMES_DATADIR}"/${PN}/pyfpdb/*.pyw
|
||||
prepgamesdirs
|
||||
}
|
||||
|
||||
pkg_postinst() {
|
||||
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 "the database and user yourself and enter it into the fpdb config."
|
||||
elog "You can find the instructions on the project's website."
|
||||
}
|
||||
|
|
|
|||
7
packaging/gentoo/dev-readme.txt
Normal file
7
packaging/gentoo/dev-readme.txt
Normal file
|
|
@ -0,0 +1,7 @@
|
|||
Repoman currently gives the following errors for our ebuilds:
|
||||
ebuild.allmasked: This error can be ignored, as all our packages are supposed to be masked
|
||||
|
||||
Useful Links:
|
||||
http://overlays.gentoo.org/proj/sunrise/wiki/SunriseFaq
|
||||
http://www.linuxhowtos.org/manpages/1/repoman.htm
|
||||
http://www.gentoo.org/proj/en/devrel/handbook/handbook.xml The gentoo devrel handbook. Of particular relevance is the "Guides" section.
|
||||
72
packaging/gentoo/fpdb-9999.ebuild
Normal file
72
packaging/gentoo/fpdb-9999.ebuild
Normal file
|
|
@ -0,0 +1,72 @@
|
|||
# Copyright 1999-2010 Gentoo Foundation
|
||||
# Distributed under the terms of the GNU General Public License v2
|
||||
# $Header: $
|
||||
|
||||
EAPI="2"
|
||||
|
||||
inherit eutils games git
|
||||
|
||||
DESCRIPTION="A free/open source tracker/HUD for use with online poker"
|
||||
HOMEPAGE="http://fpdb.wiki.sourceforge.net/"
|
||||
EGIT_REPO_URI="git://git.assembla.com/fpdb.git"
|
||||
|
||||
LICENSE="AGPL-3"
|
||||
SLOT="0"
|
||||
KEYWORDS=""
|
||||
|
||||
IUSE="graph mysql postgres sqlite linguas_de linguas_hu"
|
||||
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
|
||||
graph? ( dev-python/numpy
|
||||
dev-python/matplotlib[gtk] )
|
||||
dev-python/python-xlib
|
||||
dev-python/pytz"
|
||||
DEPEND="${RDEPEND}"
|
||||
|
||||
src_unpack() {
|
||||
git_src_unpack
|
||||
}
|
||||
|
||||
src_install() {
|
||||
insinto "${GAMES_DATADIR}"/${PN}
|
||||
doins -r gfx
|
||||
doins -r pyfpdb
|
||||
|
||||
if use linguas_de; then
|
||||
msgfmt pyfpdb/locale/fpdb-de_DE.po -o pyfpdb/locale/de.mo
|
||||
fi
|
||||
|
||||
if use linguas_hu; then
|
||||
msgfmt pyfpdb/locale/fpdb-hu_HU.po -o pyfpdb/locale/hu.mo
|
||||
fi
|
||||
|
||||
domo pyfpdb/locale/*.mo
|
||||
|
||||
doins readme.txt
|
||||
|
||||
exeinto "${GAMES_DATADIR}"/${PN}
|
||||
doexe run_fpdb.py
|
||||
|
||||
dodir "${GAMES_BINDIR}"
|
||||
dosym "${GAMES_DATADIR}"/${PN}/run_fpdb.py "${GAMES_BINDIR}"/${PN}
|
||||
|
||||
newicon gfx/fpdb-icon.png ${PN}.png
|
||||
make_desktop_entry ${PN}
|
||||
|
||||
fperms +x "${GAMES_DATADIR}"/${PN}/pyfpdb/*.pyw
|
||||
prepgamesdirs
|
||||
}
|
||||
|
||||
pkg_postinst() {
|
||||
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."
|
||||
}
|
||||
11
packaging/gentoo/metadata.xml
Normal file
11
packaging/gentoo/metadata.xml
Normal file
|
|
@ -0,0 +1,11 @@
|
|||
<?xml version='1.0' encoding='UTF-8'?>
|
||||
<!DOCTYPE pkgmetadata SYSTEM "http://www.gentoo.org/dtd/metadata.dtd">
|
||||
<pkgmetadata>
|
||||
<longdescription>
|
||||
FPDB (Free Poker Database) is a free/open source suite of steadily growing tools to track and analyse your poker game. FPDB is able to import the hand histories that poker sites write to your computer, store additional data from each hand in a database for use in later analysis.
|
||||
</longdescription>
|
||||
<use>
|
||||
<flag name='graph'>Enable dependencies for making graphs</flag>
|
||||
</use>
|
||||
</pkgmetadata>
|
||||
|
||||
9
packaging/windows/py27-links.txt
Normal file
9
packaging/windows/py27-links.txt
Normal file
|
|
@ -0,0 +1,9 @@
|
|||
Python 2.7 ... http://python.org/ftp/python/2.7/python-2.7.msi
|
||||
pywin 214 ... https://sourceforge.net/projects/pywin32/files/pywin32/Build%20214/pywin32-214.win32-py2.7.exe/download
|
||||
matplotlib X ... not available as py27 as of 16aug2010: https://sourceforge.net/projects/matplotlib/files/matplotlib/
|
||||
pygtk X ... not available as py27 as of 16aug2010: http://ftp.gnome.org/pub/GNOME/binaries/win32/pygtk/
|
||||
pycairo X ... not available as py27 as of 16aug2010: http://ftp.gnome.org/pub/GNOME/binaries/win32/pycairo/
|
||||
pyGobject X ... not available as py27 as of 16aug2010: http://ftp.gnome.org/pub/GNOME/binaries/win32/pygobject/
|
||||
py2exe 0.6.9 ... https://sourceforge.net/projects/py2exe/files/py2exe/0.6.9/py2exe-0.6.9.win32-py2.7.exe/download
|
||||
psycopg2 ... http://www.stickpeople.com/projects/python/win-psycopg/psycopg2-2.2.2.win32-py2.7-pg8.4.4-release.exe
|
||||
|
||||
|
|
@ -103,6 +103,7 @@ Step 4 Get the fpdb GIT tree
|
|||
----------------------------
|
||||
|
||||
4.1/ Best to take a copy to work with; following steps will assume that the fpdb folder is on the Desktop
|
||||
4.2/ Edit the script in packaging/windows/py2exe_setup.py to set the fpdbver variable for this release
|
||||
|
||||
|
||||
5.3/ Install correct Numpy for this build
|
||||
|
|
@ -158,7 +159,7 @@ Step 6 Run py2exe to generate fpdb.exe
|
|||
|
||||
6.1/ Run the script to create the fpdb.exe bundle
|
||||
|
||||
dos> cd Desktop\fpdb\pyfpdb
|
||||
dos> cd Desktop\fpdb\packaging\windows
|
||||
dos> c:\python26\python.exe py2exe_setup.py py2exe
|
||||
|
||||
wait a while, watch lots of copying and whatever.
|
||||
|
|
@ -183,16 +184,14 @@ Step 8 Drag out the completed bundle
|
|||
------------------------------------
|
||||
|
||||
py2exe creates a new folder for the created software bundle, drag this out to the desktop for ease of working.
|
||||
As far as I know you cannot rerun the build if the fpdb-yyyymmdd-exe exists in the tree, so dragging this out
|
||||
also allows the build to re-run at step 6.
|
||||
|
||||
8.1/ Drag Desktop\fpdb\pyfpdb\fpdb-yyyymmdd-exe to Desktop\
|
||||
8.1/ Drag Desktop\fpdb\packaging\windows\fpdb-n.nn.nnn to Desktop\
|
||||
|
||||
|
||||
Step 9 Initial run
|
||||
------------------
|
||||
|
||||
9.1/ Open the Desktop\fpdb-yyyymmdd-exe folder
|
||||
9.1/ Open the Desktop\fpdb-n.nn.nnn folder
|
||||
9.2/ In explorer...tools...folder options...View uncheck "Hide extensions for known file types"
|
||||
9.3/ Double click run_fpdb.bat
|
||||
9.4/ check the contents of pyfpdb\fpdb.exe.log, deal with any errors thrown
|
||||
|
|
@ -222,7 +221,7 @@ pyfpdb/share/man
|
|||
Step 12 rename folder
|
||||
---------------------
|
||||
|
||||
Rename the folder to something meaningful to the community. If you have built for NoSSE, append anyCPU to the directory name.
|
||||
If needed, 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
|
||||
|
|
|
|||
|
|
@ -32,14 +32,10 @@ Py2exe script for fpdb.
|
|||
|
||||
#HOW TO USE this script:
|
||||
#
|
||||
#- cd to the folder where this script is stored, usually .../pyfpdb.
|
||||
# [If there are build and dist subfolders present , delete them to get
|
||||
# rid of earlier builds. Update: script now does this for you]
|
||||
#- Run the script with "py2exe_setup.py py2exe"
|
||||
#- You will frequently get messages about missing .dll files. E. g.,
|
||||
# MSVCP90.dll. These are somewhere in your windows install, so you
|
||||
# can just copy them to your working folder. (or just assume other
|
||||
# person will have them? any copyright issues with including them?)
|
||||
#- cd to the folder where this script is stored, usually ...packaging/windows
|
||||
#- Run the script with python "py2exe_setup.py py2exe"
|
||||
#- You will frequently get messages about missing .dll files.just assume other
|
||||
# person will have them? we have copyright issues including some dll's
|
||||
#- If it works, you'll have a new dir fpdb-YYYYMMDD-exe which should
|
||||
# contain 2 dirs; gfx and pyfpdb and run_fpdb.bat
|
||||
#- [ This bit is now automated:
|
||||
|
|
@ -49,25 +45,10 @@ Py2exe script for fpdb.
|
|||
#- You can (should) then prune the etc/, lib/ and share/ folders to
|
||||
# remove components we don't need. (see output at end of program run)
|
||||
|
||||
# sqlcoder notes: this worked for me with the following notes:
|
||||
#- I used the following versions:
|
||||
# python 2.5.4
|
||||
# gtk+ 2.14.7 (gtk_2.14.7-20090119)
|
||||
# pycairo 1.4.12-2
|
||||
# pygobject 2.14.2-2
|
||||
# pygtk 2.12.1-3
|
||||
# matplotlib 0.98.3
|
||||
# numpy 1.4.0
|
||||
# py2exe-0.6.9 for python 2.5
|
||||
#
|
||||
#- I also copied these dlls manually from <gtk>/bin to /dist :
|
||||
#
|
||||
# libgobject-2.0-0.dll
|
||||
# libgdk-win32-2.0-0.dll
|
||||
#
|
||||
# Now updated to work with python 2.6 + related dependencies
|
||||
# See walkthrough in packaging directory for versions used
|
||||
# Updates to this script have broken python 2.5 compatibility (gio module, msvcr71 references now msvcp90)
|
||||
|
||||
# steffeN: Doesnt seem necessary to gettext-ify this, but feel free to if you disagree
|
||||
# Gimick: restructure to allow script to run from packaging/windows directory, and not to write to source pyfpdb
|
||||
|
||||
|
||||
import os
|
||||
|
|
@ -85,33 +66,14 @@ import py2exe
|
|||
import glob
|
||||
import matplotlib
|
||||
import shutil
|
||||
from datetime import date
|
||||
#from datetime import date
|
||||
|
||||
|
||||
origIsSystemDLL = py2exe.build_exe.isSystemDLL
|
||||
def isSystemDLL(pathname):
|
||||
#dwmapi appears to be vista-specific file, not XP
|
||||
if os.path.basename(pathname).lower() in ("dwmapi.dll"):
|
||||
return 0
|
||||
return origIsSystemDLL(pathname)
|
||||
py2exe.build_exe.isSystemDLL = isSystemDLL
|
||||
|
||||
|
||||
def remove_tree(top):
|
||||
# Delete everything reachable from the directory named in 'top',
|
||||
# assuming there are no symbolic links.
|
||||
# CAUTION: This is dangerous! For example, if top == '/', it
|
||||
# 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','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:
|
||||
os.remove(os.path.join(root, name))
|
||||
for name in dirs:
|
||||
os.rmdir(os.path.join(root, name))
|
||||
os.rmdir(top)
|
||||
|
||||
def test_and_remove(top):
|
||||
if os.path.exists(top):
|
||||
|
|
@ -121,30 +83,63 @@ def test_and_remove(top):
|
|||
print "Unexpected file '"+top+"' found. Exiting."
|
||||
exit()
|
||||
|
||||
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
|
||||
#xxx = sys.stdin.readline().rstrip()
|
||||
dist_dirname = r'fpdb-' + today + '-exe'
|
||||
dist_dir = r'..\fpdb-' + today + '-exe'
|
||||
print
|
||||
def remove_tree(top):
|
||||
# Delete everything reachable from the directory named in 'top',
|
||||
# assuming there are no symbolic links.
|
||||
# CAUTION: This is dangerous! For example, if top == '/', it
|
||||
# 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',distdir) and os.path.basename(os.getcwd()) == 'windows':
|
||||
#print "removing directory '"+top+"' ..."
|
||||
for root, dirs, files in os.walk(top, topdown=False):
|
||||
for name in files:
|
||||
os.remove(os.path.join(root, name))
|
||||
for name in dirs:
|
||||
os.rmdir(os.path.join(root, name))
|
||||
os.rmdir(top)
|
||||
|
||||
# remove build and dist dirs if they exist
|
||||
def copy_tree(source,destination):
|
||||
source = source.replace('\\', '\\\\')
|
||||
destination = destination.replace('\\', '\\\\')
|
||||
print "*** Copying " + source + " to " + destination + " ***"
|
||||
shutil.copytree( source, destination )
|
||||
|
||||
def copy_file(source,destination):
|
||||
source = source.replace('\\', '\\\\')
|
||||
destination = destination.replace('\\', '\\\\')
|
||||
print "*** Copying " + source + " to " + destination + " ***"
|
||||
shutil.copy( source, destination )
|
||||
|
||||
|
||||
fpdbver = '0.20.906'
|
||||
|
||||
distdir = r'fpdb-' + fpdbver
|
||||
rootdir = r'../../' #cwd is normally /packaging/windows
|
||||
pydir = rootdir+'pyfpdb/'
|
||||
gfxdir = rootdir+'gfx/'
|
||||
sys.path.append( pydir ) # allows fpdb modules to be found by options/includes below
|
||||
|
||||
print "\n" + r"Output will be created in "+distdir
|
||||
|
||||
print "*** Cleaning working folders ***"
|
||||
test_and_remove('dist')
|
||||
test_and_remove('build')
|
||||
test_and_remove('pyfpdb')
|
||||
test_and_remove(distdir)
|
||||
|
||||
test_and_remove(dist_dirname)
|
||||
print "*** Building now in dist folder ***"
|
||||
|
||||
origIsSystemDLL = py2exe.build_exe.isSystemDLL
|
||||
py2exe.build_exe.isSystemDLL = isSystemDLL
|
||||
|
||||
setup(
|
||||
name = 'fpdb',
|
||||
description = 'Free Poker DataBase',
|
||||
version = '0.20.903',
|
||||
version = fpdbver,
|
||||
|
||||
windows = [ {'script': 'fpdb.pyw', "icon_resources": [(1, "../gfx/fpdb_large_icon.ico")]},
|
||||
{'script': 'HUD_main.pyw', },
|
||||
{'script': 'Configuration.py', }
|
||||
windows = [ {'script': pydir+'fpdb.pyw', "icon_resources": [(1, gfxdir+"fpdb_large_icon.ico")]},
|
||||
{'script': pydir+'HUD_main.pyw', },
|
||||
{'script': pydir+'Configuration.py', }
|
||||
],
|
||||
|
||||
options = {'py2exe': {
|
||||
|
|
@ -157,74 +152,56 @@ setup(
|
|||
,'PartyPokerToFpdb', 'PokerStarsToFpdb'
|
||||
,'UltimateBetToFpdb', 'Win2dayToFpdb'
|
||||
],
|
||||
'excludes' : ['_tkagg', '_agg2', 'cocoaagg', 'fltkagg'], # surely we need this? '_gtkagg'
|
||||
'excludes' : ['_tkagg', '_agg2', 'cocoaagg', 'fltkagg'],
|
||||
'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', '../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')
|
||||
#,(r'matplotlibdata', glob.glob(r'c:\python25\Lib\site-packages\matplotlib\mpl-data\*'))
|
||||
# this code will not walk a tree
|
||||
# Note: cwd for 1st value is packaging/windows/dist (this is confusing BTW)
|
||||
# Note: only include files here which are to be put into the package pyfpdb folder or subfolders
|
||||
|
||||
data_files = [('', glob.glob(rootdir+'*.txt'))
|
||||
,('', [pydir+'HUD_config.xml.example',pydir+'Cards01.png', pydir+'logging.conf'])
|
||||
] + matplotlib.get_py2exe_datafiles()
|
||||
)
|
||||
|
||||
# rename completed output package as pyfpdb
|
||||
os.rename('dist', 'pyfpdb')
|
||||
# ,(distdir, [rootdir+'run_fpdb.bat'])
|
||||
# ,(distdir+r'\gfx', glob.glob(gfxdir+'*.*'))
|
||||
# ] +
|
||||
print "*** py2exe build phase complete ***"
|
||||
|
||||
# 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 )
|
||||
# copy zone info and fpdb translation folders
|
||||
copy_tree (r'c:\python26\Lib\site-packages\pytz\zoneinfo', os.path.join(r'dist', 'zoneinfo'))
|
||||
copy_tree (pydir+r'locale', os.path.join(r'dist', 'locale'))
|
||||
|
||||
# shunt pyfpdb package over to the distribution folder
|
||||
dest = os.path.join(dist_dirname, 'pyfpdb')
|
||||
# print "try renaming pyfpdb to", dest
|
||||
dest = dest.replace('\\', '\\\\')
|
||||
# print "dest is now", dest
|
||||
os.rename( 'pyfpdb', dest )
|
||||
# create distribution folder and populate with gfx + bat
|
||||
copy_tree (gfxdir, os.path.join(distdir, 'gfx'))
|
||||
copy_file (rootdir+'run_fpdb.bat', distdir)
|
||||
|
||||
# prompt for gtk location
|
||||
print "*** Renaming dist folder as distribution pyfpdb folder ***"
|
||||
dest = os.path.join(distdir, 'pyfpdb')
|
||||
os.rename( 'dist', dest )
|
||||
|
||||
print "*** copying GTK runtime ***"
|
||||
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
|
||||
print "Enter directory name for GTK (e.g. c:/gtk) : ", # 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')
|
||||
src = src.replace('\\', '\\\\')
|
||||
shutil.copy( src, dest )
|
||||
print "*** copying GTK runtime ***"
|
||||
dest = os.path.join(distdir, 'pyfpdb')
|
||||
copy_file(os.path.join(gtk_dir, 'bin', 'libgdk-win32-2.0-0.dll'), dest )
|
||||
copy_file(os.path.join(gtk_dir, 'bin', 'libgobject-2.0-0.dll'), dest)
|
||||
copy_tree(os.path.join(gtk_dir, 'etc'), os.path.join(dest, 'etc'))
|
||||
copy_tree(os.path.join(gtk_dir, 'lib'), os.path.join(dest, 'lib'))
|
||||
copy_tree(os.path.join(gtk_dir, 'share'), os.path.join(dest, 'share'))
|
||||
|
||||
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')
|
||||
dest_dir = dest_dir.replace('\\', '\\\\')
|
||||
shutil.copytree( src_dir, dest_dir )
|
||||
|
||||
src_dir = os.path.join(gtk_dir, 'lib')
|
||||
src_dir = src_dir.replace('\\', '\\\\')
|
||||
dest_dir = os.path.join(dest, 'lib')
|
||||
dest_dir = dest_dir.replace('\\', '\\\\')
|
||||
shutil.copytree( src_dir, dest_dir )
|
||||
|
||||
src_dir = os.path.join(gtk_dir, 'share')
|
||||
src_dir = src_dir.replace('\\', '\\\\')
|
||||
dest_dir = os.path.join(dest, 'share')
|
||||
dest_dir = dest_dir.replace('\\', '\\\\')
|
||||
shutil.copytree( src_dir, dest_dir )
|
||||
|
||||
print "\nIf py2exe was successful you should now have a new dir"
|
||||
print dist_dirname+" in your pyfpdb dir"
|
||||
print "*** All done! ***"
|
||||
test_and_remove('build')
|
||||
print distdir+" is in the pyfpdb dir"
|
||||
print """
|
||||
The following dirs can probably removed to make the final package smaller:
|
||||
|
||||
|
|
@ -242,5 +219,3 @@ pyfpdb/share/themes/Default
|
|||
|
||||
Use 7-zip to zip up the distribution and create a self extracting archive and that's it!
|
||||
"""
|
||||
|
||||
|
||||
|
|
@ -18,6 +18,9 @@
|
|||
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
########################################################################
|
||||
|
||||
import L10n
|
||||
_ = L10n.get_translation()
|
||||
|
||||
# TODO: I have no idea if AP has multi-currency options, i just copied the regex out of Everleaf converter for the currency symbols.. weeeeee - Eric
|
||||
import sys
|
||||
import logging
|
||||
|
|
@ -42,7 +45,13 @@ class Absolute(HandHistoryConverter):
|
|||
#Seat 6 - FETS63 ($0.75 in chips)
|
||||
#Board [10s 5d Kh Qh 8c]
|
||||
|
||||
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_GameInfo = re.compile(ur"""^Stage #(C?[0-9]+):\s+
|
||||
(?P<GAME>Holdem|Seven\sCard\sHi\/L|HORSE)
|
||||
(?:\s\(1\son\s1\)|)?\s+?
|
||||
(?P<LIMIT>No Limit|Pot\sLimit|Normal|)?\s?
|
||||
(?P<CURRENCY>\$|\s€|)
|
||||
(?P<SB>[.0-9]+)/?(?:\$|\s€|)(?P<BB>[.0-9]+)?
|
||||
""", re.MULTILINE|re.VERBOSE)
|
||||
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 #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)
|
||||
|
|
@ -50,12 +59,6 @@ class Absolute(HandHistoryConverter):
|
|||
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)
|
||||
re_Board = re.compile(ur"\[(?P<CARDS>[^\]]*)\]? *$", re.MULTILINE)
|
||||
# re_GameInfo = re.compile(ur"^(Blinds )?(?P<CURRENCY>\$| €|)(?P<SB>[.0-9]+)/(?:\$| €)?(?P<BB>[.0-9]+) (?P<LIMIT>NL|PL|) ?(?P<GAME>(Holdem|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|EUR|)|new player|All-in) \)", re.MULTILINE)
|
||||
# re_Board = re.compile(ur"\[ (?P<CARDS>.+) \]")
|
||||
|
||||
|
||||
def compilePlayerRegexs(self, hand):
|
||||
|
|
@ -112,16 +115,21 @@ class Absolute(HandHistoryConverter):
|
|||
|
||||
m = self.re_GameInfo.search(handText)
|
||||
if not m:
|
||||
return None
|
||||
tmp = handText[0:100]
|
||||
log.error(_("determineGameType: Unable to recognise gametype from: '%s'") % tmp)
|
||||
log.error(_("determineGameType: Raising FpdbParseError"))
|
||||
raise FpdbParseError(_("Unable to recognise gametype from: '%s'") % tmp)
|
||||
|
||||
|
||||
mg = m.groupdict()
|
||||
|
||||
# translations from captured groups to our info strings
|
||||
limits = { 'No Limit':'nl', 'Pot Limit':'pl', 'Normal':'fl', 'Limit':'fl'}
|
||||
games = { # base, category
|
||||
"Holdem" : ('hold','holdem'),
|
||||
"Holdem" : ('hold','holdem'),
|
||||
'Omaha' : ('hold','omahahi'),
|
||||
'Razz' : ('stud','razz'),
|
||||
'Seven Card Hi/L' : ('stud','studhilo'),
|
||||
'7 Card Stud' : ('stud','studhi')
|
||||
}
|
||||
currencies = { u' €':'EUR', '$':'USD', '':'T$' }
|
||||
|
|
@ -164,7 +172,7 @@ class Absolute(HandHistoryConverter):
|
|||
def readHandInfo(self, hand):
|
||||
m = self.re_HandInfo.search(hand.handText)
|
||||
if(m == None):
|
||||
logging.info("Didn't match re_HandInfo")
|
||||
logging.info(_("Didn't match re_HandInfo"))
|
||||
logging.info(hand.handText)
|
||||
return None
|
||||
logging.debug("HID %s, Table %s" % (m.group('HID'), m.group('TABLE')))
|
||||
|
|
@ -221,7 +229,7 @@ class Absolute(HandHistoryConverter):
|
|||
hand.setCommunityCards(street=street, cards=cards)
|
||||
|
||||
def readAntes(self, hand):
|
||||
logging.debug("reading antes")
|
||||
logging.debug(_("reading antes"))
|
||||
m = self.re_Antes.finditer(hand.handText)
|
||||
for player in m:
|
||||
logging.debug("hand.addAnte(%s,%s)" %(player.group('PNAME'), player.group('ANTE')))
|
||||
|
|
@ -230,17 +238,17 @@ class Absolute(HandHistoryConverter):
|
|||
def readBringIn(self, hand):
|
||||
m = self.re_BringIn.search(hand.handText,re.DOTALL)
|
||||
if m:
|
||||
logging.debug("Player bringing in: %s for %s" %(m.group('PNAME'), m.group('BRINGIN')))
|
||||
logging.debug(_("Player bringing in: %s for %s" %(m.group('PNAME'), m.group('BRINGIN'))))
|
||||
hand.addBringIn(m.group('PNAME'), m.group('BRINGIN'))
|
||||
else:
|
||||
logging.warning("No bringin found.")
|
||||
logging.warning(_("No bringin found."))
|
||||
|
||||
def readBlinds(self, hand):
|
||||
m = self.re_PostSB.search(hand.handText)
|
||||
if m is not None:
|
||||
hand.addBlind(m.group('PNAME'), 'small blind', m.group('SB'))
|
||||
else:
|
||||
logging.debug("No small blind")
|
||||
logging.debug(_("No small blind"))
|
||||
hand.addBlind(None, None, None)
|
||||
for a in self.re_PostBB.finditer(hand.handText):
|
||||
hand.addBlind(a.group('PNAME'), 'big blind', a.group('BB'))
|
||||
|
|
@ -267,7 +275,7 @@ class Absolute(HandHistoryConverter):
|
|||
|
||||
def readStudPlayerCards(self, hand, street):
|
||||
# lol. see Plymouth.txt
|
||||
logging.warning("Absolute readStudPlayerCards is only a stub.")
|
||||
logging.warning(_("Absolute readStudPlayerCards is only a stub."))
|
||||
#~ if street in ('THIRD', 'FOURTH', 'FIFTH', 'SIXTH'):
|
||||
#~ hand.addPlayerCards(player = player.group('PNAME'), street = street, closed = [], open = [])
|
||||
|
||||
|
|
@ -290,7 +298,7 @@ class Absolute(HandHistoryConverter):
|
|||
elif action.group('ATYPE') == ' complete to': # TODO: not supported yet ?
|
||||
hand.addComplete( street, action.group('PNAME'), action.group('BET'))
|
||||
else:
|
||||
logging.debug("Unimplemented readAction: %s %s" %(action.group('PNAME'),action.group('ATYPE'),))
|
||||
logging.debug(_("Unimplemented readAction: %s %s" %(action.group('PNAME'),action.group('ATYPE'),)))
|
||||
|
||||
|
||||
def readShowdownActions(self, hand):
|
||||
|
|
@ -334,9 +342,9 @@ if __name__ == "__main__":
|
|||
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="-")
|
||||
parser.add_option("-f", "--follow", dest="follow", help="follow (tail -f) the input", action="store_true", default=False)
|
||||
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="-")
|
||||
parser.add_option("-f", "--follow", dest="follow", help=_("follow (tail -f) the input"), action="store_true", default=False)
|
||||
parser.add_option("-q", "--quiet",
|
||||
action="store_const", const=logging.CRITICAL, dest="verbosity", default=logging.INFO)
|
||||
parser.add_option("-v", "--verbose",
|
||||
|
|
|
|||
|
|
@ -15,6 +15,8 @@
|
|||
#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.
|
||||
|
||||
#TODO: gettextify if file is used again
|
||||
|
||||
from decimal import Decimal
|
||||
|
||||
from sqlalchemy import types
|
||||
|
|
|
|||
|
|
@ -19,6 +19,8 @@
|
|||
This package contains all classes to be mapped and mappers themselves
|
||||
"""
|
||||
|
||||
#TODO: gettextify if file is used again
|
||||
|
||||
import logging
|
||||
import re
|
||||
from decimal import Decimal
|
||||
|
|
|
|||
|
|
@ -19,6 +19,8 @@
|
|||
Contains all sqlalchemy tables
|
||||
"""
|
||||
|
||||
#TODO: gettextify if file is used again
|
||||
|
||||
from sqlalchemy import Table, Float, Column, Integer, String, MetaData, \
|
||||
ForeignKey, Boolean, SmallInteger, DateTime, Text, Index, CHAR, \
|
||||
PickleType, Unicode
|
||||
|
|
@ -448,7 +450,6 @@ def sss():
|
|||
self.settings['os']="windows"
|
||||
|
||||
self.settings.update(self.config.get_db_parameters())
|
||||
self.settings.update(self.config.get_tv_parameters())
|
||||
self.settings.update(self.config.get_import_parameters())
|
||||
self.settings.update(self.config.get_default_paths())
|
||||
|
||||
|
|
|
|||
|
|
@ -15,6 +15,9 @@
|
|||
#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 L10n
|
||||
_ = L10n.get_translation()
|
||||
|
||||
import os
|
||||
import re
|
||||
import codecs
|
||||
|
|
@ -23,6 +26,7 @@ import HandHistoryConverter
|
|||
import Configuration
|
||||
import sys
|
||||
|
||||
|
||||
(options, argv) = Options.fpdb_options()
|
||||
config = Configuration.Config()
|
||||
|
||||
|
|
@ -40,13 +44,13 @@ if os.path.exists(options.infile):
|
|||
filecontents = in_fh.read()
|
||||
in_fh.close()
|
||||
else:
|
||||
print "Could not find file %s" % options.infile
|
||||
print _("Could not find file %s") % options.infile
|
||||
exit(1)
|
||||
|
||||
m = hhc.re_PlayerInfo.finditer(filecontents)
|
||||
|
||||
outfile = options.infile+".anon"
|
||||
print "Output being written to", outfile
|
||||
print _("Output being written to"), outfile
|
||||
|
||||
savestdout = sys.stdout
|
||||
fsock = open(outfile,"w")
|
||||
|
|
|
|||
|
|
@ -18,6 +18,9 @@
|
|||
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
########################################################################
|
||||
|
||||
import L10n
|
||||
_ = L10n.get_translation()
|
||||
|
||||
import sys
|
||||
import logging
|
||||
from HandHistoryConverter import *
|
||||
|
|
@ -32,9 +35,9 @@ class Betfair(HandHistoryConverter):
|
|||
siteId = 7 # Needs to match id entry in Sites database
|
||||
|
||||
# Static regexes
|
||||
re_GameInfo = re.compile("^(?P<LIMIT>NL|PL|) (?P<CURRENCY>\$|)?(?P<SB>[.0-9]+)/\$?(?P<BB>[.0-9]+) (?P<GAME>(Texas Hold\'em|Omaha Hi|Razz))", re.MULTILINE)
|
||||
re_GameInfo = re.compile("^(?P<LIMIT>NL|PL|) (?P<CURRENCY>\$|)?(?P<SB>[.0-9]+)/\$?(?P<BB>[.0-9]+) (?P<GAME>(Texas Hold\'em|Omaha Hi|Omaha|Razz))", re.MULTILINE)
|
||||
re_SplitHands = re.compile(r'\n\n+')
|
||||
re_HandInfo = re.compile("\*\*\*\*\* Betfair Poker Hand History for Game (?P<HID>[0-9]+) \*\*\*\*\*\n(?P<LIMIT>NL|PL|) (?P<CURRENCY>\$|)?(?P<SB>[.0-9]+)/\$?(?P<BB>[.0-9]+) (?P<GAMETYPE>(Texas Hold\'em|Omaha Hi|Razz)) - (?P<DATETIME>[a-zA-Z]+, [a-zA-Z]+ \d+, \d\d:\d\d:\d\d GMT \d\d\d\d)\nTable (?P<TABLE>[ a-zA-Z0-9]+) \d-max \(Real Money\)\nSeat (?P<BUTTON>[0-9]+)", re.MULTILINE)
|
||||
re_HandInfo = re.compile("\*\*\*\*\* Betfair Poker Hand History for Game (?P<HID>[0-9]+) \*\*\*\*\*\n(?P<LIMIT>NL|PL|) (?P<CURRENCY>\$|)?(?P<SB>[.0-9]+)/\$?(?P<BB>[.0-9]+) (?P<GAMETYPE>(Texas Hold\'em|Omaha|Razz)) - (?P<DATETIME>[a-zA-Z]+, [a-zA-Z]+ \d+, \d\d:\d\d:\d\d GMT \d\d\d\d)\nTable (?P<TABLE>[ a-zA-Z0-9]+) \d-max \(Real Money\)\nSeat (?P<BUTTON>[0-9]+)", re.MULTILINE)
|
||||
re_Button = re.compile(ur"^Seat (?P<BUTTON>\d+) is the button", re.MULTILINE)
|
||||
re_PlayerInfo = re.compile("Seat (?P<SEAT>[0-9]+): (?P<PNAME>.*)\s\(\s(\$(?P<CASH>[.0-9]+)) \)")
|
||||
re_Board = re.compile(ur"\[ (?P<CARDS>.+) \]")
|
||||
|
|
@ -60,7 +63,8 @@ class Betfair(HandHistoryConverter):
|
|||
self.re_ShownCards = re.compile(r"%s (?P<SEAT>[0-9]+) (?P<CARDS>adsfasdf)" % player_re, re.MULTILINE)
|
||||
|
||||
def readSupportedGames(self):
|
||||
return [["ring", "hold", "nl"]
|
||||
return [["ring", "hold", "nl"],
|
||||
["ring", "hold", "pl"]
|
||||
]
|
||||
|
||||
def determineGameType(self, handText):
|
||||
|
|
@ -68,8 +72,10 @@ class Betfair(HandHistoryConverter):
|
|||
|
||||
m = self.re_GameInfo.search(handText)
|
||||
if not m:
|
||||
logging.info('GameInfo regex did not match')
|
||||
return None
|
||||
tmp = handText[0:100]
|
||||
log.error(_("determineGameType: Unable to recognise gametype from: '%s'") % tmp)
|
||||
log.error(_("determineGameType: Raising FpdbParseError"))
|
||||
raise FpdbParseError(_("Unable to recognise gametype from: '%s'") % tmp)
|
||||
|
||||
mg = m.groupdict()
|
||||
|
||||
|
|
@ -78,6 +84,7 @@ class Betfair(HandHistoryConverter):
|
|||
games = { # base, category
|
||||
"Texas Hold'em" : ('hold','holdem'),
|
||||
'Omaha Hi' : ('hold','omahahi'),
|
||||
'Omaha' : ('hold','omahahi'),
|
||||
'Razz' : ('stud','razz'),
|
||||
'7 Card Stud' : ('stud','studhi')
|
||||
}
|
||||
|
|
@ -92,16 +99,14 @@ class Betfair(HandHistoryConverter):
|
|||
info['bb'] = mg['BB']
|
||||
if 'CURRENCY' in mg:
|
||||
info['currency'] = currencies[mg['CURRENCY']]
|
||||
# NB: SB, BB must be interpreted as blinds or bets depending on limit type.
|
||||
|
||||
return info
|
||||
|
||||
def readHandInfo(self, hand):
|
||||
m = self.re_HandInfo.search(hand.handText)
|
||||
if(m == None):
|
||||
logging.info("Didn't match re_HandInfo")
|
||||
logging.info(hand.handText)
|
||||
return None
|
||||
log.error(_("Didn't match re_HandInfo"))
|
||||
raise FpdbParseError(_("No match in readHandInfo."))
|
||||
logging.debug("HID %s, Table %s" % (m.group('HID'), m.group('TABLE')))
|
||||
hand.handid = m.group('HID')
|
||||
hand.tablename = m.group('TABLE')
|
||||
|
|
@ -115,7 +120,7 @@ class Betfair(HandHistoryConverter):
|
|||
|
||||
#Shouldn't really dip into the Hand object, but i've no idea how to tell the length of iter m
|
||||
if len(hand.players) < 2:
|
||||
logging.info("readPlayerStacks: Less than 2 players found in a hand")
|
||||
logging.info(_("readPlayerStacks: Less than 2 players found in a hand"))
|
||||
|
||||
def markStreets(self, hand):
|
||||
m = re.search(r"\*\* Dealing down cards \*\*(?P<PREFLOP>.+(?=\*\* Dealing Flop \*\*)|.+)"
|
||||
|
|
@ -152,10 +157,10 @@ class Betfair(HandHistoryConverter):
|
|||
def readBringIn(self, hand):
|
||||
m = self.re_BringIn.search(hand.handText,re.DOTALL)
|
||||
if m:
|
||||
logging.debug("Player bringing in: %s for %s" %(m.group('PNAME'), m.group('BRINGIN')))
|
||||
logging.debug(_("Player bringing in: %s for %s" %(m.group('PNAME'), m.group('BRINGIN'))))
|
||||
hand.addBringIn(m.group('PNAME'), m.group('BRINGIN'))
|
||||
else:
|
||||
logging.warning("No bringin found")
|
||||
logging.warning(_("No bringin found"))
|
||||
|
||||
def readButton(self, hand):
|
||||
hand.buttonpos = int(self.re_Button.search(hand.handText).group('BUTTON'))
|
||||
|
|
@ -191,7 +196,7 @@ class Betfair(HandHistoryConverter):
|
|||
elif action.group('ATYPE') == 'checks':
|
||||
hand.addCheck( street, action.group('PNAME'))
|
||||
else:
|
||||
sys.stderr.write( "DEBUG: unimplemented readAction: '%s' '%s'" %(action.group('PNAME'),action.group('ATYPE'),))
|
||||
sys.stderr.write( _("DEBUG: unimplemented readAction: '%s' '%s'") %(action.group('PNAME'),action.group('ATYPE'),))
|
||||
|
||||
|
||||
def readShowdownActions(self, hand):
|
||||
|
|
@ -214,9 +219,9 @@ class Betfair(HandHistoryConverter):
|
|||
|
||||
if __name__ == "__main__":
|
||||
parser = OptionParser()
|
||||
parser.add_option("-i", "--input", dest="ipath", help="parse input hand history", default="regression-test-files/betfair/befair.02.04.txt")
|
||||
parser.add_option("-o", "--output", dest="opath", help="output translation to", default="-")
|
||||
parser.add_option("-f", "--follow", dest="follow", help="follow (tail -f) the input", action="store_true", default=False)
|
||||
parser.add_option("-i", "--input", dest="ipath", help=_("parse input hand history"), default="regression-test-files/betfair/befair.02.04.txt")
|
||||
parser.add_option("-o", "--output", dest="opath", help=_("output translation to"), default="-")
|
||||
parser.add_option("-f", "--follow", dest="follow", help=_("follow (tail -f) the input"), action="store_true", default=False)
|
||||
parser.add_option("-q", "--quiet",
|
||||
action="store_const", const=logging.CRITICAL, dest="verbosity", default=logging.INFO)
|
||||
parser.add_option("-v", "--verbose",
|
||||
|
|
|
|||
|
|
@ -19,11 +19,13 @@
|
|||
|
||||
########################################################################
|
||||
|
||||
import L10n
|
||||
_ = L10n.get_translation()
|
||||
|
||||
# This code is based heavily on EverleafToFpdb.py, by Carl Gherardi
|
||||
#
|
||||
# TODO:
|
||||
#
|
||||
# -- No siteID assigned
|
||||
# -- No support for games other than NL hold 'em cash. Hand histories for other
|
||||
# games required
|
||||
# -- No support for limit hold 'em yet, though this would be easy to add
|
||||
|
|
@ -53,6 +55,7 @@ import logging
|
|||
from HandHistoryConverter import *
|
||||
from decimal import Decimal
|
||||
|
||||
|
||||
class Carbon(HandHistoryConverter):
|
||||
|
||||
sitename = "Carbon"
|
||||
|
|
@ -73,8 +76,8 @@ class Carbon(HandHistoryConverter):
|
|||
# The following are also static regexes: there is no need to call
|
||||
# compilePlayerRegexes (which does nothing), since players are identified
|
||||
# not by name but by seat number
|
||||
re_PostSB = re.compile(r'<event sequence="[0-9]+" type="(SMALL_BLIND|RETURN_BLIND)" player="(?P<PSEAT>[0-9])" amount="(?P<SB>[.0-9]+)"/>', re.MULTILINE)
|
||||
re_PostBB = re.compile(r'<event sequence="[0-9]+" type="(BIG_BLIND|INITIAL_BLIND)" player="(?P<PSEAT>[0-9])" amount="(?P<BB>[.0-9]+)"/>', re.MULTILINE)
|
||||
re_PostSB = re.compile(r'<event sequence="[0-9]+" type="(SMALL_BLIND|RETURN_BLIND)" (?P<TIMESTAMP>timestamp="[0-9]+" )?player="(?P<PSEAT>[0-9])" amount="(?P<SB>[.0-9]+)"/>', re.MULTILINE)
|
||||
re_PostBB = re.compile(r'<event sequence="[0-9]+" type="(BIG_BLIND|INITIAL_BLIND)" (?P<TIMESTAMP>timestamp="[0-9]+" )?player="(?P<PSEAT>[0-9])" amount="(?P<BB>[.0-9]+)"/>', re.MULTILINE)
|
||||
re_PostBoth = re.compile(r'<event sequence="[0-9]+" type="(RETURN_BLIND)" player="(?P<PSEAT>[0-9])" amount="(?P<SBBB>[.0-9]+)"/>', re.MULTILINE)
|
||||
#re_Antes = ???
|
||||
#re_BringIn = ???
|
||||
|
|
@ -119,7 +122,15 @@ or None if we fail to get the info """
|
|||
# a hand history file; hence it is not supplied with the second
|
||||
# and subsequent hands. In these cases we use the value previously
|
||||
# stored.
|
||||
return self.info
|
||||
try:
|
||||
self.info
|
||||
return self.info
|
||||
except AttributeError:
|
||||
tmp = handText[0:100]
|
||||
log.error(_("determineGameType: Unable to recognise gametype from: '%s'") % tmp)
|
||||
log.error(_("determineGameType: Raising FpdbParseError"))
|
||||
raise FpdbParseError(_("Unable to recognise gametype from: '%s'") % tmp)
|
||||
|
||||
self.info = {}
|
||||
mg = m.groupdict()
|
||||
|
||||
|
|
@ -148,9 +159,9 @@ or None if we fail to get the info """
|
|||
def readHandInfo(self, hand):
|
||||
m = self.re_HandInfo.search(hand.handText)
|
||||
if m is None:
|
||||
logging.info("Didn't match re_HandInfo")
|
||||
logging.info(_("Didn't match re_HandInfo"))
|
||||
logging.info(hand.handText)
|
||||
return None
|
||||
raise FpdbParseError(_("No match in readHandInfo."))
|
||||
logging.debug("HID %s-%s, Table %s" % (m.group('HID1'),
|
||||
m.group('HID2'), m.group('TABLE')[:-1]))
|
||||
hand.handid = m.group('HID1') + m.group('HID2')
|
||||
|
|
@ -161,7 +172,7 @@ or None if we fail to get the info """
|
|||
# Check that the hand is complete up to the awarding of the pot; if
|
||||
# not, the hand is unparseable
|
||||
if self.re_EndOfHand.search(hand.handText) is None:
|
||||
raise FpdbParseError(hid=m.group('HID1') + "-" + m.group('HID2'))
|
||||
raise FpdbParseError("readHandInfo failed: HID: '%s' HID2: '%s'" %(m.group('HID1'), m.group('HID2')))
|
||||
|
||||
def readPlayerStacks(self, hand):
|
||||
m = self.re_PlayerInfo.finditer(hand.handText)
|
||||
|
|
@ -201,15 +212,13 @@ or None if we fail to get the info """
|
|||
pass # ???
|
||||
|
||||
def readBlinds(self, hand):
|
||||
try:
|
||||
m = self.re_PostSB.search(hand.handText)
|
||||
hand.addBlind(self.playerNameFromSeatNo(m.group('PSEAT'), hand),
|
||||
'small blind', m.group('SB'))
|
||||
except: # no small blind
|
||||
hand.addBlind(None, None, None)
|
||||
for a in self.re_PostSB.finditer(hand.handText):
|
||||
#print "DEBUG: found sb: '%s' '%s'" %(self.playerNameFromSeatNo(a.group('PSEAT'), hand), a.group('SB'))
|
||||
hand.addBlind(self.playerNameFromSeatNo(a.group('PSEAT'), hand),'small blind', a.group('SB'))
|
||||
|
||||
for a in self.re_PostBB.finditer(hand.handText):
|
||||
hand.addBlind(self.playerNameFromSeatNo(a.group('PSEAT'), hand),
|
||||
'big blind', a.group('BB'))
|
||||
#print "DEBUG: found bb: '%s' '%s'" %(self.playerNameFromSeatNo(a.group('PSEAT'), hand), a.group('BB'))
|
||||
hand.addBlind(self.playerNameFromSeatNo(a.group('PSEAT'), hand), 'big blind', a.group('BB'))
|
||||
for a in self.re_PostBoth.finditer(hand.handText):
|
||||
bb = Decimal(self.info['bb'])
|
||||
amount = Decimal(a.group('SBBB'))
|
||||
|
|
@ -254,8 +263,8 @@ or None if we fail to get the info """
|
|||
elif action.group('ATYPE') == 'ALL_IN':
|
||||
hand.addAllIn(street, player, action.group('BET'))
|
||||
else:
|
||||
logging.debug("Unimplemented readAction: %s %s"
|
||||
% (action.group('PSEAT'),action.group('ATYPE'),))
|
||||
logging.debug(_("Unimplemented readAction: %s %s"
|
||||
% (action.group('PSEAT'),action.group('ATYPE'),)))
|
||||
|
||||
def readShowdownActions(self, hand):
|
||||
for shows in self.re_ShowdownAction.finditer(hand.handText):
|
||||
|
|
@ -285,9 +294,9 @@ or None if we fail to get the info """
|
|||
|
||||
if __name__ == "__main__":
|
||||
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="-")
|
||||
parser.add_option("-f", "--follow", dest="follow", help="follow (tail -f) the input", action="store_true", default=False)
|
||||
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="-")
|
||||
parser.add_option("-f", "--follow", dest="follow", help=_("follow (tail -f) the input"), action="store_true", default=False)
|
||||
parser.add_option("-q", "--quiet", action="store_const", const=logging.CRITICAL, dest="verbosity", default=logging.INFO)
|
||||
parser.add_option("-v", "--verbose", action="store_const", const=logging.INFO, dest="verbosity")
|
||||
parser.add_option("--vv", action="store_const", const=logging.DEBUG, dest="verbosity")
|
||||
|
|
|
|||
284
pyfpdb/Card.py
284
pyfpdb/Card.py
|
|
@ -15,23 +15,37 @@
|
|||
#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 L10n
|
||||
_ = L10n.get_translation()
|
||||
|
||||
# From fpdb_simple
|
||||
card_map = { "0": 0, "2": 2, "3" : 3, "4" : 4, "5" : 5, "6" : 6, "7" : 7, "8" : 8,
|
||||
"9" : 9, "T" : 10, "J" : 11, "Q" : 12, "K" : 13, "A" : 14}
|
||||
|
||||
card_map_low = { "0": 0, "A":1, "2": 2, "3" : 3, "4" : 4, "5" : 5, "6" : 6, "7" : 7, "8" : 8,
|
||||
"9" : 9, "T" : 10, "J" : 11, "Q" : 12, "K" : 13}
|
||||
|
||||
def decodeStartHandValue(game, value):
|
||||
if game == "holdem":
|
||||
return twoStartCardString(value)
|
||||
elif game == "razz":
|
||||
return decodeRazzStartHand(value)
|
||||
else:
|
||||
return "xx"
|
||||
|
||||
|
||||
# FIXME: the following is a workaround until switching to newimport.
|
||||
# This should be moved into DerivedStats
|
||||
# I'd also like to change HandsPlayers.startCards to a different datatype
|
||||
# so we can 'trivially' add different start card classifications
|
||||
|
||||
def calcStartCards(hand, player):
|
||||
hcs = hand.join_holecards(player, asList=True)
|
||||
if hand.gametype['category'] == 'holdem':
|
||||
hcs = hand.join_holecards(player, asList=True)
|
||||
#print "DEBUG: hcs: %s" % hcs
|
||||
value1 = card_map[hcs[0][0]]
|
||||
value2 = card_map[hcs[1][0]]
|
||||
return twoStartCards(value1, hcs[0][1], value2, hcs[1][1])
|
||||
elif hand.gametype['category'] == 'razz':
|
||||
return encodeRazzStartHand(hcs)
|
||||
else:
|
||||
# FIXME: Only do startCards value for holdem at the moment
|
||||
return 0
|
||||
|
|
@ -84,7 +98,7 @@ def twoStartCardString(card):
|
|||
if x == y: ret = s[x] + s[y]
|
||||
elif x > y: ret = s[x] + s[y] + 's'
|
||||
else: ret = s[y] + s[x] + 'o'
|
||||
# print "twoStartCardString(", card ,") = " + ret
|
||||
print "twoStartCardString(", card ,") = " + ret
|
||||
return ret
|
||||
|
||||
def fourStartCards(value1, suit1, value2, suit2, value3, suit3, value4, suit4):
|
||||
|
|
@ -152,8 +166,268 @@ def encodeCard(cardString):
|
|||
if cardString not in encodeCardList: return 0
|
||||
return encodeCardList[cardString]
|
||||
|
||||
def decodeRazzStartHand(idx):
|
||||
decodeRazzList = {
|
||||
-13:'(00)A',-12:'(00)2',-11:'(00)3',-10:'(00)4',-9:'(00)5',-8:'(00)6',-7:'(00)7',-6:'(00)8',-5:'(00)9',-4:'(00)T',
|
||||
-3:'(00)J',-2:'(00)Q',-1:'(00)K',0:'xxx',
|
||||
1:'(32)A',2:'(3A)2',3:'(2A)3',4:'(42)A',5:'(4A)2',6:'(2A)4',7:'(43)A',8:'(4A)3',9:'(3A)4',
|
||||
10:'(43)2',11:'(42)3',12:'(32)4',13:'(52)A',14:'(5A)2',15:'(2A)5',16:'(53)A',17:'(5A)3',18:'(3A)5',19:'(53)2',
|
||||
20:'(52)3',21:'(32)5',22:'(54)A',23:'(5A)4',24:'(4A)5',25:'(54)2',26:'(52)4',27:'(42)5',28:'(54)3',29:'(53)4',
|
||||
30:'(43)5',31:'(62)A',32:'(6A)2',33:'(2A)6',34:'(63)A',35:'(6A)3',36:'(3A)6',37:'(63)2',38:'(62)3',39:'(32)6',
|
||||
40:'(64)A',41:'(6A)4',42:'(4A)6',43:'(64)2',44:'(62)4',45:'(42)6',46:'(64)3',47:'(63)4',48:'(43)6',49:'(65)A',
|
||||
50:'(6A)5',51:'(5A)6',52:'(65)2',53:'(62)5',54:'(52)6',55:'(65)3',56:'(63)5',57:'(53)6',58:'(65)4',59:'(64)5',
|
||||
60:'(54)6',61:'(72)A',62:'(7A)2',63:'(2A)7',64:'(73)A',65:'(7A)3',66:'(3A)7',67:'(73)2',68:'(72)3',69:'(32)7',
|
||||
70:'(74)A',71:'(7A)4',72:'(4A)7',73:'(74)2',74:'(72)4',75:'(42)7',76:'(74)3',77:'(73)4',78:'(43)7',79:'(75)A',
|
||||
80:'(7A)5',81:'(5A)7',82:'(75)2',83:'(72)5',84:'(52)7',85:'(75)3',86:'(73)5',87:'(53)7',88:'(75)4',89:'(74)5',
|
||||
90:'(54)7',91:'(76)A',92:'(7A)6',93:'(6A)7',94:'(76)2',95:'(72)6',96:'(62)7',97:'(76)3',98:'(73)6',99:'(63)7',
|
||||
100:'(76)4',101:'(74)6',102:'(64)7',103:'(76)5',104:'(75)6',105:'(65)7',106:'(82)A',107:'(8A)2',108:'(2A)8',109:'(83)A',
|
||||
110:'(8A)3',111:'(3A)8',112:'(83)2',113:'(82)3',114:'(32)8',115:'(84)A',116:'(8A)4',117:'(4A)8',118:'(84)2',119:'(82)4',
|
||||
120:'(42)8',121:'(84)3',122:'(83)4',123:'(43)8',124:'(85)A',125:'(8A)5',126:'(5A)8',127:'(85)2',128:'(82)5',129:'(52)8',
|
||||
130:'(85)3',131:'(83)5',132:'(53)8',133:'(85)4',134:'(84)5',135:'(54)8',136:'(86)A',137:'(8A)6',138:'(6A)8',139:'(86)2',
|
||||
140:'(82)6',141:'(62)8',142:'(86)3',143:'(83)6',144:'(63)8',145:'(86)4',146:'(84)6',147:'(64)8',148:'(86)5',149:'(85)6',
|
||||
150:'(65)8',151:'(87)A',152:'(8A)7',153:'(7A)8',154:'(87)2',155:'(82)7',156:'(72)8',157:'(87)3',158:'(83)7',159:'(73)8',
|
||||
160:'(87)4',161:'(84)7',162:'(74)8',163:'(87)5',164:'(85)7',165:'(75)8',166:'(87)6',167:'(86)7',168:'(76)8',169:'(92)A',
|
||||
170:'(9A)2',171:'(2A)9',172:'(93)A',173:'(9A)3',174:'(3A)9',175:'(93)2',176:'(92)3',177:'(32)9',178:'(94)A',179:'(9A)4',
|
||||
180:'(4A)9',181:'(94)2',182:'(92)4',183:'(42)9',184:'(94)3',185:'(93)4',186:'(43)9',187:'(95)A',188:'(9A)5',189:'(5A)9',
|
||||
190:'(95)2',191:'(92)5',192:'(52)9',193:'(95)3',194:'(93)5',195:'(53)9',196:'(95)4',197:'(94)5',198:'(54)9',199:'(96)A',
|
||||
200:'(9A)6',201:'(6A)9',202:'(96)2',203:'(92)6',204:'(62)9',205:'(96)3',206:'(93)6',207:'(63)9',208:'(96)4',209:'(94)6',
|
||||
210:'(64)9',211:'(96)5',212:'(95)6',213:'(65)9',214:'(97)A',215:'(9A)7',216:'(7A)9',217:'(97)2',218:'(92)7',219:'(72)9',
|
||||
220:'(97)3',221:'(93)7',222:'(73)9',223:'(97)4',224:'(94)7',225:'(74)9',226:'(97)5',227:'(95)7',228:'(75)9',229:'(97)6',
|
||||
230:'(96)7',231:'(76)9',232:'(98)A',233:'(9A)8',234:'(8A)9',235:'(98)2',236:'(92)8',237:'(82)9',238:'(98)3',239:'(93)8',
|
||||
240:'(83)9',241:'(98)4',242:'(94)8',243:'(84)9',244:'(98)5',245:'(95)8',246:'(85)9',247:'(98)6',248:'(96)8',249:'(86)9',
|
||||
250:'(98)7',251:'(97)8',252:'(87)9',253:'(T2)A',254:'(TA)2',255:'(2A)T',256:'(T3)A',257:'(TA)3',258:'(3A)T',259:'(T3)2',
|
||||
260:'(T2)3',261:'(32)T',262:'(T4)A',263:'(TA)4',264:'(4A)T',265:'(T4)2',266:'(T2)4',267:'(42)T',268:'(T4)3',269:'(T3)4',
|
||||
270:'(43)T',271:'(T5)A',272:'(TA)5',273:'(5A)T',274:'(T5)2',275:'(T2)5',276:'(52)T',277:'(T5)3',278:'(T3)5',279:'(53)T',
|
||||
280:'(T5)4',281:'(T4)5',282:'(54)T',283:'(T6)A',284:'(TA)6',285:'(6A)T',286:'(T6)2',287:'(T2)6',288:'(62)T',289:'(T6)3',
|
||||
290:'(T3)6',291:'(63)T',292:'(T6)4',293:'(T4)6',294:'(64)T',295:'(T6)5',296:'(T5)6',297:'(65)T',298:'(T7)A',299:'(TA)7',
|
||||
300:'(7A)T',301:'(T7)2',302:'(T2)7',303:'(72)T',304:'(T7)3',305:'(T3)7',306:'(73)T',307:'(T7)4',308:'(T4)7',309:'(74)T',
|
||||
310:'(T7)5',311:'(T5)7',312:'(75)T',313:'(T7)6',314:'(T6)7',315:'(76)T',316:'(T8)A',317:'(TA)8',318:'(8A)T',319:'(T8)2',
|
||||
320:'(T2)8',321:'(82)T',322:'(T8)3',323:'(T3)8',324:'(83)T',325:'(T8)4',326:'(T4)8',327:'(84)T',328:'(T8)5',329:'(T5)8',
|
||||
330:'(85)T',331:'(T8)6',332:'(T6)8',333:'(86)T',334:'(T8)7',335:'(T7)8',336:'(87)T',337:'(T9)A',338:'(TA)9',339:'(9A)T',
|
||||
340:'(T9)2',341:'(T2)9',342:'(92)T',343:'(T9)3',344:'(T3)9',345:'(93)T',346:'(T9)4',347:'(T4)9',348:'(94)T',349:'(T9)5',
|
||||
350:'(T5)9',351:'(95)T',352:'(T9)6',353:'(T6)9',354:'(96)T',355:'(T9)7',356:'(T7)9',357:'(97)T',358:'(T9)8',359:'(T8)9',
|
||||
360:'(98)T',361:'(J2)A',362:'(JA)2',363:'(2A)J',364:'(J3)A',365:'(JA)3',366:'(3A)J',367:'(J3)2',368:'(J2)3',369:'(32)J',
|
||||
370:'(J4)A',371:'(JA)4',372:'(4A)J',373:'(J4)2',374:'(J2)4',375:'(42)J',376:'(J4)3',377:'(J3)4',378:'(43)J',379:'(J5)A',
|
||||
380:'(JA)5',381:'(5A)J',382:'(J5)2',383:'(J2)5',384:'(52)J',385:'(J5)3',386:'(J3)5',387:'(53)J',388:'(J5)4',389:'(J4)5',
|
||||
390:'(54)J',391:'(J6)A',392:'(JA)6',393:'(6A)J',394:'(J6)2',395:'(J2)6',396:'(62)J',397:'(J6)3',398:'(J3)6',399:'(63)J',
|
||||
400:'(J6)4',401:'(J4)6',402:'(64)J',403:'(J6)5',404:'(J5)6',405:'(65)J',406:'(J7)A',407:'(JA)7',408:'(7A)J',409:'(J7)2',
|
||||
410:'(J2)7',411:'(72)J',412:'(J7)3',413:'(J3)7',414:'(73)J',415:'(J7)4',416:'(J4)7',417:'(74)J',418:'(J7)5',419:'(J5)7',
|
||||
420:'(75)J',421:'(J7)6',422:'(J6)7',423:'(76)J',424:'(J8)A',425:'(JA)8',426:'(8A)J',427:'(J8)2',428:'(J2)8',429:'(82)J',
|
||||
430:'(J8)3',431:'(J3)8',432:'(83)J',433:'(J8)4',434:'(J4)8',435:'(84)J',436:'(J8)5',437:'(J5)8',438:'(85)J',439:'(J8)6',
|
||||
440:'(J6)8',441:'(86)J',442:'(J8)7',443:'(J7)8',444:'(87)J',445:'(J9)A',446:'(JA)9',447:'(9A)J',448:'(J9)2',449:'(J2)9',
|
||||
450:'(92)J',451:'(J9)3',452:'(J3)9',453:'(93)J',454:'(J9)4',455:'(J4)9',456:'(94)J',457:'(J9)5',458:'(J5)9',459:'(95)J',
|
||||
460:'(J9)6',461:'(J6)9',462:'(96)J',463:'(J9)7',464:'(J7)9',465:'(97)J',466:'(J9)8',467:'(J8)9',468:'(98)J',469:'(JT)A',
|
||||
470:'(JA)T',471:'(TA)J',472:'(JT)2',473:'(J2)T',474:'(T2)J',475:'(JT)3',476:'(J3)T',477:'(T3)J',478:'(JT)4',479:'(J4)T',
|
||||
480:'(T4)J',481:'(JT)5',482:'(J5)T',483:'(T5)J',484:'(JT)6',485:'(J6)T',486:'(T6)J',487:'(JT)7',488:'(J7)T',489:'(T7)J',
|
||||
490:'(JT)8',491:'(J8)T',492:'(T8)J',493:'(JT)9',494:'(J9)T',495:'(T9)J',496:'(Q2)A',497:'(QA)2',498:'(2A)Q',499:'(Q3)A',
|
||||
500:'(QA)3',501:'(3A)Q',502:'(Q3)2',503:'(Q2)3',504:'(32)Q',505:'(Q4)A',506:'(QA)4',507:'(4A)Q',508:'(Q4)2',509:'(Q2)4',
|
||||
510:'(42)Q',511:'(Q4)3',512:'(Q3)4',513:'(43)Q',514:'(Q5)A',515:'(QA)5',516:'(5A)Q',517:'(Q5)2',518:'(Q2)5',519:'(52)Q',
|
||||
520:'(Q5)3',521:'(Q3)5',522:'(53)Q',523:'(Q5)4',524:'(Q4)5',525:'(54)Q',526:'(Q6)A',527:'(QA)6',528:'(6A)Q',529:'(Q6)2',
|
||||
530:'(Q2)6',531:'(62)Q',532:'(Q6)3',533:'(Q3)6',534:'(63)Q',535:'(Q6)4',536:'(Q4)6',537:'(64)Q',538:'(Q6)5',539:'(Q5)6',
|
||||
540:'(65)Q',541:'(Q7)A',542:'(QA)7',543:'(7A)Q',544:'(Q7)2',545:'(Q2)7',546:'(72)Q',547:'(Q7)3',548:'(Q3)7',549:'(73)Q',
|
||||
550:'(Q7)4',551:'(Q4)7',552:'(74)Q',553:'(Q7)5',554:'(Q5)7',555:'(75)Q',556:'(Q7)6',557:'(Q6)7',558:'(76)Q',559:'(Q8)A',
|
||||
560:'(QA)8',561:'(8A)Q',562:'(Q8)2',563:'(Q2)8',564:'(82)Q',565:'(Q8)3',566:'(Q3)8',567:'(83)Q',568:'(Q8)4',569:'(Q4)8',
|
||||
570:'(84)Q',571:'(Q8)5',572:'(Q5)8',573:'(85)Q',574:'(Q8)6',575:'(Q6)8',576:'(86)Q',577:'(Q8)7',578:'(Q7)8',579:'(87)Q',
|
||||
580:'(Q9)A',581:'(QA)9',582:'(9A)Q',583:'(Q9)2',584:'(Q2)9',585:'(92)Q',586:'(Q9)3',587:'(Q3)9',588:'(93)Q',589:'(Q9)4',
|
||||
590:'(Q4)9',591:'(94)Q',592:'(Q9)5',593:'(Q5)9',594:'(95)Q',595:'(Q9)6',596:'(Q6)9',597:'(96)Q',598:'(Q9)7',599:'(Q7)9',
|
||||
600:'(97)Q',601:'(Q9)8',602:'(Q8)9',603:'(98)Q',604:'(QT)A',605:'(QA)T',606:'(TA)Q',607:'(QT)2',608:'(Q2)T',609:'(T2)Q',
|
||||
610:'(QT)3',611:'(Q3)T',612:'(T3)Q',613:'(QT)4',614:'(Q4)T',615:'(T4)Q',616:'(QT)5',617:'(Q5)T',618:'(T5)Q',619:'(QT)6',
|
||||
620:'(Q6)T',621:'(T6)Q',622:'(QT)7',623:'(Q7)T',624:'(T7)Q',625:'(QT)8',626:'(Q8)T',627:'(T8)Q',628:'(QT)9',629:'(Q9)T',
|
||||
630:'(T9)Q',631:'(QJ)A',632:'(QA)J',633:'(JA)Q',634:'(QJ)2',635:'(Q2)J',636:'(J2)Q',637:'(QJ)3',638:'(Q3)J',639:'(J3)Q',
|
||||
640:'(QJ)4',641:'(Q4)J',642:'(J4)Q',643:'(QJ)5',644:'(Q5)J',645:'(J5)Q',646:'(QJ)6',647:'(Q6)J',648:'(J6)Q',649:'(QJ)7',
|
||||
650:'(Q7)J',651:'(J7)Q',652:'(QJ)8',653:'(Q8)J',654:'(J8)Q',655:'(QJ)9',656:'(Q9)J',657:'(J9)Q',658:'(QJ)T',659:'(QT)J',
|
||||
660:'(JT)Q',661:'(K2)A',662:'(KA)2',663:'(2A)K',664:'(K3)A',665:'(KA)3',666:'(3A)K',667:'(K3)2',668:'(K2)3',669:'(32)K',
|
||||
670:'(K4)A',671:'(KA)4',672:'(4A)K',673:'(K4)2',674:'(K2)4',675:'(42)K',676:'(K4)3',677:'(K3)4',678:'(43)K',679:'(K5)A',
|
||||
680:'(KA)5',681:'(5A)K',682:'(K5)2',683:'(K2)5',684:'(52)K',685:'(K5)3',686:'(K3)5',687:'(53)K',688:'(K5)4',689:'(K4)5',
|
||||
690:'(54)K',691:'(K6)A',692:'(KA)6',693:'(6A)K',694:'(K6)2',695:'(K2)6',696:'(62)K',697:'(K6)3',698:'(K3)6',699:'(63)K',
|
||||
700:'(K6)4',701:'(K4)6',702:'(64)K',703:'(K6)5',704:'(K5)6',705:'(65)K',706:'(K7)A',707:'(KA)7',708:'(7A)K',709:'(K7)2',
|
||||
710:'(K2)7',711:'(72)K',712:'(K7)3',713:'(K3)7',714:'(73)K',715:'(K7)4',716:'(K4)7',717:'(74)K',718:'(K7)5',719:'(K5)7',
|
||||
720:'(75)K',721:'(K7)6',722:'(K6)7',723:'(76)K',724:'(K8)A',725:'(KA)8',726:'(8A)K',727:'(K8)2',728:'(K2)8',729:'(82)K',
|
||||
730:'(K8)3',731:'(K3)8',732:'(83)K',733:'(K8)4',734:'(K4)8',735:'(84)K',736:'(K8)5',737:'(K5)8',738:'(85)K',739:'(K8)6',
|
||||
740:'(K6)8',741:'(86)K',742:'(K8)7',743:'(K7)8',744:'(87)K',745:'(K9)A',746:'(KA)9',747:'(9A)K',748:'(K9)2',749:'(K2)9',
|
||||
750:'(92)K',751:'(K9)3',752:'(K3)9',753:'(93)K',754:'(K9)4',755:'(K4)9',756:'(94)K',757:'(K9)5',758:'(K5)9',759:'(95)K',
|
||||
760:'(K9)6',761:'(K6)9',762:'(96)K',763:'(K9)7',764:'(K7)9',765:'(97)K',766:'(K9)8',767:'(K8)9',768:'(98)K',769:'(KT)A',
|
||||
770:'(KA)T',771:'(TA)K',772:'(KT)2',773:'(K2)T',774:'(T2)K',775:'(KT)3',776:'(K3)T',777:'(T3)K',778:'(KT)4',779:'(K4)T',
|
||||
780:'(T4)K',781:'(KT)5',782:'(K5)T',783:'(T5)K',784:'(KT)6',785:'(K6)T',786:'(T6)K',787:'(KT)7',788:'(K7)T',789:'(T7)K',
|
||||
790:'(KT)8',791:'(K8)T',792:'(T8)K',793:'(KT)9',794:'(K9)T',795:'(T9)K',796:'(KJ)A',797:'(KA)J',798:'(JA)K',799:'(KJ)2',
|
||||
800:'(K2)J',801:'(J2)K',802:'(KJ)3',803:'(K3)J',804:'(J3)K',805:'(KJ)4',806:'(K4)J',807:'(J4)K',808:'(KJ)5',809:'(K5)J',
|
||||
810:'(J5)K',811:'(KJ)6',812:'(K6)J',813:'(J6)K',814:'(KJ)7',815:'(K7)J',816:'(J7)K',817:'(KJ)8',818:'(K8)J',819:'(J8)K',
|
||||
820:'(KJ)9',821:'(K9)J',822:'(J9)K',823:'(KJ)T',824:'(KT)J',825:'(JT)K',826:'(KQ)A',827:'(KA)Q',828:'(QA)K',829:'(KQ)2',
|
||||
830:'(K2)Q',831:'(Q2)K',832:'(KQ)3',833:'(K3)Q',834:'(Q3)K',835:'(KQ)4',836:'(K4)Q',837:'(Q4)K',838:'(KQ)5',839:'(K5)Q',
|
||||
840:'(Q5)K',841:'(KQ)6',842:'(K6)Q',843:'(Q6)K',844:'(KQ)7',845:'(K7)Q',846:'(Q7)K',847:'(KQ)8',848:'(K8)Q',849:'(Q8)K',
|
||||
850:'(KQ)9',851:'(K9)Q',852:'(Q9)K',853:'(KQ)T',854:'(KT)Q',855:'(QT)K',856:'(KQ)J',857:'(KJ)Q',858:'(QJ)K',859:'(2A)A',
|
||||
860:'(22)A',861:'(AA)2',862:'(2A)2',863:'(3A)A',864:'(33)A',865:'(AA)3',866:'(3A)3',867:'(32)2',868:'(33)2',869:'(22)3',
|
||||
870:'(32)3',871:'(4A)A',872:'(44)A',873:'(AA)4',874:'(4A)4',875:'(42)2',876:'(44)2',877:'(22)4',878:'(42)4',879:'(43)3',
|
||||
880:'(44)3',881:'(33)4',882:'(43)4',883:'(5A)A',884:'(55)A',885:'(AA)5',886:'(5A)5',887:'(52)2',888:'(55)2',889:'(22)5',
|
||||
890:'(52)5',891:'(53)3',892:'(55)3',893:'(33)5',894:'(53)5',895:'(54)4',896:'(55)4',897:'(44)5',898:'(54)5',899:'(6A)A',
|
||||
900:'(66)A',901:'(AA)6',902:'(6A)6',903:'(62)2',904:'(66)2',905:'(22)6',906:'(62)6',907:'(63)3',908:'(66)3',909:'(33)6',
|
||||
910:'(63)6',911:'(64)4',912:'(66)4',913:'(44)6',914:'(64)6',915:'(65)5',916:'(66)5',917:'(55)6',918:'(65)6',919:'(7A)A',
|
||||
920:'(77)A',921:'(AA)7',922:'(7A)7',923:'(72)2',924:'(77)2',925:'(22)7',926:'(72)7',927:'(73)3',928:'(77)3',929:'(33)7',
|
||||
930:'(73)7',931:'(74)4',932:'(77)4',933:'(44)7',934:'(74)7',935:'(75)5',936:'(77)5',937:'(55)7',938:'(75)7',939:'(76)6',
|
||||
940:'(77)6',941:'(66)7',942:'(76)7',943:'(8A)A',944:'(88)A',945:'(AA)8',946:'(8A)8',947:'(82)2',948:'(88)2',949:'(22)8',
|
||||
950:'(82)8',951:'(83)3',952:'(88)3',953:'(33)8',954:'(83)8',955:'(84)4',956:'(88)4',957:'(44)8',958:'(84)8',959:'(85)5',
|
||||
960:'(88)5',961:'(55)8',962:'(85)8',963:'(86)6',964:'(88)6',965:'(66)8',966:'(86)8',967:'(87)7',968:'(88)7',969:'(77)8',
|
||||
970:'(87)8',971:'(9A)A',972:'(99)A',973:'(AA)9',974:'(9A)9',975:'(92)2',976:'(99)2',977:'(22)9',978:'(92)9',979:'(93)3',
|
||||
980:'(99)3',981:'(33)9',982:'(93)9',983:'(94)4',984:'(99)4',985:'(44)9',986:'(94)9',987:'(95)5',988:'(99)5',989:'(55)9',
|
||||
990:'(95)9',991:'(96)6',992:'(99)6',993:'(66)9',994:'(96)9',995:'(97)7',996:'(99)7',997:'(77)9',998:'(97)9',999:'(98)8',
|
||||
1000:'(99)8',1001:'(88)9',1002:'(98)9',1003:'(TA)A',1004:'(TT)A',1005:'(AA)T',1006:'(TA)T',1007:'(T2)2',1008:'(TT)2',1009:'(22)T',
|
||||
1010:'(T2)T',1011:'(T3)3',1012:'(TT)3',1013:'(33)T',1014:'(T3)T',1015:'(T4)4',1016:'(TT)4',1017:'(44)T',1018:'(T4)T',1019:'(T5)5',
|
||||
1020:'(TT)5',1021:'(55)T',1022:'(T5)T',1023:'(T6)6',1024:'(TT)6',1025:'(66)T',1026:'(T6)T',1027:'(T7)7',1028:'(TT)7',1029:'(77)T',
|
||||
1030:'(T7)T',1031:'(T8)8',1032:'(TT)8',1033:'(88)T',1034:'(T8)T',1035:'(T9)9',1036:'(TT)9',1037:'(99)T',1038:'(T9)T',1039:'(JA)A',
|
||||
1040:'(JJ)A',1041:'(AA)J',1042:'(JA)J',1043:'(J2)2',1044:'(JJ)2',1045:'(22)J',1046:'(J2)J',1047:'(J3)3',1048:'(JJ)3',1049:'(33)J',
|
||||
1050:'(J3)J',1051:'(J4)4',1052:'(JJ)4',1053:'(44)J',1054:'(J4)J',1055:'(J5)5',1056:'(JJ)5',1057:'(55)J',1058:'(J5)J',1059:'(J6)6',
|
||||
1060:'(JJ)6',1061:'(66)J',1062:'(J6)J',1063:'(J7)7',1064:'(JJ)7',1065:'(77)J',1066:'(J7)J',1067:'(J8)8',1068:'(JJ)8',1069:'(88)J',
|
||||
1070:'(J8)J',1071:'(J9)9',1072:'(JJ)9',1073:'(99)J',1074:'(J9)J',1075:'(JT)T',1076:'(JJ)T',1077:'(TT)J',1078:'(JT)J',1079:'(QA)A',
|
||||
1080:'(QQ)A',1081:'(AA)Q',1082:'(QA)Q',1083:'(Q2)2',1084:'(QQ)2',1085:'(22)Q',1086:'(Q2)Q',1087:'(Q3)3',1088:'(QQ)3',1089:'(33)Q',
|
||||
1090:'(Q3)Q',1091:'(Q4)4',1092:'(QQ)4',1093:'(44)Q',1094:'(Q4)Q',1095:'(Q5)5',1096:'(QQ)5',1097:'(55)Q',1098:'(Q5)Q',1099:'(Q6)6',
|
||||
1100:'(QQ)6',1101:'(66)Q',1102:'(Q6)Q',1103:'(Q7)7',1104:'(QQ)7',1105:'(77)Q',1106:'(Q7)Q',1107:'(Q8)8',1108:'(QQ)8',1109:'(88)Q',
|
||||
1110:'(Q8)Q',1111:'(Q9)9',1112:'(QQ)9',1113:'(99)Q',1114:'(Q9)Q',1115:'(QT)T',1116:'(QQ)T',1117:'(TT)Q',1118:'(QT)Q',1119:'(QJ)J',
|
||||
1120:'(QQ)J',1121:'(JJ)Q',1122:'(QJ)Q',1123:'(KA)A',1124:'(KK)A',1125:'(AA)K',1126:'(KA)K',1127:'(K2)2',1128:'(KK)2',1129:'(22)K',
|
||||
1130:'(K2)K',1131:'(K3)3',1132:'(KK)3',1133:'(33)K',1134:'(K3)K',1135:'(K4)4',1136:'(KK)4',1137:'(44)K',1138:'(K4)K',1139:'(K5)5',
|
||||
1140:'(KK)5',1141:'(55)K',1142:'(K5)K',1143:'(K6)6',1144:'(KK)6',1145:'(66)K',1146:'(K6)K',1147:'(K7)7',1148:'(KK)7',1149:'(77)K',
|
||||
1150:'(K7)K',1151:'(K8)8',1152:'(KK)8',1153:'(88)K',1154:'(K8)K',1155:'(K9)9',1156:'(KK)9',1157:'(99)K',1158:'(K9)K',1159:'(KT)T',
|
||||
1160:'(KK)T',1161:'(TT)K',1162:'(KT)K',1163:'(KJ)J',1164:'(KK)J',1165:'(JJ)K',1166:'(KJ)K',1167:'(KQ)Q',1168:'(KK)Q',1169:'(QQ)K',
|
||||
1170:'(KQ)K',1171:'(AA)A',1172:'(22)2',1173:'(33)3',1174:'(44)4',1175:'(55)5',1176:'(66)6',1177:'(77)7',1178:'(88)8',1179:'(99)9',
|
||||
1180:'(TT)T',1181:'(JJ)J',1182:'(QQ)Q',1183:'(KK)K',
|
||||
}
|
||||
return decodeRazzList[idx]
|
||||
|
||||
def encodeRazzStartHand(cards):
|
||||
"""Take Razz starting hand and return an integer index for storing in db"""
|
||||
startHand = ""
|
||||
if card_map_low[cards[0][0]] > card_map_low[cards[1][0]]:
|
||||
startHand = "(%s%s)%s" %(cards[0][0], cards[1][0], cards[2][0])
|
||||
else:
|
||||
startHand = "(%s%s)%s" %(cards[1][0], cards[0][0], cards[2][0])
|
||||
#print "DEBUG: startHand: %s" % startHand
|
||||
encodeRazzList = {
|
||||
'(00)A':-13,'(00)2':-12,'(00)3':-11,'(00)4':-10,'(00)5':-9,'(00)6':-8,'(00)7':-7,'(00)8':-6,'(00)9':-5,'(00)T':-4,
|
||||
'(00)J':-3,'(00)Q':-2,'(00)K':-1,
|
||||
'(32)A':1,'(3A)2':2,'(2A)3':3,'(42)A':4,'(4A)2':5,'(2A)4':6,'(43)A':7,'(4A)3':8,'(3A)4':9,
|
||||
'(43)2':10,'(42)3':11,'(32)4':12,'(52)A':13,'(5A)2':14,'(2A)5':15,'(53)A':16,'(5A)3':17,'(3A)5':18,'(53)2':19,
|
||||
'(52)3':20,'(32)5':21,'(54)A':22,'(5A)4':23,'(4A)5':24,'(54)2':25,'(52)4':26,'(42)5':27,'(54)3':28,'(53)4':29,
|
||||
'(43)5':30,'(62)A':31,'(6A)2':32,'(2A)6':33,'(63)A':34,'(6A)3':35,'(3A)6':36,'(63)2':37,'(62)3':38,'(32)6':39,
|
||||
'(64)A':40,'(6A)4':41,'(4A)6':42,'(64)2':43,'(62)4':44,'(42)6':45,'(64)3':46,'(63)4':47,'(43)6':48,'(65)A':49,
|
||||
'(6A)5':50,'(5A)6':51,'(65)2':52,'(62)5':53,'(52)6':54,'(65)3':55,'(63)5':56,'(53)6':57,'(65)4':58,'(64)5':59,
|
||||
'(54)6':60,'(72)A':61,'(7A)2':62,'(2A)7':63,'(73)A':64,'(7A)3':65,'(3A)7':66,'(73)2':67,'(72)3':68,'(32)7':69,
|
||||
'(74)A':70,'(7A)4':71,'(4A)7':72,'(74)2':73,'(72)4':74,'(42)7':75,'(74)3':76,'(73)4':77,'(43)7':78,'(75)A':79,
|
||||
'(7A)5':80,'(5A)7':81,'(75)2':82,'(72)5':83,'(52)7':84,'(75)3':85,'(73)5':86,'(53)7':87,'(75)4':88,'(74)5':89,
|
||||
'(54)7':90,'(76)A':91,'(7A)6':92,'(6A)7':93,'(76)2':94,'(72)6':95,'(62)7':96,'(76)3':97,'(73)6':98,'(63)7':99,
|
||||
'(76)4':100,'(74)6':101,'(64)7':102,'(76)5':103,'(75)6':104,'(65)7':105,'(82)A':106,'(8A)2':107,'(2A)8':108,'(83)A':109,
|
||||
'(8A)3':110,'(3A)8':111,'(83)2':112,'(82)3':113,'(32)8':114,'(84)A':115,'(8A)4':116,'(4A)8':117,'(84)2':118,'(82)4':119,
|
||||
'(42)8':120,'(84)3':121,'(83)4':122,'(43)8':123,'(85)A':124,'(8A)5':125,'(5A)8':126,'(85)2':127,'(82)5':128,'(52)8':129,
|
||||
'(85)3':130,'(83)5':131,'(53)8':132,'(85)4':133,'(84)5':134,'(54)8':135,'(86)A':136,'(8A)6':137,'(6A)8':138,'(86)2':139,
|
||||
'(82)6':140,'(62)8':141,'(86)3':142,'(83)6':143,'(63)8':144,'(86)4':145,'(84)6':146,'(64)8':147,'(86)5':148,'(85)6':149,
|
||||
'(65)8':150,'(87)A':151,'(8A)7':152,'(7A)8':153,'(87)2':154,'(82)7':155,'(72)8':156,'(87)3':157,'(83)7':158,'(73)8':159,
|
||||
'(87)4':160,'(84)7':161,'(74)8':162,'(87)5':163,'(85)7':164,'(75)8':165,'(87)6':166,'(86)7':167,'(76)8':168,'(92)A':169,
|
||||
'(9A)2':170,'(2A)9':171,'(93)A':172,'(9A)3':173,'(3A)9':174,'(93)2':175,'(92)3':176,'(32)9':177,'(94)A':178,'(9A)4':179,
|
||||
'(4A)9':180,'(94)2':181,'(92)4':182,'(42)9':183,'(94)3':184,'(93)4':185,'(43)9':186,'(95)A':187,'(9A)5':188,'(5A)9':189,
|
||||
'(95)2':190,'(92)5':191,'(52)9':192,'(95)3':193,'(93)5':194,'(53)9':195,'(95)4':196,'(94)5':197,'(54)9':198,'(96)A':199,
|
||||
'(9A)6':200,'(6A)9':201,'(96)2':202,'(92)6':203,'(62)9':204,'(96)3':205,'(93)6':206,'(63)9':207,'(96)4':208,'(94)6':209,
|
||||
'(64)9':210,'(96)5':211,'(95)6':212,'(65)9':213,'(97)A':214,'(9A)7':215,'(7A)9':216,'(97)2':217,'(92)7':218,'(72)9':219,
|
||||
'(97)3':220,'(93)7':221,'(73)9':222,'(97)4':223,'(94)7':224,'(74)9':225,'(97)5':226,'(95)7':227,'(75)9':228,'(97)6':229,
|
||||
'(96)7':230,'(76)9':231,'(98)A':232,'(9A)8':233,'(8A)9':234,'(98)2':235,'(92)8':236,'(82)9':237,'(98)3':238,'(93)8':239,
|
||||
'(83)9':240,'(98)4':241,'(94)8':242,'(84)9':243,'(98)5':244,'(95)8':245,'(85)9':246,'(98)6':247,'(96)8':248,'(86)9':249,
|
||||
'(98)7':250,'(97)8':251,'(87)9':252,'(T2)A':253,'(TA)2':254,'(2A)T':255,'(T3)A':256,'(TA)3':257,'(3A)T':258,'(T3)2':259,
|
||||
'(T2)3':260,'(32)T':261,'(T4)A':262,'(TA)4':263,'(4A)T':264,'(T4)2':265,'(T2)4':266,'(42)T':267,'(T4)3':268,'(T3)4':269,
|
||||
'(43)T':270,'(T5)A':271,'(TA)5':272,'(5A)T':273,'(T5)2':274,'(T2)5':275,'(52)T':276,'(T5)3':277,'(T3)5':278,'(53)T':279,
|
||||
'(T5)4':280,'(T4)5':281,'(54)T':282,'(T6)A':283,'(TA)6':284,'(6A)T':285,'(T6)2':286,'(T2)6':287,'(62)T':288,'(T6)3':289,
|
||||
'(T3)6':290,'(63)T':291,'(T6)4':292,'(T4)6':293,'(64)T':294,'(T6)5':295,'(T5)6':296,'(65)T':297,'(T7)A':298,'(TA)7':299,
|
||||
'(7A)T':300,'(T7)2':301,'(T2)7':302,'(72)T':303,'(T7)3':304,'(T3)7':305,'(73)T':306,'(T7)4':307,'(T4)7':308,'(74)T':309,
|
||||
'(T7)5':310,'(T5)7':311,'(75)T':312,'(T7)6':313,'(T6)7':314,'(76)T':315,'(T8)A':316,'(TA)8':317,'(8A)T':318,'(T8)2':319,
|
||||
'(T2)8':320,'(82)T':321,'(T8)3':322,'(T3)8':323,'(83)T':324,'(T8)4':325,'(T4)8':326,'(84)T':327,'(T8)5':328,'(T5)8':329,
|
||||
'(85)T':330,'(T8)6':331,'(T6)8':332,'(86)T':333,'(T8)7':334,'(T7)8':335,'(87)T':336,'(T9)A':337,'(TA)9':338,'(9A)T':339,
|
||||
'(T9)2':340,'(T2)9':341,'(92)T':342,'(T9)3':343,'(T3)9':344,'(93)T':345,'(T9)4':346,'(T4)9':347,'(94)T':348,'(T9)5':349,
|
||||
'(T5)9':350,'(95)T':351,'(T9)6':352,'(T6)9':353,'(96)T':354,'(T9)7':355,'(T7)9':356,'(97)T':357,'(T9)8':358,'(T8)9':359,
|
||||
'(98)T':360,'(J2)A':361,'(JA)2':362,'(2A)J':363,'(J3)A':364,'(JA)3':365,'(3A)J':366,'(J3)2':367,'(J2)3':368,'(32)J':369,
|
||||
'(J4)A':370,'(JA)4':371,'(4A)J':372,'(J4)2':373,'(J2)4':374,'(42)J':375,'(J4)3':376,'(J3)4':377,'(43)J':378,'(J5)A':379,
|
||||
'(JA)5':380,'(5A)J':381,'(J5)2':382,'(J2)5':383,'(52)J':384,'(J5)3':385,'(J3)5':386,'(53)J':387,'(J5)4':388,'(J4)5':389,
|
||||
'(54)J':390,'(J6)A':391,'(JA)6':392,'(6A)J':393,'(J6)2':394,'(J2)6':395,'(62)J':396,'(J6)3':397,'(J3)6':398,'(63)J':399,
|
||||
'(J6)4':400,'(J4)6':401,'(64)J':402,'(J6)5':403,'(J5)6':404,'(65)J':405,'(J7)A':406,'(JA)7':407,'(7A)J':408,'(J7)2':409,
|
||||
'(J2)7':410,'(72)J':411,'(J7)3':412,'(J3)7':413,'(73)J':414,'(J7)4':415,'(J4)7':416,'(74)J':417,'(J7)5':418,'(J5)7':419,
|
||||
'(75)J':420,'(J7)6':421,'(J6)7':422,'(76)J':423,'(J8)A':424,'(JA)8':425,'(8A)J':426,'(J8)2':427,'(J2)8':428,'(82)J':429,
|
||||
'(J8)3':430,'(J3)8':431,'(83)J':432,'(J8)4':433,'(J4)8':434,'(84)J':435,'(J8)5':436,'(J5)8':437,'(85)J':438,'(J8)6':439,
|
||||
'(J6)8':440,'(86)J':441,'(J8)7':442,'(J7)8':443,'(87)J':444,'(J9)A':445,'(JA)9':446,'(9A)J':447,'(J9)2':448,'(J2)9':449,
|
||||
'(92)J':450,'(J9)3':451,'(J3)9':452,'(93)J':453,'(J9)4':454,'(J4)9':455,'(94)J':456,'(J9)5':457,'(J5)9':458,'(95)J':459,
|
||||
'(J9)6':460,'(J6)9':461,'(96)J':462,'(J9)7':463,'(J7)9':464,'(97)J':465,'(J9)8':466,'(J8)9':467,'(98)J':468,'(JT)A':469,
|
||||
'(JA)T':470,'(TA)J':471,'(JT)2':472,'(J2)T':473,'(T2)J':474,'(JT)3':475,'(J3)T':476,'(T3)J':477,'(JT)4':478,'(J4)T':479,
|
||||
'(T4)J':480,'(JT)5':481,'(J5)T':482,'(T5)J':483,'(JT)6':484,'(J6)T':485,'(T6)J':486,'(JT)7':487,'(J7)T':488,'(T7)J':489,
|
||||
'(JT)8':490,'(J8)T':491,'(T8)J':492,'(JT)9':493,'(J9)T':494,'(T9)J':495,'(Q2)A':496,'(QA)2':497,'(2A)Q':498,'(Q3)A':499,
|
||||
'(QA)3':500,'(3A)Q':501,'(Q3)2':502,'(Q2)3':503,'(32)Q':504,'(Q4)A':505,'(QA)4':506,'(4A)Q':507,'(Q4)2':508,'(Q2)4':509,
|
||||
'(42)Q':510,'(Q4)3':511,'(Q3)4':512,'(43)Q':513,'(Q5)A':514,'(QA)5':515,'(5A)Q':516,'(Q5)2':517,'(Q2)5':518,'(52)Q':519,
|
||||
'(Q5)3':520,'(Q3)5':521,'(53)Q':522,'(Q5)4':523,'(Q4)5':524,'(54)Q':525,'(Q6)A':526,'(QA)6':527,'(6A)Q':528,'(Q6)2':529,
|
||||
'(Q2)6':530,'(62)Q':531,'(Q6)3':532,'(Q3)6':533,'(63)Q':534,'(Q6)4':535,'(Q4)6':536,'(64)Q':537,'(Q6)5':538,'(Q5)6':539,
|
||||
'(65)Q':540,'(Q7)A':541,'(QA)7':542,'(7A)Q':543,'(Q7)2':544,'(Q2)7':545,'(72)Q':546,'(Q7)3':547,'(Q3)7':548,'(73)Q':549,
|
||||
'(Q7)4':550,'(Q4)7':551,'(74)Q':552,'(Q7)5':553,'(Q5)7':554,'(75)Q':555,'(Q7)6':556,'(Q6)7':557,'(76)Q':558,'(Q8)A':559,
|
||||
'(QA)8':560,'(8A)Q':561,'(Q8)2':562,'(Q2)8':563,'(82)Q':564,'(Q8)3':565,'(Q3)8':566,'(83)Q':567,'(Q8)4':568,'(Q4)8':569,
|
||||
'(84)Q':570,'(Q8)5':571,'(Q5)8':572,'(85)Q':573,'(Q8)6':574,'(Q6)8':575,'(86)Q':576,'(Q8)7':577,'(Q7)8':578,'(87)Q':579,
|
||||
'(Q9)A':580,'(QA)9':581,'(9A)Q':582,'(Q9)2':583,'(Q2)9':584,'(92)Q':585,'(Q9)3':586,'(Q3)9':587,'(93)Q':588,'(Q9)4':589,
|
||||
'(Q4)9':590,'(94)Q':591,'(Q9)5':592,'(Q5)9':593,'(95)Q':594,'(Q9)6':595,'(Q6)9':596,'(96)Q':597,'(Q9)7':598,'(Q7)9':599,
|
||||
'(97)Q':600,'(Q9)8':601,'(Q8)9':602,'(98)Q':603,'(QT)A':604,'(QA)T':605,'(TA)Q':606,'(QT)2':607,'(Q2)T':608,'(T2)Q':609,
|
||||
'(QT)3':610,'(Q3)T':611,'(T3)Q':612,'(QT)4':613,'(Q4)T':614,'(T4)Q':615,'(QT)5':616,'(Q5)T':617,'(T5)Q':618,'(QT)6':619,
|
||||
'(Q6)T':620,'(T6)Q':621,'(QT)7':622,'(Q7)T':623,'(T7)Q':624,'(QT)8':625,'(Q8)T':626,'(T8)Q':627,'(QT)9':628,'(Q9)T':629,
|
||||
'(T9)Q':630,'(QJ)A':631,'(QA)J':632,'(JA)Q':633,'(QJ)2':634,'(Q2)J':635,'(J2)Q':636,'(QJ)3':637,'(Q3)J':638,'(J3)Q':639,
|
||||
'(QJ)4':640,'(Q4)J':641,'(J4)Q':642,'(QJ)5':643,'(Q5)J':644,'(J5)Q':645,'(QJ)6':646,'(Q6)J':647,'(J6)Q':648,'(QJ)7':649,
|
||||
'(Q7)J':650,'(J7)Q':651,'(QJ)8':652,'(Q8)J':653,'(J8)Q':654,'(QJ)9':655,'(Q9)J':656,'(J9)Q':657,'(QJ)T':658,'(QT)J':659,
|
||||
'(JT)Q':660,'(K2)A':661,'(KA)2':662,'(2A)K':663,'(K3)A':664,'(KA)3':665,'(3A)K':666,'(K3)2':667,'(K2)3':668,'(32)K':669,
|
||||
'(K4)A':670,'(KA)4':671,'(4A)K':672,'(K4)2':673,'(K2)4':674,'(42)K':675,'(K4)3':676,'(K3)4':677,'(43)K':678,'(K5)A':679,
|
||||
'(KA)5':680,'(5A)K':681,'(K5)2':682,'(K2)5':683,'(52)K':684,'(K5)3':685,'(K3)5':686,'(53)K':687,'(K5)4':688,'(K4)5':689,
|
||||
'(54)K':690,'(K6)A':691,'(KA)6':692,'(6A)K':693,'(K6)2':694,'(K2)6':695,'(62)K':696,'(K6)3':697,'(K3)6':698,'(63)K':699,
|
||||
'(K6)4':700,'(K4)6':701,'(64)K':702,'(K6)5':703,'(K5)6':704,'(65)K':705,'(K7)A':706,'(KA)7':707,'(7A)K':708,'(K7)2':709,
|
||||
'(K2)7':710,'(72)K':711,'(K7)3':712,'(K3)7':713,'(73)K':714,'(K7)4':715,'(K4)7':716,'(74)K':717,'(K7)5':718,'(K5)7':719,
|
||||
'(75)K':720,'(K7)6':721,'(K6)7':722,'(76)K':723,'(K8)A':724,'(KA)8':725,'(8A)K':726,'(K8)2':727,'(K2)8':728,'(82)K':729,
|
||||
'(K8)3':730,'(K3)8':731,'(83)K':732,'(K8)4':733,'(K4)8':734,'(84)K':735,'(K8)5':736,'(K5)8':737,'(85)K':738,'(K8)6':739,
|
||||
'(K6)8':740,'(86)K':741,'(K8)7':742,'(K7)8':743,'(87)K':744,'(K9)A':745,'(KA)9':746,'(9A)K':747,'(K9)2':748,'(K2)9':749,
|
||||
'(92)K':750,'(K9)3':751,'(K3)9':752,'(93)K':753,'(K9)4':754,'(K4)9':755,'(94)K':756,'(K9)5':757,'(K5)9':758,'(95)K':759,
|
||||
'(K9)6':760,'(K6)9':761,'(96)K':762,'(K9)7':763,'(K7)9':764,'(97)K':765,'(K9)8':766,'(K8)9':767,'(98)K':768,'(KT)A':769,
|
||||
'(KA)T':770,'(TA)K':771,'(KT)2':772,'(K2)T':773,'(T2)K':774,'(KT)3':775,'(K3)T':776,'(T3)K':777,'(KT)4':778,'(K4)T':779,
|
||||
'(T4)K':780,'(KT)5':781,'(K5)T':782,'(T5)K':783,'(KT)6':784,'(K6)T':785,'(T6)K':786,'(KT)7':787,'(K7)T':788,'(T7)K':789,
|
||||
'(KT)8':790,'(K8)T':791,'(T8)K':792,'(KT)9':793,'(K9)T':794,'(T9)K':795,'(KJ)A':796,'(KA)J':797,'(JA)K':798,'(KJ)2':799,
|
||||
'(K2)J':800,'(J2)K':801,'(KJ)3':802,'(K3)J':803,'(J3)K':804,'(KJ)4':805,'(K4)J':806,'(J4)K':807,'(KJ)5':808,'(K5)J':809,
|
||||
'(J5)K':810,'(KJ)6':811,'(K6)J':812,'(J6)K':813,'(KJ)7':814,'(K7)J':815,'(J7)K':816,'(KJ)8':817,'(K8)J':818,'(J8)K':819,
|
||||
'(KJ)9':820,'(K9)J':821,'(J9)K':822,'(KJ)T':823,'(KT)J':824,'(JT)K':825,'(KQ)A':826,'(KA)Q':827,'(QA)K':828,'(KQ)2':829,
|
||||
'(K2)Q':830,'(Q2)K':831,'(KQ)3':832,'(K3)Q':833,'(Q3)K':834,'(KQ)4':835,'(K4)Q':836,'(Q4)K':837,'(KQ)5':838,'(K5)Q':839,
|
||||
'(Q5)K':840,'(KQ)6':841,'(K6)Q':842,'(Q6)K':843,'(KQ)7':844,'(K7)Q':845,'(Q7)K':846,'(KQ)8':847,'(K8)Q':848,'(Q8)K':849,
|
||||
'(KQ)9':850,'(K9)Q':851,'(Q9)K':852,'(KQ)T':853,'(KT)Q':854,'(QT)K':855,'(KQ)J':856,'(KJ)Q':857,'(QJ)K':858,'(2A)A':859,
|
||||
'(22)A':860,'(AA)2':861,'(2A)2':862,'(3A)A':863,'(33)A':864,'(AA)3':865,'(3A)3':866,'(32)2':867,'(33)2':868,'(22)3':869,
|
||||
'(32)3':870,'(4A)A':871,'(44)A':872,'(AA)4':873,'(4A)4':874,'(42)2':875,'(44)2':876,'(22)4':877,'(42)4':878,'(43)3':879,
|
||||
'(44)3':880,'(33)4':881,'(43)4':882,'(5A)A':883,'(55)A':884,'(AA)5':885,'(5A)5':886,'(52)2':887,'(55)2':888,'(22)5':889,
|
||||
'(52)5':890,'(53)3':891,'(55)3':892,'(33)5':893,'(53)5':894,'(54)4':895,'(55)4':896,'(44)5':897,'(54)5':898,'(6A)A':899,
|
||||
'(66)A':900,'(AA)6':901,'(6A)6':902,'(62)2':903,'(66)2':904,'(22)6':905,'(62)6':906,'(63)3':907,'(66)3':908,'(33)6':909,
|
||||
'(63)6':910,'(64)4':911,'(66)4':912,'(44)6':913,'(64)6':914,'(65)5':915,'(66)5':916,'(55)6':917,'(65)6':918,'(7A)A':919,
|
||||
'(77)A':920,'(AA)7':921,'(7A)7':922,'(72)2':923,'(77)2':924,'(22)7':925,'(72)7':926,'(73)3':927,'(77)3':928,'(33)7':929,
|
||||
'(73)7':930,'(74)4':931,'(77)4':932,'(44)7':933,'(74)7':934,'(75)5':935,'(77)5':936,'(55)7':937,'(75)7':938,'(76)6':939,
|
||||
'(77)6':940,'(66)7':941,'(76)7':942,'(8A)A':943,'(88)A':944,'(AA)8':945,'(8A)8':946,'(82)2':947,'(88)2':948,'(22)8':949,
|
||||
'(82)8':950,'(83)3':951,'(88)3':952,'(33)8':953,'(83)8':954,'(84)4':955,'(88)4':956,'(44)8':957,'(84)8':958,'(85)5':959,
|
||||
'(88)5':960,'(55)8':961,'(85)8':962,'(86)6':963,'(88)6':964,'(66)8':965,'(86)8':966,'(87)7':967,'(88)7':968,'(77)8':969,
|
||||
'(87)8':970,'(9A)A':971,'(99)A':972,'(AA)9':973,'(9A)9':974,'(92)2':975,'(99)2':976,'(22)9':977,'(92)9':978,'(93)3':979,
|
||||
'(99)3':980,'(33)9':981,'(93)9':982,'(94)4':983,'(99)4':984,'(44)9':985,'(94)9':986,'(95)5':987,'(99)5':988,'(55)9':989,
|
||||
'(95)9':990,'(96)6':991,'(99)6':992,'(66)9':993,'(96)9':994,'(97)7':995,'(99)7':996,'(77)9':997,'(97)9':998,'(98)8':999,
|
||||
'(99)8':1000,'(88)9':1001,'(98)9':1002,'(TA)A':1003,'(TT)A':1004,'(AA)T':1005,'(TA)T':1006,'(T2)2':1007,'(TT)2':1008,'(22)T':1009,
|
||||
'(T2)T':1010,'(T3)3':1011,'(TT)3':1012,'(33)T':1013,'(T3)T':1014,'(T4)4':1015,'(TT)4':1016,'(44)T':1017,'(T4)T':1018,'(T5)5':1019,
|
||||
'(TT)5':1020,'(55)T':1021,'(T5)T':1022,'(T6)6':1023,'(TT)6':1024,'(66)T':1025,'(T6)T':1026,'(T7)7':1027,'(TT)7':1028,'(77)T':1029,
|
||||
'(T7)T':1030,'(T8)8':1031,'(TT)8':1032,'(88)T':1033,'(T8)T':1034,'(T9)9':1035,'(TT)9':1036,'(99)T':1037,'(T9)T':1038,'(JA)A':1039,
|
||||
'(JJ)A':1040,'(AA)J':1041,'(JA)J':1042,'(J2)2':1043,'(JJ)2':1044,'(22)J':1045,'(J2)J':1046,'(J3)3':1047,'(JJ)3':1048,'(33)J':1049,
|
||||
'(J3)J':1050,'(J4)4':1051,'(JJ)4':1052,'(44)J':1053,'(J4)J':1054,'(J5)5':1055,'(JJ)5':1056,'(55)J':1057,'(J5)J':1058,'(J6)6':1059,
|
||||
'(JJ)6':1060,'(66)J':1061,'(J6)J':1062,'(J7)7':1063,'(JJ)7':1064,'(77)J':1065,'(J7)J':1066,'(J8)8':1067,'(JJ)8':1068,'(88)J':1069,
|
||||
'(J8)J':1070,'(J9)9':1071,'(JJ)9':1072,'(99)J':1073,'(J9)J':1074,'(JT)T':1075,'(JJ)T':1076,'(TT)J':1077,'(JT)J':1078,'(QA)A':1079,
|
||||
'(QQ)A':1080,'(AA)Q':1081,'(QA)Q':1082,'(Q2)2':1083,'(QQ)2':1084,'(22)Q':1085,'(Q2)Q':1086,'(Q3)3':1087,'(QQ)3':1088,'(33)Q':1089,
|
||||
'(Q3)Q':1090,'(Q4)4':1091,'(QQ)4':1092,'(44)Q':1093,'(Q4)Q':1094,'(Q5)5':1095,'(QQ)5':1096,'(55)Q':1097,'(Q5)Q':1098,'(Q6)6':1099,
|
||||
'(QQ)6':1100,'(66)Q':1101,'(Q6)Q':1102,'(Q7)7':1103,'(QQ)7':1104,'(77)Q':1105,'(Q7)Q':1106,'(Q8)8':1107,'(QQ)8':1108,'(88)Q':1109,
|
||||
'(Q8)Q':1110,'(Q9)9':1111,'(QQ)9':1112,'(99)Q':1113,'(Q9)Q':1114,'(QT)T':1115,'(QQ)T':1116,'(TT)Q':1117,'(QT)Q':1118,'(QJ)J':1119,
|
||||
'(QQ)J':1120,'(JJ)Q':1121,'(QJ)Q':1122,'(KA)A':1123,'(KK)A':1124,'(AA)K':1125,'(KA)K':1126,'(K2)2':1127,'(KK)2':1128,'(22)K':1129,
|
||||
'(K2)K':1130,'(K3)3':1131,'(KK)3':1132,'(33)K':1133,'(K3)K':1134,'(K4)4':1135,'(KK)4':1136,'(44)K':1137,'(K4)K':1138,'(K5)5':1139,
|
||||
'(KK)5':1140,'(55)K':1141,'(K5)K':1142,'(K6)6':1143,'(KK)6':1144,'(66)K':1145,'(K6)K':1146,'(K7)7':1147,'(KK)7':1148,'(77)K':1149,
|
||||
'(K7)K':1150,'(K8)8':1151,'(KK)8':1152,'(88)K':1153,'(K8)K':1154,'(K9)9':1155,'(KK)9':1156,'(99)K':1157,'(K9)K':1158,'(KT)T':1159,
|
||||
'(KK)T':1160,'(TT)K':1161,'(KT)K':1162,'(KJ)J':1163,'(KK)J':1164,'(JJ)K':1165,'(KJ)K':1166,'(KQ)Q':1167,'(KK)Q':1168,'(QQ)K':1169,
|
||||
'(KQ)K':1170,'(AA)A':1171,'(22)2':1172,'(33)3':1173,'(44)4':1174,'(55)5':1175,'(66)6':1176,'(77)7':1177,'(88)8':1178,'(99)9':1179,
|
||||
'(TT)T':1180,'(JJ)J':1181,'(QQ)Q':1182,'(KK)K':1183,
|
||||
}
|
||||
#print "DEBUG: encodeRazzList['%s']: %s" % (startHand, encodeRazzList[startHand])
|
||||
return encodeRazzList[startHand]
|
||||
|
||||
if __name__ == '__main__':
|
||||
print "fpdb card encoding(same as pokersource)"
|
||||
print _("fpdb card encoding(same as pokersource)")
|
||||
for i in xrange(1, 14):
|
||||
print "card %2d = %s card %2d = %s card %2d = %s card %2d = %s" % \
|
||||
(i, valueSuitFromCard(i), i+13, valueSuitFromCard(i+13), i+26, valueSuitFromCard(i+26), i+39, valueSuitFromCard(i+39))
|
||||
|
|
|
|||
|
|
@ -42,10 +42,10 @@ def to_utf8(s):
|
|||
_out = unicode(s, Configuration.LOCALE_ENCODING).encode('utf-8')
|
||||
return _out
|
||||
except UnicodeDecodeError:
|
||||
sys.stderr.write('Could not convert: "%s"\n' % s)
|
||||
sys.stderr.write(_('Could not convert: "%s"\n') % s)
|
||||
raise
|
||||
except UnicodeEncodeError:
|
||||
sys.stderr.write('Could not encode: "%s"\n' % s)
|
||||
sys.stderr.write(_('Could not encode: "%s"\n') % s)
|
||||
raise
|
||||
except TypeError: # TypeError is raised when we give unicode() an already encoded string
|
||||
return s
|
||||
|
|
@ -57,10 +57,10 @@ def to_db_utf8(s):
|
|||
(_out, _len) = encoder_to_utf.encode(unicode(s))
|
||||
return _out
|
||||
except UnicodeDecodeError:
|
||||
sys.stderr.write('Could not convert: "%s"\n' % s)
|
||||
sys.stderr.write(_('Could not convert: "%s"\n') % s)
|
||||
raise
|
||||
except UnicodeEncodeError:
|
||||
sys.stderr.write('Could not encode: "%s"\n' % s)
|
||||
sys.stderr.write(_('Could not encode: "%s"\n') % s)
|
||||
raise
|
||||
|
||||
def to_gui(s):
|
||||
|
|
@ -72,10 +72,10 @@ def to_gui(s):
|
|||
(_out, _len) = encoder_to_sys.encode(s, 'replace')
|
||||
return _out
|
||||
except UnicodeDecodeError:
|
||||
sys.stderr.write('Could not convert: "%s"\n' % s)
|
||||
sys.stderr.write(_('Could not convert: "%s"\n') % s)
|
||||
raise
|
||||
except UnicodeEncodeError:
|
||||
sys.stderr.write('Could not encode: "%s"\n' % s)
|
||||
sys.stderr.write(_('Could not encode: "%s"\n') % s)
|
||||
raise
|
||||
|
||||
def to_hex(s):
|
||||
|
|
@ -83,7 +83,7 @@ def to_hex(s):
|
|||
out = coder_hex.encode(s)[0]
|
||||
return out
|
||||
except UnicodeDecodeError:
|
||||
sys.stderr.write('Could not convert: "%s"\n' % s)
|
||||
sys.stderr.write(_('Could not convert: "%s"\n') % s)
|
||||
return s
|
||||
|
||||
def from_hex(s):
|
||||
|
|
@ -91,5 +91,5 @@ def from_hex(s):
|
|||
out = coder_hex.decode(s)[0]
|
||||
return out
|
||||
except UnicodeDecodeError:
|
||||
sys.stderr.write('Could not convert: "%s"\n' % s)
|
||||
sys.stderr.write(_('Could not convert: "%s"\n') % s)
|
||||
return s
|
||||
|
|
|
|||
448
pyfpdb/Configuration.py
Executable file → Normal file
448
pyfpdb/Configuration.py
Executable file → Normal file
|
|
@ -23,8 +23,13 @@ Handles HUD configuration files.
|
|||
|
||||
########################################################################
|
||||
|
||||
|
||||
# Standard Library modules
|
||||
from __future__ import with_statement
|
||||
|
||||
import L10n
|
||||
_ = L10n.get_translation()
|
||||
|
||||
import os
|
||||
import sys
|
||||
import inspect
|
||||
|
|
@ -70,6 +75,11 @@ def get_exec_path():
|
|||
|
||||
def get_config(file_name, fallback = True):
|
||||
"""Looks in cwd and in self.default_config_path for a config file."""
|
||||
|
||||
# look for example file even if not used here, path is returned to caller
|
||||
config_found,example_found,example_copy = False,False,False
|
||||
config_path, example_path = None,None
|
||||
|
||||
exec_dir = get_exec_path()
|
||||
if file_name == 'logging.conf' and not hasattr(sys, "frozen"):
|
||||
config_path = os.path.join(exec_dir, 'pyfpdb', file_name)
|
||||
|
|
@ -77,42 +87,58 @@ def get_config(file_name, fallback = True):
|
|||
config_path = os.path.join(exec_dir, file_name)
|
||||
# print "config_path=", config_path
|
||||
if os.path.exists(config_path): # there is a file in the cwd
|
||||
return (config_path,False) # so we use it
|
||||
config_found = True # so we use it
|
||||
else: # no file in the cwd, look where it should be in the first place
|
||||
default_dir = get_default_config_path()
|
||||
config_path = os.path.join(default_dir, file_name)
|
||||
# print "config path 2=", config_path
|
||||
if os.path.exists(config_path):
|
||||
return (config_path,False)
|
||||
config_found = True
|
||||
|
||||
# No file found
|
||||
if not fallback:
|
||||
return (False,False)
|
||||
# Example configuration for debian package
|
||||
if os.name == 'posix':
|
||||
# If we're on linux, try to copy example from the place
|
||||
# debian package puts it; get_default_config_path() creates
|
||||
# the config directory for us so there's no need to check it
|
||||
# again
|
||||
example_path = '/usr/share/python-fpdb/' + file_name + '.example'
|
||||
if not config_found and fallback:
|
||||
try:
|
||||
shutil.copyfile(example_path, config_path)
|
||||
example_copy = True
|
||||
msg = _("Config file has been created at %s.\n") % config_path
|
||||
logging.info(msg)
|
||||
except IOError:
|
||||
pass
|
||||
|
||||
# OK, fall back to the .example file, should be in the start dir
|
||||
if os.path.exists(file_name + ".example"):
|
||||
elif os.path.exists(file_name + ".example"):
|
||||
try:
|
||||
print ""
|
||||
example_path = file_name + ".example"
|
||||
check_dir(default_dir)
|
||||
shutil.copyfile(file_name + ".example", config_path)
|
||||
msg = "No %s found\n in %s\n or %s\n" % (file_name, exec_dir, default_dir) \
|
||||
+ "Config file has been created at %s.\n" % config_path
|
||||
print msg
|
||||
logging.info(msg)
|
||||
file_name = config_path
|
||||
if not config_found and fallback:
|
||||
shutil.copyfile(example_path, config_path)
|
||||
example_copy = True
|
||||
msg = _("No %s found\n in %s\n or %s\n") % (file_name, exec_dir, default_dir) \
|
||||
+ _("Config file has been created at %s.\n") % config_path
|
||||
print msg
|
||||
logging.info(msg)
|
||||
except:
|
||||
print "Error copying .example file, cannot fall back. Exiting.\n"
|
||||
sys.stderr.write("Error copying .example file, cannot fall back. Exiting.\n")
|
||||
print _("Error copying .example config file, cannot fall back. Exiting.\n")
|
||||
sys.stderr.write(_("Error copying .example config file, cannot fall back. Exiting.\n"))
|
||||
sys.stderr.write( str(sys.exc_info()) )
|
||||
sys.exit()
|
||||
else:
|
||||
print "No %s found, cannot fall back. Exiting.\n" % file_name
|
||||
sys.stderr.write("No %s found, cannot fall back. Exiting.\n" % file_name)
|
||||
elif fallback:
|
||||
print _("No %s found, cannot fall back. Exiting.\n") % file_name
|
||||
sys.stderr.write(_("No %s found, cannot fall back. Exiting.\n") % file_name)
|
||||
sys.exit()
|
||||
return (file_name,True)
|
||||
|
||||
#print "get_config: returning "+str( (config_path,example_copy,example_path) )
|
||||
return (config_path,example_copy,example_path)
|
||||
|
||||
def get_logger(file_name, config = "config", fallback = False, log_dir=None, log_file=None):
|
||||
(conf_file,copied) = get_config(file_name, fallback = fallback)
|
||||
(conf_file,copied,example_file) = get_config(file_name, fallback = fallback)
|
||||
|
||||
if log_dir is None:
|
||||
log_dir = os.path.join(get_exec_path(), u'log')
|
||||
|
|
@ -137,8 +163,8 @@ def get_logger(file_name, config = "config", fallback = False, log_dir=None, log
|
|||
log = logging.basicConfig(filename=file, level=logging.INFO)
|
||||
log = logging.getLogger()
|
||||
# but it looks like default is no output :-( maybe because all the calls name a module?
|
||||
log.debug("Default logger initialised for "+file)
|
||||
print "Default logger intialised for "+file
|
||||
log.debug(_("Default logger initialised for ")+file)
|
||||
print _("Default logger intialised for ")+file
|
||||
return log
|
||||
|
||||
def check_dir(path, create = True):
|
||||
|
|
@ -149,7 +175,7 @@ def check_dir(path, create = True):
|
|||
else:
|
||||
return False
|
||||
if create:
|
||||
msg = "Creating directory: '%s'" % (path)
|
||||
msg = _("Creating directory: '%s'") % (path)
|
||||
print msg
|
||||
log.info(msg)
|
||||
os.mkdir(path)#, "utf-8"))
|
||||
|
|
@ -175,7 +201,7 @@ DATABASE_TYPES = (
|
|||
#LOCALE_ENCODING = locale.getdefaultlocale()[1]
|
||||
LOCALE_ENCODING = locale.getpreferredencoding()
|
||||
if LOCALE_ENCODING == "US-ASCII":
|
||||
print "Default encoding set to US-ASCII, defaulting to CP1252 instead -- If you're not on a Mac, please report this problem."
|
||||
print _("Default encoding set to US-ASCII, defaulting to CP1252 instead -- If you're not on a Mac, please report this problem.")
|
||||
LOCALE_ENCODING = "cp1252"
|
||||
|
||||
|
||||
|
|
@ -229,6 +255,20 @@ class Layout:
|
|||
|
||||
return temp + "\n"
|
||||
|
||||
class Email:
|
||||
def __init__(self, node):
|
||||
self.node = node
|
||||
self.host= node.getAttribute("host")
|
||||
self.username = node.getAttribute("username")
|
||||
self.password = node.getAttribute("password")
|
||||
self.useSsl = node.getAttribute("useSsl")
|
||||
self.folder = node.getAttribute("folder")
|
||||
self.fetchType = node.getAttribute("fetchType")
|
||||
|
||||
def __str__(self):
|
||||
return " fetchType=%s\n host = %s\n username = %s\n password = %s\n useSsl = %s\n folder = %s\n" \
|
||||
% (self.fetchType, self.host, self.username, self.password, self.useSsl, self.folder)
|
||||
|
||||
class Site:
|
||||
def __init__(self, node):
|
||||
def normalizePath(path):
|
||||
|
|
@ -257,13 +297,18 @@ class Site:
|
|||
self.xshift = node.getAttribute("xshift")
|
||||
self.yshift = node.getAttribute("yshift")
|
||||
self.layout = {}
|
||||
self.emails = {}
|
||||
|
||||
print "Loading site", self.site_name
|
||||
print _("Loading site"), self.site_name
|
||||
|
||||
for layout_node in node.getElementsByTagName('layout'):
|
||||
lo = Layout(layout_node)
|
||||
self.layout[lo.max] = lo
|
||||
|
||||
for email_node in node.getElementsByTagName('email'):
|
||||
email = Email(email_node)
|
||||
self.emails[email.fetchType] = email
|
||||
|
||||
# Site defaults
|
||||
self.xpad = 1 if self.xpad == "" else int(self.xpad)
|
||||
self.ypad = 0 if self.ypad == "" else int(self.ypad)
|
||||
|
|
@ -432,7 +477,7 @@ class Import:
|
|||
self.callFpdbHud = node.getAttribute("callFpdbHud")
|
||||
self.hhArchiveBase = node.getAttribute("hhArchiveBase")
|
||||
self.hhBulkPath = node.getAttribute("hhBulkPath")
|
||||
self.saveActions = string_to_bool(node.getAttribute("saveActions"), default=True)
|
||||
self.saveActions = string_to_bool(node.getAttribute("saveActions"), default=False)
|
||||
self.fastStoreHudCache = string_to_bool(node.getAttribute("fastStoreHudCache"), default=False)
|
||||
self.saveStarsHH = string_to_bool(node.getAttribute("saveStarsHH"), default=False)
|
||||
|
||||
|
|
@ -440,21 +485,6 @@ class Import:
|
|||
return " interval = %s\n callFpdbHud = %s\n hhArchiveBase = %s\n saveActions = %s\n fastStoreHudCache = %s\n" \
|
||||
% (self.interval, self.callFpdbHud, self.hhArchiveBase, self.saveActions, self.fastStoreHudCache)
|
||||
|
||||
class Email:
|
||||
def __init__(self, node):
|
||||
self.node = node
|
||||
self.host= node.getAttribute("host")
|
||||
self.username = node.getAttribute("username")
|
||||
self.password = node.getAttribute("password")
|
||||
self.useSsl = node.getAttribute("useSsl")
|
||||
self.folder = node.getAttribute("folder")
|
||||
self.siteName = node.getAttribute("siteName")
|
||||
self.fetchType = node.getAttribute("fetchType")
|
||||
|
||||
def __str__(self):
|
||||
return " host = %s\n username = %s\n password = %s\n useSsl = %s\n folder = %s\n" \
|
||||
% (self.host, self.username, self.password, self.useSsl, self.folder)
|
||||
|
||||
class HudUI:
|
||||
def __init__(self, node):
|
||||
self.node = node
|
||||
|
|
@ -477,16 +507,6 @@ class HudUI:
|
|||
return " label = %s\n" % self.label
|
||||
|
||||
|
||||
class Tv:
|
||||
def __init__(self, node):
|
||||
self.combinedStealFold = string_to_bool(node.getAttribute("combinedStealFold"), default=True)
|
||||
self.combined2B3B = string_to_bool(node.getAttribute("combined2B3B"), default=True)
|
||||
self.combinedPostflop = string_to_bool(node.getAttribute("combinedPostflop"), default=True)
|
||||
|
||||
def __str__(self):
|
||||
return (" combinedStealFold = %s\n combined2B3B = %s\n combinedPostflop = %s\n" %
|
||||
(self.combinedStealFold, self.combined2B3B, self.combinedPostflop) )
|
||||
|
||||
class General(dict):
|
||||
def __init__(self):
|
||||
super(General, self).__init__()
|
||||
|
|
@ -496,9 +516,23 @@ class General(dict):
|
|||
# e.g. user could set to 4.0 for day to start at 4am local time
|
||||
# [ HH_bulk_path was here - now moved to import section ]
|
||||
for (name, value) in node.attributes.items():
|
||||
log.debug("config.general: adding %s = %s" % (name,value))
|
||||
log.debug(_("config.general: adding %s = %s") % (name,value))
|
||||
self[name] = value
|
||||
|
||||
try:
|
||||
self["version"]=int(self["version"])
|
||||
except KeyError:
|
||||
self["version"]=0
|
||||
self["ui_language"]="system"
|
||||
self["config_difficulty"]="expert"
|
||||
|
||||
def get_defaults(self):
|
||||
self["version"]=0
|
||||
self["ui_language"]="system"
|
||||
self["config_difficulty"]="expert"
|
||||
self["config_wrap_len"]="-1"
|
||||
self["day_start"]="5"
|
||||
|
||||
def __str__(self):
|
||||
s = ""
|
||||
for k in self:
|
||||
|
|
@ -529,17 +563,103 @@ class GUICashStats(list):
|
|||
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")
|
||||
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 get_defaults(self):
|
||||
"""A list of defaults to be called, should there be no entry in config"""
|
||||
# SQL column name, display title, display all, display positional, format, type, alignment
|
||||
defaults = [ [u'game', u'Game', True, True, u'%s', u'str', 0.0],
|
||||
[u'hand', u'Hand', False, False, u'%s', u'str', 0.0],
|
||||
[u'plposition', u'Posn', False, False, u'%s', u'str', 1.0],
|
||||
[u'pname', u'Name', False, False, u'%s', u'str', 0.0],
|
||||
[u'n', u'Hds', True, True, u'%1.0f', u'str', 1.0],
|
||||
[u'avgseats', u'Seats', False, False, u'%3.1f', u'str', 1.0],
|
||||
[u'vpip', u'VPIP', True, True, u'%3.1f', u'str', 1.0],
|
||||
[u'pfr', u'PFR', True, True, u'%3.1f', u'str', 1.0],
|
||||
[u'pf3', u'PF3', True, True, u'%3.1f', u'str', 1.0],
|
||||
[u'aggfac', u'AggFac', True, True, u'%2.2f', u'str', 1.0],
|
||||
[u'aggfrq', u'AggFreq', True, True, u'%3.1f', u'str', 1.0],
|
||||
[u'conbet', u'ContBet', True, True, u'%3.1f', u'str', 1.0],
|
||||
[u'rfi', u'RFI', True, True, u'%3.1f', u'str', 1.0],
|
||||
[u'steals', u'Steals', True, True, u'%3.1f', u'str', 1.0],
|
||||
[u'saw_f', u'Saw_F', True, True, u'%3.1f', u'str', 1.0],
|
||||
[u'sawsd', u'SawSD', True, True, u'%3.1f', u'str', 1.0],
|
||||
[u'wtsdwsf', u'WtSDwsF', True, True, u'%3.1f', u'str', 1.0],
|
||||
[u'wmsd', u'W$SD', True, True, u'%3.1f', u'str', 1.0],
|
||||
[u'flafq', u'FlAFq', True, True, u'%3.1f', u'str', 1.0],
|
||||
[u'tuafq', u'TuAFq', True, True, u'%3.1f', u'str', 1.0],
|
||||
[u'rvafq', u'RvAFq', True, True, u'%3.1f', u'str', 1.0],
|
||||
[u'pofafq', u'PoFAFq', False, False, u'%3.1f', u'str', 1.0],
|
||||
[u'net', u'Net($)', True, True, u'%6.2f', u'cash', 1.0],
|
||||
[u'bbper100', u'bb/100', True, True, u'%4.2f', u'str', 1.0],
|
||||
[u'rake', u'Rake($)', True, True, u'%6.2f', u'cash', 1.0],
|
||||
[u'bb100xr', u'bbxr/100', True, True, u'%4.2f', u'str', 1.0],
|
||||
[u'variance', u'Variance', True, True, u'%5.2f', u'str', 1.0]
|
||||
]
|
||||
for col in defaults:
|
||||
self.append (col)
|
||||
|
||||
# def __str__(self):
|
||||
# s = ""
|
||||
# for l in self:
|
||||
# s = s + " %s = %s\n" % (k, self[k])
|
||||
# return(s)
|
||||
|
||||
class RawHands:
|
||||
def __init__(self, node=None):
|
||||
if node==None:
|
||||
self.save="error"
|
||||
self.compression="none"
|
||||
print _("missing config section raw_hands")
|
||||
else:
|
||||
save=node.getAttribute("save")
|
||||
if save in ("none", "error", "all"):
|
||||
self.save=save
|
||||
else:
|
||||
print _("Invalid config value for raw_hands.save, defaulting to \"error\"")
|
||||
self.save="error"
|
||||
|
||||
compression=node.getAttribute("compression")
|
||||
if save in ("none", "gzip", "bzip2"):
|
||||
self.compression=compression
|
||||
else:
|
||||
print _("Invalid config value for raw_hands.compression, defaulting to \"none\"")
|
||||
self.compression="none"
|
||||
#end def __init__
|
||||
|
||||
def __str__(self):
|
||||
return " save= %s, compression= %s\n" % (self.save, self.compression)
|
||||
#end class RawHands
|
||||
|
||||
class RawTourneys:
|
||||
def __init__(self, node=None):
|
||||
if node==None:
|
||||
self.save="error"
|
||||
self.compression="none"
|
||||
print _("missing config section raw_tourneys")
|
||||
else:
|
||||
save=node.getAttribute("save")
|
||||
if save in ("none", "error", "all"):
|
||||
self.save=save
|
||||
else:
|
||||
print _("Invalid config value for raw_tourneys.save, defaulting to \"error\"")
|
||||
self.save="error"
|
||||
|
||||
compression=node.getAttribute("compression")
|
||||
if save in ("none", "gzip", "bzip2"):
|
||||
self.compression=compression
|
||||
else:
|
||||
print _("Invalid config value for raw_tourneys.compression, defaulting to \"none\"")
|
||||
self.compression="none"
|
||||
#end def __init__
|
||||
|
||||
def __str__(self):
|
||||
return " save= %s, compression= %s\n" % (self.save, self.compression)
|
||||
#end class RawTourneys
|
||||
|
||||
class Config:
|
||||
def __init__(self, file = None, dbname = ''):
|
||||
# "file" is a path to an xml file with the fpdb/HUD configuration
|
||||
|
|
@ -550,11 +670,12 @@ class Config:
|
|||
if file is not None: # config file path passed in
|
||||
file = os.path.expanduser(file)
|
||||
if not os.path.exists(file):
|
||||
print "Configuration file %s not found. Using defaults." % (file)
|
||||
sys.stderr.write("Configuration file %s not found. Using defaults." % (file))
|
||||
print _("Configuration file %s not found. Using defaults.") % (file)
|
||||
sys.stderr.write(_("Configuration file %s not found. Using defaults.") % (file))
|
||||
file = None
|
||||
|
||||
if file is None: (file,self.example_copy) = get_config("HUD_config.xml", True)
|
||||
self.example_copy,example_file = True,None
|
||||
if file is None: (file,self.example_copy,example_file) = get_config("HUD_config.xml", True)
|
||||
|
||||
self.file = file
|
||||
self.dir_self = get_exec_path()
|
||||
|
|
@ -565,41 +686,51 @@ class Config:
|
|||
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
|
||||
# If using the example, we'll edit it later
|
||||
log.info("Reading configuration file %s" % file)
|
||||
print "\nReading configuration file %s\n" % file
|
||||
try:
|
||||
doc = xml.dom.minidom.parse(file)
|
||||
self.file_error = None
|
||||
except:
|
||||
log.error("Error parsing %s. See error log file." % (file))
|
||||
traceback.print_exc(file=sys.stderr)
|
||||
self.file_error = sys.exc_info()[1]
|
||||
# we could add a parameter to decide whether to return or read a line and exit?
|
||||
return
|
||||
#print "press enter to continue"
|
||||
#sys.stdin.readline()
|
||||
#sys.exit()
|
||||
#ExpatError: not well-formed (invalid token): line 511, column 4
|
||||
#sys.exc_info = (<class 'xml.parsers.expat.ExpatError'>, ExpatError('not well-formed (invalid token): line 511,
|
||||
# column 4',), <traceback object at 0x024503A0>)
|
||||
|
||||
self.doc = doc
|
||||
self.supported_sites = {}
|
||||
self.supported_games = {}
|
||||
self.supported_databases = {} # databaseName --> Database instance
|
||||
self.aux_windows = {}
|
||||
self.hhcs = {}
|
||||
self.popup_windows = {}
|
||||
self.db_selected = None # database the user would like to use
|
||||
self.tv = None
|
||||
self.db_selected = None # database the user would like to use
|
||||
self.general = General()
|
||||
self.emails = {}
|
||||
self.gui_cash_stats = GUICashStats()
|
||||
self.site_ids = {} # site ID list from the database
|
||||
|
||||
added,n = 1,0 # use n to prevent infinite loop if add_missing_elements() fails somehow
|
||||
while added > 0 and n < 2:
|
||||
n = n + 1
|
||||
log.info(_("Reading configuration file %s") % file)
|
||||
print _("\nReading configuration file %s\n") % file
|
||||
try:
|
||||
doc = xml.dom.minidom.parse(file)
|
||||
self.doc = doc
|
||||
self.file_error = None
|
||||
except:
|
||||
log.error(_("Error parsing %s. See error log file.") % (file))
|
||||
traceback.print_exc(file=sys.stderr)
|
||||
self.file_error = sys.exc_info()[1]
|
||||
# we could add a parameter to decide whether to return or read a line and exit?
|
||||
return
|
||||
#print "press enter to continue"
|
||||
#sys.stdin.readline()
|
||||
#sys.exit()
|
||||
#ExpatError: not well-formed (invalid token): line 511, column 4
|
||||
#sys.exc_info = (<class 'xml.parsers.expat.ExpatError'>, ExpatError('not well-formed (invalid token): line 511,
|
||||
# column 4',), <traceback object at 0x024503A0>)
|
||||
|
||||
if not self.example_copy and example_file is not None:
|
||||
# reads example file and adds missing elements into current config
|
||||
added = self.add_missing_elements(doc, example_file)
|
||||
|
||||
if doc.getElementsByTagName("general") == []:
|
||||
self.general.get_defaults()
|
||||
for gen_node in doc.getElementsByTagName("general"):
|
||||
self.general.add_elements(node=gen_node) # add/overwrite elements in self.general
|
||||
|
||||
if doc.getElementsByTagName("gui_cash_stats") == []:
|
||||
self.gui_cash_stats.get_defaults()
|
||||
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
|
||||
|
||||
|
|
@ -625,6 +756,7 @@ class Config:
|
|||
raise ValueError("Database names must be unique")
|
||||
if self.db_selected is None or db.db_selected:
|
||||
self.db_selected = db.db_name
|
||||
db_node.setAttribute("default", "True")
|
||||
self.supported_databases[db.db_name] = db
|
||||
#TODO: if the user may passes '' (empty string) as database name via command line, his choice is ignored
|
||||
# ..when we parse the xml we allow for ''. there has to be a decission if to allow '' or not
|
||||
|
|
@ -653,17 +785,10 @@ class Config:
|
|||
imp = Import(node = imp_node)
|
||||
self.imp = imp
|
||||
|
||||
for email_node in doc.getElementsByTagName("email"):
|
||||
email = Email(node = email_node)
|
||||
self.email = email
|
||||
|
||||
for hui_node in doc.getElementsByTagName('hud_ui'):
|
||||
hui = HudUI(node = hui_node)
|
||||
self.ui = hui
|
||||
|
||||
for tv_node in doc.getElementsByTagName("tv"):
|
||||
self.tv = Tv(node = tv_node)
|
||||
|
||||
db = self.get_db_parameters()
|
||||
if db['db-password'] == 'YOUR MYSQL PASSWORD':
|
||||
df_file = self.find_default_conf()
|
||||
|
|
@ -674,9 +799,54 @@ class Config:
|
|||
self.set_db_parameters(db_name = 'fpdb', db_ip = df_parms['db-host'],
|
||||
db_user = df_parms['db-user'],
|
||||
db_pass = df_parms['db-password'])
|
||||
self.save(file=os.path.join(self.default_config_path, "HUD_config.xml"))
|
||||
self.save(file=os.path.join(self.dir_config, "HUD_config.xml"))
|
||||
|
||||
if doc.getElementsByTagName("raw_hands") == []:
|
||||
self.raw_hands = RawHands()
|
||||
for raw_hands_node in doc.getElementsByTagName('raw_hands'):
|
||||
self.raw_hands = RawHands(raw_hands_node)
|
||||
|
||||
if doc.getElementsByTagName("raw_tourneys") == []:
|
||||
self.raw_tourneys = RawTourneys()
|
||||
for raw_tourneys_node in doc.getElementsByTagName('raw_tourneys'):
|
||||
self.raw_tourneys = RawTourneys(raw_tourneys_node)
|
||||
|
||||
print ""
|
||||
#end def __init__
|
||||
|
||||
def add_missing_elements(self, doc, example_file):
|
||||
""" Look through example config file and add any elements that are not in the config
|
||||
May need to add some 'enabled' attributes to turn things off - can't just delete a
|
||||
config section now because this will add it back in"""
|
||||
|
||||
nodes_added = 0
|
||||
|
||||
try:
|
||||
example_doc = xml.dom.minidom.parse(example_file)
|
||||
except:
|
||||
log.error(_("Error parsing example file %s. See error log file.") % (example_file))
|
||||
return nodes_added
|
||||
|
||||
for cnode in doc.getElementsByTagName("FreePokerToolsConfig"):
|
||||
for example_cnode in example_doc.childNodes:
|
||||
if example_cnode.localName == "FreePokerToolsConfig":
|
||||
for e in example_cnode.childNodes:
|
||||
#print "nodetype", e.nodeType, "name", e.localName, "found", len(doc.getElementsByTagName(e.localName))
|
||||
if e.nodeType == e.ELEMENT_NODE and doc.getElementsByTagName(e.localName) == []:
|
||||
new = doc.importNode(e, True) # True means do deep copy
|
||||
t_node = self.doc.createTextNode(" ")
|
||||
cnode.appendChild(t_node)
|
||||
cnode.appendChild(new)
|
||||
t_node = self.doc.createTextNode("\r\n\r\n")
|
||||
cnode.appendChild(t_node)
|
||||
print "... adding missing config section: " + e.localName
|
||||
nodes_added = nodes_added + 1
|
||||
|
||||
if nodes_added > 0:
|
||||
print "Added %d missing config sections\n" % nodes_added
|
||||
self.save()
|
||||
|
||||
return nodes_added
|
||||
|
||||
def set_hhArchiveBase(self, path):
|
||||
self.imp.node.setAttribute("hhArchiveBase", path)
|
||||
|
|
@ -702,6 +872,15 @@ class Config:
|
|||
if site_node.getAttribute("site_name") == site:
|
||||
return site_node
|
||||
|
||||
def getEmailNode(self, siteName, fetchType):
|
||||
siteNode = self.get_site_node(siteName)
|
||||
for emailNode in siteNode.getElementsByTagName("email"):
|
||||
if emailNode.getAttribute("fetchType") == fetchType:
|
||||
print "found emailNode"
|
||||
return emailNode
|
||||
break
|
||||
#end def getEmailNode
|
||||
|
||||
def getGameNode(self,gameName):
|
||||
"""returns DOM game node for a given game"""
|
||||
for gameNode in self.doc.getElementsByTagName("game"):
|
||||
|
|
@ -776,6 +955,15 @@ class Config:
|
|||
else:
|
||||
return(l)
|
||||
|
||||
def editEmail(self, siteName, fetchType, newEmail):
|
||||
emailNode = self.getEmailNode(siteName, fetchType)
|
||||
emailNode.setAttribute("host", newEmail.host)
|
||||
emailNode.setAttribute("username", newEmail.username)
|
||||
emailNode.setAttribute("password", newEmail.password)
|
||||
emailNode.setAttribute("folder", newEmail.folder)
|
||||
emailNode.setAttribute("useSsl", newEmail.useSsl)
|
||||
#end def editEmail
|
||||
|
||||
def edit_layout(self, site_name, max, width = None, height = None,
|
||||
fav_seat = None, locations = None):
|
||||
site_node = self.get_site_node(site_name)
|
||||
|
|
@ -893,7 +1081,11 @@ class Config:
|
|||
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 defaultb: db_node.setAttribute("default", default)
|
||||
if defaultb or self.db_selected == db_name:
|
||||
db_node.setAttribute("default", "True")
|
||||
for dbn in self.doc.getElementsByTagName("database"):
|
||||
if dbn.getAttribute('db_name') != db_name and dbn.hasAttribute("default"):
|
||||
dbn.removeAttribute("default")
|
||||
elif db_node.hasAttribute("default"):
|
||||
db_node.removeAttribute("default")
|
||||
if self.supported_databases.has_key(db_name):
|
||||
|
|
@ -907,6 +1099,64 @@ class Config:
|
|||
self.db_selected = db_name
|
||||
return
|
||||
|
||||
def add_db_parameters(self, db_name = 'fpdb', db_ip = None, db_user = None,
|
||||
db_pass = None, db_desc = None, db_server = None,
|
||||
default = "False"):
|
||||
default = default.lower()
|
||||
defaultb = string_to_bool(default, False)
|
||||
if db_name in self.supported_databases:
|
||||
raise ValueError("Database names must be unique")
|
||||
|
||||
db_node = self.get_db_node(db_name)
|
||||
if db_node is None:
|
||||
for db_node in self.doc.getElementsByTagName("supported_databases"):
|
||||
# should only be one supported_databases element, use last one if there are several
|
||||
suppdb_node = db_node
|
||||
t_node = self.doc.createTextNode(" ")
|
||||
suppdb_node.appendChild(t_node)
|
||||
db_node = self.doc.createElement("database")
|
||||
suppdb_node.appendChild(db_node)
|
||||
t_node = self.doc.createTextNode("\r\n ")
|
||||
suppdb_node.appendChild(t_node)
|
||||
db_node.setAttribute("db_name", db_name)
|
||||
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 defaultb:
|
||||
db_node.setAttribute("default", "True")
|
||||
for dbn in self.doc.getElementsByTagName("database"):
|
||||
if dbn.getAttribute('db_name') != db_name and dbn.hasAttribute("default"):
|
||||
dbn.removeAttribute("default")
|
||||
elif db_node.hasAttribute("default"):
|
||||
db_node.removeAttribute("default")
|
||||
else:
|
||||
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 defaultb or self.db_selected == db_name:
|
||||
db_node.setAttribute("default", "True")
|
||||
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
|
||||
self.supported_databases[db_name].db_selected = defaultb
|
||||
else:
|
||||
db = Database(node=db_node)
|
||||
self.supported_databases[db.db_name] = db
|
||||
|
||||
if defaultb:
|
||||
self.db_selected = db_name
|
||||
return
|
||||
|
||||
def get_backend(self, name):
|
||||
"""Returns the number of the currently used backend"""
|
||||
if name == DATABASE_TYPE_MYSQL:
|
||||
|
|
@ -931,15 +1181,6 @@ class Config:
|
|||
return site_name
|
||||
return None
|
||||
|
||||
def get_tv_parameters(self):
|
||||
if self.tv is not None:
|
||||
return {
|
||||
'combinedStealFold': self.tv.combinedStealFold,
|
||||
'combined2B3B': self.tv.combined2B3B,
|
||||
'combinedPostflop': self.tv.combinedPostflop
|
||||
}
|
||||
return {}
|
||||
|
||||
# Allow to change the menu appearance
|
||||
def get_hud_ui_parameters(self):
|
||||
hui = {}
|
||||
|
|
@ -1016,7 +1257,7 @@ class Config:
|
|||
except: imp['hhBulkPath'] = ""
|
||||
|
||||
try: imp['saveActions'] = self.imp.saveActions
|
||||
except: imp['saveActions'] = True
|
||||
except: imp['saveActions'] = False
|
||||
|
||||
try: imp['saveStarsHH'] = self.imp.saveStarsHH
|
||||
except: imp['saveStarsHH'] = False
|
||||
|
|
@ -1145,6 +1386,12 @@ class Config:
|
|||
if font_size is not None: site_node.setAttribute("font_size", font_size)
|
||||
return
|
||||
|
||||
def set_site_ids(self, sites):
|
||||
self.site_ids = dict(sites)
|
||||
|
||||
def get_site_id(self, site):
|
||||
return( self.site_ids[site] )
|
||||
|
||||
def get_aux_windows(self):
|
||||
"""Gets the list of mucked window formats in the configuration."""
|
||||
return self.aux_windows.keys()
|
||||
|
|
@ -1232,15 +1479,10 @@ if __name__== "__main__":
|
|||
print c.imp
|
||||
print "----------- END IMPORT -----------"
|
||||
|
||||
print "\n----------- TABLE VIEW -----------"
|
||||
# print c.tv
|
||||
print "----------- END TABLE VIEW -----------"
|
||||
|
||||
c.edit_layout("PokerStars", 6, locations=( (1, 1), (2, 2), (3, 3), (4, 4), (5, 5), (6, 6) ))
|
||||
c.save(file="testout.xml")
|
||||
|
||||
print "db = ", c.get_db_parameters()
|
||||
# print "tv = ", c.get_tv_parameters()
|
||||
# print "imp = ", c.get_import_parameters()
|
||||
print "paths = ", c.get_default_paths("PokerStars")
|
||||
print "colors = ", c.get_default_colors("PokerStars")
|
||||
|
|
|
|||
File diff suppressed because it is too large
Load Diff
|
|
@ -19,19 +19,17 @@
|
|||
import Card
|
||||
from decimal import Decimal
|
||||
|
||||
DEBUG = False
|
||||
|
||||
if DEBUG:
|
||||
import pprint
|
||||
pp = pprint.PrettyPrinter(indent=4)
|
||||
|
||||
import logging
|
||||
# logging has been set up in fpdb.py or HUD_main.py, use their settings:
|
||||
log = logging.getLogger("parser")
|
||||
|
||||
class DerivedStats():
|
||||
def __init__(self, hand):
|
||||
self.hand = hand
|
||||
|
||||
self.hands = {}
|
||||
self.hands = {}
|
||||
self.handsplayers = {}
|
||||
self.handsactions = {}
|
||||
|
||||
def getStats(self, hand):
|
||||
|
||||
|
|
@ -51,8 +49,8 @@ class DerivedStats():
|
|||
self.handsplayers[player[1]]['position'] = 2
|
||||
self.handsplayers[player[1]]['street0_3BChance'] = False
|
||||
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]]['street0_4BChance'] = False #FIXME: this might not actually be implemented
|
||||
self.handsplayers[player[1]]['street0_4BDone'] = False #FIXME: this might not actually be implemented
|
||||
self.handsplayers[player[1]]['raiseFirstInChance'] = False
|
||||
self.handsplayers[player[1]]['raisedFirstIn'] = False
|
||||
self.handsplayers[player[1]]['foldBbToStealChance'] = False
|
||||
|
|
@ -74,19 +72,22 @@ class DerivedStats():
|
|||
self.handsplayers[player[1]]['foldToOtherRaisedStreet%d' %i] = False
|
||||
|
||||
#FIXME - Everything below this point is incomplete.
|
||||
self.handsplayers[player[1]]['other3BStreet0'] = False
|
||||
self.handsplayers[player[1]]['other4BStreet0'] = False
|
||||
self.handsplayers[player[1]]['otherRaisedStreet0'] = False
|
||||
self.handsplayers[player[1]]['foldToOtherRaisedStreet0'] = False
|
||||
for i in range(1,5):
|
||||
self.handsplayers[player[1]]['foldToStreet%dCBChance' %i] = False
|
||||
self.handsplayers[player[1]]['foldToStreet%dCBDone' %i] = False
|
||||
self.handsplayers[player[1]]['wonWhenSeenStreet2'] = 0.0
|
||||
self.handsplayers[player[1]]['wonWhenSeenStreet3'] = 0.0
|
||||
self.handsplayers[player[1]]['wonWhenSeenStreet4'] = 0.0
|
||||
|
||||
self.assembleHands(self.hand)
|
||||
self.assembleHandsPlayers(self.hand)
|
||||
|
||||
|
||||
if DEBUG:
|
||||
print "Hands:"
|
||||
pp.pprint(self.hands)
|
||||
print "HandsPlayers:"
|
||||
pp.pprint(self.handsplayers)
|
||||
if self.hand.saveActions:
|
||||
self.assembleHandsActions(self.hand)
|
||||
|
||||
def getHands(self):
|
||||
return self.hands
|
||||
|
|
@ -94,6 +95,9 @@ class DerivedStats():
|
|||
def getHandsPlayers(self):
|
||||
return self.handsplayers
|
||||
|
||||
def getHandsActions(self):
|
||||
return self.handsactions
|
||||
|
||||
def assembleHands(self, hand):
|
||||
self.hands['tableName'] = hand.tablename
|
||||
self.hands['siteHandNo'] = hand.handid
|
||||
|
|
@ -171,6 +175,12 @@ class DerivedStats():
|
|||
self.handsplayers[player]['rake'] = int(100* hand.rake)/len(hand.collectees)
|
||||
if self.handsplayers[player]['street1Seen'] == True:
|
||||
self.handsplayers[player]['wonWhenSeenStreet1'] = 1.0
|
||||
if self.handsplayers[player]['street2Seen'] == True:
|
||||
self.handsplayers[player]['wonWhenSeenStreet2'] = 1.0
|
||||
if self.handsplayers[player]['street3Seen'] == True:
|
||||
self.handsplayers[player]['wonWhenSeenStreet3'] = 1.0
|
||||
if self.handsplayers[player]['street4Seen'] == True:
|
||||
self.handsplayers[player]['wonWhenSeenStreet4'] = 1.0
|
||||
if self.handsplayers[player]['sawShowdown'] == True:
|
||||
self.handsplayers[player]['wonAtSD'] = 1.0
|
||||
|
||||
|
|
@ -196,6 +206,36 @@ class DerivedStats():
|
|||
# 3betSB, 3betBB
|
||||
# Squeeze, Ratchet?
|
||||
|
||||
def assembleHandsActions(self, hand):
|
||||
k = 0
|
||||
for i, street in enumerate(hand.actionStreets):
|
||||
for j, act in enumerate(hand.actions[street]):
|
||||
k += 1
|
||||
self.handsactions[k] = {}
|
||||
#default values
|
||||
self.handsactions[k]['amount'] = 0
|
||||
self.handsactions[k]['raiseTo'] = 0
|
||||
self.handsactions[k]['amountCalled'] = 0
|
||||
self.handsactions[k]['numDiscarded'] = 0
|
||||
self.handsactions[k]['cardsDiscarded'] = None
|
||||
self.handsactions[k]['allIn'] = False
|
||||
#Insert values from hand.actions
|
||||
self.handsactions[k]['player'] = act[0]
|
||||
self.handsactions[k]['street'] = i-1
|
||||
self.handsactions[k]['actionNo'] = k
|
||||
self.handsactions[k]['streetActionNo'] = (j+1)
|
||||
self.handsactions[k]['actionId'] = hand.ACTION[act[1]]
|
||||
if act[1] not in ('discards') and len(act) > 2:
|
||||
self.handsactions[k]['amount'] = int(100 * act[2])
|
||||
if act[1] in ('raises', 'completes'):
|
||||
self.handsactions[k]['raiseTo'] = int(100 * act[3])
|
||||
self.handsactions[k]['amountCalled'] = int(100 * act[4])
|
||||
if act[1] in ('discards'):
|
||||
self.handsactions[k]['numDiscarded'] = int(act[2])
|
||||
if act[1] in ('discards') and len(act) > 3:
|
||||
self.handsactions[k]['cardsDiscarded'] = act[3]
|
||||
if len(act) > 3 and act[1] not in ('discards'):
|
||||
self.handsactions[k]['allIn'] = act[-1]
|
||||
|
||||
def setPositions(self, hand):
|
||||
"""Sets the position for each player in HandsPlayers
|
||||
|
|
@ -203,44 +243,34 @@ class DerivedStats():
|
|||
first betting round is 0
|
||||
NOTE: HU, both values are negative for non-stud games
|
||||
NOTE2: I've never seen a HU stud match"""
|
||||
# The position calculation must be done differently for Stud and other games as
|
||||
# Stud the 'blind' acts first - in all other games they act last.
|
||||
#
|
||||
#This function is going to get it wrong when there in situations where there
|
||||
# is no small blind. I can live with that.
|
||||
actions = hand.actions[hand.holeStreets[0]]
|
||||
# Note: pfbao list may not include big blind if all others folded
|
||||
players = self.pfbao(actions)
|
||||
|
||||
# set blinds first, then others from pfbao list, avoids problem if bb
|
||||
# is missing from pfbao list or if there is no small blind
|
||||
sb, bb, bi = False, False, False
|
||||
if hand.gametype['base'] == 'stud':
|
||||
positions = [7, 6, 5, 4, 3, 2, 1, 0, 'S', 'B']
|
||||
seats = len(players)
|
||||
map = []
|
||||
# Could posibly change this to be either -2 or -1 depending if they complete or bring-in
|
||||
# First player to act is -1, last player is 0 for 6 players it should look like:
|
||||
# ['S', 4, 3, 2, 1, 0]
|
||||
map = positions[-seats-1:-1] # Copy required positions from postions array anding in -1
|
||||
map = map[-1:] + map[0:-1] # and move the -1 to the start of that array
|
||||
|
||||
for i, player in enumerate(players):
|
||||
#print "player %s in posn %s" % (player, str(map[i]))
|
||||
self.handsplayers[player]['position'] = map[i]
|
||||
# Stud position is determined after cards are dealt
|
||||
bi = [x[0] for x in hand.actions[hand.actionStreets[1]] if x[1] == 'bringin']
|
||||
else:
|
||||
# set blinds first, then others from pfbao list, avoids problem if bb
|
||||
# is missing from pfbao list or if there is no small blind
|
||||
bb = [x[0] for x in hand.actions[hand.actionStreets[0]] if x[2] == 'big blind']
|
||||
sb = [x[0] for x in hand.actions[hand.actionStreets[0]] if x[2] == 'small blind']
|
||||
# if there are > 1 sb or bb only the first is used!
|
||||
if bb:
|
||||
self.handsplayers[bb[0]]['position'] = 'B'
|
||||
if bb[0] in players: players.remove(bb[0])
|
||||
if sb:
|
||||
self.handsplayers[sb[0]]['position'] = 'S'
|
||||
if sb[0] in players: players.remove(sb[0])
|
||||
bb = [x[0] for x in hand.actions[hand.actionStreets[0]] if x[1] == 'big blind']
|
||||
sb = [x[0] for x in hand.actions[hand.actionStreets[0]] if x[1] == 'small blind']
|
||||
|
||||
#print "bb =", bb, "sb =", sb, "players =", players
|
||||
for i,player in enumerate(reversed(players)):
|
||||
self.handsplayers[player]['position'] = i
|
||||
# if there are > 1 sb or bb only the first is used!
|
||||
if bb:
|
||||
self.handsplayers[bb[0]]['position'] = 'B'
|
||||
if bb[0] in players: players.remove(bb[0])
|
||||
if sb:
|
||||
self.handsplayers[sb[0]]['position'] = 'S'
|
||||
if sb[0] in players: players.remove(sb[0])
|
||||
if bi:
|
||||
self.handsplayers[bi[0]]['position'] = 'S'
|
||||
if bi[0] in players: players.remove(bi[0])
|
||||
|
||||
#print "DEBUG: bb: '%s' sb: '%s' bi: '%s' plyrs: '%s'" %(bb, sb, bi, players)
|
||||
for i,player in enumerate(reversed(players)):
|
||||
self.handsplayers[player]['position'] = i
|
||||
|
||||
def assembleHudCache(self, hand):
|
||||
# No real work to be done - HandsPlayers data already contains the correct info
|
||||
|
|
@ -249,7 +279,7 @@ class DerivedStats():
|
|||
def vpip(self, hand):
|
||||
vpipers = set()
|
||||
for act in hand.actions[hand.actionStreets[1]]:
|
||||
if act[1] in ('calls','bets', 'raises'):
|
||||
if act[1] in ('calls','bets', 'raises', 'completes'):
|
||||
vpipers.add(act[0])
|
||||
|
||||
self.hands['playersVpi'] = len(vpipers)
|
||||
|
|
@ -290,9 +320,11 @@ 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)
|
||||
|
||||
# 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']])
|
||||
# hand.players includes people that are sitting out on some sites for cash games
|
||||
# actionStreets[1] is 'DEAL', 'THIRD', 'PREFLOP', so any player dealt cards
|
||||
# must act on this street if dealt cards. Almost certainly broken for the 'all-in blind' case
|
||||
# and right now i don't care - CG
|
||||
p_in = set([x[0] for x in hand.actions[hand.actionStreets[1]]])
|
||||
|
||||
for (i, street) in enumerate(hand.actionStreets):
|
||||
actions = hand.actions[street]
|
||||
|
|
@ -345,9 +377,9 @@ class DerivedStats():
|
|||
if steal_attempt and act != 'folds':
|
||||
break
|
||||
|
||||
if not steal_attempt and not raised: # if posn in steal_positions and not steal_attempt:
|
||||
if not steal_attempt and not raised and not act in ('bringin'):
|
||||
self.handsplayers[pname]['raiseFirstInChance'] = True
|
||||
if act in ('bets', 'raises'):
|
||||
if act in ('bets', 'raises', 'completes'):
|
||||
self.handsplayers[pname]['raisedFirstIn'] = True
|
||||
raised = True
|
||||
if posn in steal_positions:
|
||||
|
|
@ -355,7 +387,7 @@ class DerivedStats():
|
|||
if act == 'calls':
|
||||
break
|
||||
|
||||
if posn not in steal_positions and act != 'folds':
|
||||
if posn not in steal_positions and act not in ('folds', 'bringin'):
|
||||
break
|
||||
|
||||
def calc34BetStreet0(self, hand):
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
#!/usr/bin/env python
|
||||
#!/usr/bin/env python
|
||||
# -*- coding: utf-8 -*-
|
||||
#
|
||||
# Copyright 2008-2010, Carl Gherardi
|
||||
|
|
@ -18,6 +18,9 @@
|
|||
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
########################################################################
|
||||
|
||||
import L10n
|
||||
_ = L10n.get_translation()
|
||||
|
||||
import sys
|
||||
import logging
|
||||
from HandHistoryConverter import *
|
||||
|
|
@ -63,13 +66,16 @@ class Everleaf(HandHistoryConverter):
|
|||
self.re_SitsOut = re.compile(ur"^%s sits out" % player_re, re.MULTILINE)
|
||||
|
||||
def readSupportedGames(self):
|
||||
return [["ring", "hold", "nl"],
|
||||
return [
|
||||
["ring", "hold", "nl"],
|
||||
["ring", "hold", "pl"],
|
||||
["ring", "hold", "fl"],
|
||||
["ring", "studhi", "fl"],
|
||||
["ring", "omahahi", "pl"],
|
||||
["ring", "omahahilo", "pl"],
|
||||
["tour", "hold", "nl"]
|
||||
["ring", "stud", "fl"],
|
||||
#["ring", "omahahi", "pl"],
|
||||
#["ring", "omahahilo", "pl"],
|
||||
["tour", "hold", "nl"],
|
||||
["tour", "hold", "fl"],
|
||||
["tour", "hold", "pl"]
|
||||
]
|
||||
|
||||
def determineGameType(self, handText):
|
||||
|
|
@ -133,7 +139,7 @@ or None if we fail to get the info """
|
|||
def readHandInfo(self, hand):
|
||||
m = self.re_HandInfo.search(hand.handText)
|
||||
if(m == None):
|
||||
logging.info("Didn't match re_HandInfo")
|
||||
logging.info(_("Didn't match re_HandInfo"))
|
||||
logging.info(hand.handText)
|
||||
return None
|
||||
logging.debug("HID %s, Table %s" % (m.group('HID'), m.group('TABLE')))
|
||||
|
|
@ -168,8 +174,10 @@ or None if we fail to get the info """
|
|||
for a in m:
|
||||
seatnum = int(a.group('SEAT'))
|
||||
hand.addPlayer(seatnum, a.group('PNAME'), a.group('CASH'))
|
||||
if seatnum > 6:
|
||||
hand.maxseats = 10 # everleaf currently does 2/6/10 games, so if seats > 6 are in use, it must be 10-max.
|
||||
if seatnum > 8:
|
||||
hand.maxseats = 10 # they added 8-seat games now
|
||||
elif seatnum > 6:
|
||||
hand.maxseats = 8 # everleaf currently does 2/6/10 games, so if seats > 6 are in use, it must be 10-max.
|
||||
# TODO: implement lookup list by table-name to determine maxes, then fall back to 6 default/10 here, if there's no entry in the list?
|
||||
|
||||
|
||||
|
|
@ -202,7 +210,7 @@ or None if we fail to get the info """
|
|||
hand.setCommunityCards(street=street, cards=cards)
|
||||
|
||||
def readAntes(self, hand):
|
||||
logging.debug("reading antes")
|
||||
logging.debug(_("reading antes"))
|
||||
m = self.re_Antes.finditer(hand.handText)
|
||||
for player in m:
|
||||
logging.debug("hand.addAnte(%s,%s)" %(player.group('PNAME'), player.group('ANTE')))
|
||||
|
|
@ -214,14 +222,14 @@ or None if we fail to get the info """
|
|||
logging.debug("Player bringing in: %s for %s" %(m.group('PNAME'), m.group('BRINGIN')))
|
||||
hand.addBringIn(m.group('PNAME'), m.group('BRINGIN'))
|
||||
else:
|
||||
logging.warning("No bringin found.")
|
||||
logging.warning(_("No bringin found."))
|
||||
|
||||
def readBlinds(self, hand):
|
||||
m = self.re_PostSB.search(hand.handText)
|
||||
if m is not None:
|
||||
hand.addBlind(m.group('PNAME'), 'small blind', m.group('SB'))
|
||||
else:
|
||||
logging.debug("No small blind")
|
||||
logging.debug(_("No small blind"))
|
||||
hand.addBlind(None, None, None)
|
||||
for a in self.re_PostBB.finditer(hand.handText):
|
||||
hand.addBlind(a.group('PNAME'), 'big blind', a.group('BB'))
|
||||
|
|
@ -249,7 +257,7 @@ or None if we fail to get the info """
|
|||
|
||||
def readStudPlayerCards(self, hand, street):
|
||||
# lol. see Plymouth.txt
|
||||
logging.warning("Everleaf readStudPlayerCards is only a stub.")
|
||||
logging.warning(_("Everleaf readStudPlayerCards is only a stub."))
|
||||
#~ if street in ('THIRD', 'FOURTH', 'FIFTH', 'SIXTH'):
|
||||
#~ hand.addPlayerCards(player = player.group('PNAME'), street = street, closed = [], open = [])
|
||||
|
||||
|
|
@ -272,7 +280,7 @@ or None if we fail to get the info """
|
|||
elif action.group('ATYPE') == ' complete to':
|
||||
hand.addComplete( street, action.group('PNAME'), action.group('BET'))
|
||||
else:
|
||||
logging.debug("Unimplemented readAction: %s %s" %(action.group('PNAME'),action.group('ATYPE'),))
|
||||
logging.debug(_("Unimplemented readAction: %s %s" %(action.group('PNAME'),action.group('ATYPE'),)))
|
||||
|
||||
|
||||
def readShowdownActions(self, hand):
|
||||
|
|
@ -281,7 +289,7 @@ or None if we fail to get the info """
|
|||
for shows in self.re_ShowdownAction.finditer(hand.handText):
|
||||
cards = shows.group('CARDS')
|
||||
cards = cards.split(', ')
|
||||
logging.debug("readShowdownActions %s %s" %(cards, shows.group('PNAME')))
|
||||
logging.debug(_("readShowdownActions %s %s" %(cards, shows.group('PNAME'))))
|
||||
hand.addShownCards(cards, shows.group('PNAME'))
|
||||
|
||||
|
||||
|
|
@ -310,9 +318,9 @@ or None if we fail to get the info """
|
|||
|
||||
if __name__ == "__main__":
|
||||
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="-")
|
||||
parser.add_option("-f", "--follow", dest="follow", help="follow (tail -f) the input", action="store_true", default=False)
|
||||
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="-")
|
||||
parser.add_option("-f", "--follow", dest="follow", help=_("follow (tail -f) the input"), action="store_true", default=False)
|
||||
parser.add_option("-q", "--quiet",
|
||||
action="store_const", const=logging.CRITICAL, dest="verbosity", default=logging.INFO)
|
||||
parser.add_option("-v", "--verbose",
|
||||
|
|
|
|||
|
|
@ -73,3 +73,6 @@ class FpdbHandDuplicate(FpdbHandError):
|
|||
|
||||
class FpdbHandPartial(FpdbHandError):
|
||||
pass
|
||||
|
||||
class FpdbEndOfFile(FpdbHandError):
|
||||
pass
|
||||
|
|
|
|||
|
|
@ -15,6 +15,9 @@
|
|||
#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 L10n
|
||||
_ = L10n.get_translation()
|
||||
|
||||
import threading
|
||||
import pygtk
|
||||
pygtk.require('2.0')
|
||||
|
|
@ -30,7 +33,6 @@ import logging
|
|||
# logging has been set up in fpdb.py or HUD_main.py, use their settings:
|
||||
log = logging.getLogger("filter")
|
||||
|
||||
|
||||
import Configuration
|
||||
import Database
|
||||
import SQL
|
||||
|
|
@ -48,18 +50,19 @@ class Filters(threading.Thread):
|
|||
self.display = display
|
||||
|
||||
# text used on screen stored here so that it can be configured
|
||||
self.filterText = {'limitsall':'All', 'limitsnone':'None', 'limitsshow':'Show _Limits'
|
||||
,'seatsbetween':'Between:', 'seatsand':'And:', 'seatsshow':'Show Number of _Players'
|
||||
,'playerstitle':'Hero:', 'sitestitle':'Sites:', 'gamestitle':'Games:'
|
||||
,'limitstitle':'Limits:', 'seatstitle':'Number of Players:'
|
||||
,'groupstitle':'Grouping:', 'posnshow':'Show Position Stats:'
|
||||
,'datestitle':'Date:'
|
||||
,'groupsall':'All Players'
|
||||
,'limitsFL':'FL', 'limitsNL':'NL', 'limitsPL':'PL', 'ring':'Ring', 'tour':'Tourney'
|
||||
self.filterText = {'limitsall':_('All'), 'limitsnone':_('None'), 'limitsshow':_('Show _Limits')
|
||||
,'seatsbetween':_('Between:'), 'seatsand':_('And:'), 'seatsshow':_('Show Number of _Players')
|
||||
,'playerstitle':_('Hero:'), 'sitestitle':_('Sites:'), 'gamestitle':_('Games:')
|
||||
,'limitstitle':_('Limits:'), 'seatstitle':_('Number of Players:')
|
||||
,'groupstitle':_('Grouping:'), 'posnshow':_('Show Position Stats')
|
||||
,'datestitle':_('Date:')
|
||||
,'groupsall':_('All Players')
|
||||
,'limitsFL':'FL', 'limitsNL':'NL', 'limitsPL':'PL', 'ring':_('Ring'), 'tour':_('Tourney')
|
||||
}
|
||||
|
||||
gen = self.conf.get_general_params()
|
||||
self.day_start = 0
|
||||
|
||||
if 'day_start' in gen:
|
||||
self.day_start = float(gen['day_start'])
|
||||
|
||||
|
|
@ -81,6 +84,7 @@ class Filters(threading.Thread):
|
|||
self.siteid = {}
|
||||
self.heroes = {}
|
||||
self.boxes = {}
|
||||
self.graphops = {}
|
||||
|
||||
for site in self.conf.get_supported_sites():
|
||||
#Get db site id for filtering later
|
||||
|
|
@ -89,7 +93,7 @@ class Filters(threading.Thread):
|
|||
if len(result) == 1:
|
||||
self.siteid[site] = result[0][0]
|
||||
else:
|
||||
print "Either 0 or more than one site matched (%s) - EEK" % site
|
||||
print _("Either 0 or more than one site matched (%s) - EEK") % site
|
||||
|
||||
# For use in date ranges.
|
||||
self.start_date = gtk.Entry(max=12)
|
||||
|
|
@ -101,6 +105,12 @@ class Filters(threading.Thread):
|
|||
self.sbGroups = {}
|
||||
self.numHands = 0
|
||||
|
||||
# for use in graphops
|
||||
# dspin = display in '$' or 'B'
|
||||
self.graphops['dspin'] = "$"
|
||||
self.graphops['showdown'] = 'OFF'
|
||||
self.graphops['nonshowdown'] = 'OFF'
|
||||
|
||||
playerFrame = gtk.Frame()
|
||||
playerFrame.set_label_align(0.0, 0.0)
|
||||
vbox = gtk.VBox(False, 0)
|
||||
|
|
@ -141,6 +151,16 @@ class Filters(threading.Thread):
|
|||
self.fillLimitsFrame(vbox, self.display)
|
||||
limitsFrame.add(vbox)
|
||||
|
||||
# GraphOps
|
||||
graphopsFrame = gtk.Frame()
|
||||
#graphops.set_label_align(0,0, 0.0)
|
||||
graphopsFrame.show()
|
||||
vbox = gtk.VBox(False, 0)
|
||||
|
||||
self.fillGraphOpsFrame(vbox)
|
||||
graphopsFrame.add(vbox)
|
||||
|
||||
|
||||
# Seats
|
||||
seatsFrame = gtk.Frame()
|
||||
seatsFrame.show()
|
||||
|
|
@ -181,6 +201,7 @@ class Filters(threading.Thread):
|
|||
self.mainVBox.add(seatsFrame)
|
||||
self.mainVBox.add(groupsFrame)
|
||||
self.mainVBox.add(dateFrame)
|
||||
self.mainVBox.add(graphopsFrame)
|
||||
self.mainVBox.add(self.Button1)
|
||||
self.mainVBox.add(self.Button2)
|
||||
|
||||
|
|
@ -201,6 +222,8 @@ class Filters(threading.Thread):
|
|||
groupsFrame.hide()
|
||||
if "Dates" not in self.display or self.display["Dates"] == False:
|
||||
dateFrame.hide()
|
||||
if "GraphOps" not in self.display or self.display["GraphOps"] == False:
|
||||
graphopsFrame.hide()
|
||||
if "Button1" not in self.display or self.display["Button1"] == False:
|
||||
self.Button1.hide()
|
||||
if "Button2" not in self.display or self.display["Button2"] == False:
|
||||
|
|
@ -253,6 +276,9 @@ class Filters(threading.Thread):
|
|||
return self.heroes
|
||||
#end def getHeroes
|
||||
|
||||
def getGraphOps(self):
|
||||
return self.graphops
|
||||
|
||||
def getLimits(self):
|
||||
ltuple = []
|
||||
for l in self.limits:
|
||||
|
|
@ -299,7 +325,7 @@ class Filters(threading.Thread):
|
|||
#end def registerButton2Callback
|
||||
|
||||
def cardCallback(self, widget, data=None):
|
||||
log.debug( "%s was toggled %s" % (data, ("OFF", "ON")[widget.get_active()]) )
|
||||
log.debug( _("%s was toggled %s") % (data, (_("OFF"), _("ON"))[widget.get_active()]) )
|
||||
|
||||
def createPlayerLine(self, hbox, site, player):
|
||||
log.debug('add:"%s"' % player)
|
||||
|
|
@ -380,19 +406,19 @@ class Filters(threading.Thread):
|
|||
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]))
|
||||
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()
|
||||
self.games[game] = w.get_active()
|
||||
log.debug("self.games[%s] set to %s" %(game, self.games[game]))
|
||||
log.debug(_("self.games[%s] set to %s") %(game, self.games[game]))
|
||||
#end def __set_game_select
|
||||
|
||||
def __set_limit_select(self, w, limit):
|
||||
#print "__set_limit_select: limit =", limit, w.get_active()
|
||||
self.limits[limit] = w.get_active()
|
||||
log.debug("self.limit[%s] set to %s" %(limit, self.limits[limit]))
|
||||
log.debug(_("self.limit[%s] set to %s") %(limit, self.limits[limit]))
|
||||
if limit.isdigit() or (len(limit) > 2 and (limit[-2:] == 'nl' or limit[-2:] == 'fl' or limit[-2:] == 'pl')):
|
||||
if self.limits[limit]:
|
||||
if self.cbNoLimits is not None:
|
||||
|
|
@ -529,13 +555,21 @@ class Filters(threading.Thread):
|
|||
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]) )
|
||||
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()
|
||||
self.groups[group] = w.get_active()
|
||||
log.debug( "self.groups[%s] set to %s" %(group, self.groups[group]) )
|
||||
log.debug( _("self.groups[%s] set to %s") %(group, self.groups[group]) )
|
||||
|
||||
|
||||
def __set_displayin_select(self, w, ops):
|
||||
self.graphops['dspin'] = ops
|
||||
|
||||
def __set_graphopscheck_select(self, w, data):
|
||||
#print "%s was toggled %s" % (data, ("OFF", "ON")[w.get_active()])
|
||||
self.graphops[data] = ("OFF", "ON")[w.get_active()]
|
||||
|
||||
def fillPlayerFrame(self, vbox, display):
|
||||
top_hbox = gtk.HBox(False, 0)
|
||||
|
|
@ -568,7 +602,7 @@ class Filters(threading.Thread):
|
|||
self.sbGroups['allplayers'] = cb
|
||||
self.groups['allplayers'] = False
|
||||
|
||||
lbl = gtk.Label('Min # Hands:')
|
||||
lbl = gtk.Label(_('Min # Hands:'))
|
||||
lbl.set_alignment(xalign=1.0, yalign=0.5)
|
||||
hbox.pack_start(lbl, expand=True, padding=3)
|
||||
|
||||
|
|
@ -634,8 +668,8 @@ class Filters(threading.Thread):
|
|||
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")
|
||||
print _("INFO: No tourney types returned from database")
|
||||
log.info(_("No tourney types returned from database"))
|
||||
#end def fillTourneyTypesFrame
|
||||
|
||||
def fillGamesFrame(self, vbox):
|
||||
|
|
@ -661,8 +695,8 @@ class Filters(threading.Thread):
|
|||
vbox1.pack_start(hbox, False, True, 0)
|
||||
self.createGameLine(hbox, line[0])
|
||||
else:
|
||||
print "INFO: No games returned from database"
|
||||
log.info("No games returned from database")
|
||||
print _("INFO: No games returned from database")
|
||||
log.info(_("No games returned from database"))
|
||||
#end def fillGamesFrame
|
||||
|
||||
def fillLimitsFrame(self, vbox, display):
|
||||
|
|
@ -750,8 +784,8 @@ class Filters(threading.Thread):
|
|||
self.cbPL = self.createLimitLine(hbox, 'pl', self.filterText['limitsPL'])
|
||||
dest = vbox2 # for ring/tour buttons
|
||||
else:
|
||||
print "INFO: No games returned from database"
|
||||
log.info("No games returned from database")
|
||||
print _("INFO: No games returned from database")
|
||||
log.info(_("No games returned from database"))
|
||||
|
||||
if "Type" in display and display["Type"] == True and self.found['ring'] and self.found['tour']:
|
||||
rb1 = gtk.RadioButton(None, self.filterText['ring'])
|
||||
|
|
@ -768,8 +802,58 @@ class Filters(threading.Thread):
|
|||
# set_active doesn't seem to call this for some reason so call manually:
|
||||
self.__set_limit_select(rb1, 'ring')
|
||||
self.type = 'ring'
|
||||
top_hbox.pack_start(showb, expand=False, padding=1)
|
||||
|
||||
def fillGraphOpsFrame(self, vbox):
|
||||
top_hbox = gtk.HBox(False, 0)
|
||||
vbox.pack_start(top_hbox, False, False, 0)
|
||||
title = gtk.Label("Graphing Options:")
|
||||
title.set_alignment(xalign=0.0, yalign=0.5)
|
||||
top_hbox.pack_start(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, 'games')
|
||||
top_hbox.pack_start(showb, expand=False, padding=1)
|
||||
|
||||
hbox1 = gtk.HBox(False, 0)
|
||||
vbox.pack_start(hbox1, False, False, 0)
|
||||
hbox1.show()
|
||||
|
||||
label = gtk.Label("Show Graph In:")
|
||||
label.set_alignment(xalign=0.0, yalign=0.5)
|
||||
hbox1.pack_start(label, True, True, 0)
|
||||
label.show()
|
||||
|
||||
button = gtk.RadioButton(None, "$$")
|
||||
hbox1.pack_start(button, True, True, 0)
|
||||
button.connect("toggled", self.__set_displayin_select, "$")
|
||||
button.set_active(True)
|
||||
button.show()
|
||||
|
||||
button = gtk.RadioButton(button, "BB")
|
||||
hbox1.pack_start(button, True, True, 0)
|
||||
button.connect("toggled", self.__set_displayin_select, "BB")
|
||||
button.show()
|
||||
|
||||
vbox1 = gtk.VBox(False, 0)
|
||||
vbox.pack_start(vbox1, False, False, 0)
|
||||
vbox1.show()
|
||||
|
||||
button = gtk.CheckButton("Showdown Winnings", False)
|
||||
vbox1.pack_start(button, True, True, 0)
|
||||
# wouldn't it be awesome if there was a way to remember the state of things like
|
||||
# this and be able to set it to what it was last time?
|
||||
#button.set_active(True)
|
||||
button.connect("toggled", self.__set_graphopscheck_select, "showdown")
|
||||
button.show()
|
||||
|
||||
button = gtk.CheckButton("Non-Showdown Winnings", False)
|
||||
vbox1.pack_start(button, True, True, 0)
|
||||
# ditto as 8 lines up :)
|
||||
#button.set_active(True)
|
||||
button.connect("toggled", self.__set_graphopscheck_select, "nonshowdown");
|
||||
button.show()
|
||||
|
||||
def fillSeatsFrame(self, vbox, display):
|
||||
hbox = gtk.HBox(False, 0)
|
||||
vbox.pack_start(hbox, False, False, 0)
|
||||
|
|
@ -880,7 +964,7 @@ class Filters(threading.Thread):
|
|||
hbox = gtk.HBox()
|
||||
vbox1.pack_start(hbox, False, True, 0)
|
||||
|
||||
lbl_start = gtk.Label('From:')
|
||||
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))
|
||||
|
|
@ -894,12 +978,12 @@ class Filters(threading.Thread):
|
|||
hbox = gtk.HBox()
|
||||
vbox1.pack_start(hbox, False, True, 0)
|
||||
|
||||
lbl_end = gtk.Label(' To:')
|
||||
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 = gtk.Button(label=_(' Clear Dates '))
|
||||
btn_clear.connect('clicked', self.__clear_dates)
|
||||
|
||||
hbox.pack_start(lbl_end, expand=False, padding=3)
|
||||
|
|
@ -926,13 +1010,32 @@ class Filters(threading.Thread):
|
|||
|
||||
def __calendar_dialog(self, widget, entry):
|
||||
d = gtk.Window(gtk.WINDOW_TOPLEVEL)
|
||||
d.set_title('Pick a date')
|
||||
d.set_title(_('Pick a date'))
|
||||
|
||||
vb = gtk.VBox()
|
||||
cal = gtk.Calendar()
|
||||
|
||||
if entry == self.start_date:
|
||||
cal_date = self.start_date.get_text()
|
||||
if cal_date == '':
|
||||
self.cursor.execute(self.sql.query['get_first_date'])
|
||||
result = self.db.cursor.fetchall()
|
||||
cal_date = result[0][0].split()[0]
|
||||
self.start_date.set_text(cal_date)
|
||||
elif entry == self.end_date:
|
||||
cal_date = self.end_date.get_text()
|
||||
if cal_date == '':
|
||||
self.cursor.execute(self.sql.query['get_last_date'])
|
||||
result = self.db.cursor.fetchall()
|
||||
cal_date = result[0][0].split()[0]
|
||||
self.end_date.set_text(cal_date)
|
||||
|
||||
(year,month,day)=cal_date.split('-')
|
||||
cal.select_month(int(month)-1, int(year))
|
||||
cal.select_day(int(day))
|
||||
vb.pack_start(cal, expand=False, padding=0)
|
||||
|
||||
btn = gtk.Button('Done')
|
||||
btn = gtk.Button(_('Done'))
|
||||
btn.connect('clicked', self.__get_date, cal, entry, d)
|
||||
|
||||
vb.pack_start(btn, expand=False, padding=4)
|
||||
|
|
@ -955,9 +1058,16 @@ class Filters(threading.Thread):
|
|||
t2 = self.end_date.get_text()
|
||||
|
||||
if t1 == '':
|
||||
t1 = '1970-01-02'
|
||||
self.cursor.execute(self.sql.query['get_first_date'])
|
||||
result = self.db.cursor.fetchall()
|
||||
t1 = result[0][0].split()[0]
|
||||
self.start_date.set_text(t1)
|
||||
|
||||
if t2 == '':
|
||||
t2 = '2020-12-12'
|
||||
self.cursor.execute(self.sql.query['get_last_date'])
|
||||
result = self.db.cursor.fetchall()
|
||||
t2 = result[0][0].split()[0]
|
||||
self.end_date.set_text(t2)
|
||||
|
||||
s1 = strptime(t1, "%Y-%m-%d") # make time_struct
|
||||
s2 = strptime(t2, "%Y-%m-%d")
|
||||
|
|
|
|||
129
pyfpdb/FullTiltPokerSummary.py
Normal file
129
pyfpdb/FullTiltPokerSummary.py
Normal file
|
|
@ -0,0 +1,129 @@
|
|||
#!/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.
|
||||
|
||||
"""pokerstars-specific summary parsing code"""
|
||||
|
||||
import L10n
|
||||
_ = L10n.get_translation()
|
||||
|
||||
from decimal import Decimal
|
||||
import datetime
|
||||
|
||||
from Exceptions import FpdbParseError
|
||||
from HandHistoryConverter import *
|
||||
import PokerStarsToFpdb
|
||||
from TourneySummary import *
|
||||
|
||||
class FullTiltPokerSummary(TourneySummary):
|
||||
limits = { 'No Limit':'nl', 'Pot Limit':'pl', 'Limit':'fl', 'LIMIT':'fl' }
|
||||
games = { # base, category
|
||||
"Hold'em" : ('hold','holdem'),
|
||||
'Omaha' : ('hold','omahahi'),
|
||||
'Omaha Hi/Lo' : ('hold','omahahilo'),
|
||||
'Razz' : ('stud','razz'),
|
||||
'RAZZ' : ('stud','razz'),
|
||||
'7 Card Stud' : ('stud','studhi'),
|
||||
'7 Card Stud Hi/Lo' : ('stud','studhilo'),
|
||||
'Badugi' : ('draw','badugi'),
|
||||
'Triple Draw 2-7 Lowball' : ('draw','27_3draw'),
|
||||
'5 Card Draw' : ('draw','fivedraw')
|
||||
}
|
||||
|
||||
substitutions = {
|
||||
'LEGAL_ISO' : "USD|EUR|GBP|CAD|FPP", # legal ISO currency codes
|
||||
'LS' : "\$|\xe2\x82\xac|" # legal currency symbols - Euro(cp1252, utf-8)
|
||||
}
|
||||
|
||||
re_SplitTourneys = re.compile("^Full Tilt Poker Tournament Summary")
|
||||
|
||||
re_TourNo = re.compile("\#(?P<TOURNO>[0-9]+),")
|
||||
|
||||
re_TourneyInfo = re.compile(u"""
|
||||
\s.*
|
||||
(?P<TYPE>Tournament|Sit\s\&\sGo)\s\((?P<TOURNO>[0-9]+)\)(\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+
|
||||
(?P<LIMIT>No\sLimit|Limit|LIMIT|Pot\sLimit)\s+
|
||||
(Buy-In:\s\$(?P<BUYIN>[.\d]+)(\s\+\s\$(?P<FEE>[.\d]+))?\s+)?
|
||||
(Buy-In\sChips:\s(?P<CHIPS>\d+)\s+)?
|
||||
(?P<ENTRIES>[0-9]+)\sEntries\s+
|
||||
(\$?(?P<ADDED>[.\d]+)\sadded\sto\sthe\sprize\spool\sby\sPokerStars\.com\s+)?
|
||||
(Total\sPrize\sPool:\s\$?(?P<PRIZEPOOL>[.0-9]+)\s+)?
|
||||
(Target\sTournament\s.*)?
|
||||
Tournament\sstarted:\s
|
||||
(?P<Y>[\d]{4})\/(?P<M>[\d]{2})\/(?P<D>[\d]+)\s+(?P<H>[\d]+):(?P<MIN>[\d]+):(?P<S>[\d]+)\s??(?P<TZ>[A-Z]+)\s
|
||||
""" % substitutions ,re.VERBOSE|re.MULTILINE|re.DOTALL)
|
||||
|
||||
re_Currency = re.compile(u"""(?P<CURRENCY>[%(LS)s]|FPP)""" % substitutions)
|
||||
|
||||
re_Player = re.compile(u"""(?P<RANK>[\d]+):\s(?P<NAME>[^,\r\n]{2,15})(,(\s)?\$(?P<WINNINGS>[.\d]+))?""")
|
||||
|
||||
re_DateTime = re.compile("\[(?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]+)")
|
||||
|
||||
codepage = ["utf-16", "cp1252", "utf-8"]
|
||||
|
||||
def parseSummary(self):
|
||||
m = self.re_TourneyInfo.search(self.summaryText)
|
||||
if m == None:
|
||||
tmp = self.summaryText[0:200]
|
||||
log.error(_("parseSummary: Unable to recognise Tourney Info: '%s'") % tmp)
|
||||
log.error(_("parseSummary: Raising FpdbParseError"))
|
||||
raise FpdbParseError(_("Unable to recognise Tourney Info: '%s'") % tmp)
|
||||
|
||||
print "DEBUG: m.groupdict(): %s" % m.groupdict()
|
||||
|
||||
mg = m.groupdict()
|
||||
if 'TOURNO' in mg: self.tourNo = mg['TOURNO']
|
||||
if 'LIMIT' in mg: self.gametype['limitType'] = self.limits[mg['LIMIT']]
|
||||
if 'GAME' in mg: self.gametype['category'] = self.games[mg['GAME']][1]
|
||||
if mg['BUYIN'] != None:
|
||||
self.buyin = int(100*Decimal(mg['BUYIN']))
|
||||
if mg['FEE'] != None:
|
||||
self.fee = int(100*Decimal(mg['FEE']))
|
||||
if 'PRIZEPOOL' in mg: self.prizepool = mg['PRIZEPOOL']
|
||||
if 'ENTRIES' in mg: self.entries = mg['ENTRIES']
|
||||
|
||||
datetimestr = "%s/%s/%s %s:%s:%s" % (mg['Y'], mg['M'], mg['D'], mg['H'], mg['MIN'], mg['S'])
|
||||
self.startTime = datetime.datetime.strptime(datetimestr, "%Y/%m/%d %H:%M:%S")
|
||||
|
||||
if 'TZ' in mg:
|
||||
self.startTime = HandHistoryConverter.changeTimezone(self.startTime, mg['TZ'], "UTC")
|
||||
|
||||
|
||||
m = self.re_Currency.search(self.summaryText)
|
||||
if m == None:
|
||||
log.error(_("parseSummary: Unable to locate currency"))
|
||||
log.error(_("parseSummary: Raising FpdbParseError"))
|
||||
raise FpdbParseError(_("Unable to locate currency"))
|
||||
#print "DEBUG: m.groupdict(): %s" % m.groupdict()
|
||||
|
||||
mg = m.groupdict()
|
||||
if mg['CURRENCY'] == "$": self.currency = "USD"
|
||||
elif mg['CURRENCY'] == u"€": self.currency="EUR"
|
||||
elif mg['CURRENCY'] == "FPP": self.currency="PSFP"
|
||||
|
||||
m = self.re_Player.finditer(self.summaryText)
|
||||
for a in m:
|
||||
mg = a.groupdict()
|
||||
print "DEBUG: a.groupdict(): %s" % mg
|
||||
name = mg['NAME']
|
||||
rank = mg['RANK']
|
||||
winnings = 0
|
||||
|
||||
if 'WINNINGS' in mg and mg['WINNINGS'] != None:
|
||||
winnings = int(100*Decimal(mg['WINNINGS']))
|
||||
self.addPlayer(rank, name, winnings, self.currency, None, None, None)
|
||||
|
||||
|
|
@ -18,6 +18,9 @@
|
|||
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
########################################################################
|
||||
|
||||
import L10n
|
||||
_ = L10n.get_translation()
|
||||
|
||||
import logging
|
||||
from HandHistoryConverter import *
|
||||
#import TourneySummary
|
||||
|
|
@ -31,49 +34,55 @@ class Fulltilt(HandHistoryConverter):
|
|||
codepage = ["utf-16", "cp1252", "utf-8"]
|
||||
siteId = 1 # Needs to match id entry in Sites database
|
||||
|
||||
substitutions = {
|
||||
'LEGAL_ISO' : "USD|EUR|GBP|CAD|FPP", # legal ISO currency codes
|
||||
'LS' : u"\$|\u20AC|\xe2\x82\xac|", # legal currency symbols - Euro(cp1252, utf-8)
|
||||
'TAB' : u"-\u2013\s\da-zA-Z"
|
||||
}
|
||||
|
||||
# Static regexes
|
||||
re_GameInfo = re.compile('''.*\#(?P<HID>[0-9]+):\s
|
||||
re_GameInfo = re.compile(u'''.*\#(?P<HID>[0-9]+):\s
|
||||
(?:(?P<TOURNAMENT>.+)\s\((?P<TOURNO>\d+)\),\s)?
|
||||
.+
|
||||
-\s(?P<CURRENCY>\$|)?
|
||||
-\s(?P<CURRENCY>[%(LS)s]|)?
|
||||
(?P<SB>[.0-9]+)/
|
||||
\$?(?P<BB>[.0-9]+)\s
|
||||
[%(LS)s]?(?P<BB>[.0-9]+)\s
|
||||
(Ante\s\$?(?P<ANTE>[.0-9]+)\s)?-\s
|
||||
\$?(?P<CAP>[.0-9]+\sCap\s)?
|
||||
[%(LS)s]?(?P<CAP>[.0-9]+\sCap\s)?
|
||||
(?P<LIMIT>(No\sLimit|Pot\sLimit|Limit))?\s
|
||||
(?P<GAME>(Hold\'em|Omaha\sHi|Omaha\sH/L|7\sCard\sStud|Stud\sH/L|Razz|Stud\sHi))
|
||||
''', re.VERBOSE)
|
||||
re_SplitHands = re.compile(r"\n\n+")
|
||||
''' % substitutions, re.VERBOSE)
|
||||
re_SplitHands = re.compile(r"\n\n\n+")
|
||||
re_TailSplitHands = re.compile(r"(\n\n+)")
|
||||
re_HandInfo = re.compile(r'''.*\#(?P<HID>[0-9]+):\s
|
||||
(?:(?P<TOURNAMENT>.+)\s\((?P<TOURNO>\d+)\),\s)?
|
||||
(Table|Match)\s
|
||||
(?P<PLAY>Play\sChip\s|PC)?
|
||||
(?P<TABLE>[-\s\da-zA-Z]+)\s
|
||||
(?P<TABLE>[%(TAB)s]+)\s
|
||||
(\((?P<TABLEATTRIBUTES>.+)\)\s)?-\s
|
||||
\$?(?P<SB>[.0-9]+)/\$?(?P<BB>[.0-9]+)\s(Ante\s\$?(?P<ANTE>[.0-9]+)\s)?-\s
|
||||
\$?(?P<CAP>[.0-9]+\sCap\s)?
|
||||
[%(LS)s]?(?P<SB>[.0-9]+)/[%(LS)s]?(?P<BB>[.0-9]+)\s(Ante\s[%(LS)s]?(?P<ANTE>[.0-9]+)\s)?-\s
|
||||
[%(LS)s]?(?P<CAP>[.0-9]+\sCap\s)?
|
||||
(?P<GAMETYPE>[a-zA-Z\/\'\s]+)\s-\s
|
||||
(?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)
|
||||
''' % substitutions, re.VERBOSE|re.DOTALL)
|
||||
re_TourneyExtraInfo = re.compile('''(((?P<TOURNEY_NAME>[^$]+)?
|
||||
(?P<CURRENCY>\$)?(?P<BUYIN>[.0-9]+)?\s*\+\s*\$?(?P<FEE>[.0-9]+)?
|
||||
(?P<CURRENCY>[%(LS)s])?(?P<BUYIN>[.0-9]+)?\s*\+\s*[%(LS)s]?(?P<FEE>[.0-9]+)?
|
||||
(\s(?P<SPECIAL>(KO|Heads\sUp|Matrix\s\dx|Rebuy|Madness)))?
|
||||
(\s(?P<SHOOTOUT>Shootout))?
|
||||
(\s(?P<SNG>Sit\s&\sGo))?
|
||||
(\s\((?P<TURBO>Turbo)\))?)|(?P<UNREADABLE_INFO>.+))
|
||||
''', re.VERBOSE)
|
||||
''' % substitutions, re.VERBOSE)
|
||||
re_Button = re.compile('^The button is in seat #(?P<BUTTON>\d+)', re.MULTILINE)
|
||||
re_PlayerInfo = re.compile('Seat (?P<SEAT>[0-9]+): (?P<PNAME>.{2,15}) \(\$(?P<CASH>[,.0-9]+)\)$', re.MULTILINE)
|
||||
re_TourneysPlayerInfo = re.compile('Seat (?P<SEAT>[0-9]+): (?P<PNAME>.{2,15}) \(\$?(?P<CASH>[,.0-9]+)\)(, is sitting out)?$', re.MULTILINE)
|
||||
re_PlayerInfo = re.compile('Seat (?P<SEAT>[0-9]+): (?P<PNAME>.{2,15}) \([%(LS)s](?P<CASH>[,.0-9]+)\)$' % substitutions, re.MULTILINE)
|
||||
re_TourneysPlayerInfo = re.compile('Seat (?P<SEAT>[0-9]+): (?P<PNAME>.{2,15}) \([%(LS)s]?(?P<CASH>[,.0-9]+)\)(, is sitting out)?$' % substitutions, re.MULTILINE)
|
||||
re_Board = re.compile(r"\[(?P<CARDS>.+)\]")
|
||||
|
||||
#static regex for tourney purpose
|
||||
re_TourneyInfo = re.compile('''Tournament\sSummary\s
|
||||
(?P<TOURNAMENT_NAME>[^$(]+)?\s*
|
||||
((?P<CURRENCY>\$|)?(?P<BUYIN>[.0-9]+)\s*\+\s*\$?(?P<FEE>[.0-9]+)\s)?
|
||||
((?P<CURRENCY>[%(LS)s]|)?(?P<BUYIN>[.0-9]+)\s*\+\s*[%(LS)s]?(?P<FEE>[.0-9]+)\s)?
|
||||
((?P<SPECIAL>(KO|Heads\sUp|Matrix\s\dx|Rebuy|Madness))\s)?
|
||||
((?P<SHOOTOUT>Shootout)\s)?
|
||||
((?P<SNG>Sit\s&\sGo)\s)?
|
||||
|
|
@ -83,24 +92,24 @@ class Fulltilt(HandHistoryConverter):
|
|||
(?P<GAME>(Hold\'em|Omaha\sHi|Omaha\sH/L|7\sCard\sStud|Stud\sH/L|Razz|Stud\sHi))\s
|
||||
(\((?P<TURBO2>Turbo)\)\s)?
|
||||
(?P<LIMIT>(No\sLimit|Pot\sLimit|Limit))?
|
||||
''', re.VERBOSE)
|
||||
re_TourneyBuyInFee = re.compile("Buy-In: (?P<BUYIN_CURRENCY>\$|)?(?P<BUYIN>[.0-9]+) \+ \$?(?P<FEE>[.0-9]+)")
|
||||
''' % substitutions, re.VERBOSE)
|
||||
re_TourneyBuyInFee = re.compile("Buy-In: (?P<BUYIN_CURRENCY>[%(LS)s]|)?(?P<BUYIN>[.0-9]+) \+ [%(LS)s]?(?P<FEE>[.0-9]+)" % substitutions)
|
||||
re_TourneyBuyInChips = re.compile("Buy-In Chips: (?P<BUYINCHIPS>\d+)")
|
||||
re_TourneyEntries = re.compile("(?P<ENTRIES>\d+) Entries")
|
||||
re_TourneyPrizePool = re.compile("Total Prize Pool: (?P<PRIZEPOOL_CURRENCY>\$|)?(?P<PRIZEPOOL>[.,0-9]+)")
|
||||
re_TourneyRebuyCost = re.compile("Rebuy: (?P<REBUY_CURRENCY>\$|)?(?P<REBUY_COST>[.,0-9]+)")
|
||||
re_TourneyAddOnCost = re.compile("Add-On: (?P<ADDON_CURRENCY>\$|)?(?P<ADDON_COST>[.,0-9]+)")
|
||||
re_TourneyPrizePool = re.compile("Total Prize Pool: (?P<PRIZEPOOL_CURRENCY>[%(LS)s]|)?(?P<PRIZEPOOL>[.,0-9]+)" % substitutions)
|
||||
re_TourneyRebuyCost = re.compile("Rebuy: (?P<REBUY_CURRENCY>[%(LS)s]|)?(?P<REBUY_COST>[.,0-9]+)"% substitutions)
|
||||
re_TourneyAddOnCost = re.compile("Add-On: (?P<ADDON_CURRENCY>[%(LS)s]|)?(?P<ADDON_COST>[.,0-9]+)"% substitutions)
|
||||
re_TourneyRebuyCount = re.compile("performed (?P<REBUY_COUNT>\d+) Rebuy")
|
||||
re_TourneyAddOnCount = re.compile("performed (?P<ADDON_COUNT>\d+) Add-On")
|
||||
re_TourneyRebuysTotal = re.compile("Total Rebuys: (?P<REBUY_TOTAL>\d+)")
|
||||
re_TourneyAddOnsTotal = re.compile("Total Add-Ons: (?P<ADDONS_TOTAL>\d+)")
|
||||
re_TourneyRebuyChips = re.compile("Rebuy Chips: (?P<REBUY_CHIPS>\d+)")
|
||||
re_TourneyAddOnChips = re.compile("Add-On Chips: (?P<ADDON_CHIPS>\d+)")
|
||||
re_TourneyKOBounty = re.compile("Knockout Bounty: (?P<KO_BOUNTY_CURRENCY>\$|)?(?P<KO_BOUNTY_AMOUNT>[.,0-9]+)")
|
||||
re_TourneyKOBounty = re.compile("Knockout Bounty: (?P<KO_BOUNTY_CURRENCY>[%(LS)s]|)?(?P<KO_BOUNTY_AMOUNT>[.,0-9]+)" % substitutions)
|
||||
re_TourneyKoCount = re.compile("received (?P<COUNT_KO>\d+) Knockout Bounty Award(s)?")
|
||||
re_TourneyTimeInfo = re.compile("Tournament started: (?P<STARTTIME>.*)\nTournament ((?P<IN_PROGRESS>is still in progress)?|(finished:(?P<ENDTIME>.*))?)$")
|
||||
|
||||
re_TourneysPlayersSummary = re.compile("^(?P<RANK>(Still Playing|\d+))( - |: )(?P<PNAME>[^\n,]+)(, )?(?P<WINNING_CURRENCY>\$|)?(?P<WINNING>[.\d]+)?", re.MULTILINE)
|
||||
re_TourneysPlayersSummary = re.compile("^(?P<RANK>(Still Playing|\d+))( - |: )(?P<PNAME>[^\n,]+)(, )?(?P<WINNING_CURRENCY>[%(LS)s]|)?(?P<WINNING>[.\d]+)?" % substitutions, re.MULTILINE)
|
||||
re_TourneyHeroFinishingP = re.compile("(?P<HERO_NAME>.*) finished in (?P<HERO_FINISHING_POS>\d+)(st|nd|rd|th) place")
|
||||
|
||||
#TODO: See if we need to deal with play money tourney summaries -- Not right now (they shouldn't pass the re_TourneyInfo)
|
||||
|
|
@ -127,17 +136,19 @@ class Fulltilt(HandHistoryConverter):
|
|||
# we need to recompile the player regexs.
|
||||
self.compiledPlayers = players
|
||||
player_re = "(?P<PNAME>" + "|".join(map(re.escape, players)) + ")"
|
||||
self.substitutions['PLAYERS'] = player_re
|
||||
|
||||
logging.debug("player_re: " + player_re)
|
||||
self.re_PostSB = re.compile(r"^%s posts the small blind of \$?(?P<SB>[.0-9]+)" % player_re, re.MULTILINE)
|
||||
self.re_PostDead = re.compile(r"^%s posts a dead small blind of \$?(?P<SB>[.0-9]+)" % player_re, re.MULTILINE)
|
||||
self.re_PostBB = re.compile(r"^%s posts (the big blind of )?\$?(?P<BB>[.0-9]+)" % player_re, re.MULTILINE)
|
||||
self.re_Antes = re.compile(r"^%s antes \$?(?P<ANTE>[.0-9]+)" % player_re, re.MULTILINE)
|
||||
self.re_BringIn = re.compile(r"^%s brings in for \$?(?P<BRINGIN>[.0-9]+)" % player_re, re.MULTILINE)
|
||||
self.re_PostBoth = re.compile(r"^%s posts small \& big blinds \[\$? (?P<SBBB>[.0-9]+)" % player_re, re.MULTILINE)
|
||||
self.re_PostSB = re.compile(r"^%(PLAYERS)s posts the small blind of [%(LS)s]?(?P<SB>[.0-9]+)" % self.substitutions, re.MULTILINE)
|
||||
self.re_PostDead = re.compile(r"^%(PLAYERS)s posts a dead small blind of [%(LS)s]?(?P<SB>[.0-9]+)" % self.substitutions, re.MULTILINE)
|
||||
self.re_PostBB = re.compile(r"^%(PLAYERS)s posts (the big blind of )?[%(LS)s]?(?P<BB>[.0-9]+)" % self.substitutions, re.MULTILINE)
|
||||
self.re_Antes = re.compile(r"^%(PLAYERS)s antes [%(LS)s]?(?P<ANTE>[.0-9]+)" % self.substitutions, re.MULTILINE)
|
||||
self.re_BringIn = re.compile(r"^%(PLAYERS)s brings in for [%(LS)s]?(?P<BRINGIN>[.0-9]+)" % self.substitutions, re.MULTILINE)
|
||||
self.re_PostBoth = re.compile(r"^%(PLAYERS)s posts small \& big blinds \[[%(LS)s]? (?P<SBBB>[.0-9]+)" % self.substitutions, re.MULTILINE)
|
||||
self.re_HeroCards = re.compile(r"^Dealt to %s(?: \[(?P<OLDCARDS>.+?)\])?( \[(?P<NEWCARDS>.+?)\])" % player_re, re.MULTILINE)
|
||||
self.re_Action = re.compile(r"^%s(?P<ATYPE> bets| checks| raises to| completes it to| calls| folds)( \$?(?P<BET>[.,\d]+))?" % player_re, re.MULTILINE)
|
||||
self.re_Action = re.compile(r"^%(PLAYERS)s(?P<ATYPE> bets| checks| raises to| completes it to| calls| folds)( [%(LS)s]?(?P<BET>[.,\d]+))?" % self.substitutions, re.MULTILINE)
|
||||
self.re_ShowdownAction = re.compile(r"^%s shows \[(?P<CARDS>.*)\]" % player_re, re.MULTILINE)
|
||||
self.re_CollectPot = re.compile(r"^Seat (?P<SEAT>[0-9]+): %s (\(button\) |\(small blind\) |\(big blind\) )?(collected|showed \[.*\] and won) \(\$?(?P<POT>[.,\d]+)\)(, mucked| with.*)" % player_re, re.MULTILINE)
|
||||
self.re_CollectPot = re.compile(r"^Seat (?P<SEAT>[0-9]+): %(PLAYERS)s (\(button\) |\(small blind\) |\(big blind\) )?(collected|showed \[.*\] and won) \([%(LS)s]?(?P<POT>[.,\d]+)\)(, mucked| with.*)" % self.substitutions, re.MULTILINE)
|
||||
self.re_SitsOut = re.compile(r"^%s sits out" % player_re, re.MULTILINE)
|
||||
self.re_ShownCards = re.compile(r"^Seat (?P<SEAT>[0-9]+): %s (\(button\) |\(small blind\) |\(big blind\) )?(?P<ACT>showed|mucked) \[(?P<CARDS>.*)\].*" % player_re, re.MULTILINE)
|
||||
|
||||
|
|
@ -161,12 +172,17 @@ class Fulltilt(HandHistoryConverter):
|
|||
# Full Tilt Poker Game #10773265574: Table Butte (6 max) - $0.01/$0.02 - Pot Limit Hold'em - 21:33:46 ET - 2009/02/21
|
||||
# Full Tilt Poker Game #9403951181: Table CR - tay - $0.05/$0.10 - No Limit Hold'em - 9:40:20 ET - 2008/12/09
|
||||
# Full Tilt Poker Game #10809877615: Table Danville - $0.50/$1 Ante $0.10 - Limit Razz - 21:47:27 ET - 2009/02/23
|
||||
# Full Tilt Poker.fr Game #23057874034: Table Douai–Lens (6 max) - €0.01/€0.02 - No Limit Hold'em - 21:59:17 CET - 2010/08/13
|
||||
info = {'type':'ring'}
|
||||
|
||||
m = self.re_GameInfo.search(handText)
|
||||
if not m:
|
||||
return None
|
||||
tmp = handText[0:100]
|
||||
log.error(_("determineGameType: Unable to recognise gametype from: '%s'") % tmp)
|
||||
log.error(_("determineGameType: Raising FpdbParseError"))
|
||||
raise FpdbParseError(_("Unable to recognise gametype from: '%s'") % tmp)
|
||||
mg = m.groupdict()
|
||||
|
||||
# translations from captured groups to our info strings
|
||||
limits = { 'No Limit':'nl', 'Pot Limit':'pl', 'Limit':'fl' }
|
||||
games = { # base, category
|
||||
|
|
@ -177,7 +193,7 @@ class Fulltilt(HandHistoryConverter):
|
|||
'Stud Hi' : ('stud','studhi'),
|
||||
'Stud H/L' : ('stud','studhilo')
|
||||
}
|
||||
currencies = { u' €':'EUR', '$':'USD', '':'T$' }
|
||||
currencies = { u'€':'EUR', '$':'USD', '':'T$' }
|
||||
if mg['CAP']:
|
||||
info['limitType'] = 'cn'
|
||||
else:
|
||||
|
|
@ -196,9 +212,9 @@ class Fulltilt(HandHistoryConverter):
|
|||
def readHandInfo(self, hand):
|
||||
m = self.re_HandInfo.search(hand.handText)
|
||||
if m is None:
|
||||
logging.info("Didn't match re_HandInfo")
|
||||
logging.info(_("Didn't match re_HandInfo"))
|
||||
logging.info(hand.handText)
|
||||
return None
|
||||
raise FpdbParseError(_("No match in readHandInfo."))
|
||||
hand.handid = m.group('HID')
|
||||
hand.tablename = m.group('TABLE')
|
||||
|
||||
|
|
@ -249,16 +265,17 @@ class Fulltilt(HandHistoryConverter):
|
|||
hand.isRebuy = True
|
||||
if special == "KO":
|
||||
hand.isKO = True
|
||||
if special == "Head's Up":
|
||||
hand.maxSeats = 2
|
||||
if special == "Head's Up" or special == "Heads Up":
|
||||
hand.maxseats = 2
|
||||
if re.search("Matrix", special):
|
||||
hand.isMatrix = True
|
||||
if special == "Shootout":
|
||||
hand.isShootout = True
|
||||
if hand.buyin is None:
|
||||
hand.buyin = 0
|
||||
hand.fee=0
|
||||
hand.buyinCurrency="NA"
|
||||
|
||||
|
||||
if hand.buyin is None:
|
||||
hand.buyin = "$0.00+$0.00"
|
||||
if hand.level is None:
|
||||
hand.level = "0"
|
||||
|
||||
|
|
@ -326,7 +343,7 @@ class Fulltilt(HandHistoryConverter):
|
|||
hand.addBlind(a.group('PNAME'), 'small & big blinds', a.group('SBBB'))
|
||||
|
||||
def readAntes(self, hand):
|
||||
logging.debug("reading antes")
|
||||
logging.debug(_("reading antes"))
|
||||
m = self.re_Antes.finditer(hand.handText)
|
||||
for player in m:
|
||||
logging.debug("hand.addAnte(%s,%s)" %(player.group('PNAME'), player.group('ANTE')))
|
||||
|
|
@ -336,10 +353,10 @@ class Fulltilt(HandHistoryConverter):
|
|||
def readBringIn(self, hand):
|
||||
m = self.re_BringIn.search(hand.handText,re.DOTALL)
|
||||
if m:
|
||||
logging.debug("Player bringing in: %s for %s" %(m.group('PNAME'), m.group('BRINGIN')))
|
||||
logging.debug(_("Player bringing in: %s for %s") %(m.group('PNAME'), m.group('BRINGIN')))
|
||||
hand.addBringIn(m.group('PNAME'), m.group('BRINGIN'))
|
||||
else:
|
||||
logging.warning("No bringin found, handid =%s" % hand.handid)
|
||||
logging.warning(_("No bringin found, handid =%s") % hand.handid)
|
||||
|
||||
def readButton(self, hand):
|
||||
hand.buttonpos = int(self.re_Button.search(hand.handText).group('BUTTON'))
|
||||
|
|
@ -396,7 +413,7 @@ class Fulltilt(HandHistoryConverter):
|
|||
elif action.group('ATYPE') == ' checks':
|
||||
hand.addCheck( street, action.group('PNAME'))
|
||||
else:
|
||||
print "FullTilt: DEBUG: unimplemented readAction: '%s' '%s'" %(action.group('PNAME'),action.group('ATYPE'),)
|
||||
print _("FullTilt: DEBUG: unimplemented readAction: '%s' '%s'") %(action.group('PNAME'),action.group('ATYPE'),)
|
||||
|
||||
|
||||
def readShowdownActions(self, hand):
|
||||
|
|
@ -472,7 +489,7 @@ class Fulltilt(HandHistoryConverter):
|
|||
|
||||
m = self.re_TourneyInfo.search(tourneyText)
|
||||
if not m:
|
||||
log.info( "determineTourneyType : Parsing NOK" )
|
||||
log.info(_("determineTourneyType : Parsing NOK"))
|
||||
return False
|
||||
mg = m.groupdict()
|
||||
#print mg
|
||||
|
|
@ -530,7 +547,7 @@ class Fulltilt(HandHistoryConverter):
|
|||
if mg['TOURNO'] is not None:
|
||||
tourney.tourNo = mg['TOURNO']
|
||||
else:
|
||||
log.info( "Unable to get a valid Tournament ID -- File rejected" )
|
||||
log.info(_("Unable to get a valid Tournament ID -- File rejected"))
|
||||
return False
|
||||
if tourney.isMatrix:
|
||||
if mg['MATCHNO'] is not None:
|
||||
|
|
@ -561,18 +578,18 @@ class Fulltilt(HandHistoryConverter):
|
|||
tourney.buyin = 100*Decimal(re.sub(u',', u'', "%s" % mg['BUYIN']))
|
||||
else :
|
||||
if 100*Decimal(re.sub(u',', u'', "%s" % mg['BUYIN'])) != tourney.buyin:
|
||||
log.error( "Conflict between buyins read in topline (%s) and in BuyIn field (%s)" % (tourney.buyin, 100*Decimal(re.sub(u',', u'', "%s" % mg['BUYIN']))) )
|
||||
log.error(_("Conflict between buyins read in topline (%s) and in BuyIn field (%s)") % (tourney.buyin, 100*Decimal(re.sub(u',', u'', "%s" % mg['BUYIN']))) )
|
||||
tourney.subTourneyBuyin = 100*Decimal(re.sub(u',', u'', "%s" % mg['BUYIN']))
|
||||
if mg['FEE'] is not None:
|
||||
if tourney.fee is None:
|
||||
tourney.fee = 100*Decimal(re.sub(u',', u'', "%s" % mg['FEE']))
|
||||
else :
|
||||
if 100*Decimal(re.sub(u',', u'', "%s" % mg['FEE'])) != tourney.fee:
|
||||
log.error( "Conflict between fees read in topline (%s) and in BuyIn field (%s)" % (tourney.fee, 100*Decimal(re.sub(u',', u'', "%s" % mg['FEE']))) )
|
||||
log.error(_("Conflict between fees read in topline (%s) and in BuyIn field (%s)") % (tourney.fee, 100*Decimal(re.sub(u',', u'', "%s" % mg['FEE']))) )
|
||||
tourney.subTourneyFee = 100*Decimal(re.sub(u',', u'', "%s" % mg['FEE']))
|
||||
|
||||
if tourney.buyin is None:
|
||||
log.info( "Unable to affect a buyin to this tournament : assume it's a freeroll" )
|
||||
log.info(_("Unable to affect a buyin to this tournament : assume it's a freeroll"))
|
||||
tourney.buyin = 0
|
||||
tourney.fee = 0
|
||||
else:
|
||||
|
|
@ -673,7 +690,7 @@ class Fulltilt(HandHistoryConverter):
|
|||
|
||||
tourney.addPlayer(rank, a.group('PNAME'), winnings, "USD", 0, 0, 0) #TODO: make it store actual winnings currency
|
||||
else:
|
||||
print "FullTilt: Player finishing stats unreadable : %s" % a
|
||||
print (_("FullTilt: Player finishing stats unreadable : %s") % a)
|
||||
|
||||
# Find Hero
|
||||
n = self.re_TourneyHeroFinishingP.search(playersText)
|
||||
|
|
@ -682,17 +699,17 @@ class Fulltilt(HandHistoryConverter):
|
|||
tourney.hero = heroName
|
||||
# Is this really useful ?
|
||||
if heroName not in tourney.ranks:
|
||||
print "FullTilt:", heroName, "not found in tourney.ranks ..."
|
||||
print (_("FullTilt: %s not found in tourney.ranks ...") % heroName)
|
||||
elif (tourney.ranks[heroName] != Decimal(n.group('HERO_FINISHING_POS'))):
|
||||
print "FullTilt: Bad parsing : finish position incoherent : %s / %s" % (tourney.ranks[heroName], n.group('HERO_FINISHING_POS'))
|
||||
print (_("FullTilt: Bad parsing : finish position incoherent : %s / %s") % (tourney.ranks[heroName], n.group('HERO_FINISHING_POS')))
|
||||
|
||||
return True
|
||||
|
||||
if __name__ == "__main__":
|
||||
parser = OptionParser()
|
||||
parser.add_option("-i", "--input", dest="ipath", help="parse input hand history", default="regression-test-files/fulltilt/razz/FT20090223 Danville - $0.50-$1 Ante $0.10 - Limit Razz.txt")
|
||||
parser.add_option("-o", "--output", dest="opath", help="output translation to", default="-")
|
||||
parser.add_option("-f", "--follow", dest="follow", help="follow (tail -f) the input", action="store_true", default=False)
|
||||
parser.add_option("-i", "--input", dest="ipath", help=_("parse input hand history"), default="regression-test-files/fulltilt/razz/FT20090223 Danville - $0.50-$1 Ante $0.10 - Limit Razz.txt")
|
||||
parser.add_option("-o", "--output", dest="opath", help=_("output translation to"), default="-")
|
||||
parser.add_option("-f", "--follow", dest="follow", help=_("follow (tail -f) the input"), action="store_true", default=False)
|
||||
parser.add_option("-q", "--quiet",
|
||||
action="store_const", const=logging.CRITICAL, dest="verbosity", default=logging.INFO)
|
||||
parser.add_option("-v", "--verbose",
|
||||
|
|
@ -704,5 +721,3 @@ if __name__ == "__main__":
|
|||
|
||||
e = Fulltilt(in_path = options.ipath, out_path = options.opath, follow = options.follow)
|
||||
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -15,6 +15,9 @@
|
|||
#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 L10n
|
||||
_ = L10n.get_translation()
|
||||
|
||||
import threading
|
||||
import subprocess
|
||||
import traceback
|
||||
|
|
@ -26,13 +29,23 @@ import gobject
|
|||
import os
|
||||
import sys
|
||||
import time
|
||||
|
||||
import logging
|
||||
# logging has been set up in fpdb.py or HUD_main.py, use their settings:
|
||||
log = logging.getLogger("importer")
|
||||
|
||||
|
||||
import fpdb_import
|
||||
from optparse import OptionParser
|
||||
import Configuration
|
||||
import string
|
||||
|
||||
if os.name == "nt":
|
||||
import win32console
|
||||
|
||||
|
||||
class GuiAutoImport (threading.Thread):
|
||||
def __init__(self, settings, config, sql, parent):
|
||||
def __init__(self, settings, config, sql = None, parent = None, cli = False):
|
||||
self.importtimer = 0
|
||||
self.settings = settings
|
||||
self.config = config
|
||||
|
|
@ -41,9 +54,6 @@ class GuiAutoImport (threading.Thread):
|
|||
|
||||
imp = self.config.get_import_parameters()
|
||||
|
||||
# print "Import parameters"
|
||||
# print imp
|
||||
|
||||
self.input_settings = {}
|
||||
self.pipe_to_hud = None
|
||||
|
||||
|
|
@ -53,13 +63,21 @@ class GuiAutoImport (threading.Thread):
|
|||
self.importer.setQuiet(False)
|
||||
self.importer.setFailOnError(False)
|
||||
self.importer.setHandCount(0)
|
||||
# self.importer.setWatchTime()
|
||||
|
||||
self.server = settings['db-host']
|
||||
self.user = settings['db-user']
|
||||
self.password = settings['db-password']
|
||||
self.database = settings['db-databaseName']
|
||||
|
||||
if cli == False:
|
||||
self.setupGui()
|
||||
else:
|
||||
# TODO: Separate the code that grabs the directories from config
|
||||
# Separate the calls to the Importer API
|
||||
# Create a timer interface that doesn't rely on GTK
|
||||
pass
|
||||
|
||||
def setupGui(self):
|
||||
self.mainVBox = gtk.VBox(False,1)
|
||||
|
||||
hbox = gtk.HBox(True, 0) # contains 2 equal vboxes
|
||||
|
|
@ -70,7 +88,7 @@ class GuiAutoImport (threading.Thread):
|
|||
vbox2 = gtk.VBox(True, 0)
|
||||
hbox.pack_start(vbox2, True, True, 0)
|
||||
|
||||
self.intervalLabel = gtk.Label("Time between imports in seconds:")
|
||||
self.intervalLabel = gtk.Label(_("Time between imports in seconds:"))
|
||||
self.intervalLabel.set_alignment(xalign=1.0, yalign=0.5)
|
||||
vbox1.pack_start(self.intervalLabel, False, True, 0)
|
||||
|
||||
|
|
@ -101,7 +119,7 @@ class GuiAutoImport (threading.Thread):
|
|||
hbox.pack_start(lbl1, expand=True, fill=False)
|
||||
|
||||
self.doAutoImportBool = False
|
||||
self.startButton = gtk.ToggleButton(" Start _Autoimport ")
|
||||
self.startButton = gtk.ToggleButton(_(" Start _Auto Import "))
|
||||
self.startButton.connect("clicked", self.startClicked, "start clicked")
|
||||
hbox.pack_start(self.startButton, expand=False, fill=False)
|
||||
|
||||
|
|
@ -120,7 +138,7 @@ class GuiAutoImport (threading.Thread):
|
|||
scrolledwindow.add(self.textview)
|
||||
|
||||
self.mainVBox.show_all()
|
||||
self.addText("AutoImport Ready.")
|
||||
self.addText(_("Auto Import Ready."))
|
||||
|
||||
def addText(self, text):
|
||||
end_iter = self.textbuffer.get_end_iter()
|
||||
|
|
@ -133,7 +151,7 @@ class GuiAutoImport (threading.Thread):
|
|||
"""runs when user clicks one of the browse buttons in the auto import tab"""
|
||||
current_path=data[1].get_text()
|
||||
|
||||
dia_chooser = gtk.FileChooserDialog(title="Please choose the path that you want to auto import",
|
||||
dia_chooser = gtk.FileChooserDialog(title=_("Please choose the path that you want to Auto Import"),
|
||||
action=gtk.FILE_CHOOSER_ACTION_SELECT_FOLDER,
|
||||
buttons=(gtk.STOCK_CANCEL,gtk.RESPONSE_CANCEL,gtk.STOCK_OPEN,gtk.RESPONSE_OK))
|
||||
#dia_chooser.set_current_folder(pathname)
|
||||
|
|
@ -156,7 +174,7 @@ class GuiAutoImport (threading.Thread):
|
|||
def do_import(self):
|
||||
"""Callback for timer to do an import iteration."""
|
||||
if self.doAutoImportBool:
|
||||
self.startButton.set_label(u' _Auto Import Running ')
|
||||
self.startButton.set_label(_(u' _Auto Import Running '))
|
||||
self.importer.runUpdated()
|
||||
self.addText(".")
|
||||
#sys.stdout.write(".")
|
||||
|
|
@ -167,9 +185,9 @@ class GuiAutoImport (threading.Thread):
|
|||
|
||||
def reset_startbutton(self):
|
||||
if self.pipe_to_hud is not None:
|
||||
self.startButton.set_label(u' Stop _Autoimport ')
|
||||
self.startButton.set_label(_(u' Stop _Auto Import '))
|
||||
else:
|
||||
self.startButton.set_label(u' Start _Autoimport ')
|
||||
self.startButton.set_label(_(u' Start _Auto Import '))
|
||||
|
||||
return False
|
||||
|
||||
|
|
@ -192,17 +210,21 @@ class GuiAutoImport (threading.Thread):
|
|||
# - Ideally we want to release the lock if the auto-import is killed by some
|
||||
# kind of exception - is this possible?
|
||||
if self.settings['global_lock'].acquire(False): # returns false immediately if lock not acquired
|
||||
self.addText("\nGlobal lock taken ... Auto Import Started.\n")
|
||||
self.addText(_("\nGlobal lock taken ... Auto Import Started.\n"))
|
||||
self.doAutoImportBool = True
|
||||
widget.set_label(u' _Stop Autoimport ')
|
||||
widget.set_label(_(u' _Stop Auto Import '))
|
||||
if self.pipe_to_hud is None:
|
||||
if Configuration.FROZEN:
|
||||
if Configuration.FROZEN: # if py2exe, run hud_main.exe
|
||||
path = Configuration.EXEC_PATH
|
||||
command = "HUD_main.exe"
|
||||
bs = 0
|
||||
elif os.name == 'nt':
|
||||
path = sys.path[0].replace('\\','\\\\')
|
||||
command = 'pythonw "'+path+'\\HUD_main.pyw" ' + self.settings['cl_options']
|
||||
if win32console.GetConsoleWindow() == 0:
|
||||
command = 'pythonw "'+path+'\\HUD_main.pyw" ' + self.settings['cl_options']
|
||||
else:
|
||||
command = 'python "'+path+'\\HUD_main.pyw" ' + self.settings['cl_options']
|
||||
# uncomment above line if you want hud_main stdout to work ... and make sure you are running fpdb.py using python.exe not pythonw.exe
|
||||
bs = 0
|
||||
else:
|
||||
command = os.path.join(sys.path[0], 'HUD_main.pyw')
|
||||
|
|
@ -210,19 +232,22 @@ class GuiAutoImport (threading.Thread):
|
|||
bs = 1
|
||||
|
||||
try:
|
||||
print "opening pipe to HUD"
|
||||
self.pipe_to_hud = subprocess.Popen(command, bufsize=bs,
|
||||
stdin=subprocess.PIPE,
|
||||
stdout=subprocess.PIPE, # only needed for py2exe
|
||||
stderr=subprocess.PIPE, # only needed for py2exe
|
||||
universal_newlines=True
|
||||
)
|
||||
print _("opening pipe to HUD")
|
||||
if Configuration.FROZEN or (os.name == "nt" and win32console.GetConsoleWindow()) == 0:
|
||||
self.pipe_to_hud = subprocess.Popen(command, bufsize=bs,
|
||||
stdin=subprocess.PIPE,
|
||||
stdout=subprocess.PIPE, # needed for pythonw / py2exe
|
||||
stderr=subprocess.PIPE, # needed for pythonw / py2exe
|
||||
universal_newlines=True
|
||||
)
|
||||
else:
|
||||
self.pipe_to_hud = subprocess.Popen(command, bufsize=bs, stdin=subprocess.PIPE, universal_newlines=True)
|
||||
#self.pipe_to_hud.stdout.close()
|
||||
#self.pipe_to_hud.stderr.close()
|
||||
except:
|
||||
err = traceback.extract_tb(sys.exc_info()[2])[-1]
|
||||
#self.addText( "\n*** GuiAutoImport Error opening pipe: " + err[2] + "(" + str(err[1]) + "): " + str(sys.exc_info()[1]))
|
||||
self.addText( "\n*** GuiAutoImport Error opening pipe: " + traceback.format_exc() )
|
||||
self.addText(_("\n*** GuiAutoImport Error opening pipe: ") + traceback.format_exc() )
|
||||
else:
|
||||
for site in self.input_settings:
|
||||
self.importer.addImportDirectory(self.input_settings[site][0], True, site, self.input_settings[site][1])
|
||||
|
|
@ -234,19 +259,19 @@ class GuiAutoImport (threading.Thread):
|
|||
self.importtimer = gobject.timeout_add(interval * 1000, self.do_import)
|
||||
|
||||
else:
|
||||
self.addText("\nauto-import aborted - global lock not available")
|
||||
self.addText(_("\nAuto Import aborted - global lock not available"))
|
||||
else: # toggled off
|
||||
gobject.source_remove(self.importtimer)
|
||||
self.settings['global_lock'].release()
|
||||
self.doAutoImportBool = False # do_import will return this and stop the gobject callback timer
|
||||
self.addText("\nStopping autoimport - global lock released.")
|
||||
self.addText(_("\nStopping Auto Import - global lock released."))
|
||||
if self.pipe_to_hud.poll() is not None:
|
||||
self.addText("\n * Stop Autoimport: HUD already terminated")
|
||||
self.addText(_("\n * Stop Auto Import: HUD already terminated"))
|
||||
else:
|
||||
#print >>self.pipe_to_hud.stdin, "\n"
|
||||
self.pipe_to_hud.communicate('\n') # waits for process to terminate
|
||||
self.pipe_to_hud = None
|
||||
self.startButton.set_label(u' Start _Autoimport ')
|
||||
self.startButton.set_label(_(u' Start _Auto Import '))
|
||||
|
||||
#end def GuiAutoImport.startClicked
|
||||
|
||||
|
|
@ -268,7 +293,7 @@ class GuiAutoImport (threading.Thread):
|
|||
hbox1.pack_start(dirPath, True, True, 3)
|
||||
dirPath.show()
|
||||
|
||||
browseButton=gtk.Button("Browse...")
|
||||
browseButton=gtk.Button(_("Browse..."))
|
||||
browseButton.connect("clicked", self.browseClicked, [site] + [dirPath])
|
||||
hbox2.pack_start(browseButton, False, False, 3)
|
||||
browseButton.show()
|
||||
|
|
@ -284,6 +309,7 @@ class GuiAutoImport (threading.Thread):
|
|||
|
||||
def addSites(self, vbox1, vbox2):
|
||||
the_sites = self.config.get_supported_sites()
|
||||
#log.debug("addSites: the_sites="+str(the_sites))
|
||||
for site in the_sites:
|
||||
pathHBox1 = gtk.HBox(False, 0)
|
||||
vbox1.pack_start(pathHBox1, False, True, 0)
|
||||
|
|
@ -294,6 +320,7 @@ class GuiAutoImport (threading.Thread):
|
|||
paths = self.config.get_default_paths(site)
|
||||
self.createSiteLine(pathHBox1, pathHBox2, site, False, paths['hud-defaultPath'], params['converter'], params['enabled'])
|
||||
self.input_settings[site] = [paths['hud-defaultPath']] + [params['converter']]
|
||||
#log.debug("addSites: input_settings="+str(self.input_settings))
|
||||
|
||||
if __name__== "__main__":
|
||||
def destroy(*args): # call back for terminating the main eventloop
|
||||
|
|
@ -311,7 +338,7 @@ if __name__== "__main__":
|
|||
parser = OptionParser()
|
||||
parser.add_option("-q", "--quiet", action="store_false", dest="gui", default=True, help="don't start gui")
|
||||
parser.add_option("-m", "--minPrint", "--status", dest="minPrint", default="0", type="int",
|
||||
help="How often to print a one-line status report (0 (default) means never)")
|
||||
help=_("How often to print a one-line status report (0 (default) means never)"))
|
||||
(options, argv) = parser.parse_args()
|
||||
|
||||
config = Configuration.Config()
|
||||
|
|
@ -321,17 +348,16 @@ if __name__== "__main__":
|
|||
if os.name == 'nt': settings['os'] = 'windows'
|
||||
else: settings['os'] = 'linuxmac'
|
||||
|
||||
settings.update(config.get_db_parameters('fpdb'))
|
||||
settings.update(config.get_tv_parameters())
|
||||
settings.update(config.get_db_parameters())
|
||||
settings.update(config.get_import_parameters())
|
||||
settings.update(config.get_default_paths())
|
||||
|
||||
if(options.gui == True):
|
||||
i = GuiAutoImport(settings, config)
|
||||
i = GuiAutoImport(settings, config, None, None)
|
||||
main_window = gtk.Window()
|
||||
main_window.connect('destroy', destroy)
|
||||
main_window.add(i.mainVBox)
|
||||
main_window.show()
|
||||
gtk.main()
|
||||
else:
|
||||
pass
|
||||
i = GuiAutoImport(settings, config, cli = True)
|
||||
|
|
|
|||
|
|
@ -15,6 +15,9 @@
|
|||
#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 L10n
|
||||
_ = L10n.get_translation()
|
||||
|
||||
# Standard Library modules
|
||||
import os
|
||||
import sys
|
||||
|
|
@ -33,6 +36,7 @@ import fpdb_import
|
|||
import Configuration
|
||||
import Exceptions
|
||||
|
||||
|
||||
class GuiBulkImport():
|
||||
|
||||
# CONFIGURATION - update these as preferred:
|
||||
|
|
@ -52,8 +56,8 @@ class GuiBulkImport():
|
|||
# (see comment above about what to do if pipe already open)
|
||||
if self.settings['global_lock'].acquire(wait=False, source="GuiBulkImport"): # returns false immediately if lock not acquired
|
||||
#try:
|
||||
print "\nGlobal lock taken ..."
|
||||
self.progressbar.set_text("Importing...")
|
||||
print _("\nGlobal lock taken ...")
|
||||
self.progressbar.set_text(_("Importing..."))
|
||||
self.progressbar.pulse()
|
||||
while gtk.events_pending(): # see http://faq.pygtk.org/index.py?req=index for more hints (3.7)
|
||||
gtk.main_iteration(False)
|
||||
|
|
@ -102,7 +106,7 @@ class GuiBulkImport():
|
|||
ttime = time() - starttime
|
||||
if ttime == 0:
|
||||
ttime = 1
|
||||
print 'GuiBulkImport.load done: Stored: %d \tDuplicates: %d \tPartial: %d \tErrors: %d in %s seconds - %.0f/sec'\
|
||||
print _('GuiBulkImport.load done: Stored: %d \tDuplicates: %d \tPartial: %d \tErrors: %d in %s seconds - %.0f/sec')\
|
||||
% (stored, dups, partial, errs, ttime, (stored+0.0) / ttime)
|
||||
self.importer.clearFileList()
|
||||
# This file should really be 'logging'
|
||||
|
|
@ -116,7 +120,7 @@ class GuiBulkImport():
|
|||
self.cb_drophudcache.set_active(0)
|
||||
self.lab_hdrop.set_sensitive(True)
|
||||
|
||||
self.progressbar.set_text("Import Complete")
|
||||
self.progressbar.set_text(_("Import Complete"))
|
||||
self.progressbar.set_fraction(0)
|
||||
#except:
|
||||
#err = traceback.extract_tb(sys.exc_info()[2])[-1]
|
||||
|
|
@ -124,16 +128,18 @@ class GuiBulkImport():
|
|||
#self.settings['global_lock'].release()
|
||||
self.settings['global_lock'].release()
|
||||
else:
|
||||
print "bulk-import aborted - global lock not available"
|
||||
print _("bulk import aborted - global lock not available")
|
||||
|
||||
def get_vbox(self):
|
||||
"""returns the vbox of this thread"""
|
||||
return self.vbox
|
||||
|
||||
def __init__(self, settings, config, sql = None):
|
||||
def __init__(self, settings, config, sql = None, parent = None):
|
||||
self.settings = settings
|
||||
self.config = config
|
||||
self.importer = fpdb_import.Importer(self, self.settings, config, sql)
|
||||
self.parent = parent
|
||||
|
||||
self.importer = fpdb_import.Importer(self, self.settings, config, sql, parent)
|
||||
|
||||
self.vbox = gtk.VBox(False, 0)
|
||||
self.vbox.show()
|
||||
|
|
@ -150,14 +156,14 @@ class GuiBulkImport():
|
|||
self.table.show()
|
||||
|
||||
# checkbox - print start/stop?
|
||||
self.chk_st_st = gtk.CheckButton('Print Start/Stop Info')
|
||||
self.chk_st_st = gtk.CheckButton(_('Print Start/Stop Info'))
|
||||
self.table.attach(self.chk_st_st, 0, 1, 0, 1, xpadding=10, ypadding=0,
|
||||
yoptions=gtk.SHRINK)
|
||||
self.chk_st_st.show()
|
||||
self.chk_st_st.set_active(True)
|
||||
|
||||
# label - status
|
||||
self.lab_status = gtk.Label("Hands/status print:")
|
||||
self.lab_status = gtk.Label(_("Hands/status print:"))
|
||||
self.table.attach(self.lab_status, 1, 2, 0, 1, xpadding=0, ypadding=0,
|
||||
yoptions=gtk.SHRINK)
|
||||
self.lab_status.show()
|
||||
|
|
@ -174,7 +180,7 @@ class GuiBulkImport():
|
|||
self.spin_status.show()
|
||||
|
||||
# label - threads
|
||||
self.lab_threads = gtk.Label("Number of threads:")
|
||||
self.lab_threads = gtk.Label(_("Number of threads:"))
|
||||
self.table.attach(self.lab_threads, 3, 4, 0, 1, xpadding=0, ypadding=0,
|
||||
yoptions=gtk.SHRINK)
|
||||
self.lab_threads.show()
|
||||
|
|
@ -194,12 +200,12 @@ class GuiBulkImport():
|
|||
self.spin_threads.set_sensitive(False)
|
||||
|
||||
# checkbox - fail on error?
|
||||
self.chk_fail = gtk.CheckButton('Fail on error')
|
||||
self.chk_fail = gtk.CheckButton(_('Fail on error'))
|
||||
self.table.attach(self.chk_fail, 0, 1, 1, 2, xpadding=10, ypadding=0, yoptions=gtk.SHRINK)
|
||||
self.chk_fail.show()
|
||||
|
||||
# label - hands
|
||||
self.lab_hands = gtk.Label("Hands/file:")
|
||||
self.lab_hands = gtk.Label(_("Hands/file:"))
|
||||
self.table.attach(self.lab_hands, 1, 2, 1, 2, xpadding=0, ypadding=0, yoptions=gtk.SHRINK)
|
||||
self.lab_hands.show()
|
||||
self.lab_hands.set_justify(gtk.JUSTIFY_RIGHT)
|
||||
|
|
@ -214,7 +220,7 @@ class GuiBulkImport():
|
|||
self.spin_hands.show()
|
||||
|
||||
# label - drop indexes
|
||||
self.lab_drop = gtk.Label("Drop indexes:")
|
||||
self.lab_drop = gtk.Label(_("Drop indexes:"))
|
||||
self.table.attach(self.lab_drop, 3, 4, 1, 2, xpadding=0, ypadding=0,
|
||||
yoptions=gtk.SHRINK)
|
||||
self.lab_drop.show()
|
||||
|
|
@ -223,20 +229,20 @@ class GuiBulkImport():
|
|||
|
||||
# ComboBox - drop indexes
|
||||
self.cb_dropindexes = gtk.combo_box_new_text()
|
||||
self.cb_dropindexes.append_text('auto')
|
||||
self.cb_dropindexes.append_text("don't drop")
|
||||
self.cb_dropindexes.append_text('drop')
|
||||
self.cb_dropindexes.append_text(_('auto'))
|
||||
self.cb_dropindexes.append_text(_("don't drop"))
|
||||
self.cb_dropindexes.append_text(_('drop'))
|
||||
self.cb_dropindexes.set_active(0)
|
||||
self.table.attach(self.cb_dropindexes, 4, 5, 1, 2, xpadding=10,
|
||||
ypadding=0, yoptions=gtk.SHRINK)
|
||||
self.cb_dropindexes.show()
|
||||
|
||||
self.cb_testmode = gtk.CheckButton('HUD Test mode')
|
||||
self.cb_testmode = gtk.CheckButton(_('HUD Test mode'))
|
||||
self.table.attach(self.cb_testmode, 0, 1, 2, 3, xpadding=10, ypadding=0, yoptions=gtk.SHRINK)
|
||||
self.cb_testmode.show()
|
||||
|
||||
# label - filter
|
||||
self.lab_filter = gtk.Label("Site filter:")
|
||||
self.lab_filter = gtk.Label(_("Site filter:"))
|
||||
self.table.attach(self.lab_filter, 1, 2, 2, 3, xpadding=0, ypadding=0,
|
||||
yoptions=gtk.SHRINK)
|
||||
self.lab_filter.show()
|
||||
|
|
@ -264,7 +270,7 @@ class GuiBulkImport():
|
|||
self.cbfilter.show()
|
||||
|
||||
# label - drop hudcache
|
||||
self.lab_hdrop = gtk.Label("Drop HudCache:")
|
||||
self.lab_hdrop = gtk.Label(_("Drop HudCache:"))
|
||||
self.table.attach(self.lab_hdrop, 3, 4, 2, 3, xpadding=0, ypadding=0,
|
||||
yoptions=gtk.SHRINK)
|
||||
self.lab_hdrop.show()
|
||||
|
|
@ -273,18 +279,18 @@ class GuiBulkImport():
|
|||
|
||||
# ComboBox - drop hudcache
|
||||
self.cb_drophudcache = gtk.combo_box_new_text()
|
||||
self.cb_drophudcache.append_text('auto')
|
||||
self.cb_drophudcache.append_text("don't drop")
|
||||
self.cb_drophudcache.append_text('drop')
|
||||
self.cb_drophudcache.append_text(_('auto'))
|
||||
self.cb_drophudcache.append_text(_("don't drop"))
|
||||
self.cb_drophudcache.append_text(_('drop'))
|
||||
self.cb_drophudcache.set_active(0)
|
||||
self.table.attach(self.cb_drophudcache, 4, 5, 2, 3, xpadding=10,
|
||||
ypadding=0, yoptions=gtk.SHRINK)
|
||||
self.cb_drophudcache.show()
|
||||
|
||||
# button - Import
|
||||
self.load_button = gtk.Button('Import') # todo: rename variables to import too
|
||||
self.load_button = gtk.Button(_('_Bulk Import')) # todo: rename variables to import too
|
||||
self.load_button.connect('clicked', self.load_clicked,
|
||||
'Import clicked')
|
||||
_('Import clicked'))
|
||||
self.table.attach(self.load_button, 2, 3, 4, 5, xpadding=0, ypadding=0,
|
||||
yoptions=gtk.SHRINK)
|
||||
self.load_button.show()
|
||||
|
|
@ -302,7 +308,7 @@ class GuiBulkImport():
|
|||
self.progressbar = gtk.ProgressBar()
|
||||
self.table.attach(self.progressbar, 3, 5, 4, 5, xpadding=0, ypadding=0,
|
||||
yoptions=gtk.SHRINK)
|
||||
self.progressbar.set_text("Waiting...")
|
||||
self.progressbar.set_text(_("Waiting..."))
|
||||
self.progressbar.set_fraction(0)
|
||||
self.progressbar.show()
|
||||
|
||||
|
|
@ -331,29 +337,33 @@ def main(argv=None):
|
|||
|
||||
parser = OptionParser()
|
||||
parser.add_option("-f", "--file", dest="filename", metavar="FILE", default=None,
|
||||
help="Input file in quiet mode")
|
||||
help=_("Input file in quiet mode"))
|
||||
parser.add_option("-q", "--quiet", action="store_false", dest="gui", default=True,
|
||||
help="don't start gui; deprecated (just give a filename with -f).")
|
||||
help=_("don't start gui; deprecated (just give a filename with -f)."))
|
||||
parser.add_option("-c", "--convert", dest="filtername", default="PokerStars", metavar="FILTER",
|
||||
help="Conversion filter (*Full Tilt Poker, PokerStars, Everleaf, Absolute)")
|
||||
help=_("Conversion filter (*Full Tilt Poker, PokerStars, Everleaf, Absolute)"))
|
||||
parser.add_option("-x", "--failOnError", action="store_true", default=False,
|
||||
help="If this option is passed it quits when it encounters any error")
|
||||
help=_("If this option is passed it quits when it encounters any error"))
|
||||
parser.add_option("-m", "--minPrint", "--status", dest="minPrint", default="0", type="int",
|
||||
help="How often to print a one-line status report (0 (default) means never)")
|
||||
help=_("How often to print a one-line status report (0 (default) means never)"))
|
||||
parser.add_option("-u", "--usage", action="store_true", dest="usage", default=False,
|
||||
help="Print some useful one liners")
|
||||
help=_("Print some useful one liners"))
|
||||
parser.add_option("-s", "--starsarchive", action="store_true", dest="starsArchive", default=False,
|
||||
help="Do the required conversion for Stars Archive format (ie. as provided by support")
|
||||
help=_("Do the required conversion for Stars Archive format (ie. as provided by support"))
|
||||
parser.add_option("-F", "--ftparchive", action="store_true", dest="ftpArchive", default=False,
|
||||
help=_("Do the required conversion for FTP Archive format (ie. as provided by support"))
|
||||
parser.add_option("-t", "--testdata", action="store_true", dest="testData", default=False,
|
||||
help=_("Output the pprinted version of the HandsPlayer hash for regresion testing"))
|
||||
(options, argv) = parser.parse_args(args = argv)
|
||||
|
||||
if options.usage == True:
|
||||
#Print usage examples and exit
|
||||
print "USAGE:"
|
||||
print 'PokerStars converter: ./GuiBulkImport -c PokerStars -f filename'
|
||||
print 'Full Tilt converter: ./GuiBulkImport -c "Full Tilt Poker" -f filename'
|
||||
print "Everleaf converter: ./GuiBulkImport -c Everleaf -f filename"
|
||||
print "Absolute converter: ./GuiBulkImport -c Absolute -f filename"
|
||||
print "PartyPoker converter: ./GuiBulkImport -c PartyPoker -f filename"
|
||||
print _("USAGE:")
|
||||
print _('PokerStars converter: ./GuiBulkImport.py -c PokerStars -f filename')
|
||||
print _('Full Tilt converter: ./GuiBulkImport.py -c "Full Tilt Poker" -f filename')
|
||||
print _("Everleaf converter: ./GuiBulkImport.py -c Everleaf -f filename")
|
||||
print _("Absolute converter: ./GuiBulkImport.py -c Absolute -f filename")
|
||||
print _("PartyPoker converter: ./GuiBulkImport.py -c PartyPoker -f filename")
|
||||
sys.exit(0)
|
||||
|
||||
config = Configuration.Config()
|
||||
|
|
@ -364,15 +374,14 @@ def main(argv=None):
|
|||
else: settings['os'] = 'linuxmac'
|
||||
|
||||
settings.update(config.get_db_parameters())
|
||||
settings.update(config.get_tv_parameters())
|
||||
settings.update(config.get_import_parameters())
|
||||
settings.update(config.get_default_paths())
|
||||
|
||||
if not options.gui:
|
||||
print '-q is deprecated. Just use "-f filename" instead'
|
||||
print _('-q is deprecated. Just use "-f filename" instead')
|
||||
# This is because -q on its own causes an error, so -f is necessary and sufficient for cmd line use
|
||||
if not options.filename:
|
||||
i = GuiBulkImport(settings, config)
|
||||
i = GuiBulkImport(settings, config, None)
|
||||
main_window = gtk.Window()
|
||||
main_window.connect('destroy', destroy)
|
||||
main_window.add(i.vbox)
|
||||
|
|
@ -380,18 +389,22 @@ def main(argv=None):
|
|||
gtk.main()
|
||||
else:
|
||||
#Do something useful
|
||||
importer = fpdb_import.Importer(False,settings, config)
|
||||
importer = fpdb_import.Importer(False,settings, config, None)
|
||||
# importer.setDropIndexes("auto")
|
||||
importer.setDropIndexes("don't drop")
|
||||
importer.setDropIndexes(_("don't drop"))
|
||||
importer.setFailOnError(options.failOnError)
|
||||
importer.setThreads(-1)
|
||||
importer.addBulkImportImportFileOrDir(os.path.expanduser(options.filename), site=options.filtername)
|
||||
importer.setCallHud(False)
|
||||
if options.starsArchive:
|
||||
importer.setStarsArchive(True)
|
||||
if options.ftpArchive:
|
||||
importer.setFTPArchive(True)
|
||||
if options.testData:
|
||||
importer.setPrintTestData(True)
|
||||
(stored, dups, partial, errs, ttime) = importer.runImport()
|
||||
importer.clearFileList()
|
||||
print 'GuiBulkImport done: Stored: %d \tDuplicates: %d \tPartial: %d \tErrors: %d in %s seconds - %.0f/sec'\
|
||||
print _('GuiBulkImport done: Stored: %d \tDuplicates: %d \tPartial: %d \tErrors: %d in %s seconds - %.0f/sec')\
|
||||
% (stored, dups, partial, errs, ttime, (stored+0.0) / ttime)
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -15,10 +15,14 @@
|
|||
#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 L10n
|
||||
_ = L10n.get_translation()
|
||||
|
||||
import os
|
||||
import sys
|
||||
import traceback
|
||||
import Queue
|
||||
import re
|
||||
|
||||
import pygtk
|
||||
pygtk.require('2.0')
|
||||
|
|
@ -30,12 +34,11 @@ import logging
|
|||
# logging has been set up in fpdb.py or HUD_main.py, use their settings:
|
||||
log = logging.getLogger("maintdbs")
|
||||
|
||||
|
||||
import Exceptions
|
||||
import Configuration
|
||||
import Database
|
||||
import SQL
|
||||
|
||||
|
||||
class GuiDatabase:
|
||||
|
||||
# columns in liststore:
|
||||
|
|
@ -68,8 +71,17 @@ class GuiDatabase:
|
|||
try:
|
||||
#self.dia.set_modal(True)
|
||||
self.vbox = self.dia.vbox
|
||||
self.action_area = self.dia.action_area
|
||||
#gtk.Widget.set_size_request(self.vbox, 700, 400);
|
||||
|
||||
h = gtk.HBox(False, spacing=3)
|
||||
h.show()
|
||||
self.vbox.pack_start(h, padding=3)
|
||||
|
||||
vbtn = gtk.VBox(True, spacing=3)
|
||||
vbtn.show()
|
||||
h.pack_start(vbtn, expand=False, fill=False, padding=2)
|
||||
|
||||
# list of databases in self.config.supported_databases:
|
||||
self.liststore = gtk.ListStore(str, str, str, str, str
|
||||
,str, str, str, str, str)
|
||||
|
|
@ -90,27 +102,31 @@ class GuiDatabase:
|
|||
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)
|
||||
h.pack_start(self.scrolledwindow, expand=True, fill=True, padding=0)
|
||||
|
||||
refreshbutton = gtk.Button("Refresh")
|
||||
refreshbutton.connect("clicked", self.refresh, None)
|
||||
self.vbox.pack_start(refreshbutton, False, False, 3)
|
||||
refreshbutton.show()
|
||||
add_button = SideButton(_("_Add"), gtk.STOCK_ADD)
|
||||
add_button.connect("clicked", self.addDB, None)
|
||||
vbtn.pack_start(add_button, False, False, 3)
|
||||
|
||||
col = self.addTextColumn("Type", 0, False)
|
||||
col = self.addTextColumn("Name", 1, False)
|
||||
col = self.addTextColumn("Description", 2, True)
|
||||
col = self.addTextColumn("Username", 3, True)
|
||||
col = self.addTextColumn("Password", 4, True)
|
||||
col = self.addTextColumn("Host", 5, True)
|
||||
col = self.addTextObjColumn("Default", 6, 6)
|
||||
col = self.addTextObjColumn("Status", 7, 8)
|
||||
refresh_button = SideButton(_("_Refresh"), gtk.STOCK_REFRESH)
|
||||
refresh_button.connect("clicked", self.refresh, None)
|
||||
vbtn.pack_start(refresh_button, False, False, 3)
|
||||
|
||||
col = self.addTextColumn(_("Type"), 0, False)
|
||||
col = self.addTextColumn(_("Name"), 1, False)
|
||||
col = self.addTextColumn(_("Description"), 2, True)
|
||||
col = self.addTextColumn(_("Username"), 3, True)
|
||||
col = self.addTextColumn(_("Password"), 4, True)
|
||||
col = self.addTextColumn(_("Host"), 5, True)
|
||||
col = self.addTextObjColumn(_("Open"), 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.dia.show_all()
|
||||
self.loadDbs()
|
||||
|
||||
#self.dia.connect('response', self.dialog_response_cb)
|
||||
|
|
@ -237,9 +253,9 @@ class GuiDatabase:
|
|||
|
||||
self.liststore.clear()
|
||||
#self.listcols = []
|
||||
dia = self.info_box2(None, 'Testing database connections ... ', "", False, False)
|
||||
dia = InfoBox( parent=self.dia, str1=_('Testing database connections ... ') )
|
||||
while gtk.events_pending():
|
||||
gtk.mainiteration()
|
||||
gtk.main_iteration()
|
||||
|
||||
try:
|
||||
# want to fill: dbms, name, comment, user, passwd, host, default, status, icon
|
||||
|
|
@ -257,59 +273,14 @@ class GuiDatabase:
|
|||
default = (name == self.config.db_selected)
|
||||
default_icon = None
|
||||
if default: default_icon = gtk.STOCK_APPLY
|
||||
status = ""
|
||||
icon = None
|
||||
err_msg = ""
|
||||
|
||||
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"
|
||||
icon = gtk.STOCK_CANCEL
|
||||
except Exceptions.FpdbMySQLNoDatabase:
|
||||
err_msg = "MySQL client reports: 2002 or 2003 error. Unable to connect - " \
|
||||
+ "Please check that the MySQL service has been started"
|
||||
status = "failed"
|
||||
icon = gtk.STOCK_CANCEL
|
||||
except Exceptions.FpdbPostgresqlAccessDenied:
|
||||
err_msg = "Postgres Server reports: Access denied. Are your permissions set correctly?"
|
||||
status = "failed"
|
||||
except Exceptions.FpdbPostgresqlNoDatabase:
|
||||
err_msg = "Postgres client reports: Unable to connect - " \
|
||||
+ "Please check that the Postgres service has been started"
|
||||
status = "failed"
|
||||
icon = gtk.STOCK_CANCEL
|
||||
except:
|
||||
err = traceback.extract_tb(sys.exc_info()[2])[-1]
|
||||
log.info( 'db connection to '+str(dbms_num)+','+host+','+name+','+user+','+passwd+' failed: '
|
||||
+ 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 )
|
||||
status, err_msg, icon = GuiDatabase.testDB(self.config, dbms, dbms_num, name, user, passwd, host)
|
||||
|
||||
b = gtk.Button(name)
|
||||
b.show()
|
||||
iter = self.liststore.append( (dbms, name, comment, user, passwd, host, "", default_icon, status, icon) )
|
||||
|
||||
self.info_box2(dia[0], "finished.", "", False, True)
|
||||
dia.add_msg( _("finished."), False, True )
|
||||
self.listview.show()
|
||||
self.scrolledwindow.show()
|
||||
self.vbox.show()
|
||||
|
|
@ -319,7 +290,7 @@ class GuiDatabase:
|
|||
self.dia.show()
|
||||
except:
|
||||
err = traceback.extract_tb(sys.exc_info()[2])[-1]
|
||||
print 'loaddbs error: '+str(dbms_num)+','+host+','+name+','+user+','+passwd+' failed: ' \
|
||||
print _('loadDbs error: ')+str(dbms_num)+','+host+','+name+','+user+','+passwd+' failed: ' \
|
||||
+ err[2] + "(" + str(err[1]) + "): " + str(sys.exc_info()[1])
|
||||
|
||||
def sortCols(self, col, n):
|
||||
|
|
@ -340,71 +311,376 @@ class GuiDatabase:
|
|||
# to turn indicator off for other cols
|
||||
except:
|
||||
err = traceback.extract_tb(sys.exc_info()[2])
|
||||
print "***sortCols error: " + str(sys.exc_info()[1])
|
||||
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()) )
|
||||
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 addDB(self, widget, data):
|
||||
adb = AddDB(self.config, self.dia)
|
||||
(status, err_msg, icon, dbms, dbms_num, name, comment, user, passwd, host) = adb.run()
|
||||
adb.destroy()
|
||||
|
||||
def info_box2(self, dia, str1, str2, run, destroy):
|
||||
if dia is None:
|
||||
# create dialog and add icon and label
|
||||
# save in liststore
|
||||
if status == 'ok':
|
||||
iter = self.liststore.append( (dbms, name, comment, user, passwd, host, "", None, status, icon) )
|
||||
|
||||
# keep config save code in line with edited_cb()? call common routine?
|
||||
|
||||
valid = True
|
||||
# Validate new value (only for dbms so far, but dbms now not updateable so no validation at all!)
|
||||
#if col == self.COL_DBMS:
|
||||
# if new_text not in Configuration.DATABASE_TYPES:
|
||||
# valid = False
|
||||
|
||||
if valid:
|
||||
self.config.add_db_parameters( db_server = dbms
|
||||
, db_name = name
|
||||
, db_desc = comment
|
||||
, db_ip = host
|
||||
, db_user = user
|
||||
, db_pass = passwd )
|
||||
self.config.save()
|
||||
self.changes = False
|
||||
|
||||
|
||||
@staticmethod
|
||||
def testDB(config, dbms, dbms_num, name, user, passwd, host):
|
||||
status = ""
|
||||
icon = None
|
||||
err_msg = ""
|
||||
|
||||
sql = SQL.Sql(db_server=dbms)
|
||||
db = Database.Database(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(_("testDB: 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"
|
||||
icon = gtk.STOCK_CANCEL
|
||||
except Exceptions.FpdbMySQLNoDatabase:
|
||||
err_msg = _("MySQL client reports: 2002 or 2003 error. Unable to connect - ") \
|
||||
+ _("Please check that the MySQL service has been started")
|
||||
status = "failed"
|
||||
icon = gtk.STOCK_CANCEL
|
||||
except Exceptions.FpdbPostgresqlAccessDenied:
|
||||
err_msg = _("PostgreSQL Server reports: Access denied. Are your permissions set correctly?")
|
||||
status = "failed"
|
||||
except Exceptions.FpdbPostgresqlNoDatabase:
|
||||
err_msg = _("PostgreSQL client reports: Unable to connect - ") \
|
||||
+ _("Please check that the PostgreSQL service has been started")
|
||||
status = "failed"
|
||||
icon = gtk.STOCK_CANCEL
|
||||
except:
|
||||
# add more specific exceptions here if found (e.g. for sqlite?)
|
||||
err = traceback.extract_tb(sys.exc_info()[2])[-1]
|
||||
err_msg = err[2] + "(" + str(err[1]) + "): " + str(sys.exc_info()[1])
|
||||
status = "failed"
|
||||
icon = gtk.STOCK_CANCEL
|
||||
if err_msg:
|
||||
log.info( _('db connection to %s, %s, %s, %s, %s failed: %s') % (str(dbms_num), host, name, user, passwd, err_msg))
|
||||
|
||||
return( status, err_msg, icon )
|
||||
|
||||
|
||||
class AddDB(gtk.Dialog):
|
||||
|
||||
def __init__(self, config, parent):
|
||||
log.debug(_("AddDB starting"))
|
||||
self.dbnames = { 'Sqlite' : Configuration.DATABASE_TYPE_SQLITE
|
||||
, 'MySQL' : Configuration.DATABASE_TYPE_MYSQL
|
||||
, 'PostgreSQL' : Configuration.DATABASE_TYPE_POSTGRESQL
|
||||
}
|
||||
self.config = config
|
||||
# create dialog and add icon and label
|
||||
super(AddDB,self).__init__( parent=parent
|
||||
, flags=gtk.DIALOG_MODAL | gtk.DIALOG_DESTROY_WITH_PARENT
|
||||
, title=_("Add New Database")
|
||||
, buttons = (gtk.STOCK_CANCEL, gtk.RESPONSE_REJECT
|
||||
,gtk.STOCK_SAVE, gtk.RESPONSE_ACCEPT)
|
||||
) # , buttons=btns
|
||||
self.set_default_size(450, 280)
|
||||
#self.connect('response', self.response_cb)
|
||||
|
||||
t = gtk.Table(5, 3, True)
|
||||
self.vbox.pack_start(t, expand=False, fill=False, padding=3)
|
||||
|
||||
l = gtk.Label( _("DB Type") )
|
||||
l.set_alignment(1.0, 0.5)
|
||||
t.attach(l, 0, 1, 0, 1, xpadding=3)
|
||||
self.cb_dbms = gtk.combo_box_new_text()
|
||||
for s in ('Sqlite',): # keys(self.dbnames):
|
||||
self.cb_dbms.append_text(s)
|
||||
self.cb_dbms.set_active(0)
|
||||
t.attach(self.cb_dbms, 1, 3, 0, 1, xpadding=3)
|
||||
self.cb_dbms.connect("changed", self.db_type_changed, None)
|
||||
|
||||
l = gtk.Label( _("DB Name") )
|
||||
l.set_alignment(1.0, 0.5)
|
||||
t.attach(l, 0, 1, 1, 2, xpadding=3)
|
||||
self.e_db_name = gtk.Entry()
|
||||
self.e_db_name.set_width_chars(15)
|
||||
t.attach(self.e_db_name, 1, 3, 1, 2, xpadding=3)
|
||||
self.e_db_name.connect("focus-out-event", self.db_name_changed, None)
|
||||
|
||||
l = gtk.Label( _("DB Description") )
|
||||
l.set_alignment(1.0, 0.5)
|
||||
t.attach(l, 0, 1, 2, 3, xpadding=3)
|
||||
self.e_db_desc = gtk.Entry()
|
||||
self.e_db_desc.set_width_chars(15)
|
||||
t.attach(self.e_db_desc, 1, 3, 2, 3, xpadding=3)
|
||||
|
||||
self.l_username = gtk.Label( _("Username") )
|
||||
self.l_username.set_alignment(1.0, 0.5)
|
||||
t.attach(self.l_username, 0, 1, 3, 4, xpadding=3)
|
||||
self.e_username = gtk.Entry()
|
||||
self.e_username.set_width_chars(15)
|
||||
t.attach(self.e_username, 1, 3, 3, 4, xpadding=3)
|
||||
|
||||
self.l_password = gtk.Label( _("Password") )
|
||||
self.l_password.set_alignment(1.0, 0.5)
|
||||
t.attach(self.l_password, 0, 1, 4, 5, xpadding=3)
|
||||
self.e_password = gtk.Entry()
|
||||
self.e_password.set_width_chars(15)
|
||||
t.attach(self.e_password, 1, 3, 4, 5, xpadding=3)
|
||||
|
||||
self.l_host = gtk.Label( _("Host Computer") )
|
||||
self.l_host.set_alignment(1.0, 0.5)
|
||||
t.attach(self.l_host, 0, 1, 5, 6, xpadding=3)
|
||||
self.e_host = gtk.Entry()
|
||||
self.e_host.set_width_chars(15)
|
||||
self.e_host.set_text("localhost")
|
||||
t.attach(self.e_host, 1, 3, 5, 6, xpadding=3)
|
||||
|
||||
parent.show_all()
|
||||
self.show_all()
|
||||
|
||||
# hide username/password fields as not used by sqlite
|
||||
self.l_username.hide()
|
||||
self.e_username.hide()
|
||||
self.l_password.hide()
|
||||
self.e_password.hide()
|
||||
|
||||
def run(self):
|
||||
response = super(AddDB,self).run()
|
||||
log.debug(_("addDB.run: response is %s accept is %s" % (str(response), str(int(gtk.RESPONSE_ACCEPT)))))
|
||||
|
||||
ok,retry = False,True
|
||||
while response == gtk.RESPONSE_ACCEPT:
|
||||
ok,retry = self.check_fields()
|
||||
if retry:
|
||||
response = super(AddDB,self).run()
|
||||
else:
|
||||
response = gtk.RESPONSE_REJECT
|
||||
|
||||
(status, err_msg, icon, dbms, dbms_num
|
||||
,name, db_desc, user, passwd, host) = ("error", "error", None, None, None
|
||||
,None, None, None, None, None)
|
||||
if ok:
|
||||
log.debug(_("start creating new db"))
|
||||
# add a new db
|
||||
master_password = None
|
||||
dbms = self.dbnames[ self.cb_dbms.get_active_text() ]
|
||||
dbms_num = self.config.get_backend(dbms)
|
||||
name = self.e_db_name.get_text()
|
||||
db_desc = self.e_db_desc.get_text()
|
||||
user = self.e_username.get_text()
|
||||
passwd = self.e_password.get_text()
|
||||
host = self.e_host.get_text()
|
||||
|
||||
# TODO:
|
||||
# if self.cb_dbms.get_active_text() == 'Postgres':
|
||||
# <ask for postgres master password>
|
||||
|
||||
# create_db() in Database.py or here? ... TODO
|
||||
|
||||
# test db after creating?
|
||||
status, err_msg, icon = GuiDatabase.testDB(self.config, dbms, dbms_num, name, user, passwd, host)
|
||||
log.debug(_('tested new db, result=%s') % str((status,err_msg)))
|
||||
if status == 'ok':
|
||||
#dia = InfoBox( parent=self, str1=_('Database created') )
|
||||
str1 = _('Database created')
|
||||
else:
|
||||
#dia = InfoBox( parent=self, str1=_('Database creation failed') )
|
||||
str1 = _('Database creation failed')
|
||||
#dia.add_msg("", True, True)
|
||||
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
|
||||
dia = gtk.MessageDialog( parent=self, flags=gtk.DIALOG_DESTROY_WITH_PARENT
|
||||
, type=gtk.MESSAGE_INFO, buttons=(btns), message_format=str1 )
|
||||
dia.run()
|
||||
|
||||
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)
|
||||
return( (status, err_msg, icon, dbms, dbms_num, name, db_desc, user, passwd, host) )
|
||||
|
||||
def check_fields(self):
|
||||
"""check fields and return true/false according to whether user wants to try again
|
||||
return False if fields are ok
|
||||
"""
|
||||
log.debug(_("check_fields: starting"))
|
||||
try_again = False
|
||||
ok = True
|
||||
|
||||
# checks for all db's
|
||||
if self.e_db_name.get_text() == "":
|
||||
msg = _("No Database Name given")
|
||||
ok = False
|
||||
elif self.e_db_desc.get_text() is None or self.e_db_desc.get_text() == "":
|
||||
msg = _("No Database Description given")
|
||||
ok = False
|
||||
elif self.cb_dbms.get_active_text() != 'Sqlite' and self.e_username.get_text() == "":
|
||||
msg = _("No Username given")
|
||||
ok = False
|
||||
elif self.cb_dbms.get_active_text() != 'Sqlite' and self.e_password.get_text() == "":
|
||||
msg = _("No Password given")
|
||||
ok = False
|
||||
elif self.e_host.get_text() == "":
|
||||
msg = _("No Host given")
|
||||
ok = False
|
||||
|
||||
if ok:
|
||||
if self.cb_dbms.get_active_text() == 'Sqlite':
|
||||
# checks for sqlite
|
||||
pass
|
||||
elif self.cb_dbms.get_active_text() == 'MySQL':
|
||||
# checks for mysql
|
||||
pass
|
||||
elif self.cb_dbms.get_active_text() == 'Postgres':
|
||||
# checks for postgres
|
||||
pass
|
||||
else:
|
||||
msg = _("Unknown Database Type selected")
|
||||
ok = False
|
||||
|
||||
if not ok:
|
||||
log.debug(_("check_fields: open dialog"))
|
||||
dia = gtk.MessageDialog( parent=self
|
||||
, flags=gtk.DIALOG_DESTROY_WITH_PARENT
|
||||
, type=gtk.MESSAGE_ERROR
|
||||
, message_format=msg
|
||||
, buttons = gtk.BUTTONS_YES_NO
|
||||
)
|
||||
#l = gtk.Label(msg)
|
||||
#dia.vbox.add(l)
|
||||
l = gtk.Label( _("Do you want to try again?") )
|
||||
dia.vbox.add(l)
|
||||
dia.show_all()
|
||||
ret = dia.run()
|
||||
log.debug(_("check_fields: ret is %s cancel is %s" % (str(ret), str(int(gtk.RESPONSE_CANCEL)))))
|
||||
if ret == gtk.RESPONSE_YES:
|
||||
try_again = True
|
||||
log.debug(_("check_fields: destroy dialog"))
|
||||
dia.hide()
|
||||
dia.destroy()
|
||||
|
||||
log.debug(_("check_fields: returning ok as %s, try_again as %s") % (str(ok), str(try_again)))
|
||||
return(ok,try_again)
|
||||
|
||||
def db_type_changed(self, widget, data):
|
||||
if self.cb_dbms.get_active_text() == 'Sqlite':
|
||||
self.l_username.hide()
|
||||
self.e_username.hide()
|
||||
self.e_username.set_text("")
|
||||
self.l_password.hide()
|
||||
self.e_password.hide()
|
||||
self.e_password.set_text("")
|
||||
else:
|
||||
# add extra label
|
||||
vbox = dia.vbox
|
||||
vbox.pack_start( gtk.Label(str1) )
|
||||
dia.show_all()
|
||||
self.l_username.show()
|
||||
self.e_username.show()
|
||||
self.l_password.show()
|
||||
self.e_password.show()
|
||||
return(response)
|
||||
|
||||
def db_name_changed(self, widget, event, data):
|
||||
log.debug('db_name_changed: text='+widget.get_text())
|
||||
if not re.match('\....$', widget.get_text()):
|
||||
widget.set_text(widget.get_text()+'.db3')
|
||||
widget.show()
|
||||
|
||||
#def response_cb(self, dialog, data):
|
||||
# dialog.destroy()
|
||||
# return(data)
|
||||
|
||||
|
||||
class InfoBox(gtk.Dialog):
|
||||
|
||||
def __init__(self, parent, str1):
|
||||
# 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 )
|
||||
# so just use Dialog instead
|
||||
super(InfoBox,self).__init__( parent=parent
|
||||
, flags=gtk.DIALOG_DESTROY_WITH_PARENT
|
||||
, title="" ) # , buttons=btns
|
||||
|
||||
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)
|
||||
self.vbox.pack_start(h)
|
||||
parent.show_all()
|
||||
self.show_all()
|
||||
|
||||
def add_msg(self, str1, run, destroy):
|
||||
# add extra label
|
||||
self.vbox.pack_start( gtk.Label(str1) )
|
||||
self.show_all()
|
||||
response = None
|
||||
if run: response = dia.run()
|
||||
if destroy: dia.destroy()
|
||||
return (dia, response)
|
||||
if run: response = self.run()
|
||||
if destroy: self.destroy()
|
||||
return (response)
|
||||
|
||||
|
||||
class SideButton(gtk.Button):
|
||||
"""Create a button with the label below the icon"""
|
||||
|
||||
# to change label on buttons:
|
||||
# ( see http://faq.pygtk.org/index.py?req=show&file=faq09.005.htp )
|
||||
# gtk.stock_add([(gtk.STOCK_ADD, _("Add"), 0, 0, "")])
|
||||
|
||||
# alternatively:
|
||||
# button = gtk.Button(stock=gtk.STOCK_CANCEL)
|
||||
# button.show()
|
||||
# alignment = button.get_children()[0]
|
||||
# hbox = alignment.get_children()[0]
|
||||
# image, label = hbox.get_children()
|
||||
# label.set_text('Hide')
|
||||
|
||||
def __init__(self, label=None, stock=None, use_underline=True):
|
||||
gtk.stock_add([(stock, label, 0, 0, "")])
|
||||
|
||||
super(SideButton, self).__init__(label=label, stock=stock, use_underline=True)
|
||||
alignment = self.get_children()[0]
|
||||
hbox = alignment.get_children()[0]
|
||||
image, label = hbox.get_children()
|
||||
#label.set_text('Hide')
|
||||
hbox.remove(image)
|
||||
hbox.remove(label)
|
||||
v = gtk.VBox(False, spacing=3)
|
||||
v.pack_start(image, 3)
|
||||
v.pack_start(label, 3)
|
||||
alignment.remove(hbox)
|
||||
alignment.add(v)
|
||||
self.show_all()
|
||||
|
||||
|
||||
|
||||
if __name__=="__main__":
|
||||
|
|
@ -412,12 +688,12 @@ if __name__=="__main__":
|
|||
config = Configuration.Config()
|
||||
|
||||
win = gtk.Window(gtk.WINDOW_TOPLEVEL)
|
||||
win.set_title("Test Log Viewer")
|
||||
win.set_title(_("Test Log Viewer"))
|
||||
win.set_border_width(1)
|
||||
win.set_default_size(600, 500)
|
||||
win.set_resizable(True)
|
||||
|
||||
dia = gtk.Dialog("Log Viewer",
|
||||
dia = gtk.Dialog(_("Log Viewer"),
|
||||
win,
|
||||
gtk.DIALOG_MODAL | gtk.DIALOG_DESTROY_WITH_PARENT,
|
||||
(gtk.STOCK_CLOSE, gtk.RESPONSE_OK))
|
||||
|
|
|
|||
|
|
@ -15,6 +15,9 @@
|
|||
#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 L10n
|
||||
_ = L10n.get_translation()
|
||||
|
||||
import threading
|
||||
import pygtk
|
||||
pygtk.require('2.0')
|
||||
|
|
@ -26,9 +29,16 @@ from time import *
|
|||
from datetime import datetime
|
||||
#import pokereval
|
||||
|
||||
import fpdb_import
|
||||
import Database
|
||||
import Filters
|
||||
import Charset
|
||||
|
||||
try:
|
||||
calluse = not 'matplotlib' in sys.modules
|
||||
import matplotlib
|
||||
matplotlib.use('GTKCairo')
|
||||
if calluse:
|
||||
matplotlib.use('GTKCairo')
|
||||
from matplotlib.figure import Figure
|
||||
from matplotlib.backends.backend_gtk import FigureCanvasGTK as FigureCanvas
|
||||
from matplotlib.backends.backend_gtkagg import NavigationToolbar2GTKAgg as NavigationToolbar
|
||||
|
|
@ -36,17 +46,12 @@ try:
|
|||
from numpy import arange, cumsum
|
||||
from pylab import *
|
||||
except ImportError, inst:
|
||||
print """Failed to load libs for graphing, graphing will not function. Please in
|
||||
stall numpy and matplotlib if you want to use graphs."""
|
||||
print """This is of no consequence for other parts of the program, e.g. import
|
||||
and HUD are NOT affected by this problem."""
|
||||
print _("""Failed to load libs for graphing, graphing will not function. Please
|
||||
install numpy and matplotlib if you want to use graphs.""")
|
||||
print _("""This is of no consequence for other parts of the program, e.g. import
|
||||
and HUD are NOT affected by this problem.""")
|
||||
print "ImportError: %s" % inst.args
|
||||
|
||||
import fpdb_import
|
||||
import Database
|
||||
import Filters
|
||||
import Charset
|
||||
|
||||
class GuiGraphViewer (threading.Thread):
|
||||
|
||||
def __init__(self, querylist, config, parent, debug=True):
|
||||
|
|
@ -70,15 +75,16 @@ class GuiGraphViewer (threading.Thread):
|
|||
"Seats" : False,
|
||||
"SeatSep" : False,
|
||||
"Dates" : True,
|
||||
"GraphOps" : True,
|
||||
"Groups" : False,
|
||||
"Button1" : True,
|
||||
"Button2" : True
|
||||
}
|
||||
|
||||
self.filters = Filters.Filters(self.db, self.conf, self.sql, display = filters_display)
|
||||
self.filters.registerButton1Name("Refresh _Graph")
|
||||
self.filters.registerButton1Name(_("Refresh _Graph"))
|
||||
self.filters.registerButton1Callback(self.generateGraph)
|
||||
self.filters.registerButton2Name("_Export to File")
|
||||
self.filters.registerButton2Name(_("_Export to File"))
|
||||
self.filters.registerButton2Callback(self.exportGraph)
|
||||
|
||||
self.mainHBox = gtk.HBox(False, 0)
|
||||
|
|
@ -126,7 +132,7 @@ class GuiGraphViewer (threading.Thread):
|
|||
self.canvas = FigureCanvas(self.fig) # a gtk.DrawingArea
|
||||
except:
|
||||
err = traceback.extract_tb(sys.exc_info()[2])[-1]
|
||||
print "***Error: "+err[2]+"("+str(err[1])+"): "+str(sys.exc_info()[1])
|
||||
print _("***Error: ")+err[2]+"("+str(err[1])+"): "+str(sys.exc_info()[1])
|
||||
raise
|
||||
|
||||
def generateGraph(self, widget, data):
|
||||
|
|
@ -141,6 +147,8 @@ class GuiGraphViewer (threading.Thread):
|
|||
siteids = self.filters.getSiteIds()
|
||||
limits = self.filters.getLimits()
|
||||
games = self.filters.getGames()
|
||||
graphops = self.filters.getGraphOps()
|
||||
names = ""
|
||||
|
||||
for i in ('show', 'none'):
|
||||
if i in limits:
|
||||
|
|
@ -153,20 +161,21 @@ class GuiGraphViewer (threading.Thread):
|
|||
result = self.db.get_player_id(self.conf, site, _hname)
|
||||
if result is not None:
|
||||
playerids.append(int(result))
|
||||
names = names + "\n"+_hname + " on "+site
|
||||
|
||||
if not sitenos:
|
||||
#Should probably pop up here.
|
||||
print "No sites selected - defaulting to PokerStars"
|
||||
print _("No sites selected - defaulting to PokerStars")
|
||||
self.db.rollback()
|
||||
return
|
||||
|
||||
if not playerids:
|
||||
print "No player ids found"
|
||||
print _("No player ids found")
|
||||
self.db.rollback()
|
||||
return
|
||||
|
||||
if not limits:
|
||||
print "No limits found"
|
||||
print _("No limits found")
|
||||
self.db.rollback()
|
||||
return
|
||||
|
||||
|
|
@ -175,16 +184,18 @@ class GuiGraphViewer (threading.Thread):
|
|||
|
||||
#Get graph data from DB
|
||||
starttime = time()
|
||||
(green, blue, red) = self.getRingProfitGraph(playerids, sitenos, limits, games)
|
||||
print "Graph generated in: %s" %(time() - starttime)
|
||||
(green, blue, red) = self.getRingProfitGraph(playerids, sitenos, limits, games, graphops['dspin'])
|
||||
print _("Graph generated in: %s") %(time() - starttime)
|
||||
|
||||
|
||||
|
||||
#Set axis labels and grid overlay properites
|
||||
self.ax.set_xlabel("Hands", fontsize = 12)
|
||||
self.ax.set_ylabel("$", fontsize = 12)
|
||||
self.ax.set_xlabel(_("Hands"), fontsize = 12)
|
||||
# SET LABEL FOR X AXIS
|
||||
self.ax.set_ylabel(graphops['dspin'], fontsize = 12)
|
||||
self.ax.grid(color='g', linestyle=':', linewidth=0.2)
|
||||
if green == None or green == []:
|
||||
self.ax.set_title("No Data for Player(s) Found")
|
||||
self.ax.set_title(_("No Data for Player(s) Found"))
|
||||
green = ([ 0., 0., 0., 0., 500., 1000., 900., 800.,
|
||||
700., 600., 500., 400., 300., 200., 100., 0.,
|
||||
500., 1000., 1000., 1000., 1000., 1000., 1000., 1000.,
|
||||
|
|
@ -207,9 +218,9 @@ class GuiGraphViewer (threading.Thread):
|
|||
0., 500., 1000., 900., 800., 700., 600., 500.,
|
||||
400., 300., 200., 100., 0., 500., 1000., 1000.])
|
||||
|
||||
self.ax.plot(green, color='green', label='Hands: %d\nProfit: $%.2f' %(len(green), green[-1]))
|
||||
self.ax.plot(blue, color='blue', label='Showdown: $%.2f' %(blue[-1]))
|
||||
self.ax.plot(red, color='red', label='Non-showdown: $%.2f' %(red[-1]))
|
||||
self.ax.plot(green, color='green', label=_('Hands: %d\nProfit: $%.2f') %(len(green), green[-1]))
|
||||
self.ax.plot(blue, color='blue', label=_('Showdown: $%.2f') %(blue[-1]))
|
||||
self.ax.plot(red, color='red', label=_('Non-showdown: $%.2f') %(red[-1]))
|
||||
self.graphBox.add(self.canvas)
|
||||
self.canvas.show()
|
||||
self.canvas.draw()
|
||||
|
|
@ -217,18 +228,15 @@ class GuiGraphViewer (threading.Thread):
|
|||
#TODO: Do something useful like alert user
|
||||
#print "No hands returned by graph query"
|
||||
else:
|
||||
self.ax.set_title("Profit graph for ring games")
|
||||
#text = "Profit: $%.2f\nTotal Hands: %d" %(green[-1], len(green))
|
||||
#self.ax.annotate(text,
|
||||
# xy=(10, -10),
|
||||
# xycoords='axes points',
|
||||
# horizontalalignment='left', verticalalignment='top',
|
||||
# fontsize=10)
|
||||
self.ax.set_title(_("Profit graph for ring games"+names),fontsize=12)
|
||||
|
||||
#Draw plot
|
||||
self.ax.plot(green, color='green', label='Hands: %d\nProfit: $%.2f' %(len(green), green[-1]))
|
||||
self.ax.plot(blue, color='blue', label='Showdown: $%.2f' %(blue[-1]))
|
||||
self.ax.plot(red, color='red', label='Non-showdown: $%.2f' %(red[-1]))
|
||||
self.ax.plot(green, color='green', label=_('Hands: %d\nProfit (%s): %.2f') %(len(green),graphops['dspin'], green[-1]))
|
||||
if graphops['showdown'] == 'ON':
|
||||
self.ax.plot(blue, color='blue', label=_('Showdown (%s): %.2f') %(graphops['dspin'], blue[-1]))
|
||||
if graphops['nonshowdown'] == 'ON':
|
||||
self.ax.plot(red, color='red', label=_('Non-showdown (%s): %.2f') %(graphops['dspin'], red[-1]))
|
||||
|
||||
if sys.version[0:3] == '2.5':
|
||||
self.ax.legend(loc='upper left', shadow=True, prop=FontProperties(size='smaller'))
|
||||
else:
|
||||
|
|
@ -240,13 +248,21 @@ class GuiGraphViewer (threading.Thread):
|
|||
#self.exportButton.set_sensitive(True)
|
||||
except:
|
||||
err = traceback.extract_tb(sys.exc_info()[2])[-1]
|
||||
print "***Error: "+err[2]+"("+str(err[1])+"): "+str(sys.exc_info()[1])
|
||||
print _("***Error: ")+err[2]+"("+str(err[1])+"): "+str(sys.exc_info()[1])
|
||||
|
||||
#end of def showClicked
|
||||
|
||||
def getRingProfitGraph(self, names, sites, limits, games):
|
||||
tmp = self.sql.query['getRingProfitAllHandsPlayerIdSite']
|
||||
|
||||
def getRingProfitGraph(self, names, sites, limits, games, units):
|
||||
# tmp = self.sql.query['getRingProfitAllHandsPlayerIdSite']
|
||||
# print "DEBUG: getRingProfitGraph"
|
||||
|
||||
if units == '$':
|
||||
tmp = self.sql.query['getRingProfitAllHandsPlayerIdSiteInDollars']
|
||||
elif units == 'BB':
|
||||
tmp = self.sql.query['getRingProfitAllHandsPlayerIdSiteInBB']
|
||||
|
||||
|
||||
start_date, end_date = self.filters.getDates()
|
||||
|
||||
#Buggered if I can find a way to do this 'nicely' take a list of integers and longs
|
||||
|
|
@ -337,7 +353,7 @@ class GuiGraphViewer (threading.Thread):
|
|||
if self.fig is None:
|
||||
return # Might want to disable export button until something has been generated.
|
||||
|
||||
dia_chooser = gtk.FileChooserDialog(title="Please choose the directory you wish to export to:",
|
||||
dia_chooser = gtk.FileChooserDialog(title=_("Please choose the directory you wish to export to:"),
|
||||
action=gtk.FILE_CHOOSER_ACTION_SELECT_FOLDER,
|
||||
buttons=(gtk.STOCK_CANCEL,gtk.RESPONSE_CANCEL,gtk.STOCK_OK,gtk.RESPONSE_OK))
|
||||
dia_chooser.set_destroy_with_parent(True)
|
||||
|
|
@ -350,7 +366,7 @@ class GuiGraphViewer (threading.Thread):
|
|||
response = dia_chooser.run()
|
||||
|
||||
if response <> gtk.RESPONSE_OK:
|
||||
print 'Closed, no graph exported'
|
||||
print _('Closed, no graph exported')
|
||||
dia_chooser.destroy()
|
||||
return
|
||||
|
||||
|
|
@ -368,7 +384,7 @@ class GuiGraphViewer (threading.Thread):
|
|||
flags=gtk.DIALOG_DESTROY_WITH_PARENT,
|
||||
type=gtk.MESSAGE_INFO,
|
||||
buttons=gtk.BUTTONS_OK,
|
||||
message_format="Graph created")
|
||||
message_format=_("Graph created"))
|
||||
diainfo.format_secondary_text(self.exportFile)
|
||||
diainfo.run()
|
||||
diainfo.destroy()
|
||||
|
|
|
|||
157
pyfpdb/GuiImapFetcher.py
Normal file
157
pyfpdb/GuiImapFetcher.py
Normal file
|
|
@ -0,0 +1,157 @@
|
|||
#!/usr/bin/python
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
#Copyright 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 L10n
|
||||
_ = L10n.get_translation()
|
||||
|
||||
import threading
|
||||
import pygtk
|
||||
pygtk.require('2.0')
|
||||
import gtk
|
||||
from imaplib import IMAP4
|
||||
from socket import gaierror
|
||||
|
||||
import ImapFetcher
|
||||
|
||||
class GuiImapFetcher (threading.Thread):
|
||||
def __init__(self, config, db, sql, mainwin, debug=True):
|
||||
self.config = config
|
||||
self.db = db
|
||||
self.mainVBox = gtk.VBox()
|
||||
|
||||
|
||||
self.buttonsHBox = gtk.HBox()
|
||||
self.mainVBox.pack_end(self.buttonsHBox, expand=False)
|
||||
|
||||
label=gtk.Label(_("To cancel just close this tab."))
|
||||
self.buttonsHBox.add(label)
|
||||
|
||||
self.saveButton = gtk.Button(_("_Save"))
|
||||
self.saveButton.connect('clicked', self.saveClicked)
|
||||
self.buttonsHBox.add(self.saveButton)
|
||||
|
||||
self.importAllButton = gtk.Button(_("_Import All"))
|
||||
self.importAllButton.connect('clicked', self.importAllClicked)
|
||||
self.buttonsHBox.add(self.importAllButton)
|
||||
|
||||
self.statusLabel=gtk.Label(_("If you change the config you must save before importing"))
|
||||
self.mainVBox.pack_end(self.statusLabel, expand=False, padding=4)
|
||||
|
||||
self.passwords={}
|
||||
self.displayConfig()
|
||||
|
||||
self.mainVBox.show_all()
|
||||
#end def __init__
|
||||
|
||||
def saveClicked(self, widget, data=None):
|
||||
row = self.rowVBox.get_children()
|
||||
columns=row[0].get_children() #TODO: make save capable of handling multiple email entries - not relevant yet as only one entry is useful atm. The rest of this tab works fine for multiple entries though
|
||||
|
||||
siteName=columns[0].get_text()
|
||||
fetchType=columns[1].get_text()
|
||||
|
||||
toSave=self.config.supported_sites[siteName].emails[fetchType]
|
||||
|
||||
toSave.host=columns[2].get_text()
|
||||
toSave.username=columns[3].get_text()
|
||||
|
||||
if columns[4].get_text()=="***":
|
||||
toSave.password=self.passwords[siteName+fetchType]
|
||||
else:
|
||||
toSave.password=columns[4].get_text()
|
||||
|
||||
toSave.folder=columns[5].get_text()
|
||||
|
||||
if columns[6].get_active() == 0:
|
||||
toSave.useSsl="True"
|
||||
else:
|
||||
toSave.useSsl="False"
|
||||
|
||||
self.config.editEmail(siteName, fetchType, toSave)
|
||||
self.config.save()
|
||||
#def saveClicked
|
||||
|
||||
def importAllClicked(self, widget, data=None):
|
||||
self.statusLabel.set_label(_("Starting import. Please wait.")) #FIXME: why doesnt this one show?
|
||||
for siteName in self.config.supported_sites:
|
||||
for fetchType in self.config.supported_sites[siteName].emails:
|
||||
try:
|
||||
result=ImapFetcher.run(self.config.supported_sites[siteName].emails[fetchType], self.db)
|
||||
self.statusLabel.set_label(_("Finished import without error."))
|
||||
except IMAP4.error as error:
|
||||
if str(error)=="[AUTHENTICATIONFAILED] Authentication failed.":
|
||||
self.statusLabel.set_label(_("Login to mailserver failed: please check mailserver, username and password"))
|
||||
except gaierror as error:
|
||||
if str(error)=="[Errno -2] Name or service not known":
|
||||
self.statusLabel.set_label(_("Could not connect to mailserver: check mailserver and use SSL settings and internet connectivity"))
|
||||
#def importAllClicked
|
||||
|
||||
def get_vbox(self):
|
||||
"""returns the vbox of this thread"""
|
||||
return self.mainVBox
|
||||
#end def get_vbox
|
||||
|
||||
def displayConfig(self):
|
||||
box=gtk.HBox(homogeneous=True)
|
||||
for text in (_("Site"), _("Fetch Type"), _("Mailserver"), _("Username"), _("Password"), _("Mail Folder"), _("Use SSL")):
|
||||
label=gtk.Label(text)
|
||||
box.add(label)
|
||||
self.mainVBox.pack_start(box, expand=False)
|
||||
|
||||
self.rowVBox = gtk.VBox()
|
||||
self.mainVBox.add(self.rowVBox)
|
||||
|
||||
for siteName in self.config.supported_sites:
|
||||
for fetchType in self.config.supported_sites[siteName].emails:
|
||||
config=self.config.supported_sites[siteName].emails[fetchType]
|
||||
box=gtk.HBox(homogeneous=True)
|
||||
|
||||
for field in (siteName, config.fetchType):
|
||||
label=gtk.Label(field)
|
||||
box.add(label)
|
||||
|
||||
for field in (config.host, config.username):
|
||||
entry=gtk.Entry()
|
||||
entry.set_text(field)
|
||||
box.add(entry)
|
||||
|
||||
entry=gtk.Entry()
|
||||
self.passwords[siteName+fetchType]=config.password
|
||||
entry.set_text("***")
|
||||
box.add(entry)
|
||||
|
||||
entry=gtk.Entry()
|
||||
entry.set_text(config.folder)
|
||||
box.add(entry)
|
||||
|
||||
sslBox = gtk.combo_box_new_text()
|
||||
sslBox.append_text(_("Yes"))
|
||||
sslBox.append_text(_("No"))
|
||||
if config.useSsl:
|
||||
sslBox.set_active(0)
|
||||
else:
|
||||
sslBox.set_active(1)
|
||||
box.add(sslBox)
|
||||
|
||||
#TODO: "run just this one" button
|
||||
|
||||
self.rowVBox.pack_start(box, expand=False)
|
||||
#print
|
||||
|
||||
self.mainVBox.show_all()
|
||||
#end def displayConfig
|
||||
#end class GuiImapFetcher
|
||||
|
|
@ -15,6 +15,9 @@
|
|||
#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 L10n
|
||||
_ = L10n.get_translation()
|
||||
|
||||
import os
|
||||
import Queue
|
||||
|
||||
|
|
@ -30,7 +33,6 @@ import logging
|
|||
# logging has been set up in fpdb.py or HUD_main.py, use their settings:
|
||||
log = logging.getLogger("logview")
|
||||
|
||||
|
||||
MAX_LINES = 100000 # max lines to display in window
|
||||
EST_CHARS_PER_LINE = 150 # used to guesstimate number of lines in log file
|
||||
LOGFILES = [ [ 'Fpdb Errors', 'fpdb-errors.txt', False ] # label, filename, start value
|
||||
|
|
@ -47,7 +49,7 @@ class GuiLogView:
|
|||
self.closeq = closeq
|
||||
|
||||
self.logfile = os.path.join(self.config.dir_log, LOGFILES[1][1])
|
||||
self.dia = gtk.Dialog(title="Log Messages"
|
||||
self.dia = gtk.Dialog(title=_("Log Messages")
|
||||
,parent=None
|
||||
,flags=gtk.DIALOG_DESTROY_WITH_PARENT
|
||||
,buttons=(gtk.STOCK_CLOSE,gtk.RESPONSE_OK))
|
||||
|
|
@ -82,7 +84,7 @@ class GuiLogView:
|
|||
rb.set_active(logf[2])
|
||||
rb.connect('clicked', self.__set_logfile, logf[0])
|
||||
hb.pack_start(rb, False, False, 3)
|
||||
refreshbutton = gtk.Button("Refresh")
|
||||
refreshbutton = gtk.Button(_("Refresh"))
|
||||
refreshbutton.connect("clicked", self.refresh, None)
|
||||
hb.pack_start(refreshbutton, False, False, 3)
|
||||
refreshbutton.show()
|
||||
|
|
@ -186,7 +188,7 @@ class GuiLogView:
|
|||
# to turn indicator off for other cols
|
||||
except:
|
||||
err = traceback.extract_tb(sys.exc_info()[2])
|
||||
print "***sortCols error: " + str(sys.exc_info()[1])
|
||||
print _("***sortCols error: ") + str(sys.exc_info()[1])
|
||||
print "\n".join( [e[0]+':'+str(e[1])+" "+e[2] for e in err] )
|
||||
|
||||
def refresh(self, widget, data):
|
||||
|
|
@ -199,12 +201,12 @@ if __name__=="__main__":
|
|||
config = Configuration.Config()
|
||||
|
||||
win = gtk.Window(gtk.WINDOW_TOPLEVEL)
|
||||
win.set_title("Test Log Viewer")
|
||||
win.set_title(_("Test Log Viewer"))
|
||||
win.set_border_width(1)
|
||||
win.set_default_size(600, 500)
|
||||
win.set_resizable(True)
|
||||
|
||||
dia = gtk.Dialog("Log Viewer",
|
||||
dia = gtk.Dialog(_("Log Viewer"),
|
||||
win,
|
||||
gtk.DIALOG_MODAL | gtk.DIALOG_DESTROY_WITH_PARENT,
|
||||
(gtk.STOCK_CLOSE, gtk.RESPONSE_OK))
|
||||
|
|
|
|||
|
|
@ -22,6 +22,18 @@ import gtk
|
|||
import os
|
||||
from time import time, strftime
|
||||
|
||||
import locale
|
||||
lang=locale.getdefaultlocale()[0][0:2]
|
||||
if lang=="en":
|
||||
def _(string): return string
|
||||
else:
|
||||
import gettext
|
||||
try:
|
||||
trans = gettext.translation("fpdb", localedir="locale", languages=[lang])
|
||||
trans.install()
|
||||
except IOError:
|
||||
def _(string): return string
|
||||
|
||||
import fpdb_import
|
||||
import Database
|
||||
import Filters
|
||||
|
|
@ -41,7 +53,6 @@ class GuiPositionalStats (threading.Thread):
|
|||
|
||||
settings = {}
|
||||
settings.update(self.conf.get_db_parameters())
|
||||
settings.update(self.conf.get_tv_parameters())
|
||||
settings.update(self.conf.get_import_parameters())
|
||||
settings.update(self.conf.get_default_paths())
|
||||
|
||||
|
|
@ -132,7 +143,7 @@ class GuiPositionalStats (threading.Thread):
|
|||
def toggleCallback(self, widget, data=None):
|
||||
# print "%s was toggled %s" % (data, ("OFF", "ON")[widget.get_active()])
|
||||
self.activesite = data
|
||||
print "DEBUG: activesite set to %s" %(self.activesite)
|
||||
print _("DEBUG: activesite set to %s") %(self.activesite)
|
||||
|
||||
def refreshStats(self, widget, data):
|
||||
try: self.stats_vbox.destroy()
|
||||
|
|
@ -163,13 +174,13 @@ class GuiPositionalStats (threading.Thread):
|
|||
|
||||
if not sitenos:
|
||||
#Should probably pop up here.
|
||||
print "No sites selected - defaulting to PokerStars"
|
||||
print _("No sites selected - defaulting to PokerStars")
|
||||
sitenos = [2]
|
||||
if not playerids:
|
||||
print "No player ids found"
|
||||
print _("No player ids found")
|
||||
return
|
||||
if not limits:
|
||||
print "No limits found"
|
||||
print _("No limits found")
|
||||
return
|
||||
|
||||
self.createStatsTable(vbox, playerids, sitenos, limits, seats, dates)
|
||||
|
|
@ -318,7 +329,7 @@ class GuiPositionalStats (threading.Thread):
|
|||
vbox.show_all()
|
||||
|
||||
self.db.rollback()
|
||||
print "Positional Stats page displayed in %4.2f seconds" % (time() - starttime)
|
||||
print _("Positional Stats page displayed in %4.2f seconds") % (time() - starttime)
|
||||
#end def fillStatsFrame(self, vbox):
|
||||
|
||||
def refineQuery(self, query, playerids, sitenos, limits, seats, dates):
|
||||
|
|
|
|||
|
|
@ -23,8 +23,19 @@ pygtk.require('2.0')
|
|||
import gtk
|
||||
import gobject
|
||||
|
||||
import Configuration
|
||||
import locale
|
||||
lang=locale.getdefaultlocale()[0][0:2]
|
||||
if lang=="en":
|
||||
def _(string): return string
|
||||
else:
|
||||
import gettext
|
||||
try:
|
||||
trans = gettext.translation("fpdb", localedir="locale", languages=[lang])
|
||||
trans.install()
|
||||
except IOError:
|
||||
def _(string): return string
|
||||
|
||||
import Configuration
|
||||
|
||||
rewrite = { 'general' : 'General', 'supported_databases' : 'Databases'
|
||||
, 'import' : 'Import', 'hud_ui' : 'HUD'
|
||||
|
|
@ -67,13 +78,13 @@ class GuiPrefs:
|
|||
self.configView = gtk.TreeView(self.configStore)
|
||||
self.configView.set_enable_tree_lines(True)
|
||||
|
||||
configColumn = gtk.TreeViewColumn("Setting")
|
||||
configColumn = gtk.TreeViewColumn(_("Setting"))
|
||||
self.configView.append_column(configColumn)
|
||||
cRender = gtk.CellRendererText()
|
||||
configColumn.pack_start(cRender, True)
|
||||
configColumn.add_attribute(cRender, 'text', 1)
|
||||
|
||||
configColumn = gtk.TreeViewColumn("Value (double-click to change)")
|
||||
configColumn = gtk.TreeViewColumn(_("Value (double-click to change)"))
|
||||
self.configView.append_column(configColumn)
|
||||
cRender = gtk.CellRendererText()
|
||||
configColumn.pack_start(cRender, True)
|
||||
|
|
@ -168,19 +179,17 @@ class GuiPrefs:
|
|||
if dia is not None:
|
||||
dia.response(gtk.RESPONSE_ACCEPT)
|
||||
|
||||
|
||||
|
||||
if __name__=="__main__":
|
||||
|
||||
config = Configuration.Config()
|
||||
|
||||
win = gtk.Window(gtk.WINDOW_TOPLEVEL)
|
||||
win.set_title("Test Preferences Dialog")
|
||||
win.set_title(_("Test Preferences Dialog"))
|
||||
win.set_border_width(1)
|
||||
win.set_default_size(600, 500)
|
||||
win.set_resizable(True)
|
||||
|
||||
dia = gtk.Dialog("Preferences",
|
||||
dia = gtk.Dialog(_("Preferences"),
|
||||
win,
|
||||
gtk.DIALOG_MODAL | gtk.DIALOG_DESTROY_WITH_PARENT,
|
||||
(gtk.STOCK_CANCEL, gtk.RESPONSE_REJECT,
|
||||
|
|
@ -193,7 +202,3 @@ if __name__=="__main__":
|
|||
# save updated config
|
||||
config.save()
|
||||
dia.destroy()
|
||||
|
||||
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -15,6 +15,9 @@
|
|||
#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 L10n
|
||||
_ = L10n.get_translation()
|
||||
|
||||
import traceback
|
||||
import threading
|
||||
import pygtk
|
||||
|
|
@ -31,10 +34,72 @@ import Filters
|
|||
import Charset
|
||||
import GuiPlayerStats
|
||||
|
||||
from TreeViewTooltips import TreeViewTooltips
|
||||
|
||||
|
||||
#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}
|
||||
onlinehelp = {'Game':_('Type of Game'),
|
||||
'Hand':_('Hole cards'),
|
||||
'Posn':_('Position'),
|
||||
'Name':_('Name of the player'),
|
||||
'Hds':_('Number of hands played'),
|
||||
'Seats':_('Number of Seats'),
|
||||
'VPIP':_('Voluntarily Putting In the pot\n(blinds excluded)'),
|
||||
'PFR':_('% Pre Flop Raise'),
|
||||
'PF3':_('% Pre Flop Re-Raise / 3Bet'),
|
||||
'AggFac':_('Aggression Factor\n'),
|
||||
'AggFreq':_('Aggression Frequency\nBet or Raise vs Fold'),
|
||||
'ContBet':_('Continuation Bet on the flop'),
|
||||
'RFI':_('% Raise First In\% Raise when first to bet'),
|
||||
'Steals':_('% First to raise pre-flop\nand steal blinds'),
|
||||
'Saw_F':_('% Saw Flop vs hands dealt'),
|
||||
'SawSD':_('Saw Show Down / River'),
|
||||
'WtSDwsF':_('Went To Show Down When Saw Flop'),
|
||||
'W$SD':_('Amount Won when Show Down seen'),
|
||||
'FlAFq':_('Flop Aggression\n% Bet or Raise after seeing Flop'),
|
||||
'TuAFq':_('Turn Aggression\n% Bet or Raise after seeing Turn'),
|
||||
'RvAFq':_('River Aggression\n% Bet or Raise after seeing River'),
|
||||
'PoFAFq':_('Coming Soon\nTotal % agression'),
|
||||
'Net($)':_('Amount won'),
|
||||
'bb/100':_('Number of Big Blinds won\nor lost per 100 hands'),
|
||||
'Rake($)':_('Amount of rake paid'),
|
||||
'bbxr/100':_('Number of Big Blinds won\nor lost per 100 hands\nwhen excluding rake'),
|
||||
'Variance':_('Measure of uncertainty\nThe lower, the more stable the amounts won')
|
||||
}
|
||||
|
||||
|
||||
|
||||
class DemoTips(TreeViewTooltips):
|
||||
|
||||
def __init__(self, customer_column):
|
||||
# customer_column is an instance of gtk.TreeViewColumn and
|
||||
# is being used in the gtk.TreeView to show customer names.
|
||||
# self.cust_col = customer_column
|
||||
|
||||
# call base class init
|
||||
TreeViewTooltips.__init__(self)
|
||||
|
||||
def get_tooltip(self, view, column, path):
|
||||
model = view.get_model()
|
||||
cards = model[path][0]
|
||||
title=column.get_title()
|
||||
if (title == 'Hand' or title == 'Game'): display='' #no tooltips on headers
|
||||
else: display='<big>%s for %s</big>\n<i>%s</i>' % (title,cards,onlinehelp[title])
|
||||
return (display)
|
||||
|
||||
def location(self, x, y, w, h):
|
||||
# rename me to "location" so I override the base class
|
||||
# method. This will demonstrate being able to change
|
||||
# where the tooltip window popups, relative to the
|
||||
# pointer.
|
||||
|
||||
# this will place the tooltip above and to the right
|
||||
return x + 30, y - (h + 10)
|
||||
|
||||
|
||||
|
||||
class GuiRingPlayerStats (GuiPlayerStats.GuiPlayerStats):
|
||||
|
||||
|
|
@ -57,7 +122,6 @@ class GuiRingPlayerStats (GuiPlayerStats.GuiPlayerStats):
|
|||
|
||||
settings = {}
|
||||
settings.update(self.conf.get_db_parameters())
|
||||
settings.update(self.conf.get_tv_parameters())
|
||||
settings.update(self.conf.get_import_parameters())
|
||||
settings.update(self.conf.get_default_paths())
|
||||
|
||||
|
|
@ -92,34 +156,6 @@ class GuiRingPlayerStats (GuiPlayerStats.GuiPlayerStats):
|
|||
# columns to display, keys match column name returned by sql, values in tuple are:
|
||||
# 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
|
||||
|
|
@ -237,13 +273,13 @@ class GuiRingPlayerStats (GuiPlayerStats.GuiPlayerStats):
|
|||
|
||||
if not sitenos:
|
||||
#Should probably pop up here.
|
||||
print "No sites selected - defaulting to PokerStars"
|
||||
print _("No sites selected - defaulting to PokerStars")
|
||||
sitenos = [2]
|
||||
if not playerids:
|
||||
print "No player ids found"
|
||||
print _("No player ids found")
|
||||
return
|
||||
if not limits:
|
||||
print "No limits found"
|
||||
print _("No limits found")
|
||||
return
|
||||
|
||||
self.createStatsTable(vbox, playerids, sitenos, limits, type, seats, groups, dates, games)
|
||||
|
|
@ -308,7 +344,7 @@ class GuiRingPlayerStats (GuiPlayerStats.GuiPlayerStats):
|
|||
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)
|
||||
print (_("Stats page displayed in %4.2f seconds") % (time() - startTime))
|
||||
#end def createStatsTable
|
||||
|
||||
def reset_style_render_func(self, treeviewcolumn, cell, model, iter):
|
||||
|
|
@ -355,7 +391,7 @@ class GuiRingPlayerStats (GuiPlayerStats.GuiPlayerStats):
|
|||
#print "n =", n, "iter1[n] =", self.liststore[grid].get_value(iter1,n), "iter2[n] =", self.liststore[grid].get_value(iter2,n), "ret =", ret
|
||||
except:
|
||||
err = traceback.extract_tb(sys.exc_info()[2])
|
||||
print "***sortnums error: " + str(sys.exc_info()[1])
|
||||
print _("***sortnums error: ") + str(sys.exc_info()[1])
|
||||
print "\n".join( [e[0]+':'+str(e[1])+" "+e[2] for e in err] )
|
||||
|
||||
return(ret)
|
||||
|
|
@ -377,10 +413,11 @@ class GuiRingPlayerStats (GuiPlayerStats.GuiPlayerStats):
|
|||
# to turn indicator off for other cols
|
||||
except:
|
||||
err = traceback.extract_tb(sys.exc_info()[2])
|
||||
print "***sortcols error: " + str(sys.exc_info()[1])
|
||||
print _("***sortcols error: ") + str(sys.exc_info()[1])
|
||||
print "\n".join( [e[0]+':'+str(e[1])+" "+e[2] for e in err] )
|
||||
#end def sortcols
|
||||
|
||||
|
||||
def addGrid(self, vbox, query, flags, playerids, sitenos, limits, type, seats, groups, dates, games):
|
||||
counter = 0
|
||||
row = 0
|
||||
|
|
@ -390,6 +427,7 @@ class GuiRingPlayerStats (GuiPlayerStats.GuiPlayerStats):
|
|||
|
||||
tmp = self.sql.query[query]
|
||||
tmp = self.refineQuery(tmp, flags, playerids, sitenos, limits, type, seats, groups, dates, games)
|
||||
#print "DEBUG: query: %s" % tmp
|
||||
self.cursor.execute(tmp)
|
||||
result = self.cursor.fetchall()
|
||||
colnames = [desc[0].lower() for desc in self.cursor.description]
|
||||
|
|
@ -465,7 +503,7 @@ class GuiRingPlayerStats (GuiPlayerStats.GuiPlayerStats):
|
|||
else:
|
||||
if column[colalias] == 'game':
|
||||
if holecards:
|
||||
value = Card.twoStartCardString( result[sqlrow][hgametypeid_idx] )
|
||||
value = Card.decodeStartHandValue(result[sqlrow][colnames.index('category')], result[sqlrow][hgametypeid_idx] )
|
||||
else:
|
||||
minbb = result[sqlrow][colnames.index('minbigblind')]
|
||||
maxbb = result[sqlrow][colnames.index('maxbigblind')]
|
||||
|
|
@ -491,6 +529,9 @@ class GuiRingPlayerStats (GuiPlayerStats.GuiPlayerStats):
|
|||
#print treerow
|
||||
sqlrow += 1
|
||||
row += 1
|
||||
tips = DemoTips(column[colformat])
|
||||
tips.add_view(view)
|
||||
|
||||
vbox.show_all()
|
||||
view.show()
|
||||
if len(self.liststore) == 1:
|
||||
|
|
@ -668,7 +709,7 @@ class GuiRingPlayerStats (GuiPlayerStats.GuiPlayerStats):
|
|||
#end def refineQuery
|
||||
|
||||
def showDetailFilter(self, widget, data):
|
||||
detailDialog = gtk.Dialog(title="Detailed Filters", parent=self.main_window
|
||||
detailDialog = gtk.Dialog(title=_("Detailed Filters"), parent=self.main_window
|
||||
,flags=gtk.DIALOG_MODAL | gtk.DIALOG_DESTROY_WITH_PARENT
|
||||
,buttons=(gtk.STOCK_CANCEL, gtk.RESPONSE_REJECT,
|
||||
gtk.STOCK_OK, gtk.RESPONSE_ACCEPT))
|
||||
|
|
@ -677,7 +718,7 @@ class GuiRingPlayerStats (GuiPlayerStats.GuiPlayerStats):
|
|||
detailDialog.vbox.pack_start(handbox, False, False, 0)
|
||||
handbox.show()
|
||||
|
||||
label = gtk.Label("Hand Filters:")
|
||||
label = gtk.Label(_("Hand Filters:"))
|
||||
handbox.add(label)
|
||||
label.show()
|
||||
|
||||
|
|
@ -690,8 +731,8 @@ class GuiRingPlayerStats (GuiPlayerStats.GuiPlayerStats):
|
|||
cb = gtk.CheckButton()
|
||||
lbl_from = gtk.Label(htest[1])
|
||||
lbl_from.set_alignment(xalign=0.0, yalign=0.5)
|
||||
lbl_tween = gtk.Label('between')
|
||||
lbl_to = gtk.Label('and')
|
||||
lbl_tween = gtk.Label(_('between'))
|
||||
lbl_to = gtk.Label(_('and'))
|
||||
adj1 = gtk.Adjustment(value=htest[2], lower=0, 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=htest[3], lower=2, upper=10, step_incr=1, page_incr=1, page_size=0)
|
||||
|
|
|
|||
28
pyfpdb/GuiSessionViewer.py
Executable file → Normal file
28
pyfpdb/GuiSessionViewer.py
Executable file → Normal file
|
|
@ -15,6 +15,9 @@
|
|||
#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 L10n
|
||||
_ = L10n.get_translation()
|
||||
|
||||
import sys
|
||||
import threading
|
||||
import pygtk
|
||||
|
|
@ -27,7 +30,7 @@ try:
|
|||
calluse = not 'matplotlib' in sys.modules
|
||||
import matplotlib
|
||||
if calluse:
|
||||
matplotlib.use('GTK')
|
||||
matplotlib.use('GTKCairo')
|
||||
from matplotlib.figure import Figure
|
||||
from matplotlib.backends.backend_gtk import FigureCanvasGTK as FigureCanvas
|
||||
from matplotlib.backends.backend_gtkagg import NavigationToolbar2GTKAgg as NavigationToolbar
|
||||
|
|
@ -38,9 +41,8 @@ try:
|
|||
# DayLocator, MONDAY, timezone
|
||||
|
||||
except ImportError, inst:
|
||||
print """Failed to load numpy in Session Viewer"""
|
||||
print """This is of no consequence as the page is broken and only of interest to developers."""
|
||||
print "ImportError: %s" % inst.args
|
||||
print _("""Failed to load numpy and/or matplotlib in Session Viewer""")
|
||||
print _("ImportError: %s") % inst.args
|
||||
|
||||
import Card
|
||||
import fpdb_import
|
||||
|
|
@ -71,13 +73,11 @@ class GuiSessionViewer (threading.Thread):
|
|||
|
||||
settings = {}
|
||||
settings.update(self.conf.get_db_parameters())
|
||||
settings.update(self.conf.get_tv_parameters())
|
||||
settings.update(self.conf.get_import_parameters())
|
||||
settings.update(self.conf.get_default_paths())
|
||||
|
||||
# text used on screen stored here so that it can be configured
|
||||
self.filterText = {'handhead':'Hand Breakdown for all levels listed above'
|
||||
}
|
||||
self.filterText = {'handhead':_('Hand Breakdown for all levels listed above')}
|
||||
|
||||
filters_display = { "Heroes" : True,
|
||||
"Sites" : True,
|
||||
|
|
@ -191,13 +191,13 @@ class GuiSessionViewer (threading.Thread):
|
|||
|
||||
if not sitenos:
|
||||
#Should probably pop up here.
|
||||
print "No sites selected - defaulting to PokerStars"
|
||||
print _("No sites selected - defaulting to PokerStars")
|
||||
sitenos = [2]
|
||||
if not playerids:
|
||||
print "No player ids found"
|
||||
print _("No player ids found")
|
||||
return
|
||||
if not limits:
|
||||
print "No limits found"
|
||||
print _("No limits found")
|
||||
return
|
||||
|
||||
self.createStatsPane(vbox, playerids, sitenos, limits, seats)
|
||||
|
|
@ -236,7 +236,7 @@ class GuiSessionViewer (threading.Thread):
|
|||
self.addTable(vbox1, results)
|
||||
|
||||
self.db.rollback()
|
||||
print "Stats page displayed in %4.2f seconds" % (time() - starttime)
|
||||
print _("Stats page displayed in %4.2f seconds") % (time() - starttime)
|
||||
#end def fillStatsFrame(self, vbox):
|
||||
|
||||
def generateDatasets(self, playerids, sitenos, limits, seats):
|
||||
|
|
@ -342,7 +342,7 @@ class GuiSessionViewer (threading.Thread):
|
|||
self.canvas = FigureCanvas(self.fig) # a gtk.DrawingArea
|
||||
except:
|
||||
err = traceback.extract_tb(sys.exc_info()[2])[-1]
|
||||
print "***Error: "+err[2]+"("+str(err[1])+"): "+str(sys.exc_info()[1])
|
||||
print _("***Error: ")+err[2]+"("+str(err[1])+"): "+str(sys.exc_info()[1])
|
||||
raise
|
||||
|
||||
|
||||
|
|
@ -363,10 +363,10 @@ class GuiSessionViewer (threading.Thread):
|
|||
|
||||
self.ax = self.fig.add_subplot(111)
|
||||
|
||||
self.ax.set_title("Session candlestick graph")
|
||||
self.ax.set_title(_("Session candlestick graph"))
|
||||
|
||||
#Set axis labels and grid overlay properites
|
||||
self.ax.set_xlabel("Sessions", fontsize = 12)
|
||||
self.ax.set_xlabel(_("Sessions"), fontsize = 12)
|
||||
self.ax.set_ylabel("$", fontsize = 12)
|
||||
self.ax.grid(color='g', linestyle=':', linewidth=0.2)
|
||||
|
||||
|
|
|
|||
312
pyfpdb/GuiTourneyGraphViewer.py
Normal file
312
pyfpdb/GuiTourneyGraphViewer.py
Normal file
|
|
@ -0,0 +1,312 @@
|
|||
#!/usr/bin/python
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
#Copyright 2008-2010 Carl Gherardi
|
||||
#This program is free software: you can redistribute it and/or modify
|
||||
#it under the terms of the GNU 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 L10n
|
||||
_ = L10n.get_translation()
|
||||
|
||||
import threading
|
||||
import pygtk
|
||||
pygtk.require('2.0')
|
||||
import gtk
|
||||
import os
|
||||
import sys
|
||||
import traceback
|
||||
from time import *
|
||||
from datetime import datetime
|
||||
#import pokereval
|
||||
|
||||
import fpdb_import
|
||||
import Database
|
||||
import Filters
|
||||
import Charset
|
||||
|
||||
try:
|
||||
calluse = not 'matplotlib' in sys.modules
|
||||
import matplotlib
|
||||
if calluse:
|
||||
matplotlib.use('GTKCairo')
|
||||
from matplotlib.figure import Figure
|
||||
from matplotlib.backends.backend_gtk import FigureCanvasGTK as FigureCanvas
|
||||
from matplotlib.backends.backend_gtkagg import NavigationToolbar2GTKAgg as NavigationToolbar
|
||||
from matplotlib.font_manager import FontProperties
|
||||
from numpy import arange, cumsum
|
||||
from pylab import *
|
||||
except ImportError, inst:
|
||||
print _("""Failed to load libs for graphing, graphing will not function. Please
|
||||
install numpy and matplotlib if you want to use graphs.""")
|
||||
print _("""This is of no consequence for other parts of the program, e.g. import
|
||||
and HUD are NOT affected by this problem.""")
|
||||
print "ImportError: %s" % inst.args
|
||||
|
||||
class GuiTourneyGraphViewer (threading.Thread):
|
||||
|
||||
def __init__(self, querylist, config, parent, debug=True):
|
||||
"""Constructor for GraphViewer"""
|
||||
self.sql = querylist
|
||||
self.conf = config
|
||||
self.debug = debug
|
||||
self.parent = parent
|
||||
#print "start of GraphViewer constructor"
|
||||
self.db = Database.Database(self.conf, sql=self.sql)
|
||||
|
||||
|
||||
filters_display = { "Heroes" : True,
|
||||
"Sites" : True,
|
||||
"Games" : False,
|
||||
"Limits" : False,
|
||||
"LimitSep" : False,
|
||||
"LimitType" : False,
|
||||
"Type" : False,
|
||||
"UseType" : 'tour',
|
||||
"Seats" : False,
|
||||
"SeatSep" : False,
|
||||
"Dates" : True,
|
||||
"Groups" : False,
|
||||
"Button1" : True,
|
||||
"Button2" : True
|
||||
}
|
||||
|
||||
self.filters = Filters.Filters(self.db, self.conf, self.sql, display = filters_display)
|
||||
self.filters.registerButton1Name(_("Refresh _Graph"))
|
||||
self.filters.registerButton1Callback(self.generateGraph)
|
||||
self.filters.registerButton2Name(_("_Export to File"))
|
||||
self.filters.registerButton2Callback(self.exportGraph)
|
||||
|
||||
self.mainHBox = gtk.HBox(False, 0)
|
||||
self.mainHBox.show()
|
||||
|
||||
self.leftPanelBox = self.filters.get_vbox()
|
||||
|
||||
self.hpane = gtk.HPaned()
|
||||
self.hpane.pack1(self.leftPanelBox)
|
||||
self.mainHBox.add(self.hpane)
|
||||
# hierarchy: self.mainHBox / self.hpane / self.graphBox / self.canvas / self.fig / self.ax
|
||||
|
||||
self.graphBox = gtk.VBox(False, 0)
|
||||
self.graphBox.show()
|
||||
self.hpane.pack2(self.graphBox)
|
||||
self.hpane.show()
|
||||
|
||||
self.fig = None
|
||||
#self.exportButton.set_sensitive(False)
|
||||
self.canvas = None
|
||||
|
||||
|
||||
self.db.rollback()
|
||||
|
||||
def get_vbox(self):
|
||||
"""returns the vbox of this thread"""
|
||||
return self.mainHBox
|
||||
#end def get_vbox
|
||||
|
||||
def clearGraphData(self):
|
||||
|
||||
try:
|
||||
try:
|
||||
if self.canvas:
|
||||
self.graphBox.remove(self.canvas)
|
||||
except:
|
||||
pass
|
||||
|
||||
if self.fig != None:
|
||||
self.fig.clear()
|
||||
self.fig = Figure(figsize=(5,4), dpi=100)
|
||||
if self.canvas is not None:
|
||||
self.canvas.destroy()
|
||||
|
||||
self.canvas = FigureCanvas(self.fig) # a gtk.DrawingArea
|
||||
except:
|
||||
err = traceback.extract_tb(sys.exc_info()[2])[-1]
|
||||
print _("***Error: ")+err[2]+"("+str(err[1])+"): "+str(sys.exc_info()[1])
|
||||
raise
|
||||
|
||||
def generateGraph(self, widget, data):
|
||||
try:
|
||||
self.clearGraphData()
|
||||
|
||||
sitenos = []
|
||||
playerids = []
|
||||
|
||||
sites = self.filters.getSites()
|
||||
heroes = self.filters.getHeroes()
|
||||
siteids = self.filters.getSiteIds()
|
||||
|
||||
# Which sites are selected?
|
||||
for site in sites:
|
||||
if sites[site] == True:
|
||||
sitenos.append(siteids[site])
|
||||
_hname = Charset.to_utf8(heroes[site])
|
||||
result = self.db.get_player_id(self.conf, site, _hname)
|
||||
if result is not None:
|
||||
playerids.append(int(result))
|
||||
|
||||
if not sitenos:
|
||||
#Should probably pop up here.
|
||||
print _("No sites selected - defaulting to PokerStars")
|
||||
self.db.rollback()
|
||||
return
|
||||
|
||||
if not playerids:
|
||||
print _("No player ids found")
|
||||
self.db.rollback()
|
||||
return
|
||||
|
||||
#Set graph properties
|
||||
self.ax = self.fig.add_subplot(111)
|
||||
|
||||
#Get graph data from DB
|
||||
starttime = time()
|
||||
green = self.getData(playerids, sitenos)
|
||||
print _("Graph generated in: %s") %(time() - starttime)
|
||||
|
||||
|
||||
#Set axis labels and grid overlay properites
|
||||
self.ax.set_xlabel(_("Tournaments"), fontsize = 12)
|
||||
self.ax.set_ylabel("$", fontsize = 12)
|
||||
self.ax.grid(color='g', linestyle=':', linewidth=0.2)
|
||||
if green == None or green == []:
|
||||
self.ax.set_title(_("No Data for Player(s) Found"))
|
||||
green = ([ 0., 0., 0., 0., 500., 1000., 900., 800.,
|
||||
700., 600., 500., 400., 300., 200., 100., 0.,
|
||||
500., 1000., 1000., 1000., 1000., 1000., 1000., 1000.,
|
||||
1000., 1000., 1000., 1000., 1000., 1000., 875., 750.,
|
||||
625., 500., 375., 250., 125., 0., 0., 0.,
|
||||
0., 500., 1000., 900., 800., 700., 600., 500.,
|
||||
400., 300., 200., 100., 0., 500., 1000., 1000.])
|
||||
red = ([ 0., 0., 0., 0., 500., 1000., 900., 800.,
|
||||
700., 600., 500., 400., 300., 200., 100., 0.,
|
||||
0., 0., 0., 0., 0., 0., 125., 250.,
|
||||
375., 500., 500., 500., 500., 500., 500., 500.,
|
||||
500., 500., 375., 250., 125., 0., 0., 0.,
|
||||
0., 500., 1000., 900., 800., 700., 600., 500.,
|
||||
400., 300., 200., 100., 0., 500., 1000., 1000.])
|
||||
blue = ([ 0., 0., 0., 0., 500., 1000., 900., 800.,
|
||||
700., 600., 500., 400., 300., 200., 100., 0.,
|
||||
0., 0., 0., 0., 0., 0., 125., 250.,
|
||||
375., 500., 625., 750., 875., 1000., 875., 750.,
|
||||
625., 500., 375., 250., 125., 0., 0., 0.,
|
||||
0., 500., 1000., 900., 800., 700., 600., 500.,
|
||||
400., 300., 200., 100., 0., 500., 1000., 1000.])
|
||||
|
||||
self.ax.plot(green, color='green', label=_('Tournaments: %d\nProfit: $%.2f') %(len(green), green[-1]))
|
||||
#self.ax.plot(blue, color='blue', label=_('Showdown: $%.2f') %(blue[-1]))
|
||||
#self.ax.plot(red, color='red', label=_('Non-showdown: $%.2f') %(red[-1]))
|
||||
self.graphBox.add(self.canvas)
|
||||
self.canvas.show()
|
||||
self.canvas.draw()
|
||||
|
||||
#TODO: Do something useful like alert user
|
||||
#print "No hands returned by graph query"
|
||||
else:
|
||||
self.ax.set_title(_("Tournament Results"))
|
||||
|
||||
#Draw plot
|
||||
self.ax.plot(green, color='green', label=_('Tournaments: %d\nProfit: $%.2f') %(len(green), green[-1]))
|
||||
#self.ax.plot(blue, color='blue', label=_('Showdown: $%.2f') %(blue[-1]))
|
||||
#self.ax.plot(red, color='red', label=_('Non-showdown: $%.2f') %(red[-1]))
|
||||
if sys.version[0:3] == '2.5':
|
||||
self.ax.legend(loc='upper left', shadow=True, prop=FontProperties(size='smaller'))
|
||||
else:
|
||||
self.ax.legend(loc='upper left', fancybox=True, shadow=True, prop=FontProperties(size='smaller'))
|
||||
|
||||
self.graphBox.add(self.canvas)
|
||||
self.canvas.show()
|
||||
self.canvas.draw()
|
||||
#self.exportButton.set_sensitive(True)
|
||||
except:
|
||||
err = traceback.extract_tb(sys.exc_info()[2])[-1]
|
||||
print _("***Error: ")+err[2]+"("+str(err[1])+"): "+str(sys.exc_info()[1])
|
||||
|
||||
#end of def showClicked
|
||||
|
||||
def getData(self, names, sites):
|
||||
tmp = self.sql.query['tourneyResults']
|
||||
print "DEBUG: getData"
|
||||
start_date, end_date = self.filters.getDates()
|
||||
|
||||
#Buggered if I can find a way to do this 'nicely' take a list of integers and longs
|
||||
# and turn it into a tuple readale by sql.
|
||||
# [5L] into (5) not (5,) and [5L, 2829L] into (5, 2829)
|
||||
nametest = str(tuple(names))
|
||||
sitetest = str(tuple(sites))
|
||||
|
||||
#Must be a nicer way to deal with tuples of size 1 ie. (2,) - which makes sql barf
|
||||
tmp = tmp.replace("<player_test>", nametest)
|
||||
tmp = tmp.replace("<site_test>", sitetest)
|
||||
tmp = tmp.replace("<startdate_test>", start_date)
|
||||
tmp = tmp.replace("<enddate_test>", end_date)
|
||||
tmp = tmp.replace(",)", ")")
|
||||
|
||||
print "DEBUG: sql query:"
|
||||
print tmp
|
||||
self.db.cursor.execute(tmp)
|
||||
#returns (HandId,Winnings,Costs,Profit)
|
||||
winnings = self.db.cursor.fetchall()
|
||||
self.db.rollback()
|
||||
|
||||
if len(winnings) == 0:
|
||||
return None
|
||||
|
||||
green = map(lambda x:float(x[1]), winnings)
|
||||
#blue = map(lambda x: float(x[1]) if x[2] == True else 0.0, winnings)
|
||||
#red = map(lambda x: float(x[1]) if x[2] == False else 0.0, winnings)
|
||||
greenline = cumsum(green)
|
||||
#blueline = cumsum(blue)
|
||||
#redline = cumsum(red)
|
||||
return (greenline/100)
|
||||
|
||||
def exportGraph (self, widget, data):
|
||||
if self.fig is None:
|
||||
return # Might want to disable export button until something has been generated.
|
||||
|
||||
dia_chooser = gtk.FileChooserDialog(title=_("Please choose the directory you wish to export to:"),
|
||||
action=gtk.FILE_CHOOSER_ACTION_SELECT_FOLDER,
|
||||
buttons=(gtk.STOCK_CANCEL,gtk.RESPONSE_CANCEL,gtk.STOCK_OK,gtk.RESPONSE_OK))
|
||||
dia_chooser.set_destroy_with_parent(True)
|
||||
dia_chooser.set_transient_for(self.parent)
|
||||
try:
|
||||
dia_chooser.set_filename(self.exportFile) # use previously chosen export path as default
|
||||
except:
|
||||
pass
|
||||
|
||||
response = dia_chooser.run()
|
||||
|
||||
if response <> gtk.RESPONSE_OK:
|
||||
print _('Closed, no graph exported')
|
||||
dia_chooser.destroy()
|
||||
return
|
||||
|
||||
# generate a unique filename for export
|
||||
now = datetime.now()
|
||||
now_formatted = now.strftime("%Y%m%d%H%M%S")
|
||||
self.exportFile = dia_chooser.get_filename() + "/fpdb" + now_formatted + ".png"
|
||||
dia_chooser.destroy()
|
||||
|
||||
#print "DEBUG: self.exportFile = %s" %(self.exportFile)
|
||||
self.fig.savefig(self.exportFile, format="png")
|
||||
|
||||
#display info box to confirm graph created
|
||||
diainfo = gtk.MessageDialog(parent=self.parent,
|
||||
flags=gtk.DIALOG_DESTROY_WITH_PARENT,
|
||||
type=gtk.MESSAGE_INFO,
|
||||
buttons=gtk.BUTTONS_OK,
|
||||
message_format=_("Graph created"))
|
||||
diainfo.format_secondary_text(self.exportFile)
|
||||
diainfo.run()
|
||||
diainfo.destroy()
|
||||
|
||||
#end of def exportGraph
|
||||
|
|
@ -15,6 +15,9 @@
|
|||
#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 L10n
|
||||
_ = L10n.get_translation()
|
||||
|
||||
#import traceback
|
||||
import threading
|
||||
import pygtk
|
||||
|
|
@ -69,7 +72,7 @@ class GuiTourneyPlayerStats (GuiPlayerStats.GuiPlayerStats):
|
|||
self.filters = TourneyFilters.TourneyFilters(self.db, self.conf, self.sql, display = filters_display)
|
||||
#self.filters.registerButton1Name("_Filters")
|
||||
#self.filters.registerButton1Callback(self.showDetailFilter)
|
||||
self.filters.registerButton2Name("_Refresh Stats")
|
||||
self.filters.registerButton2Name(_("_Refresh Stats"))
|
||||
self.filters.registerButton2Callback(self.refreshStats)
|
||||
|
||||
# ToDo: store in config
|
||||
|
|
@ -86,9 +89,9 @@ class GuiTourneyPlayerStats (GuiPlayerStats.GuiPlayerStats):
|
|||
, ["playerName", False, "Name", 0.0, "%s", "str"] # true not allowed for this line (set in code)
|
||||
, ["tourneyCount", True, "#", 1.0, "%1.0f", "str"]
|
||||
, ["itm", True, "ITM%", 1.0, "%3.2f", "str"]
|
||||
, ["1st", False, "1st", 1.0, "%1.0f", "str"]
|
||||
, ["2nd", True, "2nd", 1.0, "%1.0f", "str"]
|
||||
, ["3rd", True, "3rd", 1.0, "%1.0f", "str"]
|
||||
, ["_1st", False, "1st", 1.0, "%1.0f", "str"]
|
||||
, ["_2nd", True, "2nd", 1.0, "%1.0f", "str"]
|
||||
, ["_3rd", True, "3rd", 1.0, "%1.0f", "str"]
|
||||
, ["unknownRank", True, "Rank?", 1.0, "%1.0f", "str"]
|
||||
, ["spent", True, "Spent", 1.0, "%3.2f", "str"]
|
||||
, ["won", True, "Won", 1.0, "%3.2f", "str"]
|
||||
|
|
@ -237,7 +240,7 @@ class GuiTourneyPlayerStats (GuiPlayerStats.GuiPlayerStats):
|
|||
self.addGrid(swin, 'playerDetailedStats', flags, playerids, sitenos, seats, dates)
|
||||
|
||||
self.db.rollback()
|
||||
print "Stats page displayed in %4.2f seconds" % (time() - startTime)
|
||||
print _("Stats page displayed in %4.2f seconds") % (time() - startTime)
|
||||
#end def createStatsTable
|
||||
|
||||
def fillStatsFrame(self, vbox):
|
||||
|
|
@ -262,10 +265,10 @@ class GuiTourneyPlayerStats (GuiPlayerStats.GuiPlayerStats):
|
|||
|
||||
if not sitenos:
|
||||
#Should probably pop up here.
|
||||
print "No sites selected - defaulting to PokerStars"
|
||||
print _("No sites selected - defaulting to PokerStars")
|
||||
sitenos = [2]
|
||||
if not playerids:
|
||||
print "No player ids found"
|
||||
print _("No player ids found")
|
||||
return
|
||||
|
||||
self.createStatsTable(vbox, tourneyTypes, playerids, sitenos, seats, dates)
|
||||
|
|
@ -451,7 +454,7 @@ class GuiTourneyPlayerStats (GuiPlayerStats.GuiPlayerStats):
|
|||
# to turn indicator off for other cols
|
||||
except:
|
||||
err = traceback.extract_tb(sys.exc_info()[2])
|
||||
print "***sortCols error: " + str(sys.exc_info()[1])
|
||||
print _("***sortCols error: ") + str(sys.exc_info()[1])
|
||||
print "\n".join( [e[0]+':'+str(e[1])+" "+e[2] for e in err] )
|
||||
#end def sortCols
|
||||
#end class GuiTourneyPlayerStats
|
||||
|
|
|
|||
142
pyfpdb/GuiTourneyViewer.py
Normal file
142
pyfpdb/GuiTourneyViewer.py
Normal file
|
|
@ -0,0 +1,142 @@
|
|||
#!/usr/bin/python
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
#Copyright 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 L10n
|
||||
_ = L10n.get_translation()
|
||||
|
||||
import threading
|
||||
import pygtk
|
||||
pygtk.require('2.0')
|
||||
import gtk
|
||||
|
||||
class GuiTourneyViewer (threading.Thread):
|
||||
def __init__(self, config, db, sql, mainwin, debug=True):
|
||||
self.db = db
|
||||
|
||||
self.mainVBox = gtk.VBox()
|
||||
self.interfaceHBox = gtk.HBox()
|
||||
self.mainVBox.pack_start(self.interfaceHBox, expand=False)
|
||||
|
||||
self.siteBox = gtk.combo_box_new_text()
|
||||
for site in config.supported_sites:
|
||||
self.siteBox.append_text(site)
|
||||
self.siteBox.set_active(0)
|
||||
self.interfaceHBox.add(self.siteBox)
|
||||
|
||||
label=gtk.Label(_("Enter the tourney number you want to display:"))
|
||||
self.interfaceHBox.add(label)
|
||||
|
||||
self.entryTourney = gtk.Entry()
|
||||
self.interfaceHBox.add(self.entryTourney)
|
||||
|
||||
self.displayButton = gtk.Button(_("_Display"))
|
||||
self.displayButton.connect('clicked', self.displayClicked)
|
||||
self.interfaceHBox.add(self.displayButton)
|
||||
|
||||
self.entryPlayer = gtk.Entry()
|
||||
self.interfaceHBox.add(self.entryPlayer)
|
||||
|
||||
self.playerButton = gtk.Button(_("Display _Player"))
|
||||
self.playerButton.connect('clicked', self.displayPlayerClicked)
|
||||
self.interfaceHBox.add(self.playerButton)
|
||||
|
||||
self.table = gtk.Table(columns=10, rows=9)
|
||||
self.mainVBox.add(self.table)
|
||||
|
||||
self.mainVBox.show_all()
|
||||
#end def __init__
|
||||
|
||||
def displayClicked(self, widget, data=None):
|
||||
if self.prepare(10, 9):
|
||||
result=self.db.getTourneyInfo(self.siteName, self.tourneyNo)
|
||||
if result[1] == None:
|
||||
self.table.destroy()
|
||||
self.errorLabel=gtk.Label(_("Tournament not found - please ensure you imported it and selected the correct site"))
|
||||
self.mainVBox.add(self.errorLabel)
|
||||
else:
|
||||
x=0
|
||||
y=0
|
||||
for i in range(1,len(result[0])):
|
||||
if y==9:
|
||||
x+=2
|
||||
y=0
|
||||
|
||||
label=gtk.Label(result[0][i])
|
||||
self.table.attach(label,x,x+1,y,y+1)
|
||||
|
||||
if result[1][i]==None:
|
||||
label=gtk.Label("N/A")
|
||||
else:
|
||||
label=gtk.Label(result[1][i])
|
||||
self.table.attach(label,x+1,x+2,y,y+1)
|
||||
|
||||
y+=1
|
||||
self.mainVBox.show_all()
|
||||
#def displayClicked
|
||||
|
||||
def displayPlayerClicked(self, widget, data=None):
|
||||
if self.prepare(4, 5):
|
||||
result=self.db.getTourneyPlayerInfo(self.siteName, self.tourneyNo, self.playerName)
|
||||
if result[1] == None:
|
||||
self.table.destroy()
|
||||
self.errorLabel=gtk.Label(_("Player or tourney not found - please ensure you imported it and selected the correct site"))
|
||||
self.mainVBox.add(self.errorLabel)
|
||||
else:
|
||||
x=0
|
||||
y=0
|
||||
for i in range(1,len(result[0])):
|
||||
if y==5:
|
||||
x+=2
|
||||
y=0
|
||||
|
||||
label=gtk.Label(result[0][i])
|
||||
self.table.attach(label,x,x+1,y,y+1)
|
||||
|
||||
if result[1][i]==None:
|
||||
label=gtk.Label(_("N/A"))
|
||||
else:
|
||||
label=gtk.Label(result[1][i])
|
||||
self.table.attach(label,x+1,x+2,y,y+1)
|
||||
|
||||
y+=1
|
||||
self.mainVBox.show_all()
|
||||
#def displayPlayerClicked
|
||||
|
||||
def get_vbox(self):
|
||||
"""returns the vbox of this thread"""
|
||||
return self.mainVBox
|
||||
#end def get_vbox
|
||||
|
||||
def prepare(self, columns, rows):
|
||||
try: self.errorLabel.destroy()
|
||||
except: pass
|
||||
|
||||
try:
|
||||
self.tourneyNo=int(self.entryTourney.get_text())
|
||||
except ValueError:
|
||||
self.errorLabel=gtk.Label(_("invalid entry in tourney number - must enter numbers only"))
|
||||
self.mainVBox.add(self.errorLabel)
|
||||
return False
|
||||
self.siteName=self.siteBox.get_active_text()
|
||||
self.playerName=self.entryPlayer.get_text()
|
||||
|
||||
self.table.destroy()
|
||||
self.table=gtk.Table(columns=columns, rows=rows)
|
||||
self.mainVBox.add(self.table)
|
||||
return True
|
||||
#end def readInfo
|
||||
#end class GuiTourneyViewer
|
||||
83
pyfpdb/HHReplayer.py
Normal file
83
pyfpdb/HHReplayer.py
Normal file
|
|
@ -0,0 +1,83 @@
|
|||
#!/usr/bin/env python
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
#Copyright 2008-2010 Carl Gherardi
|
||||
#This program is free software: you can redistribute it and/or modify
|
||||
#it under the terms of the GNU 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 os, pygame
|
||||
import time
|
||||
from pygame.locals import *
|
||||
from pygame.compat import geterror
|
||||
|
||||
main_dir = os.path.split(os.path.abspath(__file__))[0]
|
||||
data_dir = os.path.join(main_dir, '.')
|
||||
|
||||
def load_image(name, colorkey=None):
|
||||
fullname = os.path.join(data_dir, name)
|
||||
try:
|
||||
image = pygame.image.load(fullname)
|
||||
except pygame.error:
|
||||
print ('Cannot load image:', fullname)
|
||||
print "data_dir: '%s' name: '%s'" %( data_dir, name)
|
||||
raise SystemExit(str(geterror()))
|
||||
image = image.convert()
|
||||
if colorkey is not None:
|
||||
if colorkey is -1:
|
||||
colorkey = image.get_at((0,0))
|
||||
image.set_colorkey(colorkey, RLEACCEL)
|
||||
return image, image.get_rect()
|
||||
|
||||
|
||||
def main():
|
||||
#Initialize Everything
|
||||
pygame.init()
|
||||
clock = pygame.time.Clock()
|
||||
screen = pygame.display.set_mode((640, 480))
|
||||
table_string = "Tournament 2010090009 Table %s - Blinds $600/$1200 Anto $150"
|
||||
table_no = 1
|
||||
table_title = "Nongoma V - $200/$400 USD - Limit Holdem"
|
||||
pygame.display.set_caption(table_title)
|
||||
pygame.mouse.set_visible(0)
|
||||
|
||||
# Load background image
|
||||
bgimage, rect = load_image('../gfx/Table.png')
|
||||
background = pygame.Surface(screen.get_size())
|
||||
background.blit(bgimage, (0, 0))
|
||||
|
||||
#Put Text On The Background, Centered
|
||||
if pygame.font:
|
||||
font = pygame.font.Font(None, 24)
|
||||
text = font.render("FPDB Replayer Table", 1, (10, 10, 10))
|
||||
textpos = text.get_rect(centerx=background.get_width()/2)
|
||||
background.blit(text, textpos)
|
||||
|
||||
#Display The Background
|
||||
screen.blit(background, (0, 0))
|
||||
pygame.display.flip()
|
||||
|
||||
going = True
|
||||
while going:
|
||||
clock.tick(6000)
|
||||
# Draw
|
||||
screen.blit(background, (0, 0))
|
||||
# Change table #
|
||||
#table_no += 1
|
||||
#table_title = "Tournament 2010090009 Table %s - Blinds $600/$1200 Anto $150" % table_no
|
||||
#pygame.display.set_caption(table_title)
|
||||
time.sleep(10)
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
main()
|
||||
|
||||
|
|
@ -573,7 +573,11 @@ Left-Drag to Move"
|
|||
<hhc site="Absolute" converter="AbsoluteToFpdb"/>
|
||||
<hhc site="PartyPoker" converter="PartyPokerToFpdb"/>
|
||||
<hhc site="Betfair" converter="BetfairToFpdb"/>
|
||||
<hhc site="Partouche" converter="PartoucheToFpdb"/>
|
||||
<hhc site="OnGame" converter="OnGameToFpdb"/>
|
||||
<hhc site="Carbon" converter="CarbonToFpdb"/>
|
||||
<hhc site="PKR" converter="PkrToFpdb"/>
|
||||
<hhc site="iPoker" converter="iPokerToFpdb"/>
|
||||
<hhc site="Winamax" converter="WinamaxToFpdb"/>
|
||||
</hhcs>
|
||||
|
||||
<supported_databases>
|
||||
|
|
|
|||
|
|
@ -5,12 +5,45 @@
|
|||
<!-- config_wrap_len is preferred max line length in this file, -1 means no max
|
||||
day_start is time that logical day starts, e.g. 5 means that any play
|
||||
between 00:00 and 04:59:59 counts as being on the previous day -->
|
||||
<general config_wrap_len="-1"
|
||||
<general version="1"
|
||||
config_wrap_len="-1"
|
||||
day_start="5"
|
||||
ui_language="system"
|
||||
config_difficulty="expert"
|
||||
/>
|
||||
|
||||
<import callFpdbHud = "True" interval = "10" fastStoreHudCache="False" hhArchiveBase="~/.fpdb/HandHistories/" saveActions="True"></import>
|
||||
|
||||
<gui_cash_stats>
|
||||
<col col_name="game" disp_all="True" disp_posn="True" col_title="Game" xalignment="0.0" field_format="%s" field_type="str" />
|
||||
<col col_name="hand" disp_all="False" disp_posn="False" col_title="Hand" xalignment="0.0" field_format="%s" field_type="str" />
|
||||
<col col_name="plposition" disp_all="False" disp_posn="False" col_title="Posn" xalignment="1.0" field_format="%s" field_type="str" />
|
||||
<col col_name="pname" disp_all="False" disp_posn="False" col_title="Name" xalignment="0.0" field_format="%s" field_type="str" />
|
||||
<col col_name="n" disp_all="True" disp_posn="True" col_title="Hds" xalignment="1.0" field_format="%1.0f" field_type="str" />
|
||||
<col col_name="avgseats" disp_all="False" disp_posn="False" col_title="Seats" xalignment="1.0" field_format="%3.1f" field_type="str" />
|
||||
<col col_name="vpip" disp_all="True" disp_posn="True" col_title="VPIP" xalignment="1.0" field_format="%3.1f" field_type="str" />
|
||||
<col col_name="pfr" disp_all="True" disp_posn="True" col_title="PFR" xalignment="1.0" field_format="%3.1f" field_type="str" />
|
||||
<col col_name="pf3" disp_all="True" disp_posn="True" col_title="PF3" xalignment="1.0" field_format="%3.1f" field_type="str" />
|
||||
<col col_name="aggfac" disp_all="True" disp_posn="True" col_title="AggFac" xalignment="1.0" field_format="%2.2f" field_type="str" />
|
||||
<col col_name="aggfrq" disp_all="True" disp_posn="True" col_title="AggFreq" xalignment="1.0" field_format="%3.1f" field_type="str" />
|
||||
<col col_name="conbet" disp_all="True" disp_posn="True" col_title="ContBet" xalignment="1.0" field_format="%3.1f" field_type="str" />
|
||||
<col col_name="rfi" disp_all="True" disp_posn="True" col_title="RFI" xalignment="1.0" field_format="%3.1f" field_type="str" />
|
||||
<col col_name="steals" disp_all="True" disp_posn="True" col_title="Steals" xalignment="1.0" field_format="%3.1f" field_type="str" />
|
||||
<col col_name="saw_f" disp_all="True" disp_posn="True" col_title="Saw_F" xalignment="1.0" field_format="%3.1f" field_type="str" />
|
||||
<col col_name="sawsd" disp_all="True" disp_posn="True" col_title="SawSD" xalignment="1.0" field_format="%3.1f" field_type="str" />
|
||||
<col col_name="wtsdwsf" disp_all="True" disp_posn="True" col_title="WtSDwsF" xalignment="1.0" field_format="%3.1f" field_type="str" />
|
||||
<col col_name="wmsd" disp_all="True" disp_posn="True" col_title="W$SD" xalignment="1.0" field_format="%3.1f" field_type="str" />
|
||||
<col col_name="flafq" disp_all="True" disp_posn="True" col_title="FlAFq" xalignment="1.0" field_format="%3.1f" field_type="str" />
|
||||
<col col_name="tuafq" disp_all="True" disp_posn="True" col_title="TuAFq" xalignment="1.0" field_format="%3.1f" field_type="str" />
|
||||
<col col_name="rvafq" disp_all="True" disp_posn="True" col_title="RvAFq" xalignment="1.0" field_format="%3.1f" field_type="str" />
|
||||
<col col_name="pofafq" disp_all="False" disp_posn="False" col_title="PoFAFq" xalignment="1.0" field_format="%3.1f" field_type="str" />
|
||||
<col col_name="net" disp_all="True" disp_posn="True" col_title="Net($)" xalignment="1.0" field_format="%6.2f" field_type="cash" />
|
||||
<col col_name="bbper100" disp_all="True" disp_posn="True" col_title="bb/100" xalignment="1.0" field_format="%4.2f" field_type="str" />
|
||||
<col col_name="rake" disp_all="True" disp_posn="True" col_title="Rake($)" xalignment="1.0" field_format="%6.2f" field_type="cash" />
|
||||
<col col_name="bb100xr" disp_all="True" disp_posn="True" col_title="bbxr/100" xalignment="1.0" field_format="%4.2f" field_type="str" />
|
||||
<col col_name="variance" disp_all="True" disp_posn="True" col_title="Variance" xalignment="1.0" field_format="%5.2f" field_type="str" />
|
||||
</gui_cash_stats>
|
||||
|
||||
<!-- These values determine what stats are displayed in the HUD
|
||||
|
||||
The following values define how opponents' stats are done, the first 2 determine
|
||||
|
|
@ -126,6 +159,7 @@ Left-Drag to Move"
|
|||
xshift="0"
|
||||
yshift="0"
|
||||
supported_games="holdem,razz,omahahi,omahahilo,studhi,studhilo">
|
||||
<email fetchType="request-summary" host="YOUR_EMAIL_SERVER" username="YOUR_EMAIL_USERNAME" password="YOUR_EMAIL_PASSWORD" useSsl="True" folder="INBOX"/>
|
||||
<layout max="8" width="792" height="546" fav_seat="0">
|
||||
<location seat="1" x="684" y="61"> </location>
|
||||
<location seat="2" x="689" y="239"> </location>
|
||||
|
|
@ -222,49 +256,58 @@ Left-Drag to Move"
|
|||
</layout>
|
||||
</site>
|
||||
|
||||
<site enabled="False"
|
||||
site_name="Everleaf"
|
||||
table_finder="Everleaf.exe"
|
||||
screen_name="YOUR SCREEN NAME HERE"
|
||||
site_path=""
|
||||
HH_path=""
|
||||
decoder="everleaf_decode_table"
|
||||
converter="EverleafToFpdb"
|
||||
supported_games="holdem">
|
||||
<layout fav_seat="0" height="547" max="8" width="794">
|
||||
<location seat="1" x="640" y="64"> </location>
|
||||
<location seat="2" x="650" y="230"> </location>
|
||||
<location seat="3" x="650" y="385"> </location>
|
||||
<location seat="4" x="588" y="425"> </location>
|
||||
<location seat="5" x="92" y="425"> </location>
|
||||
<location seat="6" x="0" y="373"> </location>
|
||||
<location seat="7" x="0" y="223"> </location>
|
||||
<location seat="8" x="25" y="50"> </location>
|
||||
</layout>
|
||||
<layout fav_seat="0" height="547" max="6" width="794">
|
||||
<location seat="1" x="640" y="58"> </location>
|
||||
<location seat="2" x="654" y="288"> </location>
|
||||
<location seat="3" x="615" y="424"> </location>
|
||||
<location seat="4" x="70" y="421"> </location>
|
||||
<location seat="5" x="0" y="280"> </location>
|
||||
<location seat="6" x="70" y="58"> </location>
|
||||
</layout>
|
||||
<layout fav_seat="0" height="547" max="2" width="794">
|
||||
<location seat="1" x="651" y="288"> </location>
|
||||
<location seat="2" x="10" y="288"> </location>
|
||||
</layout>
|
||||
<layout fav_seat="0" height="547" max="9" width="794">
|
||||
<location seat="1" x="634" y="38"> </location>
|
||||
<location seat="2" x="667" y="184"> </location>
|
||||
<location seat="3" x="667" y="321"> </location>
|
||||
<location seat="4" x="667" y="445"> </location>
|
||||
<location seat="5" x="337" y="459"> </location>
|
||||
<location seat="6" x="0" y="400"> </location>
|
||||
<location seat="7" x="0" y="322"> </location>
|
||||
<location seat="8" x="0" y="181"> </location>
|
||||
<location seat="9" x="70" y="53"> </location>
|
||||
</layout>
|
||||
</site>
|
||||
<site HH_path="C:\Users\WindowsUserName\Documents\EverleafSiteName\HandHistory\PlayerName"
|
||||
bgcolor="#000000"
|
||||
converter="EverleafToFpdb"
|
||||
decoder="everleaf_decode_table"
|
||||
enabled="False"
|
||||
fgcolor="#EEEEEE"
|
||||
hudopacity="0.75"
|
||||
screen_name="PlayerName"
|
||||
site_name="Everleaf"
|
||||
site_path="C:\Users\WindowsUserName\AppData\Roaming\EverleafSiteName\"
|
||||
supported_games="holdem,omahahi,omahahilo"
|
||||
table_finder="Poker.exe">
|
||||
<layout fav_seat="0" height="546" max="6" width="792">
|
||||
<location seat="0" x="0" y="0"> </location>
|
||||
<location seat="1" x="586" y="109"> </location>
|
||||
<location seat="2" x="605" y="283"> </location>
|
||||
<location seat="3" x="544" y="383"> </location>
|
||||
<location seat="4" x="67" y="383"> </location>
|
||||
<location seat="5" x="5" y="284"> </location>
|
||||
<location seat="6" x="61" y="111"> </location>
|
||||
</layout>
|
||||
<layout fav_seat="0" height="546" max="10" width="792">
|
||||
<location seat="0" x="182" y="69"> </location>
|
||||
<location seat="1" x="456" y="74"> </location>
|
||||
<location seat="2" x="630" y="81"> </location>
|
||||
<location seat="3" x="637" y="208"> </location>
|
||||
<location seat="4" x="629" y="347"> </location>
|
||||
<location seat="5" x="412" y="377"> </location>
|
||||
<location seat="6" x="232" y="377"> </location>
|
||||
<location seat="7" x="21" y="349"> </location>
|
||||
<location seat="8" x="4" y="208"> </location>
|
||||
<location seat="9" x="7" y="88"> </location>
|
||||
<location seat="10" x="196" y="69"> </location>
|
||||
</layout>
|
||||
<layout fav_seat="0" height="546" max="8" width="792">
|
||||
<location seat="0" x="182" y="69"> </location>
|
||||
<location seat="1" x="456" y="74"> </location>
|
||||
<location seat="2" x="630" y="81"> </location>
|
||||
<location seat="3" x="618" y="352"> </location>
|
||||
<location seat="4" x="426" y="380"> </location>
|
||||
<location seat="5" x="243" y="382"> </location>
|
||||
<location seat="6" x="34" y="351"> </location>
|
||||
<location seat="7" x="22" y="82"> </location>
|
||||
<location seat="8" x="213" y="74"> </location>
|
||||
</layout>
|
||||
|
||||
<layout fav_seat="0" height="546" max="2" width="792">
|
||||
<location seat="1" x="651" y="288"> </location>
|
||||
<location seat="2" x="10" y="288"> </location>
|
||||
</layout>
|
||||
|
||||
</site>
|
||||
|
||||
<site enabled="False"
|
||||
site_name="Win2day"
|
||||
|
|
@ -412,52 +455,6 @@ Left-Drag to Move"
|
|||
</layout>
|
||||
</site>
|
||||
|
||||
|
||||
<site enabled="False"
|
||||
site_name="Betfair"
|
||||
table_finder="Betfair Poker.exe"
|
||||
screen_name="YOUR SCREEN NAME HERE"
|
||||
site_path="C:/Program Files/Betfair/Betfair Poker/"
|
||||
HH_path="C:/Program Files/Betfair/Betfair Poker/HandHistory/YOUR SCREEN NAME HERE/"
|
||||
decoder="everleaf_decode_table"
|
||||
converter="BetfairToFpdb"
|
||||
supported_games="holdem">
|
||||
<layout fav_seat="0" height="547" max="8" width="794">
|
||||
<location seat="1" x="640" y="64"> </location>
|
||||
<location seat="2" x="650" y="230"> </location>
|
||||
<location seat="3" x="650" y="385"> </location>
|
||||
<location seat="4" x="588" y="425"> </location>
|
||||
<location seat="5" x="92" y="425"> </location>
|
||||
<location seat="6" x="0" y="373"> </location>
|
||||
<location seat="7" x="0" y="223"> </location>
|
||||
<location seat="8" x="25" y="50"> </location>
|
||||
</layout>
|
||||
<layout fav_seat="0" height="547" max="6" width="794">
|
||||
<location seat="1" x="640" y="58"> </location>
|
||||
<location seat="2" x="654" y="288"> </location>
|
||||
<location seat="3" x="615" y="424"> </location>
|
||||
<location seat="4" x="70" y="421"> </location>
|
||||
<location seat="5" x="0" y="280"> </location>
|
||||
<location seat="6" x="70" y="58"> </location>
|
||||
</layout>
|
||||
<layout fav_seat="0" height="547" max="2" width="794">
|
||||
<location seat="1" x="651" y="288"> </location>
|
||||
<location seat="2" x="10" y="288"> </location>
|
||||
</layout>
|
||||
<layout fav_seat="0" height="547" max="9" width="794">
|
||||
<location seat="1" x="634" y="38"> </location>
|
||||
<location seat="2" x="667" y="184"> </location>
|
||||
<location seat="3" x="667" y="321"> </location>
|
||||
<location seat="4" x="667" y="445"> </location>
|
||||
<location seat="5" x="337" y="459"> </location>
|
||||
<location seat="6" x="0" y="400"> </location>
|
||||
<location seat="7" x="0" y="322"> </location>
|
||||
<location seat="8" x="0" y="181"> </location>
|
||||
<location seat="9" x="70" y="53"> </location>
|
||||
</layout>
|
||||
</site>
|
||||
|
||||
|
||||
<site HH_path="C:/Program Files/Carbon Poker/HandHistory/YOUR SCREEN NAME HERE/" converter="CarbonToFpdb" decoder="everleaf_decode_table" enabled="True" screen_name="YOUR SCREEN NAME HERE" site_name="Carbon" site_path="C:/Program Files/Carbin/" supported_games="holdem" table_finder="Carbon Poker.exe">
|
||||
<layout fav_seat="0" height="547" max="8" width="794">
|
||||
<location seat="1" x="640" y="64"> </location>
|
||||
|
|
@ -493,6 +490,115 @@ Left-Drag to Move"
|
|||
<location seat="9" x="70" y="53"> </location>
|
||||
</layout>
|
||||
</site>
|
||||
|
||||
<site HH_path="C:/Program Files/OnGame Sking/HandHistory/YOUR SCREEN NAME HERE/" converter="OnGameToFpdb" decoder="everleaf_decode_table" enabled="False" screen_name="YOUR SCREEN NAME HERE" site_name="OnGame" site_path="C:/Program Files/OnGame/" supported_games="holdem" table_finder="OnGame.exe">
|
||||
<layout fav_seat="0" height="547" max="8" width="794">
|
||||
<location seat="1" x="640" y="64"> </location>
|
||||
<location seat="2" x="650" y="230"> </location>
|
||||
<location seat="3" x="650" y="385"> </location>
|
||||
<location seat="4" x="588" y="425"> </location>
|
||||
<location seat="5" x="92" y="425"> </location>
|
||||
<location seat="6" x="0" y="373"> </location>
|
||||
<location seat="7" x="0" y="223"> </location>
|
||||
<location seat="8" x="25" y="50"> </location>
|
||||
</layout>
|
||||
<layout fav_seat="0" height="547" max="6" width="794">
|
||||
<location seat="1" x="640" y="58"> </location>
|
||||
<location seat="2" x="654" y="288"> </location>
|
||||
<location seat="3" x="615" y="424"> </location>
|
||||
<location seat="4" x="70" y="421"> </location>
|
||||
<location seat="5" x="0" y="280"> </location>
|
||||
<location seat="6" x="70" y="58"> </location>
|
||||
</layout>
|
||||
<layout fav_seat="0" height="547" max="2" width="794">
|
||||
<location seat="1" x="651" y="288"> </location>
|
||||
<location seat="2" x="10" y="288"> </location>
|
||||
</layout>
|
||||
<layout fav_seat="0" height="547" max="9" width="794">
|
||||
<location seat="1" x="634" y="38"> </location>
|
||||
<location seat="2" x="667" y="184"> </location>
|
||||
<location seat="3" x="667" y="321"> </location>
|
||||
<location seat="4" x="667" y="445"> </location>
|
||||
<location seat="5" x="337" y="459"> </location>
|
||||
<location seat="6" x="0" y="400"> </location>
|
||||
<location seat="7" x="0" y="322"> </location>
|
||||
<location seat="8" x="0" y="181"> </location>
|
||||
<location seat="9" x="70" y="53"> </location>
|
||||
</layout>
|
||||
</site>
|
||||
|
||||
<site HH_path="C:/Program Files/PKR/HandHistory/YOUR SCREEN NAME HERE/" converter="PkrToFpdb" decoder="everleaf_decode_table" enabled="False" screen_name="YOUR SCREEN NAME HERE" site_name="PKR" site_path="C:/Program Files/PKR/" supported_games="holdem" table_finder="PKR.exe">
|
||||
<layout fav_seat="0" height="547" max="8" width="794">
|
||||
<location seat="1" x="640" y="64"> </location>
|
||||
<location seat="2" x="650" y="230"> </location>
|
||||
<location seat="3" x="650" y="385"> </location>
|
||||
<location seat="4" x="588" y="425"> </location>
|
||||
<location seat="5" x="92" y="425"> </location>
|
||||
<location seat="6" x="0" y="373"> </location>
|
||||
<location seat="7" x="0" y="223"> </location>
|
||||
<location seat="8" x="25" y="50"> </location>
|
||||
</layout>
|
||||
<layout fav_seat="0" height="547" max="6" width="794">
|
||||
<location seat="1" x="640" y="58"> </location>
|
||||
<location seat="2" x="654" y="288"> </location>
|
||||
<location seat="3" x="615" y="424"> </location>
|
||||
<location seat="4" x="70" y="421"> </location>
|
||||
<location seat="5" x="0" y="280"> </location>
|
||||
<location seat="6" x="70" y="58"> </location>
|
||||
</layout>
|
||||
<layout fav_seat="0" height="547" max="2" width="794">
|
||||
<location seat="1" x="651" y="288"> </location>
|
||||
<location seat="2" x="10" y="288"> </location>
|
||||
</layout>
|
||||
<layout fav_seat="0" height="547" max="9" width="794">
|
||||
<location seat="1" x="634" y="38"> </location>
|
||||
<location seat="2" x="667" y="184"> </location>
|
||||
<location seat="3" x="667" y="321"> </location>
|
||||
<location seat="4" x="667" y="445"> </location>
|
||||
<location seat="5" x="337" y="459"> </location>
|
||||
<location seat="6" x="0" y="400"> </location>
|
||||
<location seat="7" x="0" y="322"> </location>
|
||||
<location seat="8" x="0" y="181"> </location>
|
||||
<location seat="9" x="70" y="53"> </location>
|
||||
</layout>
|
||||
</site>
|
||||
|
||||
<site HH_path="C:/Program Files/Winamax/HandHistory/YOUR SCREEN NAME HERE/" converter="WinamaxToFpdb" decoder="everleaf_decode_table" enabled="False" screen_name="YOUR SCREEN NAME HERE" site_name="Winamax" site_path="C:/Program Files/Winamax/" supported_games="holdem" table_finder="Winamax.exe">
|
||||
<layout fav_seat="0" height="547" max="8" width="794">
|
||||
<location seat="1" x="640" y="64"> </location>
|
||||
<location seat="2" x="650" y="230"> </location>
|
||||
<location seat="3" x="650" y="385"> </location>
|
||||
<location seat="4" x="588" y="425"> </location>
|
||||
<location seat="5" x="92" y="425"> </location>
|
||||
<location seat="6" x="0" y="373"> </location>
|
||||
<location seat="7" x="0" y="223"> </location>
|
||||
<location seat="8" x="25" y="50"> </location>
|
||||
</layout>
|
||||
<layout fav_seat="0" height="547" max="6" width="794">
|
||||
<location seat="1" x="640" y="58"> </location>
|
||||
<location seat="2" x="654" y="288"> </location>
|
||||
<location seat="3" x="615" y="424"> </location>
|
||||
<location seat="4" x="70" y="421"> </location>
|
||||
<location seat="5" x="0" y="280"> </location>
|
||||
<location seat="6" x="70" y="58"> </location>
|
||||
</layout>
|
||||
<layout fav_seat="0" height="547" max="2" width="794">
|
||||
<location seat="1" x="651" y="288"> </location>
|
||||
<location seat="2" x="10" y="288"> </location>
|
||||
</layout>
|
||||
<layout fav_seat="0" height="547" max="9" width="794">
|
||||
<location seat="1" x="634" y="38"> </location>
|
||||
<location seat="2" x="667" y="184"> </location>
|
||||
<location seat="3" x="667" y="321"> </location>
|
||||
<location seat="4" x="667" y="445"> </location>
|
||||
<location seat="5" x="337" y="459"> </location>
|
||||
<location seat="6" x="0" y="400"> </location>
|
||||
<location seat="7" x="0" y="322"> </location>
|
||||
<location seat="8" x="0" y="181"> </location>
|
||||
<location seat="9" x="70" y="53"> </location>
|
||||
</layout>
|
||||
</site>
|
||||
|
||||
</supported_sites>
|
||||
|
||||
<supported_games>
|
||||
|
|
@ -552,6 +658,43 @@ Left-Drag to Move"
|
|||
<stat click="tog_decorate" col="0" popup="default" row="2" stat_name="saw_f" tip="tip1"> </stat>
|
||||
<stat click="tog_decorate" col="1" popup="default" row="2" stat_name="ffreq1" tip="tip1"> </stat>
|
||||
</game>
|
||||
|
||||
<game cols="3" db="fpdb" game_name="27_3draw" rows="2">
|
||||
<stat click="tog_decorate" col="0" popup="default" row="0" stat_name="vpip" tip="tip1"> </stat>
|
||||
<stat click="tog_decorate" col="1" popup="default" row="0" stat_name="pfr" tip="tip1"> </stat>
|
||||
<stat click="tog_decorate" col="2" popup="default" row="0" stat_name="ffreq1" tip="tip1"> </stat>
|
||||
<stat click="tog_decorate" col="0" popup="default" row="1" stat_name="n" tip="tip1"> </stat>
|
||||
<stat click="tog_decorate" col="1" popup="default" row="1" stat_name="wtsd" tip="tip1"> </stat>
|
||||
<stat click="tog_decorate" col="2" popup="default" row="1" stat_name="wmsd" tip="tip1"> </stat>
|
||||
</game>
|
||||
|
||||
<game cols="3" db="fpdb" game_name="27_1draw" rows="2">
|
||||
<stat click="tog_decorate" col="0" popup="default" row="0" stat_name="vpip" tip="tip1"> </stat>
|
||||
<stat click="tog_decorate" col="1" popup="default" row="0" stat_name="pfr" tip="tip1"> </stat>
|
||||
<stat click="tog_decorate" col="2" popup="default" row="0" stat_name="ffreq1" tip="tip1"> </stat>
|
||||
<stat click="tog_decorate" col="0" popup="default" row="1" stat_name="n" tip="tip1"> </stat>
|
||||
<stat click="tog_decorate" col="1" popup="default" row="1" stat_name="wtsd" tip="tip1"> </stat>
|
||||
<stat click="tog_decorate" col="2" popup="default" row="1" stat_name="wmsd" tip="tip1"> </stat>
|
||||
</game>
|
||||
|
||||
<game cols="3" db="fpdb" game_name="badugi" rows="2">
|
||||
<stat click="tog_decorate" col="0" popup="default" row="0" stat_name="vpip" tip="tip1"> </stat>
|
||||
<stat click="tog_decorate" col="1" popup="default" row="0" stat_name="pfr" tip="tip1"> </stat>
|
||||
<stat click="tog_decorate" col="2" popup="default" row="0" stat_name="ffreq1" tip="tip1"> </stat>
|
||||
<stat click="tog_decorate" col="0" popup="default" row="1" stat_name="n" tip="tip1"> </stat>
|
||||
<stat click="tog_decorate" col="1" popup="default" row="1" stat_name="wtsd" tip="tip1"> </stat>
|
||||
<stat click="tog_decorate" col="2" popup="default" row="1" stat_name="wmsd" tip="tip1"> </stat>
|
||||
</game>
|
||||
|
||||
<game cols="3" db="fpdb" game_name="fivedraw" rows="2">
|
||||
<stat click="tog_decorate" col="0" popup="default" row="0" stat_name="vpip" tip="tip1"> </stat>
|
||||
<stat click="tog_decorate" col="1" popup="default" row="0" stat_name="pfr" tip="tip1"> </stat>
|
||||
<stat click="tog_decorate" col="2" popup="default" row="0" stat_name="ffreq1" tip="tip1"> </stat>
|
||||
<stat click="tog_decorate" col="0" popup="default" row="1" stat_name="n" tip="tip1"> </stat>
|
||||
<stat click="tog_decorate" col="1" popup="default" row="1" stat_name="wtsd" tip="tip1"> </stat>
|
||||
<stat click="tog_decorate" col="2" popup="default" row="1" stat_name="wmsd" tip="tip1"> </stat>
|
||||
</game>
|
||||
|
||||
</supported_games>
|
||||
|
||||
<popup_windows>
|
||||
|
|
@ -559,6 +702,8 @@ Left-Drag to Move"
|
|||
<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="bbper100"> </pu_stat>
|
||||
<pu_stat pu_stat_name="BBper100"> </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>
|
||||
|
|
@ -639,18 +784,21 @@ Left-Drag to Move"
|
|||
<hhc site="Absolute" converter="AbsoluteToFpdb"/>
|
||||
<hhc site="PartyPoker" converter="PartyPokerToFpdb"/>
|
||||
<hhc site="Betfair" converter="BetfairToFpdb"/>
|
||||
<hhc site="Partouche" converter="PartoucheToFpdb"/>
|
||||
<hhc site="Carbon" converter="CarbonToFpdb"/>
|
||||
<hhc site="OnGame" converter="OnGameToFpdb"/>
|
||||
<hhc site="PKR" converter="PkrToFpdb"/>
|
||||
<hhc site="iPoker" converter="iPokerToFpdb"/>
|
||||
<hhc site="Winamax" converter="WinamaxToFpdb"/>
|
||||
</hhcs>
|
||||
|
||||
<raw_hands save="none" compression="none"/>
|
||||
|
||||
<raw_tourneys save="none" compression="none"/>
|
||||
|
||||
<supported_databases>
|
||||
<!-- <database db_name="fpdb" db_server="mysql" db_ip="localhost" db_user="fpdb" db_pass="YOUR MYSQL PASSWORD"></database> -->
|
||||
<database db_ip="localhost" db_server="sqlite" db_name="fpdb.db3" db_user="fpdb" db_pass="fpdb"/>
|
||||
</supported_databases>
|
||||
|
||||
<email>
|
||||
<email siteName="PokerStars" fetchType="request-summary" host="YOUR_EMAIL_SERVER" username="YOUR_EMAIL_USERNAME" password="YOUR_EMAIL_PASSWORD" useSsl="True" folder="INBOX"/>
|
||||
</email>
|
||||
</FreePokerToolsConfig>
|
||||
<!-- IMPORTANT: Please note that fpdb stores your email password in clear text.
|
||||
So do not post a config containing a password on the Internet or anywhere else without removing the password! -->
|
||||
|
|
|
|||
128
pyfpdb/HUD_main.pyw
Executable file → Normal file
128
pyfpdb/HUD_main.pyw
Executable file → Normal file
|
|
@ -60,6 +60,20 @@ elif os.name == 'nt':
|
|||
#import Tables
|
||||
import Hud
|
||||
|
||||
import locale
|
||||
lang = locale.getdefaultlocale()[0][0:2]
|
||||
print "lang:", lang
|
||||
if lang == "en":
|
||||
def _(string):
|
||||
return string
|
||||
else:
|
||||
import gettext
|
||||
try:
|
||||
trans = gettext.translation("fpdb", localedir="locale", languages=[lang])
|
||||
trans.install()
|
||||
except IOError:
|
||||
def _(string):
|
||||
return string
|
||||
|
||||
# get config and set up logger
|
||||
c = Configuration.Config(file=options.config, dbname=options.dbname)
|
||||
|
|
@ -70,48 +84,80 @@ class HUD_main(object):
|
|||
"""A main() object to own both the read_stdin thread and the gui."""
|
||||
# This class mainly provides state for controlling the multiple HUDs.
|
||||
|
||||
def __init__(self, db_name = 'fpdb'):
|
||||
print "\nHUD_main: starting ..."
|
||||
def __init__(self, db_name='fpdb'):
|
||||
print _("\nHUD_main: starting ...")
|
||||
self.db_name = db_name
|
||||
self.config = c
|
||||
print "Logfile is " + os.path.join(self.config.dir_log, 'HUD-log.txt')
|
||||
log.info("HUD_main starting: using db name = %s" % (db_name))
|
||||
print _("Logfile is ") + os.path.join(self.config.dir_log, 'HUD-log.txt')
|
||||
log.info(_("HUD_main starting: using db name = %s") % (db_name))
|
||||
|
||||
try:
|
||||
if not options.errorsToConsole:
|
||||
fileName = os.path.join(self.config.dir_log, 'HUD-errors.txt')
|
||||
print "Note: error output is being diverted to:\n"+fileName \
|
||||
+ "\nAny major error will be reported there _only_.\n"
|
||||
log.info("Note: error output is being diverted to:"+fileName)
|
||||
log.info("Any major error will be reported there _only_.")
|
||||
print _("Note: error output is being diverted to:\n") + fileName \
|
||||
+ _("\nAny major error will be reported there _only_.\n")
|
||||
log.info(_("Note: error output is being diverted to:") + fileName)
|
||||
log.info(_("Any major error will be reported there _only_."))
|
||||
errorFile = open(fileName, 'w', 0)
|
||||
sys.stderr = errorFile
|
||||
sys.stderr.write("HUD_main: starting ...\n")
|
||||
sys.stderr.write(_("HUD_main: starting ...\n"))
|
||||
|
||||
self.hud_dict = {}
|
||||
self.hud_params = self.config.get_hud_ui_parameters()
|
||||
|
||||
# a thread to read stdin
|
||||
gobject.threads_init() # this is required
|
||||
thread.start_new_thread(self.read_stdin, ()) # starts the thread
|
||||
gobject.threads_init() # this is required
|
||||
thread.start_new_thread(self.read_stdin, ()) # starts the thread
|
||||
|
||||
# a main window
|
||||
self.main_window = gtk.Window()
|
||||
self.main_window.connect("client_moved", self.client_moved)
|
||||
self.main_window.connect("client_resized", self.client_resized)
|
||||
self.main_window.connect("client_destroyed", self.client_destroyed)
|
||||
self.main_window.connect("game_changed", self.game_changed)
|
||||
self.main_window.connect("table_changed", self.table_changed)
|
||||
self.main_window.connect("destroy", self.destroy)
|
||||
self.vb = gtk.VBox()
|
||||
self.label = gtk.Label('Closing this window will exit from the HUD.')
|
||||
self.label = gtk.Label(_('Closing this window will exit from the HUD.'))
|
||||
self.vb.add(self.label)
|
||||
self.main_window.add(self.vb)
|
||||
self.main_window.set_title("HUD Main Window")
|
||||
self.main_window.set_title(_("HUD Main Window"))
|
||||
cards = os.path.join(os.getcwd(), '..','gfx','fpdb-cards.png')
|
||||
if os.path.exists(cards):
|
||||
self.main_window.set_icon_from_file(cards)
|
||||
elif os.path.exists('/usr/share/pixmaps/fpdb-cards.png'):
|
||||
self.main_window.set_icon_from_file('/usr/share/pixmaps/fpdb-cards.png')
|
||||
else:
|
||||
self.main_window.set_icon_stock(gtk.STOCK_HOME)
|
||||
self.main_window.show_all()
|
||||
gobject.timeout_add(100, self.check_tables)
|
||||
|
||||
except:
|
||||
log.error( "*** Exception in HUD_main.init() *** " )
|
||||
log.error("*** Exception in HUD_main.init() *** ")
|
||||
for e in traceback.format_tb(sys.exc_info()[2]):
|
||||
log.error(e)
|
||||
|
||||
def client_moved(self, widget, hud):
|
||||
print "hud_main: client moved"
|
||||
print hud, hud.table.name, "moved", hud.table.x, hud.table.y
|
||||
|
||||
def client_resized(self, widget, hud):
|
||||
print _("hud_main: Client resized")
|
||||
print hud, hud.table.name, hud.table.x, hud.table.y
|
||||
|
||||
def client_destroyed(self, widget, hud): # call back for terminating the main eventloop
|
||||
print _("hud_main: Client destroyed")
|
||||
self.kill_hud(None, hud.table.name)
|
||||
|
||||
def game_changed(self, widget, hud):
|
||||
print _("hud_main: Game changed.")
|
||||
|
||||
def table_changed(self, widget, hud):
|
||||
print _("hud_main: Table changed.")
|
||||
self.kill_hud(None, hud.table.name)
|
||||
|
||||
def destroy(self, *args): # call back for terminating the main eventloop
|
||||
log.info("Terminating normally.")
|
||||
log.info(_("Terminating normally."))
|
||||
gtk.main_quit()
|
||||
|
||||
def kill_hud(self, event, table):
|
||||
|
|
@ -121,7 +167,12 @@ class HUD_main(object):
|
|||
self.hud_dict[table].main_window.destroy()
|
||||
self.vb.remove(self.hud_dict[table].tablehudlabel)
|
||||
del(self.hud_dict[table])
|
||||
self.main_window.resize(1,1)
|
||||
self.main_window.resize(1, 1)
|
||||
|
||||
def check_tables(self):
|
||||
for hud in self.hud_dict.keys():
|
||||
self.hud_dict[hud].table.check_table(self.hud_dict[hud])
|
||||
return True
|
||||
|
||||
def create_HUD(self, new_hand_id, table, table_name, max, poker_game, type, stat_dict, cards):
|
||||
"""type is "ring" or "tour" used to set hud_params"""
|
||||
|
|
@ -144,7 +195,7 @@ class HUD_main(object):
|
|||
self.hud_dict[table_name].update(new_hand_id, self.config)
|
||||
self.hud_dict[table_name].reposition_windows()
|
||||
except:
|
||||
log.error( "*** Exception in HUD_main::idle_func() *** " + str(sys.exc_info()) )
|
||||
log.error("*** Exception in HUD_main::idle_func() *** " + str(sys.exc_info()))
|
||||
for e in traceback.format_tb(sys.exc_info()[2]):
|
||||
log.error(e)
|
||||
finally:
|
||||
|
|
@ -210,12 +261,12 @@ class HUD_main(object):
|
|||
self.hero, self.hero_ids = {}, {}
|
||||
found = False
|
||||
|
||||
while 1: # wait for a new hand number on stdin
|
||||
while 1: # wait for a new hand number on stdin
|
||||
new_hand_id = sys.stdin.readline()
|
||||
t0 = time.time()
|
||||
t1 = t2 = t3 = t4 = t5 = t6 = t0
|
||||
new_hand_id = string.rstrip(new_hand_id)
|
||||
log.debug("Received hand no %s" % new_hand_id)
|
||||
log.debug(_("Received hand no %s") % new_hand_id)
|
||||
if new_hand_id == "": # blank line means quit
|
||||
self.destroy()
|
||||
break # this thread is not always killed immediately with gtk.main_quit()
|
||||
|
|
@ -234,12 +285,12 @@ class HUD_main(object):
|
|||
|
||||
# get basic info about the new hand from the db
|
||||
# if there is a db error, complain, skip hand, and proceed
|
||||
log.info("HUD_main.read_stdin: hand processing starting ...")
|
||||
log.info(_("HUD_main.read_stdin: hand processing starting ..."))
|
||||
try:
|
||||
(table_name, max, poker_game, type, site_id, site_name, num_seats, tour_number, tab_number) = \
|
||||
self.db_connection.get_table_info(new_hand_id)
|
||||
except Exception:
|
||||
log.error("db error: skipping %s" % new_hand_id)
|
||||
log.error(_("db error: skipping %s" % new_hand_id))
|
||||
continue
|
||||
t1 = time.time()
|
||||
|
||||
|
|
@ -254,18 +305,19 @@ class HUD_main(object):
|
|||
self.db_connection.init_hud_stat_vars( self.hud_dict[temp_key].hud_params['hud_days']
|
||||
, self.hud_dict[temp_key].hud_params['h_hud_days'])
|
||||
t2 = time.time()
|
||||
stat_dict = self.db_connection.get_stats_from_hand(new_hand_id, type, self.hud_dict[temp_key].hud_params
|
||||
,self.hero_ids[site_id], num_seats)
|
||||
stat_dict = self.db_connection.get_stats_from_hand(new_hand_id, type, self.hud_dict[temp_key].hud_params,
|
||||
self.hero_ids[site_id], num_seats)
|
||||
t3 = time.time()
|
||||
|
||||
try:
|
||||
self.hud_dict[temp_key].stat_dict = stat_dict
|
||||
except KeyError: # HUD instance has been killed off, key is stale
|
||||
log.error('hud_dict[%s] was not found\n' % temp_key)
|
||||
log.error('will not send hand\n')
|
||||
log.error(_('hud_dict[%s] was not found\n') % temp_key)
|
||||
log.error(_('will not send hand\n'))
|
||||
# Unlocks table, copied from end of function
|
||||
self.db_connection.connection.rollback()
|
||||
return
|
||||
cards = self.db_connection.get_cards(new_hand_id)
|
||||
cards = self.db_connection.get_cards(new_hand_id)
|
||||
t4 = time.time()
|
||||
comm_cards = self.db_connection.get_common_cards(new_hand_id)
|
||||
t5 = time.time()
|
||||
|
|
@ -279,24 +331,20 @@ class HUD_main(object):
|
|||
else:
|
||||
# get stats using default params--also get cards
|
||||
self.db_connection.init_hud_stat_vars( self.hud_params['hud_days'], self.hud_params['h_hud_days'] )
|
||||
stat_dict = self.db_connection.get_stats_from_hand(new_hand_id, type, self.hud_params
|
||||
,self.hero_ids[site_id], num_seats)
|
||||
stat_dict = self.db_connection.get_stats_from_hand(new_hand_id, type, self.hud_params,
|
||||
self.hero_ids[site_id], num_seats)
|
||||
cards = self.db_connection.get_cards(new_hand_id)
|
||||
comm_cards = self.db_connection.get_common_cards(new_hand_id)
|
||||
if comm_cards != {}: # stud!
|
||||
cards['common'] = comm_cards['common']
|
||||
|
||||
table_kwargs = dict(table_name = table_name, tournament = tour_number, table_number = tab_number)
|
||||
search_string = getTableTitleRe(self.config, site_name, type, **table_kwargs)
|
||||
# print "getTableTitleRe ", self.config, site_name, type, "=", search_string
|
||||
tablewindow = Tables.Table(search_string, **table_kwargs)
|
||||
|
||||
table_kwargs = dict(table_name=table_name, tournament=tour_number, table_number=tab_number)
|
||||
tablewindow = Tables.Table(self.config, site_name, **table_kwargs)
|
||||
if tablewindow is None:
|
||||
# If no client window is found on the screen, complain and continue
|
||||
if type == "tour":
|
||||
table_name = "%s %s" % (tour_number, tab_number)
|
||||
# log.error("HUD create: table name "+table_name+" not found, skipping.\n")
|
||||
log.error("HUD create: table name %s not found, skipping." % table_name)
|
||||
log.error(_("HUD create: table name %s not found, skipping.") % table_name)
|
||||
else:
|
||||
tablewindow.max = max
|
||||
tablewindow.site = site_name
|
||||
|
|
@ -304,13 +352,15 @@ class HUD_main(object):
|
|||
if hasattr(tablewindow, 'number'):
|
||||
self.create_HUD(new_hand_id, tablewindow, temp_key, max, poker_game, type, stat_dict, cards)
|
||||
else:
|
||||
log.error('Table "%s" no longer exists\n' % table_name)
|
||||
log.error(_('Table "%s" no longer exists\n') % table_name)
|
||||
|
||||
t6 = time.time()
|
||||
log.info("HUD_main.read_stdin: hand read in %4.3f seconds (%4.3f,%4.3f,%4.3f,%4.3f,%4.3f,%4.3f)"
|
||||
% (t6-t0,t1-t0,t2-t0,t3-t0,t4-t0,t5-t0,t6-t0))
|
||||
log.info(_("HUD_main.read_stdin: hand read in %4.3f seconds (%4.3f,%4.3f,%4.3f,%4.3f,%4.3f,%4.3f)")
|
||||
% (t6 - t0,t1 - t0,t2 - t0,t3 - t0,t4 - t0,t5 - t0,t6 - t0))
|
||||
self.db_connection.connection.rollback()
|
||||
|
||||
if type == "tour":
|
||||
tablewindow.check_table_no(None)
|
||||
# Ray!! tablewindow::check_table_no expects a HUD as an argument!
|
||||
if __name__== "__main__":
|
||||
|
||||
# start the HUD_main object
|
||||
|
|
|
|||
|
|
@ -42,13 +42,13 @@ def destroy(*args): # call back for terminating the main eventloop
|
|||
|
||||
|
||||
if __name__== "__main__":
|
||||
sys.stderr.write("HUD_main starting\n")
|
||||
sys.stderr.write(_("HUD_main starting\n"))
|
||||
|
||||
try:
|
||||
HUD_main.db_name = sys.argv[1]
|
||||
except:
|
||||
HUD_main.db_name = 'fpdb'
|
||||
sys.stderr.write("Using db name = %s\n" % (HUD_main.db_name))
|
||||
sys.stderr.write(_("Using db name = %s\n") % (HUD_main.db_name))
|
||||
|
||||
HUD_main.config = Configuration.Config()
|
||||
|
||||
|
|
@ -59,11 +59,11 @@ if __name__== "__main__":
|
|||
HUD_main.main_window = gtk.Window()
|
||||
HUD_main.main_window.connect("destroy", destroy)
|
||||
HUD_main.eb = gtk.VBox()
|
||||
label = gtk.Label('Closing this window will exit from the HUD.')
|
||||
label = gtk.Label(_('Closing this window will exit from the HUD.'))
|
||||
HUD_main.eb.add(label)
|
||||
HUD_main.main_window.add(HUD_main.eb)
|
||||
|
||||
HUD_main.main_window.set_title("HUD Main Window")
|
||||
HUD_main.main_window.set_title(_("HUD Main Window"))
|
||||
HUD_main.main_window.show_all()
|
||||
|
||||
gtk.main()
|
||||
|
|
|
|||
506
pyfpdb/Hand.py
506
pyfpdb/Hand.py
|
|
@ -15,6 +15,9 @@
|
|||
#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 L10n
|
||||
_ = L10n.get_translation()
|
||||
|
||||
# TODO: get writehand() encoding correct
|
||||
|
||||
import re
|
||||
|
|
@ -44,16 +47,19 @@ class Hand(object):
|
|||
# Class Variables
|
||||
UPS = {'a':'A', 't':'T', 'j':'J', 'q':'Q', 'k':'K', 'S':'s', 'C':'c', 'H':'h', 'D':'d'}
|
||||
LCS = {'H':'h', 'D':'d', 'C':'c', 'S':'s'}
|
||||
SYMBOL = {'USD': '$', 'EUR': u'$', 'T$': '', 'play': ''}
|
||||
SYMBOL = {'USD': '$', 'EUR': u'$', 'GBP': '$', 'T$': '', 'play': ''}
|
||||
MS = {'horse' : 'HORSE', '8game' : '8-Game', 'hose' : 'HOSE', 'ha': 'HA'}
|
||||
SITEIDS = {'Fulltilt':1, 'PokerStars':2, 'Everleaf':3, 'Win2day':4, 'OnGame':5, 'UltimateBet':6, 'Betfair':7, 'Absolute':8, 'PartyPoker':9, 'Partouche':10, 'Carbon':11 }
|
||||
ACTION = {'ante': 1, 'small blind': 2, 'secondsb': 3, 'big blind': 4, 'both': 5, 'calls': 6, 'raises': 7,
|
||||
'bets': 8, 'stands pat': 9, 'folds': 10, 'checks': 11, 'discards': 12, 'bringin': 13, 'completes': 14}
|
||||
|
||||
|
||||
def __init__(self, config, sitename, gametype, handText, builtFrom = "HHC"):
|
||||
#log.debug( _("Hand.init(): handText is ") + str(handText) )
|
||||
self.config = config
|
||||
self.saveActions = self.config.get_import_parameters().get('saveActions')
|
||||
#log = Configuration.get_logger("logging.conf", "db", log_dir=self.config.dir_log)
|
||||
self.sitename = sitename
|
||||
self.siteId = self.SITEIDS[sitename]
|
||||
self.siteId = self.config.get_site_id(sitename)
|
||||
self.stats = DerivedStats.DerivedStats(self)
|
||||
self.gametype = gametype
|
||||
self.startTime = 0
|
||||
|
|
@ -62,6 +68,7 @@ class Hand(object):
|
|||
self.cancelled = False
|
||||
self.dbid_hands = 0
|
||||
self.dbid_pids = None
|
||||
self.dbid_hpid = None
|
||||
self.dbid_gt = 0
|
||||
self.tablename = ""
|
||||
self.hero = ""
|
||||
|
|
@ -79,13 +86,13 @@ class Hand(object):
|
|||
self.fee = None # the Database code is looking for this one .. ?
|
||||
self.level = None
|
||||
self.mixed = None
|
||||
self.speed = None
|
||||
self.isRebuy = None
|
||||
self.isAddOn = None
|
||||
self.isKO = None
|
||||
self.speed = "Normal"
|
||||
self.isRebuy = False
|
||||
self.isAddOn = False
|
||||
self.isKO = False
|
||||
self.koBounty = None
|
||||
self.isMatrix = None
|
||||
self.isShootout = None
|
||||
self.isMatrix = False
|
||||
self.isShootout = False
|
||||
self.added = None
|
||||
self.addedCurrency = None
|
||||
self.tourneyComment = None
|
||||
|
|
@ -135,59 +142,59 @@ class Hand(object):
|
|||
self.is_duplicate = False # i.e. don't update hudcache if true
|
||||
|
||||
def __str__(self):
|
||||
vars = ( ("BB", self.bb),
|
||||
("SB", self.sb),
|
||||
("BUTTONPOS", self.buttonpos),
|
||||
("HAND NO.", self.handid),
|
||||
("SITE", self.sitename),
|
||||
("TABLE NAME", self.tablename),
|
||||
("HERO", self.hero),
|
||||
("MAXSEATS", self.maxseats),
|
||||
("LEVEL", self.level),
|
||||
("MIXED", self.mixed),
|
||||
("LASTBET", self.lastBet),
|
||||
("ACTION STREETS", self.actionStreets),
|
||||
("STREETS", self.streets),
|
||||
("ALL STREETS", self.allStreets),
|
||||
("COMMUNITY STREETS", self.communityStreets),
|
||||
("HOLE STREETS", self.holeStreets),
|
||||
("COUNTED SEATS", self.counted_seats),
|
||||
("DEALT", self.dealt),
|
||||
("SHOWN", self.shown),
|
||||
("MUCKED", self.mucked),
|
||||
("TOTAL POT", self.totalpot),
|
||||
("TOTAL COLLECTED", self.totalcollected),
|
||||
("RAKE", self.rake),
|
||||
("START TIME", self.startTime),
|
||||
("TOURNAMENT NO", self.tourNo),
|
||||
("TOURNEY ID", self.tourneyId),
|
||||
("TOURNEY TYPE ID", self.tourneyTypeId),
|
||||
("BUYIN", self.buyin),
|
||||
("BUYIN CURRENCY", self.buyinCurrency),
|
||||
("BUYIN CHIPS", self.buyInChips),
|
||||
("FEE", self.fee),
|
||||
("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),
|
||||
vars = ( (_("BB"), self.bb),
|
||||
(_("SB"), self.sb),
|
||||
(_("BUTTONPOS"), self.buttonpos),
|
||||
(_("HAND NO."), self.handid),
|
||||
(_("SITE"), self.sitename),
|
||||
(_("TABLE NAME"), self.tablename),
|
||||
(_("HERO"), self.hero),
|
||||
(_("MAXSEATS"), self.maxseats),
|
||||
(_("LEVEL"), self.level),
|
||||
(_("MIXED"), self.mixed),
|
||||
(_("LASTBET"), self.lastBet),
|
||||
(_("ACTION STREETS"), self.actionStreets),
|
||||
(_("STREETS"), self.streets),
|
||||
(_("ALL STREETS"), self.allStreets),
|
||||
(_("COMMUNITY STREETS"), self.communityStreets),
|
||||
(_("HOLE STREETS"), self.holeStreets),
|
||||
(_("COUNTED SEATS"), self.counted_seats),
|
||||
(_("DEALT"), self.dealt),
|
||||
(_("SHOWN"), self.shown),
|
||||
(_("MUCKED"), self.mucked),
|
||||
(_("TOTAL POT"), self.totalpot),
|
||||
(_("TOTAL COLLECTED"), self.totalcollected),
|
||||
(_("RAKE"), self.rake),
|
||||
(_("START TIME"), self.startTime),
|
||||
(_("TOURNAMENT NO"), self.tourNo),
|
||||
(_("TOURNEY ID"), self.tourneyId),
|
||||
(_("TOURNEY TYPE ID"), self.tourneyTypeId),
|
||||
(_("BUYIN"), self.buyin),
|
||||
(_("BUYIN CURRENCY"), self.buyinCurrency),
|
||||
(_("BUYIN CHIPS"), self.buyInChips),
|
||||
(_("FEE"), self.fee),
|
||||
(_("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),
|
||||
)
|
||||
|
||||
structs = ( ("PLAYERS", self.players),
|
||||
("STACKS", self.stacks),
|
||||
("POSTED", self.posted),
|
||||
("POT", self.pot),
|
||||
("SEATING", self.seating),
|
||||
("GAMETYPE", self.gametype),
|
||||
("ACTION", self.actions),
|
||||
("COLLECTEES", self.collectees),
|
||||
("BETS", self.bets),
|
||||
("BOARD", self.board),
|
||||
("DISCARDS", self.discards),
|
||||
("HOLECARDS", self.holecards),
|
||||
("TOURNEYS PLAYER IDS", self.tourneysPlayersIds),
|
||||
structs = ( (_("PLAYERS"), self.players),
|
||||
(_("STACKS"), self.stacks),
|
||||
(_("POSTED"), self.posted),
|
||||
(_("POT"), self.pot),
|
||||
(_("SEATING"), self.seating),
|
||||
(_("GAMETYPE"), self.gametype),
|
||||
(_("ACTION"), self.actions),
|
||||
(_("COLLECTEES"), self.collectees),
|
||||
(_("BETS"), self.bets),
|
||||
(_("BOARD"), self.board),
|
||||
(_("DISCARDS"), self.discards),
|
||||
(_("HOLECARDS"), self.holecards),
|
||||
(_("TOURNEYS PLAYER IDS"), self.tourneysPlayersIds),
|
||||
)
|
||||
str = ''
|
||||
for (name, var) in vars:
|
||||
|
|
@ -210,7 +217,7 @@ dealt whether they were seen in a 'dealt to' line
|
|||
try:
|
||||
self.checkPlayerExists(player)
|
||||
except FpdbParseError, e:
|
||||
print "[ERROR] Tried to add holecards for unknown player: %s" % (player,)
|
||||
print _("[ERROR] Tried to add holecards for unknown player: %s") % (player,)
|
||||
return
|
||||
|
||||
if dealt: self.dealt.add(player)
|
||||
|
|
@ -239,7 +246,7 @@ dealt whether they were seen in a 'dealt to' line
|
|||
db.commit()
|
||||
#end def prepInsert
|
||||
|
||||
def insert(self, db):
|
||||
def insert(self, db, printtest = False):
|
||||
""" Function to insert Hand into database
|
||||
Should not commit, and do minimal selects. Callers may want to cache commits
|
||||
db: a connected Database object"""
|
||||
|
|
@ -259,11 +266,13 @@ db: a connected Database object"""
|
|||
hh['seats'] = len(self.dbid_pids)
|
||||
|
||||
self.dbid_hands = db.storeHand(hh)
|
||||
db.storeHandsPlayers(self.dbid_hands, self.dbid_pids, self.stats.getHandsPlayers())
|
||||
# TODO HandsActions - all actions for all players for all streets - self.actions
|
||||
# HudCache data can be generated from HandsActions (HandsPlayers?)
|
||||
self.dbid_hpid = db.storeHandsPlayers(self.dbid_hands, self.dbid_pids,
|
||||
self.stats.getHandsPlayers(), printdata = printtest)
|
||||
if self.saveActions:
|
||||
db.storeHandsActions(self.dbid_hands, self.dbid_pids, self.dbid_hpid,
|
||||
self.stats.getHandsActions(), printdata = printtest)
|
||||
else:
|
||||
log.info("Hand.insert(): hid #: %s is a duplicate" % hh['siteHandNo'])
|
||||
log.info(_("Hand.insert(): hid #: %s is a duplicate") % hh['siteHandNo'])
|
||||
self.is_duplicate = True # i.e. don't update hudcache
|
||||
raise FpdbHandDuplicate(hh['siteHandNo'])
|
||||
|
||||
|
|
@ -272,9 +281,143 @@ db: a connected Database object"""
|
|||
|
||||
def select(self, handId):
|
||||
""" Function to create Hand object from database """
|
||||
c = cnxn.cursor()
|
||||
|
||||
# We need at least sitename, gametype, handid
|
||||
# for the Hand.__init__
|
||||
c.execute("""SELECT
|
||||
s.name,
|
||||
g.category,
|
||||
g.base,
|
||||
g.type,
|
||||
g.limitType,
|
||||
g.hilo,
|
||||
round(g.smallBlind / 100.0,2),
|
||||
round(g.bigBlind / 100.0,2),
|
||||
round(g.smallBet / 100.0,2),
|
||||
round(g.bigBet / 100.0,2),
|
||||
s.currency,
|
||||
h.boardcard1,
|
||||
h.boardcard2,
|
||||
h.boardcard3,
|
||||
h.boardcard4,
|
||||
h.boardcard5
|
||||
FROM
|
||||
hands as h,
|
||||
sites as s,
|
||||
gametypes as g,
|
||||
handsplayers as hp,
|
||||
players as p
|
||||
WHERE
|
||||
h.id = %(handid)s
|
||||
and g.id = h.gametypeid
|
||||
and hp.handid = h.id
|
||||
and p.id = hp.playerid
|
||||
and s.id = p.siteid
|
||||
limit 1""", {'handid':handid})
|
||||
#TODO: siteid should be in hands table - we took the scenic route through players here.
|
||||
res = c.fetchone()
|
||||
gametype = {'category':res[1],'base':res[2],'type':res[3],'limitType':res[4],'hilo':res[5],'sb':res[6],'bb':res[7], 'currency':res[10]}
|
||||
c = Configuration.Config()
|
||||
h = HoldemOmahaHand(config = c, hhc = None, sitename=res[0], gametype = gametype, handText=None, builtFrom = "DB", handid=handid)
|
||||
cards = map(Card.valueSuitFromCard, res[11:16] )
|
||||
if cards[0]:
|
||||
h.setCommunityCards('FLOP', cards[0:3])
|
||||
if cards[3]:
|
||||
h.setCommunityCards('TURN', [cards[3]])
|
||||
if cards[4]:
|
||||
h.setCommunityCards('RIVER', [cards[4]])
|
||||
#[Card.valueSuitFromCard(x) for x in cards]
|
||||
|
||||
# HandInfo : HID, TABLE
|
||||
# BUTTON - why is this treated specially in Hand?
|
||||
# answer: it is written out in hand histories
|
||||
# still, I think we should record all the active seat positions in a seat_order array
|
||||
c.execute("""SELECT
|
||||
h.sitehandno as hid,
|
||||
h.tablename as table,
|
||||
h.startTime as startTime
|
||||
FROM
|
||||
hands as h
|
||||
WHERE h.id = %(handid)s
|
||||
""", {'handid':handid})
|
||||
res = c.fetchone()
|
||||
h.handid = res[0]
|
||||
h.tablename = res[1]
|
||||
h.startTime = res[2] # automatically a datetime
|
||||
|
||||
# PlayerStacks
|
||||
c.execute("""SELECT
|
||||
hp.seatno,
|
||||
round(hp.winnings / 100.0,2) as winnings,
|
||||
p.name,
|
||||
round(hp.startcash / 100.0,2) as chips,
|
||||
hp.card1,hp.card2,
|
||||
hp.position
|
||||
FROM
|
||||
handsplayers as hp,
|
||||
players as p
|
||||
WHERE
|
||||
hp.handid = %(handid)s
|
||||
and p.id = hp.playerid
|
||||
""", {'handid':handid})
|
||||
for (seat, winnings, name, chips, card1,card2, position) in c.fetchall():
|
||||
h.addPlayer(seat,name,chips)
|
||||
if card1 and card2:
|
||||
h.addHoleCards(map(Card.valueSuitFromCard, (card1,card2)), name, dealt=True)
|
||||
if winnings > 0:
|
||||
h.addCollectPot(name, winnings)
|
||||
if position == 'B':
|
||||
h.buttonpos = seat
|
||||
|
||||
|
||||
# actions
|
||||
c.execute("""SELECT
|
||||
(ha.street,ha.actionno) as actnum,
|
||||
p.name,
|
||||
ha.street,
|
||||
ha.action,
|
||||
ha.allin,
|
||||
round(ha.amount / 100.0,2)
|
||||
FROM
|
||||
handsplayers as hp,
|
||||
handsactions as ha,
|
||||
players as p
|
||||
WHERE
|
||||
hp.handid = %(handid)s
|
||||
and ha.handsplayerid = hp.id
|
||||
and p.id = hp.playerid
|
||||
ORDER BY
|
||||
ha.street,ha.actionno
|
||||
""", {'handid':handid})
|
||||
res = c.fetchall()
|
||||
for (actnum,player, streetnum, act, allin, amount) in res:
|
||||
act=act.strip()
|
||||
street = h.allStreets[streetnum+1]
|
||||
if act==u'blind':
|
||||
h.addBlind(player, 'big blind', amount)
|
||||
# TODO: The type of blind is not recorded in the DB.
|
||||
# TODO: preflop street name anomalies in Hand
|
||||
elif act==u'fold':
|
||||
h.addFold(street,player)
|
||||
elif act==u'call':
|
||||
h.addCall(street,player,amount)
|
||||
elif act==u'bet':
|
||||
h.addBet(street,player,amount)
|
||||
elif act==u'check':
|
||||
h.addCheck(street,player)
|
||||
elif act==u'unbet':
|
||||
pass
|
||||
else:
|
||||
print act, player, streetnum, allin, amount
|
||||
# TODO : other actions
|
||||
|
||||
#hhc.readShowdownActions(self)
|
||||
#hc.readShownCards(self)
|
||||
h.totalPot()
|
||||
h.rake = h.totalpot - h.totalcollected
|
||||
|
||||
return h
|
||||
|
||||
def addPlayer(self, seat, name, chips):
|
||||
"""\
|
||||
|
|
@ -302,17 +445,14 @@ If a player has None chips he won't be added."""
|
|||
log.debug("markStreets:\n"+ str(self.streets))
|
||||
else:
|
||||
tmp = self.handText[0:100]
|
||||
log.error("markstreets didn't match")
|
||||
log.error(" - Assuming hand cancelled")
|
||||
log.error(_("markstreets didn't match - Assuming hand %s was cancelled") % self.handid)
|
||||
self.cancelled = True
|
||||
raise FpdbParseError("FpdbParseError: markStreets appeared to fail: First 100 chars: '%s'" % tmp)
|
||||
raise FpdbParseError(_("FpdbParseError: markStreets appeared to fail: First 100 chars: '%s'") % tmp)
|
||||
|
||||
def checkPlayerExists(self,player):
|
||||
if player not in [p[1] for p in self.players]:
|
||||
print "DEBUG: checkPlayerExists %s fail" % player
|
||||
raise FpdbParseError("checkPlayerExists: '%s' failed." % player)
|
||||
|
||||
|
||||
print (_("DEBUG: checkPlayerExists %s fail on hand number %s") % (player, self.handid))
|
||||
raise FpdbParseError(_("checkPlayerExists: '%s fail on hand number %s") % (player, self.handid))
|
||||
|
||||
def setCommunityCards(self, street, cards):
|
||||
log.debug("setCommunityCards %s %s" %(street, cards))
|
||||
|
|
@ -349,7 +489,7 @@ For sites (currently only Carbon Poker) which record "all in" as a special actio
|
|||
ante = re.sub(u',', u'', ante) #some sites have commas
|
||||
self.bets['BLINDSANTES'][player].append(Decimal(ante))
|
||||
self.stacks[player] -= Decimal(ante)
|
||||
act = (player, 'posts', "ante", ante, self.stacks[player]==0)
|
||||
act = (player, 'ante', Decimal(ante), self.stacks[player]==0)
|
||||
self.actions['BLINDSANTES'].append(act)
|
||||
# self.pot.addMoney(player, Decimal(ante))
|
||||
self.pot.addCommonMoney(player, Decimal(ante))
|
||||
|
|
@ -368,7 +508,7 @@ For sites (currently only Carbon Poker) which record "all in" as a special actio
|
|||
if player is not None:
|
||||
amount = re.sub(u',', u'', amount) #some sites have commas
|
||||
self.stacks[player] -= Decimal(amount)
|
||||
act = (player, 'posts', blindtype, amount, self.stacks[player]==0)
|
||||
act = (player, blindtype, Decimal(amount), self.stacks[player]==0)
|
||||
self.actions['BLINDSANTES'].append(act)
|
||||
|
||||
if blindtype == 'both':
|
||||
|
|
@ -393,7 +533,7 @@ For sites (currently only Carbon Poker) which record "all in" as a special actio
|
|||
def addCall(self, street, player=None, amount=None):
|
||||
if amount:
|
||||
amount = re.sub(u',', u'', amount) #some sites have commas
|
||||
log.debug("%s %s calls %s" %(street, player, amount))
|
||||
log.debug(_("%s %s calls %s") %(street, player, amount))
|
||||
# Potentially calculate the amount of the call if not supplied
|
||||
# corner cases include if player would be all in
|
||||
if amount is not None:
|
||||
|
|
@ -401,7 +541,7 @@ For sites (currently only Carbon Poker) which record "all in" as a special actio
|
|||
#self.lastBet[street] = Decimal(amount)
|
||||
self.stacks[player] -= Decimal(amount)
|
||||
#print "DEBUG %s calls %s, stack %s" % (player, amount, self.stacks[player])
|
||||
act = (player, 'calls', amount, self.stacks[player]==0)
|
||||
act = (player, 'calls', Decimal(amount), self.stacks[player]==0)
|
||||
self.actions[street].append(act)
|
||||
self.pot.addMoney(player, Decimal(amount))
|
||||
|
||||
|
|
@ -462,11 +602,11 @@ Add a raise on [street] by [player] to [amountTo]
|
|||
Rb = Rt - C - Bc
|
||||
self._addRaise(street, player, C, Rb, Rt)
|
||||
|
||||
def _addRaise(self, street, player, C, Rb, Rt):
|
||||
log.debug("%s %s raise %s" %(street, player, Rt))
|
||||
def _addRaise(self, street, player, C, Rb, Rt, action = 'raises'):
|
||||
log.debug(_("%s %s raise %s") %(street, player, Rt))
|
||||
self.bets[street][player].append(C + Rb)
|
||||
self.stacks[player] -= (C + Rb)
|
||||
act = (player, 'raises', Rb, Rt, C, self.stacks[player]==0)
|
||||
act = (player, action, Rb, Rt, C, self.stacks[player]==0)
|
||||
self.actions[street].append(act)
|
||||
self.lastBet[street] = Rt # TODO check this is correct
|
||||
self.pot.addMoney(player, C+Rb)
|
||||
|
|
@ -474,13 +614,13 @@ Add a raise on [street] by [player] to [amountTo]
|
|||
|
||||
|
||||
def addBet(self, street, player, amount):
|
||||
log.debug("%s %s bets %s" %(street, player, amount))
|
||||
log.debug(_("%s %s bets %s") %(street, player, amount))
|
||||
amount = re.sub(u',', u'', amount) #some sites have commas
|
||||
self.checkPlayerExists(player)
|
||||
self.bets[street][player].append(Decimal(amount))
|
||||
self.stacks[player] -= Decimal(amount)
|
||||
#print "DEBUG %s bets %s, stack %s" % (player, amount, self.stacks[player])
|
||||
act = (player, 'bets', amount, self.stacks[player]==0)
|
||||
act = (player, 'bets', Decimal(amount), self.stacks[player]==0)
|
||||
self.actions[street].append(act)
|
||||
self.lastBet[street] = Decimal(amount)
|
||||
self.pot.addMoney(player, Decimal(amount))
|
||||
|
|
@ -493,7 +633,7 @@ Add a raise on [street] by [player] to [amountTo]
|
|||
|
||||
|
||||
def addFold(self, street, player):
|
||||
log.debug("%s %s folds" % (street, player))
|
||||
log.debug(_("%s %s folds") % (street, player))
|
||||
self.checkPlayerExists(player)
|
||||
self.folded.add(player)
|
||||
self.pot.addFold(player)
|
||||
|
|
@ -502,7 +642,7 @@ Add a raise on [street] by [player] to [amountTo]
|
|||
|
||||
def addCheck(self, street, player):
|
||||
#print "DEBUG: %s %s checked" % (street, player)
|
||||
logging.debug("%s %s checks" % (street, player))
|
||||
logging.debug(_("%s %s checks") % (street, player))
|
||||
self.checkPlayerExists(player)
|
||||
self.actions[street].append((player, 'checks'))
|
||||
|
||||
|
|
@ -522,7 +662,7 @@ Add a raise on [street] by [player] to [amountTo]
|
|||
For when a player shows cards for any reason (for showdown or out of choice).
|
||||
Card ranks will be uppercased
|
||||
"""
|
||||
log.debug("addShownCards %s hole=%s all=%s" % (player, cards, holeandboard))
|
||||
log.debug(_("addShownCards %s hole=%s all=%s") % (player, cards, holeandboard))
|
||||
if cards is not None:
|
||||
self.addHoleCards(cards,player,shown, mucked)
|
||||
elif holeandboard is not None:
|
||||
|
|
@ -633,9 +773,9 @@ Map the tuple self.gametype onto the pokerstars string describing it
|
|||
try:
|
||||
timestr = datetime.datetime.strftime(self.startTime, '%Y/%m/%d %H:%M:%S ET')
|
||||
except TypeError:
|
||||
print "*** ERROR - HAND: calling writeGameLine with unexpected STARTTIME value, expecting datetime.date object, received:", self.startTime
|
||||
print "*** Make sure your HandHistoryConverter is setting hand.startTime properly!"
|
||||
print "*** Game String:", gs
|
||||
print _("*** ERROR - HAND: calling writeGameLine with unexpected STARTTIME value, expecting datetime.date object, received:"), self.startTime
|
||||
print _("*** Make sure your HandHistoryConverter is setting hand.startTime properly!")
|
||||
print _("*** Game String:"), gs
|
||||
return gs
|
||||
else:
|
||||
return gs + timestr
|
||||
|
|
@ -683,9 +823,12 @@ class HoldemOmahaHand(Hand):
|
|||
hhc.readPlayerStacks(self)
|
||||
hhc.compilePlayerRegexs(self)
|
||||
hhc.markStreets(self)
|
||||
|
||||
if self.cancelled:
|
||||
return
|
||||
|
||||
hhc.readBlinds(self)
|
||||
|
||||
hhc.readAntes(self)
|
||||
hhc.readButton(self)
|
||||
hhc.readHeroCards(self)
|
||||
|
|
@ -710,9 +853,9 @@ class HoldemOmahaHand(Hand):
|
|||
if handid is not None:
|
||||
self.select(handid) # Will need a handId
|
||||
else:
|
||||
log.warning("HoldemOmahaHand.__init__:Can't assemble hand from db without a handid")
|
||||
log.warning(_("HoldemOmahaHand.__init__:Can't assemble hand from db without a handid"))
|
||||
else:
|
||||
log.warning("HoldemOmahaHand.__init__:Neither HHC nor DB+handid provided")
|
||||
log.warning(_("HoldemOmahaHand.__init__:Neither HHC nor DB+handid provided"))
|
||||
pass
|
||||
|
||||
|
||||
|
|
@ -1016,7 +1159,7 @@ class DrawHand(Hand):
|
|||
self.bets['DEAL'][player].append(Decimal(amount))
|
||||
self.stacks[player] -= Decimal(amount)
|
||||
#print "DEBUG %s posts, stack %s" % (player, self.stacks[player])
|
||||
act = (player, 'posts', blindtype, amount, self.stacks[player]==0)
|
||||
act = (player, blindtype, Decimal(amount), self.stacks[player]==0)
|
||||
self.actions['BLINDSANTES'].append(act)
|
||||
self.pot.addMoney(player, Decimal(amount))
|
||||
if blindtype == 'big blind':
|
||||
|
|
@ -1046,10 +1189,10 @@ class DrawHand(Hand):
|
|||
def addDiscard(self, street, player, num, cards):
|
||||
self.checkPlayerExists(player)
|
||||
if cards:
|
||||
act = (player, 'discards', num, cards)
|
||||
act = (player, 'discards', Decimal(num), cards)
|
||||
self.discardDrawHoleCards(cards, player, street)
|
||||
else:
|
||||
act = (player, 'discards', num)
|
||||
act = (player, 'discards', Decimal(num))
|
||||
self.actions[street].append(act)
|
||||
|
||||
def holecardsAsSet(self, street, player):
|
||||
|
|
@ -1208,7 +1351,8 @@ class StudHand(Hand):
|
|||
self.addHoleCards('FOURTH', player, open=[cards[3]], closed=[cards[2]], shown=shown, mucked=mucked)
|
||||
self.addHoleCards('FIFTH', player, open=[cards[4]], closed=cards[2:4], shown=shown, mucked=mucked)
|
||||
self.addHoleCards('SIXTH', player, open=[cards[5]], closed=cards[2:5], shown=shown, mucked=mucked)
|
||||
self.addHoleCards('SEVENTH', player, open=[], closed=[cards[6]], shown=shown, mucked=mucked)
|
||||
if len(cards) > 6:
|
||||
self.addHoleCards('SEVENTH', player, open=[], closed=[cards[6]], shown=shown, mucked=mucked)
|
||||
|
||||
|
||||
def addPlayerCards(self, player, street, open=[], closed=[]):
|
||||
|
|
@ -1224,7 +1368,7 @@ closed likewise, but known only to player
|
|||
self.checkPlayerExists(player)
|
||||
self.holecards[street][player] = (open, closed)
|
||||
except FpdbParseError, e:
|
||||
print "[ERROR] Tried to add holecards for unknown player: %s" % (player,)
|
||||
print _("[ERROR] Tried to add holecards for unknown player: %s") % (player,)
|
||||
|
||||
# TODO: def addComplete(self, player, amount):
|
||||
def addComplete(self, street, player, amountTo):
|
||||
|
|
@ -1233,7 +1377,7 @@ closed likewise, but known only to player
|
|||
"""\
|
||||
Add a complete on [street] by [player] to [amountTo]
|
||||
"""
|
||||
log.debug("%s %s completes %s" % (street, player, amountTo))
|
||||
log.debug(_("%s %s completes %s") % (street, player, amountTo))
|
||||
amountTo = re.sub(u',', u'', amountTo) #some sites have commas
|
||||
self.checkPlayerExists(player)
|
||||
Bp = self.lastBet['THIRD']
|
||||
|
|
@ -1241,7 +1385,7 @@ Add a complete on [street] by [player] to [amountTo]
|
|||
Rt = Decimal(amountTo)
|
||||
C = Bp - Bc
|
||||
Rb = Rt - C
|
||||
self._addRaise(street, player, C, Rb, Rt)
|
||||
self._addRaise(street, player, C, Rb, Rt, 'completes')
|
||||
#~ self.bets[street][player].append(C + Rb)
|
||||
#~ self.stacks[player] -= (C + Rb)
|
||||
#~ act = (player, 'raises', Rb, Rt, C, self.stacks[player]==0)
|
||||
|
|
@ -1251,10 +1395,10 @@ Add a complete on [street] by [player] to [amountTo]
|
|||
|
||||
def addBringIn(self, player, bringin):
|
||||
if player is not None:
|
||||
log.debug("Bringin: %s, %s" % (player , bringin))
|
||||
log.debug(_("Bringin: %s, %s") % (player , bringin))
|
||||
self.bets['THIRD'][player].append(Decimal(bringin))
|
||||
self.stacks[player] -= Decimal(bringin)
|
||||
act = (player, 'bringin', bringin, self.stacks[player]==0)
|
||||
act = (player, 'bringin', Decimal(bringin), self.stacks[player]==0)
|
||||
self.actions['THIRD'].append(act)
|
||||
self.lastBet['THIRD'] = Decimal(bringin)
|
||||
self.pot.addMoney(player, Decimal(bringin))
|
||||
|
|
@ -1431,8 +1575,8 @@ Add a complete on [street] by [player] to [amountTo]
|
|||
#Non hero folded before showdown, add first two downcards
|
||||
holecards = [u'0x', u'0x'] + holecards
|
||||
else:
|
||||
log.warning("join_holecards: # of holecards should be either < 4, 4 or 7 - 5 and 6 should be impossible for anyone who is not a hero")
|
||||
log.warning("join_holcards: holecards(%s): %s" %(player, holecards))
|
||||
log.warning(_("join_holecards: # of holecards should be either < 4, 4 or 7 - 5 and 6 should be impossible for anyone who is not a hero"))
|
||||
log.warning(_("join_holcards: holecards(%s): %s") %(player, holecards))
|
||||
return holecards
|
||||
|
||||
|
||||
|
|
@ -1498,11 +1642,15 @@ class Pot(object):
|
|||
commitsall = sorted([(v,k) for (k,v) in self.committed.items() if v >0])
|
||||
|
||||
self.pots = []
|
||||
while len(commitsall) > 0:
|
||||
commitslive = [(v,k) for (v,k) in commitsall if k in self.contenders]
|
||||
v1 = commitslive[0][0]
|
||||
self.pots += [sum([min(v,v1) for (v,k) in commitsall])]
|
||||
commitsall = [((v-v1),k) for (v,k) in commitsall if v-v1 >0]
|
||||
try:
|
||||
while len(commitsall) > 0:
|
||||
commitslive = [(v,k) for (v,k) in commitsall if k in self.contenders]
|
||||
v1 = commitslive[0][0]
|
||||
self.pots += [sum([min(v,v1) for (v,k) in commitsall])]
|
||||
commitsall = [((v-v1),k) for (v,k) in commitsall if v-v1 >0]
|
||||
except IndexError, e:
|
||||
log.error(_("Pot.end(): Major failure while calculating pot: '%s'" % e))
|
||||
raise FpdbParseError(_("Pot.end(): Major failure while calculating pot: '%s'" % e))
|
||||
|
||||
# TODO: I think rake gets taken out of the pots.
|
||||
# so it goes:
|
||||
|
|
@ -1515,9 +1663,9 @@ class Pot(object):
|
|||
if self.sym is None:
|
||||
self.sym = "C"
|
||||
if self.total is None:
|
||||
print "DEBUG: call Pot.end() before printing pot total"
|
||||
print _("DEBUG: call Pot.end() before printing pot total")
|
||||
# NB if I'm sure end() is idempotent, call it here.
|
||||
raise FpdbParseError("FpdbError in printing Hand object")
|
||||
raise FpdbParseError(_("FpdbError in printing Hand object"))
|
||||
|
||||
ret = "Total pot %s%.2f" % (self.sym, self.total)
|
||||
if len(self.pots) < 2:
|
||||
|
|
@ -1526,146 +1674,4 @@ class Pot(object):
|
|||
|
||||
return ret + ''.join([ (" Side pot %s%.2f." % (self.sym, self.pots[x]) ) for x in xrange(1, len(self.pots)) ])
|
||||
|
||||
def assemble(cnxn, handid):
|
||||
c = cnxn.cursor()
|
||||
|
||||
# We need at least sitename, gametype, handid
|
||||
# for the Hand.__init__
|
||||
c.execute("""
|
||||
select
|
||||
s.name,
|
||||
g.category,
|
||||
g.base,
|
||||
g.type,
|
||||
g.limitType,
|
||||
g.hilo,
|
||||
round(g.smallBlind / 100.0,2),
|
||||
round(g.bigBlind / 100.0,2),
|
||||
round(g.smallBet / 100.0,2),
|
||||
round(g.bigBet / 100.0,2),
|
||||
s.currency,
|
||||
h.boardcard1,
|
||||
h.boardcard2,
|
||||
h.boardcard3,
|
||||
h.boardcard4,
|
||||
h.boardcard5
|
||||
from
|
||||
hands as h,
|
||||
sites as s,
|
||||
gametypes as g,
|
||||
handsplayers as hp,
|
||||
players as p
|
||||
where
|
||||
h.id = %(handid)s
|
||||
and g.id = h.gametypeid
|
||||
and hp.handid = h.id
|
||||
and p.id = hp.playerid
|
||||
and s.id = p.siteid
|
||||
limit 1""", {'handid':handid})
|
||||
#TODO: siteid should be in hands table - we took the scenic route through players here.
|
||||
res = c.fetchone()
|
||||
gametype = {'category':res[1],'base':res[2],'type':res[3],'limitType':res[4],'hilo':res[5],'sb':res[6],'bb':res[7], 'currency':res[10]}
|
||||
c = Configuration.Config()
|
||||
h = HoldemOmahaHand(config = c, hhc = None, sitename=res[0], gametype = gametype, handText=None, builtFrom = "DB", handid=handid)
|
||||
cards = map(Card.valueSuitFromCard, res[11:16] )
|
||||
if cards[0]:
|
||||
h.setCommunityCards('FLOP', cards[0:3])
|
||||
if cards[3]:
|
||||
h.setCommunityCards('TURN', [cards[3]])
|
||||
if cards[4]:
|
||||
h.setCommunityCards('RIVER', [cards[4]])
|
||||
#[Card.valueSuitFromCard(x) for x in cards]
|
||||
|
||||
# HandInfo : HID, TABLE
|
||||
# BUTTON - why is this treated specially in Hand?
|
||||
# answer: it is written out in hand histories
|
||||
# still, I think we should record all the active seat positions in a seat_order array
|
||||
c.execute("""
|
||||
SELECT
|
||||
h.sitehandno as hid,
|
||||
h.tablename as table,
|
||||
h.startTime as startTime
|
||||
FROM
|
||||
hands as h
|
||||
WHERE h.id = %(handid)s
|
||||
""", {'handid':handid})
|
||||
res = c.fetchone()
|
||||
h.handid = res[0]
|
||||
h.tablename = res[1]
|
||||
h.startTime = res[2] # automatically a datetime
|
||||
|
||||
# PlayerStacks
|
||||
c.execute("""
|
||||
SELECT
|
||||
hp.seatno,
|
||||
round(hp.winnings / 100.0,2) as winnings,
|
||||
p.name,
|
||||
round(hp.startcash / 100.0,2) as chips,
|
||||
hp.card1,hp.card2,
|
||||
hp.position
|
||||
FROM
|
||||
handsplayers as hp,
|
||||
players as p
|
||||
WHERE
|
||||
hp.handid = %(handid)s
|
||||
and p.id = hp.playerid
|
||||
""", {'handid':handid})
|
||||
for (seat, winnings, name, chips, card1,card2, position) in c.fetchall():
|
||||
h.addPlayer(seat,name,chips)
|
||||
if card1 and card2:
|
||||
h.addHoleCards(map(Card.valueSuitFromCard, (card1,card2)), name, dealt=True)
|
||||
if winnings > 0:
|
||||
h.addCollectPot(name, winnings)
|
||||
if position == 'B':
|
||||
h.buttonpos = seat
|
||||
|
||||
|
||||
# actions
|
||||
c.execute("""
|
||||
SELECT
|
||||
(ha.street,ha.actionno) as actnum,
|
||||
p.name,
|
||||
ha.street,
|
||||
ha.action,
|
||||
ha.allin,
|
||||
round(ha.amount / 100.0,2)
|
||||
FROM
|
||||
handsplayers as hp,
|
||||
handsactions as ha,
|
||||
players as p
|
||||
WHERE
|
||||
hp.handid = %(handid)s
|
||||
and ha.handsplayerid = hp.id
|
||||
and p.id = hp.playerid
|
||||
ORDER BY
|
||||
ha.street,ha.actionno
|
||||
""", {'handid':handid})
|
||||
res = c.fetchall()
|
||||
for (actnum,player, streetnum, act, allin, amount) in res:
|
||||
act=act.strip()
|
||||
street = h.allStreets[streetnum+1]
|
||||
if act==u'blind':
|
||||
h.addBlind(player, 'big blind', amount)
|
||||
# TODO: The type of blind is not recorded in the DB.
|
||||
# TODO: preflop street name anomalies in Hand
|
||||
elif act==u'fold':
|
||||
h.addFold(street,player)
|
||||
elif act==u'call':
|
||||
h.addCall(street,player,amount)
|
||||
elif act==u'bet':
|
||||
h.addBet(street,player,amount)
|
||||
elif act==u'check':
|
||||
h.addCheck(street,player)
|
||||
elif act==u'unbet':
|
||||
pass
|
||||
else:
|
||||
print act, player, streetnum, allin, amount
|
||||
# TODO : other actions
|
||||
|
||||
#hhc.readShowdownActions(self)
|
||||
#hc.readShownCards(self)
|
||||
h.totalPot()
|
||||
h.rake = h.totalpot - h.totalcollected
|
||||
|
||||
|
||||
return h
|
||||
|
|
|
|||
|
|
@ -15,6 +15,9 @@
|
|||
#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 L10n
|
||||
_ = L10n.get_translation()
|
||||
|
||||
import re
|
||||
import sys
|
||||
import traceback
|
||||
|
|
@ -41,10 +44,6 @@ import Hand
|
|||
from Exceptions import FpdbParseError
|
||||
import Configuration
|
||||
|
||||
import gettext
|
||||
gettext.install('fpdb')
|
||||
|
||||
|
||||
import pygtk
|
||||
import gtk
|
||||
|
||||
|
|
@ -62,8 +61,11 @@ class HandHistoryConverter():
|
|||
# "utf_8" is more likely if there are funny characters
|
||||
codepage = "cp1252"
|
||||
|
||||
re_tzOffset = re.compile('^\w+[+-]\d{4}$')
|
||||
|
||||
def __init__(self, config, in_path = '-', out_path = '-', follow=False, index=0, autostart=True, starsArchive=False, ftpArchive=False):
|
||||
# maybe archive params should be one archive param, then call method in specific converter. if archive: convert_archive()
|
||||
def __init__( self, config, in_path = '-', out_path = '-', follow=False, index=0
|
||||
, autostart=True, starsArchive=False, ftpArchive=False, sitename="PokerStars" ):
|
||||
"""\
|
||||
in_path (default '-' = sys.stdin)
|
||||
out_path (default '-' = sys.stdout)
|
||||
|
|
@ -71,8 +73,10 @@ follow : whether to tail -f the input"""
|
|||
|
||||
self.config = config
|
||||
self.import_parameters = self.config.get_import_parameters()
|
||||
self.sitename = sitename
|
||||
#log = Configuration.get_logger("logging.conf", "parser", log_dir=self.config.dir_log)
|
||||
log.info("HandHistory init - %s subclass, in_path '%s'; out_path '%s'" % (self.sitename, in_path, out_path) )
|
||||
log.info("HandHistory init - %s site, %s subclass, in_path '%s'; out_path '%s'"
|
||||
% (self.sitename, self.__class__, in_path, out_path) ) # should use self.filter, not self.sitename
|
||||
|
||||
self.index = index
|
||||
self.starsArchive = starsArchive
|
||||
|
|
@ -123,7 +127,7 @@ Otherwise, finish at EOF.
|
|||
|
||||
starttime = time.time()
|
||||
if not self.sanityCheck():
|
||||
log.warning("Failed sanity check")
|
||||
log.warning(_("Failed sanity check"))
|
||||
return
|
||||
|
||||
try:
|
||||
|
|
@ -131,17 +135,18 @@ Otherwise, finish at EOF.
|
|||
self.numErrors = 0
|
||||
if self.follow:
|
||||
#TODO: See how summary files can be handled on the fly (here they should be rejected as before)
|
||||
log.info("Tailing '%s'" % self.in_path)
|
||||
log.info(_("Tailing '%s'") % self.in_path)
|
||||
for handText in self.tailHands():
|
||||
try:
|
||||
self.processHand(handText)
|
||||
self.numHands += 1
|
||||
except FpdbParseError, e:
|
||||
self.numErrors += 1
|
||||
log.warning("HHC.start(follow): processHand failed: Exception msg: '%s'" % e)
|
||||
log.warning(_("HHC.start(follow): processHand failed: Exception msg: '%s'") % e)
|
||||
log.debug(handText)
|
||||
else:
|
||||
handsList = self.allHandsAsList()
|
||||
log.debug( _("handsList is ") + str(handsList) )
|
||||
log.info("Parsing %d hands" % len(handsList))
|
||||
# Determine if we're dealing with a HH file or a Summary file
|
||||
# quick fix : empty files make the handsList[0] fail ==> If empty file, go on with HH parsing
|
||||
|
|
@ -152,22 +157,22 @@ Otherwise, finish at EOF.
|
|||
self.processedHands.append(self.processHand(handText))
|
||||
except FpdbParseError, e:
|
||||
self.numErrors += 1
|
||||
log.warning("HHC.start(): processHand failed: Exception msg: '%s'" % e)
|
||||
log.warning(_("HHC.start(): processHand failed: Exception msg: '%s'") % e)
|
||||
log.debug(handText)
|
||||
self.numHands = len(handsList)
|
||||
endtime = time.time()
|
||||
log.info("Read %d hands (%d failed) in %.3f seconds" % (self.numHands, self.numErrors, endtime - starttime))
|
||||
log.info(_("Read %d hands (%d failed) in %.3f seconds") % (self.numHands, self.numErrors, endtime - starttime))
|
||||
else:
|
||||
self.parsedObjectType = "Summary"
|
||||
summaryParsingStatus = self.readSummaryInfo(handsList)
|
||||
endtime = time.time()
|
||||
if summaryParsingStatus :
|
||||
log.info("Summary file '%s' correctly parsed (took %.3f seconds)" % (self.in_path, endtime - starttime))
|
||||
log.info(_("Summary file '%s' correctly parsed (took %.3f seconds)") % (self.in_path, endtime - starttime))
|
||||
else :
|
||||
log.warning("Error converting summary file '%s' (took %.3f seconds)" % (self.in_path, endtime - starttime))
|
||||
log.warning(_("Error converting summary file '%s' (took %.3f seconds)") % (self.in_path, endtime - starttime))
|
||||
|
||||
except IOError, ioe:
|
||||
log.exception("Error converting '%s'" % self.in_path)
|
||||
log.exception(_("Error converting '%s'") % self.in_path)
|
||||
finally:
|
||||
if self.out_fh != sys.stdout:
|
||||
self.out_fh.close()
|
||||
|
|
@ -198,7 +203,7 @@ which it expects to find at self.re_TailSplitHands -- see for e.g. Everleaf.py.
|
|||
time.sleep(interval)
|
||||
fd.seek(where)
|
||||
else:
|
||||
log.debug("%s changed inode numbers from %d to %d" % (self.in_path, fd_results[1], st_results[1]))
|
||||
log.debug(_("%s changed inode numbers from %d to %d") % (self.in_path, fd_results[1], st_results[1]))
|
||||
fd = codecs.open(self.in_path, 'r', self.codepage)
|
||||
fd.seek(where)
|
||||
else:
|
||||
|
|
@ -242,20 +247,31 @@ which it expects to find at self.re_TailSplitHands -- see for e.g. Everleaf.py.
|
|||
self.readFile()
|
||||
self.obs = self.obs.strip()
|
||||
self.obs = self.obs.replace('\r\n', '\n')
|
||||
# maybe archive params should be one archive param, then call method in specific converter?
|
||||
# if self.archive:
|
||||
# self.obs = self.convert_archive(self.obs)
|
||||
if self.starsArchive == True:
|
||||
log.debug("Converting starsArchive format to readable")
|
||||
log.debug(_("Converting starsArchive format to readable"))
|
||||
m = re.compile('^Hand #\d+', re.MULTILINE)
|
||||
self.obs = m.sub('', self.obs)
|
||||
|
||||
if self.ftpArchive == True:
|
||||
log.debug("Converting ftpArchive format to readable")
|
||||
m = re.compile('^\*\*\*\*\*\*+\s#\s\d+\s\*\*\*\*\*+$', re.MULTILINE)
|
||||
log.debug(_("Converting ftpArchive format to readable"))
|
||||
# Remove ******************** # 1 *************************
|
||||
m = re.compile('\*{20}\s#\s\d+\s\*{25}\s+', re.MULTILINE)
|
||||
self.obs = m.sub('', self.obs)
|
||||
|
||||
if self.obs is None or self.obs == "":
|
||||
log.info("Read no hands.")
|
||||
log.error(_("Read no hands."))
|
||||
return []
|
||||
return re.split(self.re_SplitHands, self.obs)
|
||||
handlist = re.split(self.re_SplitHands, self.obs)
|
||||
# Some HH formats leave dangling text after the split
|
||||
# ie. </game> (split) </session>EOL
|
||||
# Remove this dangler if less than 50 characters and warn in the log
|
||||
if len(handlist[-1]) <= 50:
|
||||
handlist.pop()
|
||||
log.warn(_("Removing text < 50 characters"))
|
||||
return handlist
|
||||
|
||||
def processHand(self, handText):
|
||||
gametype = self.determineGameType(handText)
|
||||
|
|
@ -264,14 +280,15 @@ which it expects to find at self.re_TailSplitHands -- see for e.g. Everleaf.py.
|
|||
l = None
|
||||
if gametype is None:
|
||||
gametype = "unmatched"
|
||||
# TODO: not ideal, just trying to not error.
|
||||
# TODO: Need to count failed hands.
|
||||
# TODO: not ideal, just trying to not error. Throw ParseException?
|
||||
self.numErrors += 1
|
||||
else:
|
||||
# See if gametype is supported.
|
||||
type = gametype['type']
|
||||
base = gametype['base']
|
||||
limit = gametype['limitType']
|
||||
l = [type] + [base] + [limit]
|
||||
|
||||
if l in self.readSupportedGames():
|
||||
if gametype['base'] == 'hold':
|
||||
log.debug("hand = Hand.HoldemOmahaHand(self, self.sitename, gametype, handtext)")
|
||||
|
|
@ -281,15 +298,15 @@ which it expects to find at self.re_TailSplitHands -- see for e.g. Everleaf.py.
|
|||
elif gametype['base'] == 'draw':
|
||||
hand = Hand.DrawHand(self.config, self, self.sitename, gametype, handText)
|
||||
else:
|
||||
log.info("Unsupported game type: %s" % gametype)
|
||||
log.info(_("Unsupported game type: %s" % gametype))
|
||||
raise FpdbParseError(_("Unsupported game type: %s" % gametype))
|
||||
|
||||
if hand:
|
||||
#hand.writeHand(self.out_fh)
|
||||
return hand
|
||||
else:
|
||||
log.info("Unsupported game type: %s" % gametype)
|
||||
log.error(_("Unsupported game type: %s" % gametype))
|
||||
# TODO: pity we don't know the HID at this stage. Log the entire hand?
|
||||
# From the log we can deduce that it is the hand after the one before :)
|
||||
|
||||
|
||||
# These functions are parse actions that may be overridden by the inheriting class
|
||||
|
|
@ -318,33 +335,104 @@ which it expects to find at self.re_TailSplitHands -- see for e.g. Everleaf.py.
|
|||
or None if we fail to get the info """
|
||||
#TODO: which parts are optional/required?
|
||||
|
||||
# Read any of:
|
||||
# HID HandID
|
||||
# TABLE Table name
|
||||
# SB small blind
|
||||
# BB big blind
|
||||
# GAMETYPE gametype
|
||||
# YEAR MON DAY HR MIN SEC datetime
|
||||
# BUTTON button seat number
|
||||
def readHandInfo(self, hand): abstract
|
||||
"""Read and set information about the hand being dealt, and set the correct
|
||||
variables in the Hand object 'hand
|
||||
|
||||
* hand.startTime - a datetime object
|
||||
* hand.handid - The site identified for the hand - a string.
|
||||
* hand.tablename
|
||||
* hand.buttonpos
|
||||
* hand.maxseats
|
||||
* hand.mixed
|
||||
|
||||
Tournament fields:
|
||||
|
||||
* hand.tourNo - The site identified tournament id as appropriate - a string.
|
||||
* hand.buyin
|
||||
* hand.fee
|
||||
* hand.buyinCurrency
|
||||
* hand.koBounty
|
||||
* hand.isKO
|
||||
* hand.level
|
||||
"""
|
||||
#TODO: which parts are optional/required?
|
||||
|
||||
# Needs to return a list of lists in the format
|
||||
# [['seat#', 'player1name', 'stacksize'] ['seat#', 'player2name', 'stacksize'] [...]]
|
||||
def readPlayerStacks(self, hand): abstract
|
||||
"""This function is for identifying players at the table, and to pass the
|
||||
information on to 'hand' via Hand.addPlayer(seat, name, chips)
|
||||
|
||||
At the time of writing the reference function in the PS converter is:
|
||||
log.debug("readPlayerStacks")
|
||||
m = self.re_PlayerInfo.finditer(hand.handText)
|
||||
for a in m:
|
||||
hand.addPlayer(int(a.group('SEAT')), a.group('PNAME'), a.group('CASH'))
|
||||
|
||||
Which is pretty simple because the hand history format is consistent. Other hh formats aren't so nice.
|
||||
|
||||
This is the appropriate place to identify players that are sitting out and ignore them
|
||||
|
||||
*** NOTE: You may find this is a more appropriate place to set hand.maxseats ***
|
||||
"""
|
||||
|
||||
def compilePlayerRegexs(self): abstract
|
||||
"""Compile dynamic regexes -- these explicitly match known player names and must be updated if a new player joins"""
|
||||
"""Compile dynamic regexes -- compile player dependent regexes.
|
||||
|
||||
Depending on the ambiguity of lines you may need to match, and the complexity of
|
||||
player names - we found that we needed to recompile some regexes for player actions so that they actually contained the player names.
|
||||
|
||||
eg.
|
||||
We need to match the ante line:
|
||||
<Player> antes $1.00
|
||||
|
||||
But <Player> is actually named
|
||||
|
||||
YesI antes $4000 - A perfectly legal playername
|
||||
|
||||
Giving:
|
||||
|
||||
YesI antes $4000 antes $1.00
|
||||
|
||||
Which without care in your regexes most people would match 'YesI' and not 'YesI antes $4000'
|
||||
"""
|
||||
|
||||
# Needs to return a MatchObject with group names identifying the streets into the Hand object
|
||||
# so groups are called by street names 'PREFLOP', 'FLOP', 'STREET2' etc
|
||||
# blinds are done seperately
|
||||
def markStreets(self, hand): abstract
|
||||
"""For dividing the handText into sections.
|
||||
|
||||
The function requires you to pass a MatchObject with groups specifically labeled with
|
||||
the 'correct' street names.
|
||||
|
||||
The Hand object will use the various matches for assigning actions to the correct streets.
|
||||
|
||||
Flop Based Games:
|
||||
PREFLOP, FLOP, TURN, RIVER
|
||||
|
||||
Draw Based Games:
|
||||
PREDEAL, DEAL, DRAWONE, DRAWTWO, DRAWTHREE
|
||||
|
||||
Stud Based Games:
|
||||
ANTES, THIRD, FOURTH, FIFTH, SIXTH, SEVENTH
|
||||
|
||||
The Stars HHC has a good reference implementation
|
||||
"""
|
||||
|
||||
#Needs to return a list in the format
|
||||
# ['player1name', 'player2name', ...] where player1name is the sb and player2name is bb,
|
||||
# addtional players are assumed to post a bb oop
|
||||
def readBlinds(self, hand): abstract
|
||||
"""Function for reading the various blinds from the hand history.
|
||||
|
||||
Pass any small blind to hand.addBlind(<name>, "small blind", <value>)
|
||||
- unless it is a single dead small blind then use:
|
||||
hand.addBlind(<name>, 'secondsb', <value>)
|
||||
Pass any big blind to hand.addBlind(<name>, "big blind", <value>)
|
||||
Pass any play posting both big and small blinds to hand.addBlind(<name>, 'both', <vale>)
|
||||
"""
|
||||
def readAntes(self, hand): abstract
|
||||
"""Function for reading the antes from the hand history and passing the hand.addAnte"""
|
||||
def readBringIn(self, hand): abstract
|
||||
def readButton(self, hand): abstract
|
||||
def readHeroCards(self, hand): abstract
|
||||
|
|
@ -390,7 +478,7 @@ or None if we fail to get the info """
|
|||
sane = True
|
||||
|
||||
if self.in_path != '-' and self.out_path == self.in_path:
|
||||
print "HH Sanity Check: output and input files are the same, check config"
|
||||
print _("HH Sanity Check: output and input files are the same, check config")
|
||||
sane = False
|
||||
|
||||
|
||||
|
|
@ -401,18 +489,6 @@ or None if we fail to get the info """
|
|||
self.filetype = filetype
|
||||
self.codepage = codepage
|
||||
|
||||
#This function doesn't appear to be used
|
||||
def splitFileIntoHands(self):
|
||||
hands = []
|
||||
self.obs = self.obs.strip()
|
||||
list = self.re_SplitHands.split(self.obs)
|
||||
list.pop() #Last entry is empty
|
||||
for l in list:
|
||||
# print "'" + l + "'"
|
||||
hands = hands + [Hand.Hand(self.config, self.sitename, self.gametype, l)]
|
||||
# TODO: This looks like it could be replaced with a list comp.. ?
|
||||
return hands
|
||||
|
||||
def __listof(self, x):
|
||||
if isinstance(x, list) or isinstance(x, tuple):
|
||||
return x
|
||||
|
|
@ -425,7 +501,7 @@ or None if we fail to get the info """
|
|||
if self.filetype == "text":
|
||||
if self.in_path == '-':
|
||||
# read from stdin
|
||||
log.debug("Reading stdin with %s" % self.codepage) # is this necessary? or possible? or what?
|
||||
log.debug(_("Reading stdin with %s") % self.codepage) # is this necessary? or possible? or what?
|
||||
in_fh = codecs.getreader('cp1252')(sys.stdin)
|
||||
else:
|
||||
for kodec in self.__listof(self.codepage):
|
||||
|
|
@ -440,7 +516,8 @@ or None if we fail to get the info """
|
|||
except:
|
||||
pass
|
||||
else:
|
||||
print "unable to read file with any codec in list!", self.in_path
|
||||
print _("unable to read file with any codec in list!"), self.in_path
|
||||
self.obs = ""
|
||||
elif self.filetype == "xml":
|
||||
doc = xml.dom.minidom.parse(filename)
|
||||
self.doc = doc
|
||||
|
|
@ -500,17 +577,32 @@ or None if we fail to get the info """
|
|||
|
||||
@staticmethod
|
||||
def changeTimezone(time, givenTimezone, wantedTimezone):
|
||||
#print "raw time:",time, "given TZ:", givenTimezone
|
||||
"""Takes a givenTimezone in format AAA or AAA+HHMM where AAA is a standard timezone
|
||||
and +HHMM is an optional offset (+/-) in hours (HH) and minutes (MM)
|
||||
(See OnGameToFpdb.py for example use of the +HHMM part)
|
||||
Tries to convert the time parameter (with no timezone) from the givenTimezone to
|
||||
the wantedTimeZone (currently only allows "UTC")
|
||||
"""
|
||||
log.debug( _("raw time:")+str(time) + _(" given TZ:")+str(givenTimezone) )
|
||||
if wantedTimezone=="UTC":
|
||||
wantedTimezone = pytz.utc
|
||||
else:
|
||||
raise Error #TODO raise appropriate error
|
||||
|
||||
givenTZ = None
|
||||
if HandHistoryConverter.re_tzOffset.match(givenTimezone):
|
||||
offset = int(givenTimezone[-5:])
|
||||
givenTimezone = givenTimezone[0:-5]
|
||||
log.debug( _("changeTimeZone: offset=") + str(offset) )
|
||||
else: offset=0
|
||||
|
||||
if givenTimezone=="ET":
|
||||
givenTimezone = timezone('US/Eastern')
|
||||
givenTZ = timezone('US/Eastern')
|
||||
elif givenTimezone=="CET":
|
||||
givenTimezone = timezone('Europe/Berlin')
|
||||
givenTZ = timezone('Europe/Berlin')
|
||||
#Note: Daylight Saving Time is standardised across the EU so this should be fine
|
||||
elif givenTimezone == 'GMT': # Greenwich Mean Time (same as UTC - no change to time)
|
||||
givenTZ = timezone('GMT')
|
||||
elif givenTimezone == 'HST': # Hawaiian Standard Time
|
||||
pass
|
||||
elif givenTimezone == 'AKT': # Alaska Time
|
||||
|
|
@ -544,23 +636,27 @@ or None if we fail to get the info """
|
|||
elif givenTimezone == 'JST': # Japan Standard Time
|
||||
pass
|
||||
elif givenTimezone == 'AWST': # Australian Western Standard Time
|
||||
givenTimezone = timezone('Australia/West')
|
||||
givenTZ = timezone('Australia/West')
|
||||
elif givenTimezone == 'ACST': # Australian Central Standard Time
|
||||
givenTimezone = timezone('Australia/Darwin')
|
||||
givenTZ = 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')
|
||||
givenTZ = 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
|
||||
if givenTZ is None:
|
||||
raise Error #TODO raise appropriate error
|
||||
# (or just return time unchanged?)
|
||||
|
||||
localisedTime = givenTZ.localize(time)
|
||||
utcTime = localisedTime.astimezone(wantedTimezone) + datetime.timedelta(seconds=-3600*(offset/100)-60*(offset%100))
|
||||
log.debug( _("utcTime:")+str(utcTime) )
|
||||
return utcTime
|
||||
#end @staticmethod def changeTimezone
|
||||
|
||||
|
|
@ -572,12 +668,23 @@ or None if we fail to get the info """
|
|||
else:
|
||||
return table_name
|
||||
|
||||
|
||||
@staticmethod
|
||||
def getTableNoRe(tournament):
|
||||
"Returns string to search window title for tournament table no."
|
||||
# Full Tilt: $30 + $3 Tournament (181398949), Table 1 - 600/1200 Ante 100 - Limit Razz
|
||||
# PokerStars: WCOOP 2nd Chance 02: $1,050 NLHE - Tournament 307521826 Table 1 - Blinds $30/$60
|
||||
return "%s.+Table (\d+)" % (tournament, )
|
||||
|
||||
def getTableTitleRe(config, sitename, *args, **kwargs):
|
||||
"Returns string to search in windows titles for current site"
|
||||
return getSiteHhc(config, sitename).getTableTitleRe(*args, **kwargs)
|
||||
|
||||
def getTableNoRe(config, sitename, *args, **kwargs):
|
||||
"Returns string to search window titles for tournament table no."
|
||||
return getSiteHhc(config, sitename).getTableNoRe(*args, **kwargs)
|
||||
|
||||
|
||||
|
||||
def getSiteHhc(config, sitename):
|
||||
"Returns HHC class for current site"
|
||||
hhcName = config.supported_sites[sitename].converter
|
||||
|
|
@ -593,13 +700,13 @@ def get_out_fh(out_path, parameters):
|
|||
try:
|
||||
os.makedirs(out_dir)
|
||||
except: # we get a WindowsError here in Windows.. pretty sure something else for Linux :D
|
||||
log.error("Unable to create output directory %s for HHC!" % out_dir)
|
||||
print "*** ERROR: UNABLE TO CREATE OUTPUT DIRECTORY", out_dir
|
||||
log.error(_("Unable to create output directory %s for HHC!") % out_dir)
|
||||
print _("*** ERROR: UNABLE TO CREATE OUTPUT DIRECTORY"), out_dir
|
||||
else:
|
||||
log.info("Created directory '%s'" % out_dir)
|
||||
log.info(_("Created directory '%s'") % out_dir)
|
||||
try:
|
||||
return(codecs.open(out_path, 'w', 'utf8'))
|
||||
except:
|
||||
log.error("out_path %s couldn't be opened" % (out_path))
|
||||
log.error(_("out_path %s couldn't be opened") % (out_path))
|
||||
else:
|
||||
return(sys.stdout)
|
||||
|
|
|
|||
|
|
@ -41,10 +41,10 @@ from Mucked import Aux_Seats
|
|||
class Hello(Aux_Window):
|
||||
"""A 'Hello World' Aux_Window demo."""
|
||||
def create(self):
|
||||
print "creating Hello"
|
||||
print _("creating Hello")
|
||||
# This demo simply creates a label in a window.
|
||||
self.container = gtk.Window()
|
||||
self.container.add(gtk.Label("Hello World"))
|
||||
self.container.add(gtk.Label(_("Hello World")))
|
||||
# and shows it. There is no functionality.
|
||||
self.container.show_all()
|
||||
|
||||
|
|
@ -62,7 +62,7 @@ class Hello_plus(Aux_Window):
|
|||
|
||||
# get the site we are playing from the HUD
|
||||
self.site = hud.site
|
||||
print "site =", hud.site # print it to the terminal, to make sure
|
||||
print _("site ="), hud.site # print it to the terminal, to make sure
|
||||
|
||||
# now get our screen name for that site from the configuration
|
||||
# wrap it in a try/except in case screen name isn't set up in the config file
|
||||
|
|
@ -70,7 +70,7 @@ class Hello_plus(Aux_Window):
|
|||
site_params = self.config.get_site_parameters(self.hud.site)
|
||||
self.hero = site_params['screen_name']
|
||||
except:
|
||||
self.hero = 'YOUR NAME HERE'
|
||||
self.hero = _('YOUR NAME HERE')
|
||||
print "hero =", self.hero
|
||||
|
||||
|
||||
|
|
@ -101,7 +101,7 @@ class Hello_plus(Aux_Window):
|
|||
|
||||
# Here, we just update the label in our aux_window from the number of
|
||||
# hands played that was updated in the "update_data()" function.
|
||||
self.label.set_text("Hello %s\nYou have played %d hands\n on %s." % (self.hero, self.hands_played, self.site))
|
||||
self.label.set_text(_("Hello %s\nYou have played %d hands\n on %s.") % (self.hero, self.hands_played, self.site))
|
||||
|
||||
class Hello_Seats(Aux_Seats):
|
||||
"""A 'Hello World' Seat_Window demo."""
|
||||
|
|
|
|||
259
pyfpdb/Hud.py
259
pyfpdb/Hud.py
|
|
@ -22,6 +22,10 @@ Create and manage the hud overlays.
|
|||
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
|
||||
########################################################################
|
||||
|
||||
import L10n
|
||||
_ = L10n.get_translation()
|
||||
|
||||
# Standard Library modules
|
||||
import os
|
||||
import sys
|
||||
|
|
@ -43,13 +47,13 @@ if os.name == 'nt':
|
|||
import win32api
|
||||
|
||||
# FreePokerTools modules
|
||||
import Tables # needed for testing only
|
||||
import Configuration
|
||||
import Stats
|
||||
import Mucked
|
||||
import Database
|
||||
#import HUD_main
|
||||
|
||||
|
||||
def importName(module_name, name):
|
||||
"""Import a named object 'name' from module 'module_name'."""
|
||||
# Recipe 16.3 in the Python Cookbook, 2nd ed. Thanks!!!!
|
||||
|
|
@ -60,14 +64,15 @@ def importName(module_name, name):
|
|||
return None
|
||||
return(getattr(module, name))
|
||||
|
||||
class Hud:
|
||||
|
||||
class Hud:
|
||||
def __init__(self, parent, table, max, poker_game, config, db_connection):
|
||||
# __init__ is (now) intended to be called from the stdin thread, so it
|
||||
# cannot touch the gui
|
||||
if parent is None: # running from cli ..
|
||||
if parent is None: # running from cli ..
|
||||
self.parent = self
|
||||
self.parent = parent
|
||||
else:
|
||||
self.parent = parent
|
||||
self.table = table
|
||||
self.config = config
|
||||
self.poker_game = poker_game
|
||||
|
|
@ -79,11 +84,11 @@ class Hud:
|
|||
self.mw_created = False
|
||||
self.hud_params = parent.hud_params
|
||||
|
||||
|
||||
self.stat_windows = {}
|
||||
self.popup_windows = {}
|
||||
self.aux_windows = []
|
||||
|
||||
# configure default font and colors from the configuration
|
||||
(font, font_size) = config.get_default_font(self.table.site)
|
||||
self.colors = config.get_default_colors(self.table.site)
|
||||
self.hud_ui = config.get_hud_ui_parameters()
|
||||
|
|
@ -96,6 +101,7 @@ class Hud:
|
|||
# do we need to add some sort of condition here for dealing with a request for a font that doesn't exist?
|
||||
|
||||
game_params = config.get_game_parameters(self.poker_game)
|
||||
# if there are AUX windows configured, set them up (Ray knows how this works, if anyone needs info)
|
||||
if not game_params['aux'] == [""]:
|
||||
for aux in game_params['aux']:
|
||||
aux_params = config.get_aux_parameters(aux)
|
||||
|
|
@ -107,14 +113,16 @@ class Hud:
|
|||
self.creation_attrs = None
|
||||
|
||||
def create_mw(self):
|
||||
|
||||
# Set up a main window for this this instance of the HUD
|
||||
win = gtk.Window()
|
||||
win.set_skip_taskbar_hint(True) # invisible to taskbar
|
||||
win.set_gravity(gtk.gdk.GRAVITY_STATIC)
|
||||
win.set_title("%s FPDBHUD" % (self.table.name))
|
||||
win.set_skip_taskbar_hint(True)
|
||||
win.set_decorated(False)
|
||||
win.set_opacity(self.colors["hudopacity"])
|
||||
win.set_title("%s FPDBHUD" % (self.table.name)) # give it a title that we can easily filter out in the window list when Table search code is looking
|
||||
win.set_decorated(False) # kill titlebars
|
||||
win.set_opacity(self.colors["hudopacity"]) # set it to configured hud opacity
|
||||
win.set_focus(None)
|
||||
win.set_focus_on_map(False)
|
||||
win.set_accept_focus(False)
|
||||
|
||||
eventbox = gtk.EventBox()
|
||||
label = gtk.Label(self.hud_ui['label'])
|
||||
|
|
@ -122,6 +130,7 @@ class Hud:
|
|||
win.add(eventbox)
|
||||
eventbox.add(label)
|
||||
|
||||
# set it to the desired color of the HUD for this site
|
||||
label.modify_bg(gtk.STATE_NORMAL, self.backgroundcolor)
|
||||
label.modify_fg(gtk.STATE_NORMAL, self.foregroundcolor)
|
||||
|
||||
|
|
@ -129,158 +138,160 @@ class Hud:
|
|||
eventbox.modify_fg(gtk.STATE_NORMAL, self.foregroundcolor)
|
||||
|
||||
self.main_window = win
|
||||
# move it to the table window's X/Y position (0,0 on the table window usually)
|
||||
self.main_window.move(self.table.x, self.table.y)
|
||||
|
||||
# A popup menu for the main window
|
||||
# This menu code has become extremely long - is there a better way to do this?
|
||||
menu = gtk.Menu()
|
||||
|
||||
killitem = gtk.MenuItem('Kill This HUD')
|
||||
killitem = gtk.MenuItem(_('Kill This HUD'))
|
||||
menu.append(killitem)
|
||||
if self.parent is not None:
|
||||
killitem.connect("activate", self.parent.kill_hud, self.table_name)
|
||||
|
||||
saveitem = gtk.MenuItem('Save HUD Layout')
|
||||
saveitem = gtk.MenuItem(_('Save HUD Layout'))
|
||||
menu.append(saveitem)
|
||||
saveitem.connect("activate", self.save_layout)
|
||||
|
||||
repositem = gtk.MenuItem('Reposition StatWindows')
|
||||
repositem = gtk.MenuItem(_('Reposition StatWindows'))
|
||||
menu.append(repositem)
|
||||
repositem.connect("activate", self.reposition_windows)
|
||||
|
||||
aggitem = gtk.MenuItem('Show Player Stats')
|
||||
aggitem = gtk.MenuItem(_('Show Player Stats'))
|
||||
menu.append(aggitem)
|
||||
self.aggMenu = gtk.Menu()
|
||||
aggitem.set_submenu(self.aggMenu)
|
||||
# set agg_bb_mult to 1 to stop aggregation
|
||||
item = gtk.CheckMenuItem('For This Blind Level Only')
|
||||
item = gtk.CheckMenuItem(_('For This Blind Level Only'))
|
||||
self.aggMenu.append(item)
|
||||
item.connect("activate", self.set_aggregation, ('P',1))
|
||||
item.connect("activate", self.set_aggregation, ('P', 1))
|
||||
setattr(self, 'h_aggBBmultItem1', item)
|
||||
#
|
||||
item = gtk.MenuItem('For Multiple Blind Levels:')
|
||||
|
||||
item = gtk.MenuItem(_('For Multiple Blind Levels:'))
|
||||
self.aggMenu.append(item)
|
||||
#
|
||||
item = gtk.CheckMenuItem(' 0.5 to 2.0 x Current Blinds')
|
||||
|
||||
item = gtk.CheckMenuItem(_(' 0.5 to 2.0 x Current Blinds'))
|
||||
self.aggMenu.append(item)
|
||||
item.connect("activate", self.set_aggregation, ('P',2))
|
||||
setattr(self, 'h_aggBBmultItem2', item)
|
||||
#
|
||||
item = gtk.CheckMenuItem(' 0.33 to 3.0 x Current Blinds')
|
||||
|
||||
item = gtk.CheckMenuItem(_(' 0.33 to 3.0 x Current Blinds'))
|
||||
self.aggMenu.append(item)
|
||||
item.connect("activate", self.set_aggregation, ('P',3))
|
||||
setattr(self, 'h_aggBBmultItem3', item)
|
||||
#
|
||||
item = gtk.CheckMenuItem(' 0.1 to 10 x Current Blinds')
|
||||
|
||||
item = gtk.CheckMenuItem(_(' 0.1 to 10 x Current Blinds'))
|
||||
self.aggMenu.append(item)
|
||||
item.connect("activate", self.set_aggregation, ('P',10))
|
||||
setattr(self, 'h_aggBBmultItem10', item)
|
||||
#
|
||||
item = gtk.CheckMenuItem(' All Levels')
|
||||
|
||||
item = gtk.CheckMenuItem(_(' All Levels'))
|
||||
self.aggMenu.append(item)
|
||||
item.connect("activate", self.set_aggregation, ('P',10000))
|
||||
setattr(self, 'h_aggBBmultItem10000', item)
|
||||
#
|
||||
item = gtk.MenuItem('For #Seats:')
|
||||
|
||||
item = gtk.MenuItem(_('For #Seats:'))
|
||||
self.aggMenu.append(item)
|
||||
#
|
||||
item = gtk.CheckMenuItem(' Any Number')
|
||||
|
||||
item = gtk.CheckMenuItem(_(' Any Number'))
|
||||
self.aggMenu.append(item)
|
||||
item.connect("activate", self.set_seats_style, ('P','A'))
|
||||
setattr(self, 'h_seatsStyleOptionA', item)
|
||||
#
|
||||
item = gtk.CheckMenuItem(' Custom')
|
||||
|
||||
item = gtk.CheckMenuItem(_(' Custom'))
|
||||
self.aggMenu.append(item)
|
||||
item.connect("activate", self.set_seats_style, ('P','C'))
|
||||
setattr(self, 'h_seatsStyleOptionC', item)
|
||||
#
|
||||
item = gtk.CheckMenuItem(' Exact')
|
||||
|
||||
item = gtk.CheckMenuItem(_(' Exact'))
|
||||
self.aggMenu.append(item)
|
||||
item.connect("activate", self.set_seats_style, ('P','E'))
|
||||
setattr(self, 'h_seatsStyleOptionE', item)
|
||||
#
|
||||
item = gtk.MenuItem('Since:')
|
||||
|
||||
item = gtk.MenuItem(_('Since:'))
|
||||
self.aggMenu.append(item)
|
||||
#
|
||||
item = gtk.CheckMenuItem(' All Time')
|
||||
|
||||
item = gtk.CheckMenuItem(_(' All Time'))
|
||||
self.aggMenu.append(item)
|
||||
item.connect("activate", self.set_hud_style, ('P','A'))
|
||||
setattr(self, 'h_hudStyleOptionA', item)
|
||||
#
|
||||
item = gtk.CheckMenuItem(' Session')
|
||||
|
||||
item = gtk.CheckMenuItem(_(' Session'))
|
||||
self.aggMenu.append(item)
|
||||
item.connect("activate", self.set_hud_style, ('P','S'))
|
||||
setattr(self, 'h_hudStyleOptionS', item)
|
||||
#
|
||||
item = gtk.CheckMenuItem(' %s Days' % (self.hud_params['h_hud_days']))
|
||||
|
||||
item = gtk.CheckMenuItem(_(' %s Days') % (self.hud_params['h_hud_days']))
|
||||
self.aggMenu.append(item)
|
||||
item.connect("activate", self.set_hud_style, ('P','T'))
|
||||
setattr(self, 'h_hudStyleOptionT', item)
|
||||
|
||||
aggitem = gtk.MenuItem('Show Opponent Stats')
|
||||
aggitem = gtk.MenuItem(_('Show Opponent Stats'))
|
||||
menu.append(aggitem)
|
||||
self.aggMenu = gtk.Menu()
|
||||
aggitem.set_submenu(self.aggMenu)
|
||||
# set agg_bb_mult to 1 to stop aggregation
|
||||
item = gtk.CheckMenuItem('For This Blind Level Only')
|
||||
item = gtk.CheckMenuItem(_('For This Blind Level Only'))
|
||||
self.aggMenu.append(item)
|
||||
item.connect("activate", self.set_aggregation, ('O',1))
|
||||
setattr(self, 'aggBBmultItem1', item)
|
||||
#
|
||||
item = gtk.MenuItem('For Multiple Blind Levels:')
|
||||
|
||||
item = gtk.MenuItem(_('For Multiple Blind Levels:'))
|
||||
self.aggMenu.append(item)
|
||||
#
|
||||
item = gtk.CheckMenuItem(' 0.5 to 2.0 x Current Blinds')
|
||||
|
||||
item = gtk.CheckMenuItem(_(' 0.5 to 2.0 x Current Blinds'))
|
||||
self.aggMenu.append(item)
|
||||
item.connect("activate", self.set_aggregation, ('O',2))
|
||||
setattr(self, 'aggBBmultItem2', item)
|
||||
#
|
||||
item = gtk.CheckMenuItem(' 0.33 to 3.0 x Current Blinds')
|
||||
|
||||
item = gtk.CheckMenuItem(_(' 0.33 to 3.0 x Current Blinds'))
|
||||
self.aggMenu.append(item)
|
||||
item.connect("activate", self.set_aggregation, ('O',3))
|
||||
setattr(self, 'aggBBmultItem3', item)
|
||||
#
|
||||
item = gtk.CheckMenuItem(' 0.1 to 10 x Current Blinds')
|
||||
|
||||
item = gtk.CheckMenuItem(_(' 0.1 to 10 x Current Blinds'))
|
||||
self.aggMenu.append(item)
|
||||
item.connect("activate", self.set_aggregation, ('O',10))
|
||||
setattr(self, 'aggBBmultItem10', item)
|
||||
#
|
||||
item = gtk.CheckMenuItem(' All Levels')
|
||||
|
||||
item = gtk.CheckMenuItem(_(' All Levels'))
|
||||
self.aggMenu.append(item)
|
||||
item.connect("activate", self.set_aggregation, ('O',10000))
|
||||
setattr(self, 'aggBBmultItem10000', item)
|
||||
#
|
||||
item = gtk.MenuItem('For #Seats:')
|
||||
|
||||
item = gtk.MenuItem(_('For #Seats:'))
|
||||
self.aggMenu.append(item)
|
||||
#
|
||||
item = gtk.CheckMenuItem(' Any Number')
|
||||
|
||||
item = gtk.CheckMenuItem(_(' Any Number'))
|
||||
self.aggMenu.append(item)
|
||||
item.connect("activate", self.set_seats_style, ('O','A'))
|
||||
setattr(self, 'seatsStyleOptionA', item)
|
||||
#
|
||||
item = gtk.CheckMenuItem(' Custom')
|
||||
|
||||
item = gtk.CheckMenuItem(_(' Custom'))
|
||||
self.aggMenu.append(item)
|
||||
item.connect("activate", self.set_seats_style, ('O','C'))
|
||||
setattr(self, 'seatsStyleOptionC', item)
|
||||
#
|
||||
item = gtk.CheckMenuItem(' Exact')
|
||||
|
||||
item = gtk.CheckMenuItem(_(' Exact'))
|
||||
self.aggMenu.append(item)
|
||||
item.connect("activate", self.set_seats_style, ('O','E'))
|
||||
setattr(self, 'seatsStyleOptionE', item)
|
||||
#
|
||||
item = gtk.MenuItem('Since:')
|
||||
|
||||
item = gtk.MenuItem(_('Since:'))
|
||||
self.aggMenu.append(item)
|
||||
#
|
||||
item = gtk.CheckMenuItem(' All Time')
|
||||
|
||||
item = gtk.CheckMenuItem(_(' All Time'))
|
||||
self.aggMenu.append(item)
|
||||
item.connect("activate", self.set_hud_style, ('O','A'))
|
||||
setattr(self, 'hudStyleOptionA', item)
|
||||
#
|
||||
item = gtk.CheckMenuItem(' Session')
|
||||
|
||||
item = gtk.CheckMenuItem(_(' Session'))
|
||||
self.aggMenu.append(item)
|
||||
item.connect("activate", self.set_hud_style, ('O','S'))
|
||||
setattr(self, 'hudStyleOptionS', item)
|
||||
#
|
||||
item = gtk.CheckMenuItem(' %s Days' % (self.hud_params['h_hud_days']))
|
||||
|
||||
item = gtk.CheckMenuItem(_(' %s Days') % (self.hud_params['h_hud_days']))
|
||||
self.aggMenu.append(item)
|
||||
item.connect("activate", self.set_hud_style, ('O','T'))
|
||||
setattr(self, 'hudStyleOptionT', item)
|
||||
|
|
@ -296,7 +307,7 @@ class Hud:
|
|||
getattr(self, 'h_aggBBmultItem10').set_active(True)
|
||||
elif self.hud_params['h_agg_bb_mult'] > 9000:
|
||||
getattr(self, 'h_aggBBmultItem10000').set_active(True)
|
||||
#
|
||||
|
||||
if self.hud_params['agg_bb_mult'] == 1:
|
||||
getattr(self, 'aggBBmultItem1').set_active(True)
|
||||
elif self.hud_params['agg_bb_mult'] == 2:
|
||||
|
|
@ -307,28 +318,28 @@ class Hud:
|
|||
getattr(self, 'aggBBmultItem10').set_active(True)
|
||||
elif self.hud_params['agg_bb_mult'] > 9000:
|
||||
getattr(self, 'aggBBmultItem10000').set_active(True)
|
||||
#
|
||||
|
||||
if self.hud_params['h_seats_style'] == 'A':
|
||||
getattr(self, 'h_seatsStyleOptionA').set_active(True)
|
||||
elif self.hud_params['h_seats_style'] == 'C':
|
||||
getattr(self, 'h_seatsStyleOptionC').set_active(True)
|
||||
elif self.hud_params['h_seats_style'] == 'E':
|
||||
getattr(self, 'h_seatsStyleOptionE').set_active(True)
|
||||
#
|
||||
|
||||
if self.hud_params['seats_style'] == 'A':
|
||||
getattr(self, 'seatsStyleOptionA').set_active(True)
|
||||
elif self.hud_params['seats_style'] == 'C':
|
||||
getattr(self, 'seatsStyleOptionC').set_active(True)
|
||||
elif self.hud_params['seats_style'] == 'E':
|
||||
getattr(self, 'seatsStyleOptionE').set_active(True)
|
||||
#
|
||||
|
||||
if self.hud_params['h_hud_style'] == 'A':
|
||||
getattr(self, 'h_hudStyleOptionA').set_active(True)
|
||||
elif self.hud_params['h_hud_style'] == 'S':
|
||||
getattr(self, 'h_hudStyleOptionS').set_active(True)
|
||||
elif self.hud_params['h_hud_style'] == 'T':
|
||||
getattr(self, 'h_hudStyleOptionT').set_active(True)
|
||||
#
|
||||
|
||||
if self.hud_params['hud_style'] == 'A':
|
||||
getattr(self, 'hudStyleOptionA').set_active(True)
|
||||
elif self.hud_params['hud_style'] == 'S':
|
||||
|
|
@ -338,11 +349,11 @@ class Hud:
|
|||
|
||||
eventbox.connect_object("button-press-event", self.on_button_press, menu)
|
||||
|
||||
debugitem = gtk.MenuItem('Debug StatWindows')
|
||||
debugitem = gtk.MenuItem(_('Debug StatWindows'))
|
||||
menu.append(debugitem)
|
||||
debugitem.connect("activate", self.debug_stat_windows)
|
||||
|
||||
item5 = gtk.MenuItem('Set max seats')
|
||||
item5 = gtk.MenuItem(_('Set max seats'))
|
||||
menu.append(item5)
|
||||
maxSeatsMenu = gtk.Menu()
|
||||
item5.set_submenu(maxSeatsMenu)
|
||||
|
|
@ -351,7 +362,7 @@ class Hud:
|
|||
item.ms = i
|
||||
maxSeatsMenu.append(item)
|
||||
item.connect("activate", self.change_max_seats)
|
||||
setattr(self, 'maxSeatsMenuItem%d' % (i-1), item)
|
||||
setattr(self, 'maxSeatsMenuItem%d' % (i - 1), item)
|
||||
|
||||
eventbox.connect_object("button-press-event", self.on_button_press, menu)
|
||||
|
||||
|
|
@ -382,7 +393,7 @@ class Hud:
|
|||
|
||||
if self.hud_params['h_agg_bb_mult'] != num \
|
||||
and getattr(self, 'h_aggBBmultItem'+str(num)).get_active():
|
||||
log.debug('set_player_aggregation', num)
|
||||
log.debug('set_player_aggregation %d', num)
|
||||
self.hud_params['h_agg_bb_mult'] = num
|
||||
for mult in ('1', '2', '3', '10', '10000'):
|
||||
if mult != str(num):
|
||||
|
|
@ -393,7 +404,7 @@ class Hud:
|
|||
|
||||
if self.hud_params['agg_bb_mult'] != num \
|
||||
and getattr(self, 'aggBBmultItem'+str(num)).get_active():
|
||||
log.debug('set_opponent_aggregation', num)
|
||||
log.debug('set_opponent_aggregation %d', num)
|
||||
self.hud_params['agg_bb_mult'] = num
|
||||
for mult in ('1', '2', '3', '10', '10000'):
|
||||
if mult != str(num):
|
||||
|
|
@ -446,6 +457,13 @@ class Hud:
|
|||
log.debug("setting self.hud_params[%s] = %s" % (param, style))
|
||||
|
||||
def update_table_position(self):
|
||||
# get table's X/Y position on the desktop, and relocate all of our child windows to accomodate
|
||||
# In Windows, we can verify the existence of a Window, with win32gui.IsWindow(). In Linux, there doesn't seem to be a
|
||||
# way to verify the existence of a Window, without trying to access it, which if it doesn't exist anymore, results in a
|
||||
# big giant X trap and crash.
|
||||
# People tell me this is a bad idea, because theoretically, IsWindow() could return true now, but not be true when we actually
|
||||
# use it, but accessing a dead window doesn't result in a complete windowing system shutdown in Windows, whereas it does
|
||||
# in X. - Eric
|
||||
if os.name == 'nt':
|
||||
if not win32gui.IsWindow(self.table.number):
|
||||
self.parent.kill_hud(self, self.table.name)
|
||||
|
|
@ -454,17 +472,19 @@ class Hud:
|
|||
return False
|
||||
# anyone know how to do this in unix, or better yet, trap the X11 error that is triggered when executing the get_origin() for a closed window?
|
||||
if self.table.gdkhandle is not None:
|
||||
(x, y) = self.table.gdkhandle.get_origin()
|
||||
if self.table.x != x or self.table.y != y:
|
||||
self.table.x = x
|
||||
self.table.y = y
|
||||
self.main_window.move(x + self.site_params['xshift'], y + self.site_params['yshift'])
|
||||
(oldx, oldy) = self.table.gdkhandle.get_origin() # In Windows, this call returns (0,0) if it's an invalid window. In X, the X server is immediately killed.
|
||||
#(x, y, width, height) = self.table.get_geometry()
|
||||
#print "self.table.get_geometry=",x,y,width,height
|
||||
if self.table.oldx != oldx or self.table.oldy != oldy: # If the current position does not equal the stored position, save the new position, and then move all the sub windows.
|
||||
self.table.oldx = oldx
|
||||
self.table.oldy = oldy
|
||||
self.main_window.move(oldx + self.site_params['xshift'], oldy + self.site_params['yshift'])
|
||||
adj = self.adj_seats(self.hand, self.config)
|
||||
loc = self.config.get_locations(self.table.site, self.max)
|
||||
# TODO: is stat_windows getting converted somewhere from a list to a dict, for no good reason?
|
||||
for i, w in enumerate(self.stat_windows.itervalues()):
|
||||
(x, y) = loc[adj[i+1]]
|
||||
w.relocate(x, y)
|
||||
(oldx, oldy) = loc[adj[i+1]]
|
||||
w.relocate(oldx, oldy)
|
||||
|
||||
# While we're at it, fix the positions of mucked cards too
|
||||
for aux in self.aux_windows:
|
||||
|
|
@ -476,10 +496,10 @@ class Hud:
|
|||
return True
|
||||
|
||||
def on_button_press(self, widget, event):
|
||||
if event.button == 1:
|
||||
if event.button == 1: # if primary button, start movement
|
||||
self.main_window.begin_move_drag(event.button, int(event.x_root), int(event.y_root), event.time)
|
||||
return True
|
||||
if event.button == 3:
|
||||
if event.button == 3: # if secondary button, popup our main popup window
|
||||
widget.popup(None, None, None, event.button, event.time)
|
||||
return True
|
||||
return False
|
||||
|
|
@ -513,7 +533,10 @@ class Hud:
|
|||
def debug_stat_windows(self, *args):
|
||||
# print self.table, "\n", self.main_window.window.get_transient_for()
|
||||
for w in self.stat_windows:
|
||||
print self.stat_windows[w].window.window.get_transient_for()
|
||||
try:
|
||||
print self.stat_windows[w].window.window.get_transient_for()
|
||||
except AttributeError:
|
||||
print "this window doesnt have get_transient_for"
|
||||
|
||||
def save_layout(self, *args):
|
||||
new_layout = [(0, 0)] * self.max
|
||||
|
|
@ -521,20 +544,20 @@ class Hud:
|
|||
loc = self.stat_windows[sw].window.get_position()
|
||||
new_loc = (loc[0] - self.table.x, loc[1] - self.table.y)
|
||||
new_layout[self.stat_windows[sw].adj - 1] = new_loc
|
||||
self.config.edit_layout(self.table.site, self.max, locations = new_layout)
|
||||
self.config.edit_layout(self.table.site, self.max, locations=new_layout)
|
||||
# ask each aux to save its layout back to the config object
|
||||
[aux.save_layout() for aux in self.aux_windows]
|
||||
# save the config object back to the file
|
||||
print "Updating config file"
|
||||
print _("Updating config file")
|
||||
self.config.save()
|
||||
|
||||
def adj_seats(self, hand, config):
|
||||
|
||||
# determine how to adjust seating arrangements, if a "preferred seat" is set in the hud layout configuration
|
||||
# Need range here, not xrange -> need the actual list
|
||||
adj = range(0, self.max + 1) # default seat adjustments = no adjustment
|
||||
# does the user have a fav_seat?
|
||||
if self.max not in config.supported_sites[self.table.site].layout:
|
||||
sys.stderr.write("No layout found for %d-max games for site %s\n" % (self.max, self.table.site) )
|
||||
sys.stderr.write(_("No layout found for %d-max games for site %s\n") % (self.max, self.table.site))
|
||||
return adj
|
||||
if self.table.site != None and int(config.supported_sites[self.table.site].layout[self.max].fav_seat) > 0:
|
||||
try:
|
||||
|
|
@ -548,15 +571,15 @@ class Hud:
|
|||
if adj[j] > self.max:
|
||||
adj[j] = adj[j] - self.max
|
||||
except Exception, inst:
|
||||
sys.stderr.write("exception in adj!!!\n\n")
|
||||
sys.stderr.write("error is %s" % inst) # __str__ allows args to printed directly
|
||||
sys.stderr.write(_("exception in Hud.adj_seats\n\n"))
|
||||
sys.stderr.write(_("error is %s") % inst) # __str__ allows args to printed directly
|
||||
return adj
|
||||
|
||||
def get_actual_seat(self, name):
|
||||
for key in self.stat_dict:
|
||||
if self.stat_dict[key]['screen_name'] == name:
|
||||
return self.stat_dict[key]['seat']
|
||||
sys.stderr.write("Error finding actual seat.\n")
|
||||
sys.stderr.write(_("Error finding actual seat.\n"))
|
||||
|
||||
def create(self, hand, config, stat_dict, cards):
|
||||
# update this hud, to the stats and players as of "hand"
|
||||
|
|
@ -572,7 +595,7 @@ class Hud:
|
|||
|
||||
self.stat_dict = stat_dict
|
||||
self.cards = cards
|
||||
sys.stderr.write("------------------------------------------------------------\nCreating hud from hand %s\n" % hand)
|
||||
log.info(_('Creating hud from hand ')+str(hand))
|
||||
adj = self.adj_seats(hand, config)
|
||||
loc = self.config.get_locations(self.table.site, self.max)
|
||||
if loc is None and self.max != 10:
|
||||
|
|
@ -607,7 +630,7 @@ class Hud:
|
|||
[config.supported_games[self.poker_game].stats[stat].col] = \
|
||||
config.supported_games[self.poker_game].stats[stat].stat_name
|
||||
|
||||
if os.name == "nt":
|
||||
if os.name == "nt": # we call update_table_position() regularly in Windows to see if we're moving around. See comments on that function for why this isn't done in X.
|
||||
gobject.timeout_add(500, self.update_table_position)
|
||||
|
||||
def update(self, hand, config):
|
||||
|
|
@ -621,8 +644,8 @@ class Hud:
|
|||
try:
|
||||
statd = self.stat_dict[s]
|
||||
except KeyError:
|
||||
log.error("KeyError at the start of the for loop in update in hud_main. How this can possibly happen is totally beyond my comprehension. Your HUD may be about to get really weird. -Eric")
|
||||
log.error("(btw, the key was ", s, " and statd is...", statd)
|
||||
log.error(_("KeyError at the start of the for loop in update in hud_main. How this can possibly happen is totally beyond my comprehension. Your HUD may be about to get really weird. -Eric"))
|
||||
log.error(_("(btw, the key was %s and statd is %s") % (s, statd))
|
||||
continue
|
||||
try:
|
||||
self.stat_windows[statd['seat']].player_id = statd['player_id']
|
||||
|
|
@ -654,9 +677,12 @@ class Hud:
|
|||
|
||||
window.label[r][c].set_text(statstring)
|
||||
if statstring != "xxx": # is there a way to tell if this particular stat window is visible already, or no?
|
||||
window.window.show_all()
|
||||
unhidewindow = True
|
||||
tip = "%s\n%s\n%s, %s" % (statd['screen_name'], number[5], number[3], number[4])
|
||||
Stats.do_tip(window.e_box[r][c], tip)
|
||||
if unhidewindow: #and not window.window.visible: # there is no "visible" attribute in gtk.Window, although the docs seem to indicate there should be
|
||||
window.window.show_all()
|
||||
unhidewindow = False
|
||||
|
||||
def topify_window(self, window):
|
||||
window.set_focus_on_map(False)
|
||||
|
|
@ -672,7 +698,7 @@ class Stat_Window:
|
|||
# This handles all callbacks from button presses on the event boxes in
|
||||
# the stat windows. There is a bit of an ugly kludge to separate single-
|
||||
# and double-clicks.
|
||||
self.window.show_all()
|
||||
self.window.show() #_all()
|
||||
|
||||
if event.button == 3: # right button event
|
||||
newpopup = Popup_window(self.window, self)
|
||||
|
|
@ -731,11 +757,13 @@ class Stat_Window:
|
|||
|
||||
self.window = gtk.Window()
|
||||
self.window.set_decorated(0)
|
||||
self.window.set_property("skip-taskbar-hint", True)
|
||||
self.window.set_gravity(gtk.gdk.GRAVITY_STATIC)
|
||||
|
||||
self.window.set_title("%s" % seat)
|
||||
self.window.set_property("skip-taskbar-hint", True)
|
||||
self.window.set_focus(None) # set gtk default focus widget for this window to None
|
||||
self.window.set_focus_on_map(False)
|
||||
self.window.set_accept_focus(False)
|
||||
|
||||
grid = gtk.Table(rows = game.rows, columns = game.cols, homogeneous = False)
|
||||
self.grid = grid
|
||||
|
|
@ -926,26 +954,3 @@ class Popup_window:
|
|||
# window.present()
|
||||
|
||||
|
||||
if __name__== "__main__":
|
||||
main_window = gtk.Window()
|
||||
main_window.connect("destroy", destroy)
|
||||
label = gtk.Label('Fake main window, blah blah, blah\nblah, blah')
|
||||
main_window.add(label)
|
||||
main_window.show_all()
|
||||
|
||||
c = Configuration.Config()
|
||||
#tables = Tables.discover(c)
|
||||
t = Tables.discover_table_by_name(c, "Corona")
|
||||
if t is None:
|
||||
print "Table not found."
|
||||
db = Database.Database(c, 'fpdb', 'holdem')
|
||||
|
||||
stat_dict = db.get_stats_from_hand(1)
|
||||
|
||||
# for t in tables:
|
||||
win = Hud(None, t, 10, 'holdem', c, db) # parent, table, max, poker_game, config, db_connection
|
||||
win.create(1, c, stat_dict, None) # hand, config, stat_dict, cards):
|
||||
# t.get_details()
|
||||
win.update(8300, c) # self, hand, config):
|
||||
|
||||
gtk.main()
|
||||
|
|
|
|||
122
pyfpdb/IdentifySite.py
Normal file
122
pyfpdb/IdentifySite.py
Normal file
|
|
@ -0,0 +1,122 @@
|
|||
#!/usr/bin/python
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
#Copyright 2010 Chaz Littlejohn
|
||||
#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 L10n
|
||||
_ = L10n.get_translation()
|
||||
|
||||
import re
|
||||
import sys
|
||||
import os
|
||||
import os.path
|
||||
from optparse import OptionParser
|
||||
import codecs
|
||||
import Configuration
|
||||
import Database
|
||||
|
||||
__ARCHIVE_PRE_HEADER_REGEX='^Hand #(\d+)\s*$|\*{20}\s#\s\d+\s\*+\s+'
|
||||
re_SplitArchive = re.compile(__ARCHIVE_PRE_HEADER_REGEX)
|
||||
|
||||
|
||||
class IdentifySite:
|
||||
def __init__(self, config, in_path = '-'):
|
||||
self.in_path = in_path
|
||||
self.config = config
|
||||
self.db = Database.Database(config)
|
||||
self.sitelist = {}
|
||||
self.filelist = {}
|
||||
self.generateSiteList()
|
||||
self.walkDirectory(self.in_path, self.sitelist)
|
||||
|
||||
def generateSiteList(self):
|
||||
"""Generates a ordered dictionary of site, filter and filter name for each site in hhcs"""
|
||||
for site, hhc in self.config.hhcs.iteritems():
|
||||
filter = hhc.converter
|
||||
filter_name = filter.replace("ToFpdb", "")
|
||||
result = self.db.get_site_id(site)
|
||||
if len(result) == 1:
|
||||
self.sitelist[result[0][0]] = (site, filter, filter_name)
|
||||
else:
|
||||
pass
|
||||
|
||||
def walkDirectory(self, dir, sitelist):
|
||||
"""Walks a directory, and executes a callback on each file"""
|
||||
dir = os.path.abspath(dir)
|
||||
for file in [file for file in os.listdir(dir) if not file in [".",".."]]:
|
||||
nfile = os.path.join(dir,file)
|
||||
if os.path.isdir(nfile):
|
||||
self.walkDirectory(nfile, sitelist)
|
||||
else:
|
||||
self.idSite(nfile, sitelist)
|
||||
|
||||
def __listof(self, x):
|
||||
if isinstance(x, list) or isinstance(x, tuple):
|
||||
return x
|
||||
else:
|
||||
return [x]
|
||||
|
||||
def idSite(self, file, sitelist):
|
||||
"""Identifies the site the hh file originated from"""
|
||||
if file.endswith('.txt'):
|
||||
self.filelist[file] = ''
|
||||
archive = False
|
||||
for site, info in sitelist.iteritems():
|
||||
mod = __import__(info[1])
|
||||
obj = getattr(mod, info[2], None)
|
||||
|
||||
for kodec in self.__listof(obj.codepage):
|
||||
try:
|
||||
in_fh = codecs.open(file, 'r', kodec)
|
||||
whole_file = in_fh.read()
|
||||
in_fh.close()
|
||||
|
||||
if info[2] in ('OnGame', 'Winamax'):
|
||||
m = obj.re_HandInfo.search(whole_file)
|
||||
elif info[2] in ('PartyPoker'):
|
||||
m = obj.re_GameInfoRing.search(whole_file)
|
||||
if not m:
|
||||
m = obj.re_GameInfoTrny.search(whole_file)
|
||||
else:
|
||||
m = obj.re_GameInfo.search(whole_file)
|
||||
if re_SplitArchive.search(whole_file):
|
||||
archive = True
|
||||
if m:
|
||||
self.filelist[file] = [info[0]] + [info[1]] + [kodec] + [archive]
|
||||
break
|
||||
except:
|
||||
pass
|
||||
|
||||
def main(argv=None):
|
||||
if argv is None:
|
||||
argv = sys.argv[1:]
|
||||
|
||||
config = Configuration.Config(file = "HUD_config.test.xml")
|
||||
in_path = 'regression-test-files/'
|
||||
IdSite = IdentifySite(config, in_path)
|
||||
|
||||
print "\n----------- SITE LIST -----------"
|
||||
for site, info in IdSite.sitelist.iteritems():
|
||||
print site, info
|
||||
print "----------- END SITE LIST -----------"
|
||||
|
||||
print "\n----------- ID REGRESSION FILES -----------"
|
||||
for file, site in IdSite.filelist.iteritems():
|
||||
print file, site
|
||||
print "----------- END ID REGRESSION FILES -----------"
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
sys.exit(main())
|
||||
|
|
@ -19,30 +19,55 @@
|
|||
#see http://docs.python.org/library/imaplib.html for the python interface
|
||||
#see http://tools.ietf.org/html/rfc2060#section-6.4.4 for IMAP4 search criteria
|
||||
|
||||
from imaplib import IMAP4, IMAP4_SSL
|
||||
import PokerStarsSummary
|
||||
import L10n
|
||||
_ = L10n.get_translation()
|
||||
|
||||
from imaplib import IMAP4, IMAP4_SSL
|
||||
import sys
|
||||
import codecs
|
||||
import re
|
||||
|
||||
import Configuration
|
||||
import Database
|
||||
from Exceptions import FpdbParseError
|
||||
import SQL
|
||||
import Options
|
||||
import PokerStarsSummary
|
||||
import FullTiltPokerSummary
|
||||
|
||||
|
||||
def splitPokerStarsSummaries(summaryText): #TODO: this needs to go to PSS.py
|
||||
re_SplitTourneys = PokerStarsSummary.PokerStarsSummary.re_SplitTourneys
|
||||
splitSummaries = re.split(re_SplitTourneys, summaryText)
|
||||
|
||||
if len(splitSummaries) <= 1:
|
||||
print _("DEBUG: re_SplitTourneys isn't matching")
|
||||
|
||||
return splitSummaries
|
||||
|
||||
def splitFullTiltSummaries(summaryText):#TODO: this needs to go to FTPS.py
|
||||
re_SplitTourneys = FullTiltPokerSummary.FullTiltPokerSummary.re_SplitTourneys
|
||||
splitSummaries = re.split(re_SplitTourneys, summaryText)
|
||||
|
||||
if len(splitSummaries) <= 1:
|
||||
print _("DEBUG: re_SplitTourneys isn't matching")
|
||||
|
||||
def splitPokerStarsSummaries(emailText):
|
||||
splitSummaries=emailText.split("\nPokerStars Tournament #")[1:]
|
||||
for i in range(len(splitSummaries)):
|
||||
splitSummaries[i]="PokerStars Tournament #"+splitSummaries[i]
|
||||
return splitSummaries
|
||||
#end def emailText
|
||||
|
||||
def run(config, db):
|
||||
#print "start of IS.run"
|
||||
server=None
|
||||
#try:
|
||||
#print "useSSL",config.email.useSsl,"host",config.email.host
|
||||
if config.email.useSsl:
|
||||
server = IMAP4_SSL(config.email.host)
|
||||
#print "useSSL",config.useSsl,"host",config.host
|
||||
if config.useSsl:
|
||||
server = IMAP4_SSL(config.host)
|
||||
else:
|
||||
server = IMAP4(config.email.host)
|
||||
response = server.login(config.email.username, config.email.password) #TODO catch authentication error
|
||||
print "response to logging in:",response
|
||||
server = IMAP4(config.host)
|
||||
response = server.login(config.username, config.password) #TODO catch authentication error
|
||||
print _("response to logging in:"),response
|
||||
#print "server.list():",server.list() #prints list of folders
|
||||
|
||||
response = server.select(config.email.folder)
|
||||
response = server.select(config.folder)
|
||||
#print "response to selecting INBOX:",response
|
||||
if response[0]!="OK":
|
||||
raise error #TODO: show error message
|
||||
|
|
@ -51,31 +76,118 @@ def run(config, db):
|
|||
response, searchData = server.search(None, "SUBJECT", "PokerStars Tournament History Request")
|
||||
for messageNumber in searchData[0].split(" "):
|
||||
response, headerData = server.fetch(messageNumber, "(BODY[HEADER.FIELDS (SUBJECT)])")
|
||||
#print "response to fetch subject:",response
|
||||
if response!="OK":
|
||||
raise error #TODO: show error message
|
||||
if headerData[1].find("Subject: PokerStars Tournament History Request - Last x")!=1:
|
||||
neededMessages.append(("PS", messageNumber))
|
||||
neededMessages.append(("PS", messageNumber))
|
||||
|
||||
print _("ImapFetcher: Found %s messages to fetch") %(len(neededMessages))
|
||||
|
||||
if (len(neededMessages)==0):
|
||||
raise error #TODO: show error message
|
||||
for messageData in neededMessages:
|
||||
|
||||
email_bodies = []
|
||||
for i, messageData in enumerate(neededMessages, start=1):
|
||||
print "Retrieving message %s" % i
|
||||
response, bodyData = server.fetch(messageData[1], "(UID BODY[TEXT])")
|
||||
bodyData=bodyData[0][1]
|
||||
if response!="OK":
|
||||
raise error #TODO: show error message
|
||||
if messageData[0]=="PS":
|
||||
summaryTexts=(splitPokerStarsSummaries(bodyData))
|
||||
for summaryText in summaryTexts:
|
||||
result=PokerStarsSummary.PokerStarsSummary(db=db, config=config, siteName=u"PokerStars", summaryText=summaryText, builtFrom = "IMAP")
|
||||
#print "finished importing a PS summary with result:",result
|
||||
#TODO: count results and output to shell like hand importer does
|
||||
|
||||
print "completed running Imap import, closing server connection"
|
||||
email_bodies.append(bodyData)
|
||||
#finally:
|
||||
# try:
|
||||
server.close()
|
||||
# finally:
|
||||
# pass
|
||||
server.logout()
|
||||
print _("Completed retrieving IMAP messages, closing server connection")
|
||||
|
||||
errors = 0
|
||||
if len(email_bodies) > 0:
|
||||
errors = importSummaries(db, config, email_bodies, options = None)
|
||||
else:
|
||||
print _("No Tournament summaries found.")
|
||||
|
||||
print _("Errors: %s" % errors)
|
||||
|
||||
def readFile(filename, options):
|
||||
codepage = ["utf8"]
|
||||
whole_file = None
|
||||
if options.hhc == "PokerStars":
|
||||
codepage = PokerStarsSummary.PokerStarsSummary.codepage
|
||||
elif options.hhc == "Full Tilt Poker":
|
||||
codepage = FullTiltPokerSummary.FullTiltPokerSummary.codepage
|
||||
|
||||
for kodec in codepage:
|
||||
#print "trying", kodec
|
||||
try:
|
||||
in_fh = codecs.open(filename, 'r', kodec)
|
||||
whole_file = in_fh.read()
|
||||
in_fh.close()
|
||||
break
|
||||
except:
|
||||
pass
|
||||
|
||||
return whole_file
|
||||
|
||||
def runFake(db, config, options):
|
||||
summaryText = readFile(options.infile, options)
|
||||
importSummaries(db, config,[summaryText], options=options)
|
||||
|
||||
def importSummaries(db, config, summaries, options = None):
|
||||
# TODO: At this point we should have:
|
||||
# - list of strings to process
|
||||
# - The sitename OR specialised TourneySummary object
|
||||
# Using options is pretty ugly
|
||||
errors = 0
|
||||
for summaryText in summaries:
|
||||
# And we should def be using a 'Split' from the site object
|
||||
if options == None or options.hhc == "PokerStars":
|
||||
summaryTexts=(splitPokerStarsSummaries(summaryText))
|
||||
elif options.hhc == "Full Tilt Poker":
|
||||
summaryTexts=(splitFullTiltSummaries(summaryText))
|
||||
|
||||
print "Found %s summaries in email" %(len(summaryTexts))
|
||||
for j, summaryText in enumerate(summaryTexts, start=1):
|
||||
try:
|
||||
if options == None or options.hhc == "PokerStars":
|
||||
PokerStarsSummary.PokerStarsSummary(db=db, config=config, siteName=u"PokerStars", summaryText=summaryText, builtFrom = "IMAP")
|
||||
elif options.hhc == "Full Tilt Poker":
|
||||
FullTiltPokerSummary.FullTiltPokerSummary(db=db, config=config, siteName=u"Fulltilt", summaryText=summaryText, builtFrom = "IMAP")
|
||||
except FpdbParseError, e:
|
||||
errors += 1
|
||||
print _("Finished importing %s/%s PS summaries") %(j, len(summaryTexts))
|
||||
|
||||
return errors
|
||||
|
||||
|
||||
def main(argv=None):
|
||||
if argv is None:
|
||||
argv = sys.argv[1:]
|
||||
|
||||
(options, argv) = Options.fpdb_options()
|
||||
|
||||
if options.usage == True:
|
||||
#Print usage examples and exit
|
||||
print _("USAGE:")
|
||||
sys.exit(0)
|
||||
|
||||
if options.hhc == "PokerStarsToFpdb":
|
||||
print _("Need to define a converter")
|
||||
exit(0)
|
||||
|
||||
# These options should really come from the OptionsParser
|
||||
config = Configuration.Config()
|
||||
db = Database.Database(config)
|
||||
sql = SQL.Sql(db_server = 'sqlite')
|
||||
settings = {}
|
||||
settings.update(config.get_db_parameters())
|
||||
settings.update(config.get_import_parameters())
|
||||
settings.update(config.get_default_paths())
|
||||
db.recreate_tables()
|
||||
|
||||
runFake(db, config, options)
|
||||
|
||||
if __name__ == '__main__':
|
||||
sys.exit(main())
|
||||
|
||||
37
pyfpdb/L10n.py
Normal file
37
pyfpdb/L10n.py
Normal file
|
|
@ -0,0 +1,37 @@
|
|||
#!/usr/bin/python
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
#Copyright 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 locale
|
||||
def pass_through(to_translate): return to_translate
|
||||
|
||||
(lang, charset) = locale.getdefaultlocale()
|
||||
if lang==None or lang[:2]=="en":
|
||||
translation=pass_through
|
||||
else:
|
||||
import gettext
|
||||
try:
|
||||
trans = gettext.translation("fpdb", localedir="locale", languages=[lang])
|
||||
trans.install()
|
||||
translation=_
|
||||
except IOError:
|
||||
translation=pass_through
|
||||
|
||||
#def translate(to_translate):
|
||||
# return _(to_translate)
|
||||
|
||||
def get_translation():
|
||||
return translation
|
||||
|
|
@ -324,7 +324,7 @@ class Stud_cards:
|
|||
for k in self.parent.hud.stat_dict.keys():
|
||||
if self.parent.hud.stat_dict[k]['seat'] == seat_no:
|
||||
return self.parent.hud.stat_dict[k]['screen_name']
|
||||
return "No Name"
|
||||
return _("No Name")
|
||||
|
||||
def clear(self):
|
||||
for r in range(0, self.rows):
|
||||
|
|
|
|||
|
|
@ -18,185 +18,318 @@
|
|||
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
########################################################################
|
||||
|
||||
import L10n
|
||||
_ = L10n.get_translation()
|
||||
|
||||
import sys
|
||||
import exceptions
|
||||
|
||||
import logging
|
||||
# logging has been set up in fpdb.py or HUD_main.py, use their settings:
|
||||
log = logging.getLogger("parser")
|
||||
|
||||
|
||||
import Configuration
|
||||
from HandHistoryConverter import *
|
||||
from decimal import Decimal
|
||||
|
||||
# OnGame HH Format
|
||||
|
||||
#Texas Hold'em $.5-$1 NL (real money), hand #P4-76915775-797
|
||||
#Table Kuopio, 20 Sep 2008 11:59 PM
|
||||
|
||||
#Seat 1: .Lucchess ($4.17 in chips)
|
||||
#Seat 3: Gloff1 ($108 in chips)
|
||||
#Seat 4: far a ($13.54 in chips)
|
||||
#Seat 5: helander2222 ($49.77 in chips)
|
||||
#Seat 6: lopllopl ($62.06 in chips)
|
||||
#Seat 7: crazyhorse6 ($101.91 in chips)
|
||||
#Seat 8: peeci ($25.02 in chips)
|
||||
#Seat 9: Manuelhertz ($49 in chips)
|
||||
#Seat 10: Eurolll ($58.25 in chips)
|
||||
#ANTES/BLINDS
|
||||
#helander2222 posts blind ($0.25), lopllopl posts blind ($0.50).
|
||||
|
||||
#PRE-FLOP
|
||||
#crazyhorse6 folds, peeci folds, Manuelhertz folds, Eurolll calls $0.50, .Lucchess calls $0.50, Gloff1 folds, far a folds, helander2222 folds, lopllopl checks.
|
||||
|
||||
#FLOP [board cards AH,8H,KH ]
|
||||
#lopllopl checks, Eurolll checks, .Lucchess checks.
|
||||
|
||||
#TURN [board cards AH,8H,KH,6S ]
|
||||
#lopllopl checks, Eurolll checks, .Lucchess checks.
|
||||
|
||||
#RIVER [board cards AH,8H,KH,6S,8S ]
|
||||
#lopllopl checks, Eurolll bets $1.25, .Lucchess folds, lopllopl folds.
|
||||
|
||||
#SHOWDOWN
|
||||
#Eurolll wins $2.92.
|
||||
|
||||
#SUMMARY
|
||||
#Dealer: far a
|
||||
#Pot: $3, (including rake: $0.08)
|
||||
#.Lucchess, loses $0.50
|
||||
#Gloff1, loses $0
|
||||
#far a, loses $0
|
||||
#helander2222, loses $0.25
|
||||
#lopllopl, loses $0.50
|
||||
#crazyhorse6, loses $0
|
||||
#peeci, loses $0
|
||||
#Manuelhertz, loses $0
|
||||
#Eurolll, bets $1.75, collects $2.92, net $1.17
|
||||
|
||||
|
||||
class OnGame(HandHistoryConverter):
|
||||
def __init__(self, config, file):
|
||||
print "Initialising OnGame converter class"
|
||||
HandHistoryConverter.__init__(self, config, file, sitename="OnGame") # Call super class init.
|
||||
self.sitename = "OnGame"
|
||||
self.setFileType("text", "cp1252")
|
||||
self.siteId = 5 # Needs to match id entry in Sites database
|
||||
#self.rexx.setGameInfoRegex('.*Blinds \$?(?P<SB>[.0-9]+)/\$?(?P<BB>[.0-9]+)')
|
||||
self.rexx.setSplitHandRegex('\n\n\n+')
|
||||
filter = "OnGame"
|
||||
filetype = "text"
|
||||
codepage = ("utf8", "cp1252")
|
||||
siteId = 5 # Needs to match id entry in Sites database
|
||||
|
||||
#Texas Hold'em $.5-$1 NL (real money), hand #P4-76915775-797
|
||||
#Table Kuopio, 20 Sep 2008 11:59 PM
|
||||
self.rexx.setHandInfoRegex(r"Texas Hold'em \$?(?P<SB>[.0-9]+)-\$?(?P<BB>[.0-9]+) NL \(real money\), hand #(?P<HID>[-A-Z\d]+)\nTable\ (?P<TABLE>[\' \w]+), (?P<DATETIME>\d\d \w+ \d\d\d\d \d\d:\d\d (AM|PM))")
|
||||
# SB BB HID TABLE DAY MON YEAR HR12 MIN AMPM
|
||||
mixes = { } # Legal mixed games
|
||||
sym = {'USD': "\$", 'CAD': "\$", 'T$': "", "EUR": "\xe2\x82\xac", "GBP": "\xa3"} # ADD Euro, Sterling, etc HERE
|
||||
substitutions = {
|
||||
'LEGAL_ISO' : "USD|EUR|GBP|CAD|FPP", # legal ISO currency codes
|
||||
'LS' : "\$|\xe2\x82\xac|" # legal currency symbols - Euro(cp1252, utf-8)
|
||||
}
|
||||
|
||||
self.rexx.button_re = re.compile('#SUMMARY\nDealer: (?P<BUTTONPNAME>.*)\n')
|
||||
limits = { 'NO_LIMIT':'nl', 'LIMIT':'fl'}
|
||||
|
||||
#Seat 1: .Lucchess ($4.17 in chips)
|
||||
self.rexx.setPlayerInfoRegex('Seat (?P<SEAT>[0-9]+): (?P<PNAME>.*) \((\$(?P<CASH>[.0-9]+) in chips)\)')
|
||||
games = { # base, category
|
||||
"TEXAS_HOLDEM" : ('hold','holdem'),
|
||||
'OMAHA_HI' : ('hold','omahahi'),
|
||||
# 'Omaha Hi/Lo' : ('hold','omahahilo'),
|
||||
# 'Razz' : ('stud','razz'),
|
||||
# 'RAZZ' : ('stud','razz'),
|
||||
'SEVEN_CARD_STUD' : ('stud','studhi'),
|
||||
'SEVEN_CARD_STUD_HI_LO' : ('stud','studhilo'),
|
||||
# 'Badugi' : ('draw','badugi'),
|
||||
# 'Triple Draw 2-7 Lowball' : ('draw','27_3draw'),
|
||||
'FIVE_CARD_DRAW' : ('draw','fivedraw')
|
||||
}
|
||||
|
||||
#ANTES/BLINDS
|
||||
#helander2222 posts blind ($0.25), lopllopl posts blind ($0.50).
|
||||
self.rexx.setPostSbRegex('(?P<PNAME>.*) posts blind \(\$?(?P<SB>[.0-9]+)\), ')
|
||||
self.rexx.setPostBbRegex('\), (?P<PNAME>.*) posts blind \(\$?(?P<BB>[.0-9]+)\).')
|
||||
self.rexx.setPostBothRegex('.*\n(?P<PNAME>.*): posts small \& big blinds \[\$? (?P<SBBB>[.0-9]+)')
|
||||
self.rexx.setHeroCardsRegex('.*\nDealt\sto\s(?P<PNAME>.*)\s\[ (?P<CARDS>.*) \]')
|
||||
# Static regexes
|
||||
# ***** End of hand R5-75443872-57 *****
|
||||
re_SplitHands = re.compile(u'\*\*\*\*\*\sEnd\sof\shand\s[-A-Z\d]+.*\n(?=\*)')
|
||||
|
||||
#lopllopl checks, Eurolll checks, .Lucchess checks.
|
||||
self.rexx.setActionStepRegex('(, )?(?P<PNAME>.*?)(?P<ATYPE> bets| checks| raises| calls| folds)( \$(?P<BET>\d*\.?\d*))?( and is all-in)?')
|
||||
# ***** History for hand R5-75443872-57 *****
|
||||
# Start hand: Wed Aug 18 19:29:10 GMT+0100 2010
|
||||
# Table: someplace [75443872] (LIMIT TEXAS_HOLDEM 0.50/1, Real money)
|
||||
#***** History for hand R5-78042004-262 *****
|
||||
#Start hand: Fri Aug 27 21:40:46 GMT+0100 2010
|
||||
#Table: Bamako [78042004] (LIMIT TEXAS_HOLDEM $0.25/$0.50, Real money)
|
||||
#User: sagi34
|
||||
#{ u'BB': None
|
||||
#, u'DATETIME': u'Fri Aug 27 22:38:26 GMT+0100 2010\\n'
|
||||
#, u'GAME': None
|
||||
#, u'HID': u'R5-78042004-346'
|
||||
#, u'TABLE': u'Bamako'
|
||||
#, u'LIMIT': None
|
||||
#, u'SB': None
|
||||
#}
|
||||
re_HandInfo = re.compile(u"""
|
||||
\*\*\*\*\*\sHistory\sfor\shand\s(?P<HID>[-A-Z\d]+).*
|
||||
Start\shand:\s(?P<DATETIME>.*)
|
||||
Table:\s(?P<TABLE>[\'\w\s]+)\s\[\d+\]\s\(
|
||||
(
|
||||
(?P<LIMIT>NO_LIMIT|Limit|LIMIT|Pot\sLimit)\s
|
||||
(?P<GAME>TEXAS_HOLDEM|OMAHA_HI|SEVEN_CARD_STUD|SEVEN_CARD_STUD_HI_LO|RAZZ|FIVE_CARD_DRAW)\s
|
||||
(%(LS)s)?(?P<SB>[.0-9]+)/
|
||||
(%(LS)s)?(?P<BB>[.0-9]+)
|
||||
)?
|
||||
""" % substitutions, re.MULTILINE|re.DOTALL|re.VERBOSE)
|
||||
|
||||
#Uchilka shows [ KC,JD ]
|
||||
self.rexx.setShowdownActionRegex('(?P<PNAME>.*) shows \[ (?P<CARDS>.+) \]')
|
||||
re_TailSplitHands = re.compile(u'(\*\*\*\*\*\sEnd\sof\shand\s[-A-Z\d]+.*\n)(?=\*)')
|
||||
re_Button = re.compile('Button: seat (?P<BUTTON>\d+)', re.MULTILINE) # Button: seat 2
|
||||
re_Board = re.compile(r"\[(?P<CARDS>.+)\]")
|
||||
|
||||
# TODO: read SUMMARY correctly for collected pot stuff.
|
||||
#Uchilka, bets $11.75, collects $23.04, net $11.29
|
||||
self.rexx.setCollectPotRegex('(?P<PNAME>.*), bets.+, collects \$(?P<POT>\d*\.?\d*), net.* ')
|
||||
self.rexx.sits_out_re = re.compile('(?P<PNAME>.*) sits out')
|
||||
self.rexx.compileRegexes()
|
||||
# Wed Aug 18 19:45:30 GMT+0100 2010
|
||||
re_DateTime = re.compile("""
|
||||
[a-zA-Z]{3}\s
|
||||
(?P<M>[a-zA-Z]{3})\s
|
||||
(?P<D>[0-9]+)\s
|
||||
(?P<H>[0-9]+):(?P<MIN>[0-9]+):(?P<S>[0-9]+)\s
|
||||
(?P<OFFSET>\w+[-+]\d+)\s
|
||||
(?P<Y>[0-9]{4})
|
||||
""", re.MULTILINE|re.VERBOSE)
|
||||
|
||||
#Seat 1: .Lucchess ($4.17 in chips)
|
||||
#Seat 1: phantomaas ($27.11)
|
||||
#Seat 5: mleo17 ($9.37)
|
||||
re_PlayerInfo = re.compile(u'Seat (?P<SEAT>[0-9]+):\s(?P<PNAME>.*)\s\((%(LS)s)?(?P<CASH>[.0-9]+)\)' % substitutions)
|
||||
|
||||
def compilePlayerRegexs(self, hand):
|
||||
players = set([player[1] for player in hand.players])
|
||||
if not players <= self.compiledPlayers: # x <= y means 'x is subset of y'
|
||||
# we need to recompile the player regexs.
|
||||
# TODO: should probably rename re_HeroCards and corresponding method,
|
||||
# since they are used to find all cards on lines starting with "Dealt to:"
|
||||
# They still identify the hero.
|
||||
self.compiledPlayers = players
|
||||
|
||||
#ANTES/BLINDS
|
||||
#helander2222 posts blind ($0.25), lopllopl posts blind ($0.50).
|
||||
player_re = "(?P<PNAME>" + "|".join(map(re.escape, players)) + ")"
|
||||
subst = {'PLYR': player_re, 'CUR': self.sym[hand.gametype['currency']]}
|
||||
self.re_PostSB = re.compile('(?P<PNAME>.*) posts small blind \((%(CUR)s)?(?P<SB>[\.0-9]+)\)' % subst, re.MULTILINE)
|
||||
self.re_PostBB = re.compile('(?P<PNAME>.*) posts big blind \((%(CUR)s)?(?P<BB>[\.0-9]+)\)' % subst, re.MULTILINE)
|
||||
self.re_Antes = re.compile(r"^%(PLYR)s: posts the ante (%(CUR)s)?(?P<ANTE>[\.0-9]+)" % subst, re.MULTILINE)
|
||||
self.re_BringIn = re.compile(r"^%(PLYR)s: brings[- ]in( low|) for (%(CUR)s)?(?P<BRINGIN>[\.0-9]+)" % subst, re.MULTILINE)
|
||||
self.re_PostBoth = re.compile('(?P<PNAME>.*): posts small \& big blind \( (%(CUR)s)?(?P<SBBB>[\.0-9]+)\)' % subst)
|
||||
self.re_PostDead = re.compile('(?P<PNAME>.*) posts dead blind \((%(CUR)s)?(?P<DEAD>[\.0-9]+)\)' % subst, re.MULTILINE)
|
||||
self.re_HeroCards = re.compile('Dealing\sto\s%(PLYR)s:\s\[(?P<CARDS>.*)\]' % subst)
|
||||
|
||||
#lopllopl checks, Eurolll checks, .Lucchess checks.
|
||||
#chumley. calls $0.25
|
||||
self.re_Action = re.compile('(, )?(?P<PNAME>.*?)(?P<ATYPE> bets| checks| raises| calls| folds)( (%(CUR)s)?(?P<BET>[\d\.]+))?( and is all-in)?' % subst)
|
||||
#self.re_Board = re.compile(r"\[board cards (?P<CARDS>.+) \]")
|
||||
|
||||
#Uchilka shows [ KC,JD ]
|
||||
self.re_ShowdownAction = re.compile('(?P<PNAME>.*) shows \[ (?P<CARDS>.+) \]')
|
||||
|
||||
#Main pot: $3.57 won by mleo17 ($3.40)
|
||||
#Side pot 1: $3.26 won by maac_5 ($3.10)
|
||||
#Main pot: $2.87 won by maac_5 ($1.37), sagi34 ($1.36)
|
||||
self.re_Pot = re.compile('(Main|Side)\spot(\s\d+)?:\s.*won\sby\s(?P<POT>.*$)', re.MULTILINE)
|
||||
self.re_CollectPot = re.compile('\s*(?P<PNAME>.*)\s\((%(CUR)s)?(?P<POT>[\.\d]+)\)' % subst)
|
||||
#Seat 5: mleo17 ($3.40), net: +$2.57, [Jd, Qd] (TWO_PAIR QUEEN, JACK)
|
||||
self.re_ShownCards = re.compile("^Seat (?P<SEAT>[0-9]+): (?P<PNAME>.*) \(.*\), net:.* \[(?P<CARDS>.*)\].*" % subst, re.MULTILINE)
|
||||
self.re_sitsOut = re.compile('(?P<PNAME>.*) sits out')
|
||||
|
||||
def readSupportedGames(self):
|
||||
pass
|
||||
return [
|
||||
["ring", "hold", "fl"],
|
||||
["ring", "hold", "nl"],
|
||||
["ring", "stud", "fl"],
|
||||
["ring", "draw", "fl"],
|
||||
]
|
||||
|
||||
def determineGameType(self):
|
||||
# Cheating with this regex, only support nlhe at the moment
|
||||
gametype = ["ring", "hold", "nl"]
|
||||
def determineGameType(self, handText):
|
||||
# Inspect the handText and return the gametype dict
|
||||
# gametype dict is: {'limitType': xxx, 'base': xxx, 'category': xxx}
|
||||
info = {}
|
||||
|
||||
m = self.rexx.hand_info_re.search(self.obs)
|
||||
gametype = gametype + [m.group('SB')]
|
||||
gametype = gametype + [m.group('BB')]
|
||||
m = self.re_HandInfo.search(handText)
|
||||
if not m:
|
||||
tmp = handText[0:100]
|
||||
log.error(_("determineGameType: Unable to recognise gametype from: '%s'") % tmp)
|
||||
log.error(_("determineGameType: Raising FpdbParseError"))
|
||||
raise FpdbParseError(_("Unable to recognise gametype from: '%s'") % tmp)
|
||||
|
||||
return gametype
|
||||
mg = m.groupdict()
|
||||
|
||||
info['type'] = 'ring'
|
||||
info['currency'] = 'USD'
|
||||
|
||||
if 'LIMIT' in mg:
|
||||
if mg['LIMIT'] in self.limits:
|
||||
info['limitType'] = self.limits[mg['LIMIT']]
|
||||
else:
|
||||
tmp = handText[0:100]
|
||||
log.error(_("determineGameType: limit not found in self.limits(%s). hand: '%s'") % (str(mg),tmp))
|
||||
log.error(_("determineGameType: Raising FpdbParseError"))
|
||||
raise FpdbParseError(_("limit not found in self.limits(%s). hand: '%s'") % (str(mg),tmp))
|
||||
if 'GAME' in mg:
|
||||
(info['base'], info['category']) = self.games[mg['GAME']]
|
||||
if 'SB' in mg:
|
||||
info['sb'] = mg['SB']
|
||||
if 'BB' in mg:
|
||||
info['bb'] = mg['BB']
|
||||
|
||||
#log.debug("determinegametype: returning "+str(info))
|
||||
return info
|
||||
|
||||
def readHandInfo(self, hand):
|
||||
m = self.rexx.hand_info_re.search(hand.string)
|
||||
hand.handid = m.group('HID')
|
||||
hand.tablename = m.group('TABLE')
|
||||
#hand.buttonpos = self.rexx.button_re.search(hand.string).group('BUTTONPNAME')
|
||||
# These work, but the info is already in the Hand class - should be used for tourneys though.
|
||||
# m.group('SB')
|
||||
# m.group('BB')
|
||||
# m.group('GAMETYPE')
|
||||
info = {}
|
||||
m = self.re_HandInfo.search(hand.handText)
|
||||
|
||||
# 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)
|
||||
if m:
|
||||
info.update(m.groupdict())
|
||||
|
||||
hand.startTime = time.strptime(m.group('DATETIME'), "%d %b %Y %I:%M %p")
|
||||
#hand.starttime = "%d/%02d/%02d %d:%02d:%02d ET" %(int(m.group('YEAR')), int(m.group('MON')), int(m.group('DAY')),
|
||||
#int(m.group('HR')), int(m.group('MIN')), int(m.group('SEC')))
|
||||
#log.debug("readHandInfo: %s" % info)
|
||||
for key in info:
|
||||
if key == 'DATETIME':
|
||||
#'Wed Aug 18 19:45:30 GMT+0100 2010
|
||||
# %a %b %d %H:%M:%S %z %Y
|
||||
#hand.startTime = time.strptime(m.group('DATETIME'), "%a %b %d %H:%M:%S GMT%z %Y")
|
||||
# Stupid library doesn't seem to support %z (http://docs.python.org/library/time.html?highlight=strptime#time.strptime)
|
||||
# So we need to re-interpret te string to be useful
|
||||
a = self.re_DateTime.search(info[key])
|
||||
if a:
|
||||
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'))
|
||||
tzoffset = a.group('OFFSET')
|
||||
else:
|
||||
datetimestr = "2010/Jan/01 01:01:01"
|
||||
log.error(_("readHandInfo: DATETIME not matched: '%s'" % info[key]))
|
||||
print "DEBUG: readHandInfo: DATETIME not matched: '%s'" % info[key]
|
||||
# TODO: Manually adjust time against OFFSET
|
||||
hand.startTime = datetime.datetime.strptime(datetimestr, "%Y/%b/%d %H:%M:%S") # also timezone at end, e.g. " ET"
|
||||
hand.startTime = HandHistoryConverter.changeTimezone(hand.startTime, tzoffset, "UTC")
|
||||
if key == 'HID':
|
||||
hand.handid = info[key]
|
||||
# Need to remove non-alphanumerics for MySQL
|
||||
hand.handid = hand.handid.replace('R','')
|
||||
hand.handid = hand.handid.replace('-','')
|
||||
if key == 'TABLE':
|
||||
hand.tablename = info[key]
|
||||
|
||||
# TODO: These
|
||||
hand.buttonpos = 1
|
||||
hand.maxseats = None # Set to None - Hand.py will guessMaxSeats()
|
||||
hand.mixed = None
|
||||
|
||||
def readPlayerStacks(self, hand):
|
||||
m = self.rexx.player_info_re.finditer(hand.string)
|
||||
players = []
|
||||
#log.debug("readplayerstacks: re is '%s'" % self.re_PlayerInfo)
|
||||
m = self.re_PlayerInfo.finditer(hand.handText)
|
||||
for a in m:
|
||||
hand.addPlayer(int(a.group('SEAT')), a.group('PNAME'), a.group('CASH'))
|
||||
|
||||
def markStreets(self, hand):
|
||||
# PREFLOP = ** Dealing down cards **
|
||||
# This re fails if, say, river is missing; then we don't get the ** that starts the river.
|
||||
#m = re.search('(\*\* Dealing down cards \*\*\n)(?P<PREFLOP>.*?\n\*\*)?( Dealing Flop \*\* \[ (?P<FLOP1>\S\S), (?P<FLOP2>\S\S), (?P<FLOP3>\S\S) \])?(?P<FLOP>.*?\*\*)?( Dealing Turn \*\* \[ (?P<TURN1>\S\S) \])?(?P<TURN>.*?\*\*)?( Dealing River \*\* \[ (?P<RIVER1>\S\S) \])?(?P<RIVER>.*)', hand.string,re.DOTALL)
|
||||
|
||||
m = re.search(r"PRE-FLOP(?P<PREFLOP>.+(?=FLOP)|.+(?=SHOWDOWN))"
|
||||
r"(FLOP (?P<FLOP>\[board cards .+ \].+(?=TURN)|.+(?=SHOWDOWN)))?"
|
||||
r"(TURN (?P<TURN>\[board cards .+ \].+(?=RIVER)|.+(?=SHOWDOWN)))?"
|
||||
r"(RIVER (?P<RIVER>\[board cards .+ \].+(?=SHOWDOWN)))?", hand.string,re.DOTALL)
|
||||
if hand.gametype['base'] in ("hold"):
|
||||
m = re.search(r"pocket cards(?P<PREFLOP>.+(?= Dealing flop )|.+(?=Summary))"
|
||||
r"( Dealing flop (?P<FLOP>\[\S\S, \S\S, \S\S\].+(?= Dealing turn)|.+(?=Summary)))?"
|
||||
r"( Dealing turn (?P<TURN>\[\S\S\].+(?= Dealing river)|.+(?=Summary)))?"
|
||||
r"( Dealing river (?P<RIVER>\[\S\S\].+(?=Summary)))?", hand.handText, re.DOTALL)
|
||||
elif hand.gametype['base'] in ("stud"):
|
||||
m = re.search(r"(?P<ANTES>.+(?=Dealing pocket cards)|.+)"
|
||||
r"(Dealing pocket cards(?P<THIRD>.+(?=Dealing 4th street)|.+))?"
|
||||
r"(Dealing 4th street(?P<FOURTH>.+(?=Dealing 5th street)|.+))?"
|
||||
r"(Dealing 5th street(?P<FIFTH>.+(?=Dealing 6th street)|.+))?"
|
||||
r"(Dealing 6th street(?P<SIXTH>.+(?=Dealing river)|.+))?"
|
||||
r"(Dealing river(?P<SEVENTH>.+))?", hand.handText,re.DOTALL)
|
||||
elif hand.gametype['base'] in ("draw"):
|
||||
m = re.search(r"(?P<PREDEAL>.+(?=Dealing pocket cards)|.+)"
|
||||
r"(Dealing pocket cards(?P<DEAL>.+(?=\*\*\* FIRST DRAW \*\*\*)|.+))?"
|
||||
r"(\*\*\* FIRST DRAW \*\*\*(?P<DRAWONE>.+(?=\*\*\* SECOND DRAW \*\*\*)|.+))?"
|
||||
r"(\*\*\* SECOND DRAW \*\*\*(?P<DRAWTWO>.+(?=\*\*\* THIRD DRAW \*\*\*)|.+))?"
|
||||
r"(\*\*\* THIRD DRAW \*\*\*(?P<DRAWTHREE>.+))?", hand.handText,re.DOTALL)
|
||||
|
||||
hand.addStreets(m)
|
||||
|
||||
#Needs to return a list in the format
|
||||
# ['player1name', 'player2name', ...] where player1name is the sb and player2name is bb,
|
||||
# addtional players are assumed to post a bb oop
|
||||
|
||||
def readCommunityCards(self, hand, street):
|
||||
self.rexx.board_re = re.compile(r"\[board cards (?P<CARDS>.+) \]")
|
||||
print hand.streets.group(street)
|
||||
def readButton(self, hand):
|
||||
m = self.re_Button.search(hand.handText)
|
||||
if m:
|
||||
hand.buttonpos = int(m.group('BUTTON'))
|
||||
else:
|
||||
log.info(_('readButton: not found'))
|
||||
|
||||
# def readCommunityCards(self, hand, street):
|
||||
# #print hand.streets.group(street)
|
||||
# if street in ('FLOP','TURN','RIVER'): # a list of streets which get dealt community cards (i.e. all but PREFLOP)
|
||||
# m = self.re_Board.search(hand.streets.group(street))
|
||||
# hand.setCommunityCards(street, m.group('CARDS').split(','))
|
||||
|
||||
def readCommunityCards(self, hand, street): # street has been matched by markStreets, so exists in this hand
|
||||
if street in ('FLOP','TURN','RIVER'): # a list of streets which get dealt community cards (i.e. all but PREFLOP)
|
||||
m = self.rexx.board_re.search(hand.streets.group(street))
|
||||
hand.setCommunityCards(street, m.group('CARDS').split(','))
|
||||
#print "DEBUG readCommunityCards:", street, hand.streets.group(street)
|
||||
m = self.re_Board.search(hand.streets[street])
|
||||
hand.setCommunityCards(street, m.group('CARDS').split(', '))
|
||||
|
||||
def readBlinds(self, hand):
|
||||
try:
|
||||
m = self.rexx.small_blind_re.search(hand.string)
|
||||
m = self.re_PostSB.search(hand.handText)
|
||||
hand.addBlind(m.group('PNAME'), 'small blind', m.group('SB'))
|
||||
except: # no small blind
|
||||
hand.addBlind(None, None, None)
|
||||
for a in self.rexx.big_blind_re.finditer(hand.string):
|
||||
except exceptions.AttributeError: # no small blind
|
||||
log.debug( _("readBlinds in noSB exception - no SB created")+str(sys.exc_info()) )
|
||||
#hand.addBlind(None, None, None)
|
||||
for a in self.re_PostBB.finditer(hand.handText):
|
||||
hand.addBlind(a.group('PNAME'), 'big blind', a.group('BB'))
|
||||
for a in self.rexx.both_blinds_re.finditer(hand.string):
|
||||
for a in self.re_PostDead.finditer(hand.handText):
|
||||
#print "DEBUG: Found dead blind: addBlind(%s, 'secondsb', %s)" %(a.group('PNAME'), a.group('DEAD'))
|
||||
hand.addBlind(a.group('PNAME'), 'secondsb', a.group('DEAD'))
|
||||
for a in self.re_PostBoth.finditer(hand.handText):
|
||||
hand.addBlind(a.group('PNAME'), 'small & big blinds', a.group('SBBB'))
|
||||
|
||||
def readAntes(self, hand):
|
||||
log.debug(_("reading antes"))
|
||||
m = self.re_Antes.finditer(hand.handText)
|
||||
for player in m:
|
||||
#~ logging.debug("hand.addAnte(%s,%s)" %(player.group('PNAME'), player.group('ANTE')))
|
||||
hand.addAnte(player.group('PNAME'), player.group('ANTE'))
|
||||
|
||||
def readBringIn(self, hand):
|
||||
m = self.re_BringIn.search(hand.handText,re.DOTALL)
|
||||
if m:
|
||||
#~ logging.debug("readBringIn: %s for %s" %(m.group('PNAME'), m.group('BRINGIN')))
|
||||
hand.addBringIn(m.group('PNAME'), m.group('BRINGIN'))
|
||||
|
||||
def readHeroCards(self, hand):
|
||||
m = self.rexx.hero_cards_re.search(hand.string)
|
||||
if(m == None):
|
||||
#Not involved in hand
|
||||
hand.involved = False
|
||||
else:
|
||||
hand.hero = m.group('PNAME')
|
||||
# "2c, qh" -> set(["2c","qc"])
|
||||
# Also works with Omaha hands.
|
||||
cards = m.group('CARDS')
|
||||
cards = set(cards.split(','))
|
||||
hand.addHoleCards(cards, m.group('PNAME'))
|
||||
# streets PREFLOP, PREDRAW, and THIRD are special cases beacause
|
||||
# we need to grab hero's cards
|
||||
for street in ('PREFLOP', 'DEAL'):
|
||||
if street in hand.streets.keys():
|
||||
m = self.re_HeroCards.finditer(hand.streets[street])
|
||||
for found in m:
|
||||
hand.hero = found.group('PNAME')
|
||||
newcards = found.group('CARDS').split(', ')
|
||||
hand.addHoleCards(street, hand.hero, closed=newcards, shown=False, mucked=False, dealt=True)
|
||||
|
||||
def readAction(self, hand, street):
|
||||
m = self.rexx.action_re.finditer(hand.streets.group(street))
|
||||
m = self.re_Action.finditer(hand.streets[street])
|
||||
for action in m:
|
||||
acts = action.groupdict()
|
||||
#log.debug("readaction: acts: %s" %acts)
|
||||
if action.group('ATYPE') == ' raises':
|
||||
hand.addRaiseTo( street, action.group('PNAME'), action.group('BET') )
|
||||
hand.addRaiseBy( street, action.group('PNAME'), action.group('BET') )
|
||||
elif action.group('ATYPE') == ' calls':
|
||||
hand.addCall( street, action.group('PNAME'), action.group('BET') )
|
||||
elif action.group('ATYPE') == ' bets':
|
||||
|
|
@ -205,28 +338,34 @@ class OnGame(HandHistoryConverter):
|
|||
hand.addFold( street, action.group('PNAME'))
|
||||
elif action.group('ATYPE') == ' checks':
|
||||
hand.addCheck( street, action.group('PNAME'))
|
||||
elif action.group('ATYPE') == ' discards':
|
||||
hand.addDiscard(street, action.group('PNAME'), action.group('BET'), action.group('DISCARDED'))
|
||||
elif action.group('ATYPE') == ' stands pat':
|
||||
hand.addStandsPat( street, action.group('PNAME'))
|
||||
else:
|
||||
print "DEBUG: unimplemented readAction: %s %s" %(action.group('PNAME'),action.group('ATYPE'),)
|
||||
#hand.actions[street] += [[action.group('PNAME'), action.group('ATYPE')]]
|
||||
# TODO: Everleaf does not record uncalled bets.
|
||||
print _("DEBUG: unimplemented readAction: '%s' '%s'") %(action.group('PNAME'),action.group('ATYPE'),)
|
||||
|
||||
def readShowdownActions(self, hand):
|
||||
for shows in self.rexx.showdown_action_re.finditer(hand.string):
|
||||
for shows in self.re_ShowdownAction.finditer(hand.handText):
|
||||
cards = shows.group('CARDS')
|
||||
cards = set(cards.split(','))
|
||||
hand.addShownCards(cards, shows.group('PNAME'))
|
||||
|
||||
def readCollectPot(self,hand):
|
||||
for m in self.rexx.collect_pot_re.finditer(hand.string):
|
||||
hand.addCollectPot(player=m.group('PNAME'),pot=m.group('POT'))
|
||||
for m in self.re_Pot.finditer(hand.handText):
|
||||
for splitpot in m.group('POT').split(','):
|
||||
for m in self.re_CollectPot.finditer(splitpot):
|
||||
hand.addCollectPot(player=m.group('PNAME'),pot=m.group('POT'))
|
||||
|
||||
def readShownCards(self,hand):
|
||||
return
|
||||
#for m in self.rexx.collect_pot_re.finditer(hand.string):
|
||||
#if m.group('CARDS') is not None:
|
||||
#cards = m.group('CARDS')
|
||||
#cards = set(cards.split(','))
|
||||
#hand.addShownCards(cards=None, player=m.group('PNAME'), holeandboard=cards)
|
||||
for m in self.re_ShownCards.finditer(hand.handText):
|
||||
cards = m.group('CARDS')
|
||||
cards = cards.split(', ') # needs to be a list, not a set--stud needs the order
|
||||
|
||||
(shown, mucked) = (False, False)
|
||||
if m.group('CARDS') is not None:
|
||||
shown = True
|
||||
hand.addShownCards(cards=cards, player=m.group('PNAME'), shown=shown, mucked=mucked)
|
||||
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -15,6 +15,9 @@
|
|||
#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 L10n
|
||||
_ = L10n.get_translation()
|
||||
|
||||
import sys
|
||||
from optparse import OptionParser
|
||||
# http://docs.python.org/library/optparse.html
|
||||
|
|
@ -25,29 +28,41 @@ def fpdb_options():
|
|||
parser = OptionParser()
|
||||
parser.add_option("-x", "--errorsToConsole",
|
||||
action="store_true",
|
||||
help="If passed error output will go to the console rather than .")
|
||||
help=_("If passed error output will go to the console rather than ."))
|
||||
parser.add_option("-d", "--databaseName",
|
||||
dest="dbname",
|
||||
help="Overrides the default database name")
|
||||
help=_("Overrides the default database name"))
|
||||
parser.add_option("-c", "--configFile",
|
||||
dest="config", default=None,
|
||||
help="Specifies a configuration file.")
|
||||
help=_("Specifies a configuration file."))
|
||||
parser.add_option("-r", "--rerunPython",
|
||||
action="store_true",
|
||||
help="Indicates program was restarted with a different path (only allowed once).")
|
||||
help=_("Indicates program was restarted with a different path (only allowed once)."))
|
||||
parser.add_option("-i", "--infile",
|
||||
dest="infile", default="Slartibartfast",
|
||||
help="Input file")
|
||||
help=_("Input file"))
|
||||
parser.add_option("-k", "--konverter",
|
||||
dest="hhc", default="PokerStarsToFpdb",
|
||||
help="Module name for Hand History Converter")
|
||||
help=_("Module name for Hand History Converter"))
|
||||
parser.add_option("-l", "--logging",
|
||||
dest = "log_level",
|
||||
choices = ('DEBUG', 'INFO', 'WARNING', 'ERROR', 'CRITICAL', 'EMPTY'),
|
||||
help = "Error logging level. (DEBUG, INFO, WARNING, ERROR, CRITICAL, EMPTY)",
|
||||
help = _("Error logging level:")+" (DEBUG, INFO, WARNING, ERROR, CRITICAL, EMPTY)",
|
||||
default = 'EMPTY')
|
||||
parser.add_option("-v", "--version", action = "store_true",
|
||||
help = "Print version information and exit.")
|
||||
help = _("Print version information and exit."))
|
||||
parser.add_option("-u", "--usage", action="store_true", dest="usage", default=False,
|
||||
help=_("Print some useful one liners"))
|
||||
# The following options are used for SplitHandHistory.py
|
||||
parser.add_option("-f", "--file", dest="filename", metavar="FILE", default=None,
|
||||
help=_("Input file in quiet mode"))
|
||||
parser.add_option("-o", "--outpath", dest="outpath", metavar="FILE", default=None,
|
||||
help=_("Input out path in quiet mode"))
|
||||
parser.add_option("-a", "--archive", action="store_true", dest="archive", default=False,
|
||||
help=_("File to be split is a PokerStars or Full Tilt Poker archive file"))
|
||||
parser.add_option("-n", "--numhands", dest="hands", default="100", type="int",
|
||||
help=_("How many hands do you want saved to each file. Default is 100"))
|
||||
|
||||
|
||||
(options, argv) = parser.parse_args()
|
||||
return (options, argv)
|
||||
|
|
@ -58,5 +73,5 @@ if __name__== "__main__":
|
|||
print "database name =", options.dbname
|
||||
print "config file =", options.config
|
||||
|
||||
print "press enter to end"
|
||||
print _("press enter to end")
|
||||
sys.stdin.readline()
|
||||
|
|
|
|||
|
|
@ -1,3 +1,4 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
import urllib2, re
|
||||
import pprint
|
||||
from BeautifulSoup import BeautifulSoup
|
||||
|
|
@ -6,7 +7,7 @@ from BeautifulSoup import BeautifulSoup
|
|||
playername = ''
|
||||
|
||||
if playername == '':
|
||||
print "You need to manually enter the playername"
|
||||
print _("You need to manually enter the playername")
|
||||
exit(0)
|
||||
|
||||
page = urllib2.urlopen("http://www.pocketfives.com/poker-scores/%s/" %playername)
|
||||
|
|
|
|||
|
|
@ -18,6 +18,9 @@
|
|||
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
########################################################################
|
||||
|
||||
import L10n
|
||||
_ = L10n.get_translation()
|
||||
|
||||
import sys
|
||||
from collections import defaultdict
|
||||
|
||||
|
|
@ -50,7 +53,7 @@ class PartyPoker(HandHistoryConverter):
|
|||
re_GameInfoRing = re.compile("""
|
||||
(?P<CURRENCY>\$|)\s*(?P<RINGLIMIT>[.,0-9]+)([.,0-9/$]+)?\s*(?:USD)?\s*
|
||||
(?P<LIMIT>(NL|PL|))\s*
|
||||
(?P<GAME>(Texas\ Hold\'em|Omaha))
|
||||
(?P<GAME>(Texas\ Hold\'em|Omaha|7 Card Stud Hi-Lo))
|
||||
\s*\-\s*
|
||||
(?P<DATETIME>.+)
|
||||
""", re.VERBOSE | re.UNICODE)
|
||||
|
|
@ -97,8 +100,7 @@ class PartyPoker(HandHistoryConverter):
|
|||
re_NoSmallBlind = re.compile(
|
||||
'^There is no Small Blind in this hand as the Big Blind '
|
||||
'of the previous hand left the table', re.MULTILINE)
|
||||
re_ringSB = re.compile(r"(?P<PLAYER>.*) posts small blind \[\$(?P<RINGSB>[.,0-9]*) USD\]\.")
|
||||
re_ringBB = re.compile(r"(?P<PLAYER>.*) posts big blind \[\$(?P<RINGBB>[.,0-9]*) USD\]\.")
|
||||
re_20BBmin = re.compile(r"Table 20BB Min")
|
||||
|
||||
def allHandsAsList(self):
|
||||
list = HandHistoryConverter.allHandsAsList(self)
|
||||
|
|
@ -192,9 +194,12 @@ class PartyPoker(HandHistoryConverter):
|
|||
info = {}
|
||||
handText = self.decode_hand_text(handText)
|
||||
m = self._getGameType(handText)
|
||||
m_sb = self.re_ringSB.search(handText)
|
||||
m_bb = self.re_ringBB.search(handText)
|
||||
m_20BBmin = self.re_20BBmin.search(handText)
|
||||
if m is None:
|
||||
tmp = handText[0:100]
|
||||
log.error(_("determineGameType: Unable to recognise gametype from: '%s'") % tmp)
|
||||
log.error(_("determineGameType: Raising FpdbParseError"))
|
||||
raise FpdbParseError(_("Unable to recognise gametype from: '%s'") % tmp)
|
||||
return None
|
||||
|
||||
mg = m.groupdict()
|
||||
|
|
@ -203,21 +208,22 @@ class PartyPoker(HandHistoryConverter):
|
|||
games = { # base, category
|
||||
"Texas Hold'em" : ('hold','holdem'),
|
||||
'Omaha' : ('hold','omahahi'),
|
||||
"7 Card Stud Hi-Lo" : ('stud','studhi'),
|
||||
}
|
||||
currencies = { '$':'USD', '':'T$' }
|
||||
|
||||
for expectedField in ['LIMIT', 'GAME']:
|
||||
if mg[expectedField] is None:
|
||||
raise FpdbParseError( "Cannot fetch field '%s'" % expectedField)
|
||||
raise FpdbParseError(_("Cannot fetch field '%s'") % expectedField)
|
||||
try:
|
||||
info['limitType'] = limits[mg['LIMIT'].strip()]
|
||||
except:
|
||||
raise FpdbParseError("Unknown limit '%s'" % mg['LIMIT'])
|
||||
raise FpdbParseError(_("Unknown limit '%s'") % mg['LIMIT'])
|
||||
|
||||
try:
|
||||
(info['base'], info['category']) = games[mg['GAME']]
|
||||
except:
|
||||
raise FpdbParseError("Unknown game type '%s'" % mg['GAME'])
|
||||
raise FpdbParseError(_("Unknown game type '%s'") % mg['GAME'])
|
||||
|
||||
if 'TOURNO' in mg:
|
||||
info['type'] = 'tour'
|
||||
|
|
@ -225,8 +231,18 @@ class PartyPoker(HandHistoryConverter):
|
|||
info['type'] = 'ring'
|
||||
|
||||
if info['type'] == 'ring':
|
||||
info['sb'] = m_sb.group('RINGSB')
|
||||
info['bb'] = m_bb.group('RINGBB')
|
||||
if m_20BBmin is None:
|
||||
bb = float(mg['RINGLIMIT'])/100.0
|
||||
else:
|
||||
bb = float(mg['RINGLIMIT'])/40.0
|
||||
|
||||
if bb == 0.25:
|
||||
sb = 0.10
|
||||
else:
|
||||
sb = bb/2.0
|
||||
|
||||
info['bb'] = "%.2f" % (bb)
|
||||
info['sb'] = "%.2f" % (sb)
|
||||
info['currency'] = currencies[mg['CURRENCY']]
|
||||
else:
|
||||
info['sb'] = clearMoneyString(mg['SB'])
|
||||
|
|
@ -245,17 +261,17 @@ class PartyPoker(HandHistoryConverter):
|
|||
try:
|
||||
info.update(self.re_Hid.search(hand.handText).groupdict())
|
||||
except:
|
||||
raise FpdbParseError("Cannot read HID for current hand")
|
||||
raise FpdbParseError(_("Cannot read HID for current hand"))
|
||||
|
||||
try:
|
||||
info.update(self.re_HandInfo.search(hand.handText,re.DOTALL).groupdict())
|
||||
except:
|
||||
raise FpdbParseError("Cannot read Handinfo for current hand", hid = info['HID'])
|
||||
raise FpdbParseError(_("Cannot read Handinfo for current hand"), hid = info['HID'])
|
||||
|
||||
try:
|
||||
info.update(self._getGameType(hand.handText).groupdict())
|
||||
except:
|
||||
raise FpdbParseError("Cannot read GameType for current hand", hid = info['HID'])
|
||||
raise FpdbParseError(_("Cannot read GameType for current hand"), hid = info['HID'])
|
||||
|
||||
|
||||
m = self.re_CountedSeats.search(hand.handText)
|
||||
|
|
@ -310,9 +326,9 @@ class PartyPoker(HandHistoryConverter):
|
|||
if key == 'TABLE':
|
||||
hand.tablename = info[key]
|
||||
if key == 'MTTTABLE':
|
||||
if info[key] != None:
|
||||
hand.tablename = info[key]
|
||||
hand.tourNo = info['TABLE']
|
||||
if info[key] != None:
|
||||
hand.tablename = info[key]
|
||||
hand.tourNo = info['TABLE']
|
||||
if key == 'BUTTON':
|
||||
hand.buttonpos = info[key]
|
||||
if key == 'TOURNO':
|
||||
|
|
@ -343,15 +359,59 @@ class PartyPoker(HandHistoryConverter):
|
|||
if m:
|
||||
hand.buttonpos = int(m.group('BUTTON'))
|
||||
else:
|
||||
log.info('readButton: not found')
|
||||
log.info(_('readButton: not found'))
|
||||
|
||||
def readPlayerStacks(self, hand):
|
||||
log.debug("readPlayerStacks")
|
||||
m = self.re_PlayerInfo.finditer(hand.handText)
|
||||
players = []
|
||||
maxKnownStack = 0
|
||||
zeroStackPlayers = []
|
||||
for a in m:
|
||||
hand.addPlayer(int(a.group('SEAT')), a.group('PNAME'),
|
||||
clearMoneyString(a.group('CASH')))
|
||||
if a.group('CASH') > '0':
|
||||
#record max known stack for use with players with unknown stack
|
||||
maxKnownStack = max(a.group('CASH'),maxKnownStack)
|
||||
hand.addPlayer(int(a.group('SEAT')), a.group('PNAME'), clearMoneyString(a.group('CASH')))
|
||||
else:
|
||||
#zero stacked players are added later
|
||||
zeroStackPlayers.append([int(a.group('SEAT')), a.group('PNAME'), clearMoneyString(a.group('CASH'))])
|
||||
|
||||
if hand.gametype['type'] == 'ring':
|
||||
#finds first vacant seat after an exact seat
|
||||
def findFirstEmptySeat(startSeat):
|
||||
while startSeat in occupiedSeats:
|
||||
if startSeat >= hand.maxseats:
|
||||
startSeat = 0
|
||||
startSeat += 1
|
||||
return startSeat
|
||||
|
||||
re_JoiningPlayers = re.compile(r"(?P<PLAYERNAME>.*) has joined the table")
|
||||
re_BBPostingPlayers = re.compile(r"(?P<PLAYERNAME>.*) posts big blind")
|
||||
|
||||
match_JoiningPlayers = re_JoiningPlayers.findall(hand.handText)
|
||||
match_BBPostingPlayers = re_BBPostingPlayers.findall(hand.handText)
|
||||
|
||||
#add every player with zero stack, but:
|
||||
#if a zero stacked player is just joined the table in this very hand then set his stack to maxKnownStack
|
||||
for p in zeroStackPlayers:
|
||||
if p[1] in match_JoiningPlayers:
|
||||
p[2] = clearMoneyString(maxKnownStack)
|
||||
hand.addPlayer(p[0],p[1],p[2])
|
||||
|
||||
seatedPlayers = list([(f[1]) for f in hand.players])
|
||||
|
||||
#it works for all known cases as of 2010-09-28
|
||||
#should be refined with using match_ActivePlayers instead of match_BBPostingPlayers
|
||||
#as a leaving and rejoining player could be active without posting a BB (sample HH needed)
|
||||
unseatedActivePlayers = list(set(match_BBPostingPlayers) - set(seatedPlayers))
|
||||
|
||||
if unseatedActivePlayers:
|
||||
for player in unseatedActivePlayers:
|
||||
previousBBPoster = match_BBPostingPlayers[match_BBPostingPlayers.index(player)-1]
|
||||
previousBBPosterSeat = dict([(f[1], f[0]) for f in hand.players])[previousBBPoster]
|
||||
occupiedSeats = list([(f[0]) for f in hand.players])
|
||||
occupiedSeats.sort()
|
||||
newPlayerSeat = findFirstEmptySeat(previousBBPosterSeat)
|
||||
hand.addPlayer(newPlayerSeat,player,clearMoneyString(maxKnownStack))
|
||||
|
||||
def markStreets(self, hand):
|
||||
m = re.search(
|
||||
|
|
@ -471,7 +531,7 @@ class PartyPoker(HandHistoryConverter):
|
|||
hand.addCheck( street, playerName )
|
||||
else:
|
||||
raise FpdbParseError(
|
||||
"Unimplemented readAction: '%s' '%s'" % (playerName,actionType,),
|
||||
_("Unimplemented readAction: '%s' '%s'") % (playerName,actionType,),
|
||||
hid = hand.hid, )
|
||||
|
||||
def readShowdownActions(self, hand):
|
||||
|
|
@ -496,7 +556,11 @@ class PartyPoker(HandHistoryConverter):
|
|||
"Returns string to search in windows titles"
|
||||
if type=="tour":
|
||||
TableName = table_name.split(" ")
|
||||
return "%s.+Table\s#%s" % (TableName[0], table_number)
|
||||
print 'party', 'getTableTitleRe', "%s.+Table\s#%s" % (TableName[0], table_number)
|
||||
if len(TableName[1]) > 6:
|
||||
return "#%s" % (table_number)
|
||||
else:
|
||||
return "%s.+Table\s#%s" % (TableName[0], table_number)
|
||||
else:
|
||||
return table_name
|
||||
|
||||
|
|
@ -512,9 +576,9 @@ def renderCards(string):
|
|||
|
||||
if __name__ == "__main__":
|
||||
parser = OptionParser()
|
||||
parser.add_option("-i", "--input", dest="ipath", help="parse input hand history")
|
||||
parser.add_option("-o", "--output", dest="opath", help="output translation to", default="-")
|
||||
parser.add_option("-f", "--follow", dest="follow", help="follow (tail -f) the input", action="store_true", default=False)
|
||||
parser.add_option("-i", "--input", dest="ipath", help=_("parse input hand history"))
|
||||
parser.add_option("-o", "--output", dest="opath", help=_("output translation to"), default="-")
|
||||
parser.add_option("-f", "--follow", dest="follow", help=_("follow (tail -f) the input"), action="store_true", default=False)
|
||||
parser.add_option("-q", "--quiet",
|
||||
action="store_const", const=logging.CRITICAL, dest="verbosity", default=logging.INFO)
|
||||
parser.add_option("-v", "--verbose",
|
||||
|
|
|
|||
389
pyfpdb/PkrToFpdb.py
Executable file
389
pyfpdb/PkrToFpdb.py
Executable file
|
|
@ -0,0 +1,389 @@
|
|||
#!/usr/bin/env python
|
||||
# -*- coding: utf-8 -*-
|
||||
#
|
||||
# Copyright 2010, Carl Gherardi
|
||||
#
|
||||
# This program is free software; you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License as published by
|
||||
# the Free Software Foundation; either version 2 of the License, or
|
||||
# (at your option) any later version.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with this program; if not, write to the Free Software
|
||||
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
########################################################################
|
||||
|
||||
import L10n
|
||||
_ = L10n.get_translation()
|
||||
|
||||
import sys
|
||||
from HandHistoryConverter import *
|
||||
|
||||
|
||||
class Pkr(HandHistoryConverter):
|
||||
|
||||
# Class Variables
|
||||
|
||||
sitename = "PKR"
|
||||
filetype = "text"
|
||||
codepage = ("utf8", "cp1252")
|
||||
siteId = 12 # Needs to match id entry in Sites database
|
||||
|
||||
mixes = { 'HORSE': 'horse', '8-Game': '8game', 'HOSE': 'hose'} # Legal mixed games
|
||||
sym = {'USD': "\$"} # ADD Euro, Sterling, etc HERE
|
||||
substitutions = {
|
||||
'LEGAL_ISO' : "USD", # legal ISO currency codes
|
||||
'LS' : "\$|" # legal currency symbols - Euro(cp1252, utf-8)
|
||||
}
|
||||
|
||||
limits = { 'NO LIMIT':'nl', 'POT LIMIT':'pl', 'LIMIT':'fl' }
|
||||
games = { # base, category
|
||||
"HOLD'EM" : ('hold','holdem'),
|
||||
'FIXMEOmaha' : ('hold','omahahi'),
|
||||
'FIXMEOmaha Hi/Lo' : ('hold','omahahilo'),
|
||||
'FIXME5 Card Draw' : ('draw','fivedraw')
|
||||
}
|
||||
currencies = { u'€':'EUR', '$':'USD', '':'T$' }
|
||||
|
||||
# Static regexes
|
||||
re_GameInfo = re.compile(u"""
|
||||
Table\s\#\d+\s\-\s(?P<TABLE>[a-zA-Z\ \d]+)\s
|
||||
Starting\sHand\s\#(?P<HID>[0-9]+)\s
|
||||
Start\stime\sof\shand:\s(?P<DATETIME>.*)\s
|
||||
Last\sHand\s\#[0-9]+\s
|
||||
Game\sType:\s(?P<GAME>HOLD'EM|5\sCard\sDraw)\s
|
||||
Limit\sType:\s(?P<LIMIT>NO\sLIMIT|LIMIT|POT\sLIMIT)\s
|
||||
Table\sType\:\sRING\s
|
||||
Money\sType:\sREAL\sMONEY\s
|
||||
Blinds\sare\snow\s(?P<CURRENCY>%(LS)s|)?
|
||||
(?P<SB>[.0-9]+)/(%(LS)s)?
|
||||
(?P<BB>[.0-9]+)
|
||||
""" % substitutions, re.MULTILINE|re.VERBOSE)
|
||||
|
||||
re_PlayerInfo = re.compile(u"""
|
||||
^Seat\s(?P<SEAT>[0-9]+):\s
|
||||
(?P<PNAME>.*)\s-\s
|
||||
(%(LS)s)?(?P<CASH>[.0-9]+)
|
||||
""" % substitutions, re.MULTILINE|re.VERBOSE)
|
||||
|
||||
re_HandInfo = re.compile("""
|
||||
^Table\s\'(?P<TABLE>[-\ a-zA-Z\d]+)\'\s
|
||||
((?P<MAX>\d+)-max\s)?
|
||||
(?P<PLAY>\(Play\sMoney\)\s)?
|
||||
(Seat\s\#(?P<BUTTON>\d+)\sis\sthe\sbutton)?""",
|
||||
re.MULTILINE|re.VERBOSE)
|
||||
|
||||
re_SplitHands = re.compile('\n\n+')
|
||||
re_TailSplitHands = re.compile('(\n\n\n+)')
|
||||
re_Button = re.compile('Seat #(?P<BUTTON>\d+) is the button', re.MULTILINE)
|
||||
re_Board = re.compile(r"\[(?P<CARDS>.+)\]")
|
||||
# self.re_setHandInfoRegex('.*#(?P<HID>[0-9]+): Table (?P<TABLE>[ a-zA-Z]+) - \$?(?P<SB>[.0-9]+)/\$?(?P<BB>[.0-9]+) - (?P<GAMETYPE>.*) - (?P<HR>[0-9]+):(?P<MIN>[0-9]+) ET - (?P<YEAR>[0-9]+)/(?P<MON>[0-9]+)/(?P<DAY>[0-9]+)Table (?P<TABLE>[ a-zA-Z]+)\nSeat (?P<BUTTON>[0-9]+)')
|
||||
|
||||
re_DateTime = re.compile("""(?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]+)""", re.MULTILINE)
|
||||
|
||||
def compilePlayerRegexs(self, hand):
|
||||
players = set([player[1] for player in hand.players])
|
||||
if not players <= self.compiledPlayers: # x <= y means 'x is subset of y'
|
||||
# we need to recompile the player regexs.
|
||||
self.compiledPlayers = players
|
||||
player_re = "(?P<PNAME>" + "|".join(map(re.escape, players)) + ")"
|
||||
subst = {'PLYR': player_re, 'CUR': self.sym[hand.gametype['currency']]}
|
||||
log.debug("player_re: " + player_re)
|
||||
self.re_PostSB = re.compile(r"^%(PLYR)s posts small blind %(CUR)s(?P<SB>[.0-9]+)" % subst, re.MULTILINE)
|
||||
# FIXME: Sionel posts $0.04 is a second big blind in a different format.
|
||||
self.re_PostBB = re.compile(r"^%(PLYR)s posts big blind %(CUR)s(?P<BB>[.0-9]+)" % subst, re.MULTILINE)
|
||||
self.re_Antes = re.compile(r"^%(PLYR)s: posts the ante %(CUR)s(?P<ANTE>[.0-9]+)" % subst, re.MULTILINE)
|
||||
self.re_BringIn = re.compile(r"^%(PLYR)s: brings[- ]in( low|) for %(CUR)s(?P<BRINGIN>[.0-9]+)" % subst, re.MULTILINE)
|
||||
self.re_PostBoth = re.compile(r"^%(PLYR)s: posts small \& big blinds %(CUR)s(?P<SBBB>[.0-9]+)" % subst, re.MULTILINE)
|
||||
self.re_HeroCards = re.compile(r"^Dealing( \[(?P<OLDCARDS>.+?)\])?( \[(?P<NEWCARDS>.+?)\]) to %(PLYR)s" % subst, re.MULTILINE)
|
||||
self.re_Action = re.compile(r"""
|
||||
^%(PLYR)s(?P<ATYPE>\sbets|\schecks|\sraises|\scalls|\sfolds)(\sto)?
|
||||
(\s(%(CUR)s)?(?P<BET>[.\d]+))?
|
||||
""" % subst, re.MULTILINE|re.VERBOSE)
|
||||
self.re_ShowdownAction = re.compile(r"^%(PLYR)s shows \[(?P<CARDS>.*)\]" % subst, re.MULTILINE)
|
||||
self.re_CollectPot = re.compile(r"^%(PLYR)s wins %(CUR)s(?P<POT>[.\d]+)" % subst, re.MULTILINE)
|
||||
self.re_sitsOut = re.compile("^%s sits out" % player_re, re.MULTILINE)
|
||||
self.re_ShownCards = re.compile("^Seat (?P<SEAT>[0-9]+): %s (\(.*\) )?(?P<SHOWED>showed|mucked) \[(?P<CARDS>.*)\].*" % player_re, re.MULTILINE)
|
||||
|
||||
def readSupportedGames(self):
|
||||
return [["ring", "hold", "nl"],
|
||||
["ring", "hold", "pl"],
|
||||
["ring", "hold", "fl"],
|
||||
|
||||
["tour", "hold", "nl"],
|
||||
["tour", "hold", "pl"],
|
||||
["tour", "hold", "fl"],
|
||||
]
|
||||
|
||||
def determineGameType(self, handText):
|
||||
info = {}
|
||||
m = self.re_GameInfo.search(handText)
|
||||
if not m:
|
||||
tmp = handText[0:100]
|
||||
log.error(_("determineGameType: Unable to recognise gametype from: '%s'") % tmp)
|
||||
log.error(_("determineGameType: Raising FpdbParseError"))
|
||||
raise FpdbParseError(_("Unable to recognise gametype from: '%s'") % tmp)
|
||||
|
||||
mg = m.groupdict()
|
||||
#print "DEBUG: %s" % mg
|
||||
|
||||
info['type'] = 'ring'
|
||||
|
||||
if 'LIMIT' in mg:
|
||||
info['limitType'] = self.limits[mg['LIMIT']]
|
||||
if 'GAME' in mg:
|
||||
(info['base'], info['category']) = self.games[mg['GAME']]
|
||||
if 'SB' in mg:
|
||||
info['sb'] = mg['SB']
|
||||
if 'BB' in mg:
|
||||
info['bb'] = mg['BB']
|
||||
if 'CURRENCY' in mg:
|
||||
info['currency'] = self.currencies[mg['CURRENCY']]
|
||||
|
||||
if info['limitType'] == 'fl' and info['bb'] is not None and info['type'] == 'ring' and info['base'] != 'stud':
|
||||
try:
|
||||
info['sb'] = self.Lim_Blinds[mg['BB']][0]
|
||||
info['bb'] = self.Lim_Blinds[mg['BB']][1]
|
||||
except KeyError:
|
||||
log.error(_("determineGameType: Lim_Blinds has no lookup for '%s'" % mg['BB']))
|
||||
log.error(_("determineGameType: Raising FpdbParseError"))
|
||||
raise FpdbParseError(_("Lim_Blinds has no lookup for '%s'") % mg['BB'])
|
||||
|
||||
return info
|
||||
|
||||
def readHandInfo(self, hand):
|
||||
info = {}
|
||||
m = self.re_HandInfo.search(hand.handText,re.DOTALL)
|
||||
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]
|
||||
#2008/08/17 - 01:14:43 (ET)
|
||||
#2008/09/07 06:23:14 ET
|
||||
m1 = self.re_DateTime.finditer(info[key])
|
||||
datetimestr = "2000/01/01 00:00:00" # default used if time not found
|
||||
for a in m1:
|
||||
datetimestr = "%s/%s/%s %s:%s:%s" % (a.group('Y'), a.group('M'),a.group('D'),a.group('H'),a.group('MIN'),a.group('S'))
|
||||
hand.startTime = datetime.datetime.strptime(datetimestr, "%Y/%m/%d %H:%M:%S")
|
||||
if key == 'HID':
|
||||
hand.handid = info[key]
|
||||
if key == 'TOURNO':
|
||||
hand.tourNo = info[key]
|
||||
if key == 'BUYIN':
|
||||
if info[key] == 'Freeroll':
|
||||
hand.buyin = '$0+$0'
|
||||
else:
|
||||
#FIXME: The key looks like: '€0.82+€0.18 EUR'
|
||||
# This should be parsed properly and used
|
||||
hand.buyin = info[key]
|
||||
if key == 'LEVEL':
|
||||
hand.level = info[key]
|
||||
|
||||
if key == 'TABLE':
|
||||
if hand.tourNo != None:
|
||||
hand.tablename = re.split(" ", info[key])[1]
|
||||
else:
|
||||
hand.tablename = info[key]
|
||||
if key == 'BUTTON':
|
||||
hand.buttonpos = info[key]
|
||||
if key == 'MAX':
|
||||
hand.maxseats = int(info[key])
|
||||
|
||||
if key == 'MIXED':
|
||||
hand.mixed = self.mixes[info[key]] if info[key] is not None else None
|
||||
if key == 'PLAY' and info['PLAY'] is not None:
|
||||
# hand.currency = 'play' # overrides previously set value
|
||||
hand.gametype['currency'] = 'play'
|
||||
|
||||
def readButton(self, hand):
|
||||
m = self.re_Button.search(hand.handText)
|
||||
if m:
|
||||
hand.buttonpos = int(m.group('BUTTON'))
|
||||
else:
|
||||
log.info('readButton: not found')
|
||||
|
||||
def readPlayerStacks(self, hand):
|
||||
log.debug("readPlayerStacks")
|
||||
m = self.re_PlayerInfo.finditer(hand.handText)
|
||||
players = {} # Player Stacks are printed in the same format
|
||||
# At the beginning and end of the hand history
|
||||
# The hash is to cache the player names, and ignore
|
||||
# The second round
|
||||
for a in m:
|
||||
if players.has_key(a.group('PNAME')):
|
||||
pass # Ignore
|
||||
else:
|
||||
#print "DEBUG: addPlayer(%s, %s, %s)" % (a.group('SEAT'), a.group('PNAME'), a.group('CASH'))
|
||||
hand.addPlayer(int(a.group('SEAT')), a.group('PNAME'), a.group('CASH'))
|
||||
players[a.group('PNAME')] = True
|
||||
|
||||
def markStreets(self, hand):
|
||||
# PREFLOP = ** Dealing down cards **
|
||||
# This re fails if, say, river is missing; then we don't get the ** that starts the river.
|
||||
if hand.gametype['base'] in ("hold"):
|
||||
m = re.search(r"Dealing Cards(?P<PREFLOP>.+(?=Dealing Flop)|.+)"
|
||||
r"(Dealing Flop(?P<FLOP> \[\S\S \S\S \S\S\].+(?=Dealing Turn)|.+))?"
|
||||
r"(Dealing Turn (?P<TURN>\[\S\S\].+(?=Dealing River)|.+))?"
|
||||
r"(Dealing River (?P<RIVER>\[\S\S\].+))?", hand.handText,re.DOTALL)
|
||||
elif hand.gametype['base'] in ("stud"):
|
||||
m = re.search(r"(?P<ANTES>.+(?=\*\*\* 3rd STREET \*\*\*)|.+)"
|
||||
r"(\*\*\* 3rd STREET \*\*\*(?P<THIRD>.+(?=\*\*\* 4th STREET \*\*\*)|.+))?"
|
||||
r"(\*\*\* 4th STREET \*\*\*(?P<FOURTH>.+(?=\*\*\* 5th STREET \*\*\*)|.+))?"
|
||||
r"(\*\*\* 5th STREET \*\*\*(?P<FIFTH>.+(?=\*\*\* 6th STREET \*\*\*)|.+))?"
|
||||
r"(\*\*\* 6th STREET \*\*\*(?P<SIXTH>.+(?=\*\*\* RIVER \*\*\*)|.+))?"
|
||||
r"(\*\*\* RIVER \*\*\*(?P<SEVENTH>.+))?", hand.handText,re.DOTALL)
|
||||
elif hand.gametype['base'] in ("draw"):
|
||||
m = re.search(r"(?P<PREDEAL>.+(?=\*\*\* DEALING HANDS \*\*\*)|.+)"
|
||||
r"(\*\*\* DEALING HANDS \*\*\*(?P<DEAL>.+(?=\*\*\* FIRST DRAW \*\*\*)|.+))?"
|
||||
r"(\*\*\* FIRST DRAW \*\*\*(?P<DRAWONE>.+(?=\*\*\* SECOND DRAW \*\*\*)|.+))?"
|
||||
r"(\*\*\* SECOND DRAW \*\*\*(?P<DRAWTWO>.+(?=\*\*\* THIRD DRAW \*\*\*)|.+))?"
|
||||
r"(\*\*\* THIRD DRAW \*\*\*(?P<DRAWTHREE>.+))?", hand.handText,re.DOTALL)
|
||||
hand.addStreets(m)
|
||||
|
||||
def readCommunityCards(self, hand, street): # street has been matched by markStreets, so exists in this hand
|
||||
if street in ('FLOP','TURN','RIVER'): # a list of streets which get dealt community cards (i.e. all but PREFLOP)
|
||||
#print "DEBUG readCommunityCards:", street, hand.streets.group(street)
|
||||
m = self.re_Board.search(hand.streets[street])
|
||||
hand.setCommunityCards(street, m.group('CARDS').split(' '))
|
||||
|
||||
def readAntes(self, hand):
|
||||
log.debug("reading antes")
|
||||
m = self.re_Antes.finditer(hand.handText)
|
||||
for player in m:
|
||||
#~ logging.debug("hand.addAnte(%s,%s)" %(player.group('PNAME'), player.group('ANTE')))
|
||||
hand.addAnte(player.group('PNAME'), player.group('ANTE'))
|
||||
|
||||
def readBringIn(self, hand):
|
||||
m = self.re_BringIn.search(hand.handText,re.DOTALL)
|
||||
if m:
|
||||
#~ logging.debug("readBringIn: %s for %s" %(m.group('PNAME'), m.group('BRINGIN')))
|
||||
hand.addBringIn(m.group('PNAME'), m.group('BRINGIN'))
|
||||
|
||||
def readBlinds(self, hand):
|
||||
try:
|
||||
m = self.re_PostSB.search(hand.handText)
|
||||
hand.addBlind(m.group('PNAME'), 'small blind', m.group('SB'))
|
||||
except: # no small blind
|
||||
hand.addBlind(None, None, None)
|
||||
for a in self.re_PostBB.finditer(hand.handText):
|
||||
hand.addBlind(a.group('PNAME'), 'big blind', a.group('BB'))
|
||||
for a in self.re_PostBoth.finditer(hand.handText):
|
||||
hand.addBlind(a.group('PNAME'), 'both', a.group('SBBB'))
|
||||
|
||||
def readHeroCards(self, hand):
|
||||
# streets PREFLOP, PREDRAW, and THIRD are special cases beacause
|
||||
# we need to grab hero's cards
|
||||
for street in ('PREFLOP', 'DEAL'):
|
||||
if street in hand.streets.keys():
|
||||
m = self.re_HeroCards.finditer(hand.streets[street])
|
||||
for found in m:
|
||||
# if m == None:
|
||||
# hand.involved = False
|
||||
# else:
|
||||
hand.hero = found.group('PNAME')
|
||||
newcards = found.group('NEWCARDS').split(' ')
|
||||
hand.addHoleCards(street, hand.hero, closed=newcards, shown=False, mucked=False, dealt=True)
|
||||
|
||||
for street, text in hand.streets.iteritems():
|
||||
if not text or street in ('PREFLOP', 'DEAL'): continue # already done these
|
||||
m = self.re_HeroCards.finditer(hand.streets[street])
|
||||
for found in m:
|
||||
player = found.group('PNAME')
|
||||
if found.group('NEWCARDS') is None:
|
||||
newcards = []
|
||||
else:
|
||||
newcards = found.group('NEWCARDS').split(' ')
|
||||
if found.group('OLDCARDS') is None:
|
||||
oldcards = []
|
||||
else:
|
||||
oldcards = found.group('OLDCARDS').split(' ')
|
||||
|
||||
if street == 'THIRD' and len(newcards) == 3: # hero in stud game
|
||||
hand.hero = player
|
||||
hand.dealt.add(player) # need this for stud??
|
||||
hand.addHoleCards(street, player, closed=newcards[0:2], open=[newcards[2]], shown=False, mucked=False, dealt=False)
|
||||
else:
|
||||
hand.addHoleCards(street, player, open=newcards, closed=oldcards, shown=False, mucked=False, dealt=False)
|
||||
|
||||
|
||||
def readAction(self, hand, street):
|
||||
m = self.re_Action.finditer(hand.streets[street])
|
||||
for action in m:
|
||||
acts = action.groupdict()
|
||||
#print "DEBUG: readAction: acts: %s" % acts
|
||||
if action.group('ATYPE') == ' raises':
|
||||
hand.addRaiseTo( street, action.group('PNAME'), action.group('BET') )
|
||||
elif action.group('ATYPE') == ' calls':
|
||||
# Amount in hand history is not cumulative
|
||||
# ie. Player3 calls 0.08
|
||||
# Player5 raises to 0.16
|
||||
# Player3 calls 0.16 (Doh! he's only calling 0.08
|
||||
# TODO: Going to have to write an addCallStoopid()
|
||||
#print "DEBUG: addCall( %s, %s, None)" %(street,action.group('PNAME'))
|
||||
hand.addCall( street, action.group('PNAME'), action.group('BET') )
|
||||
elif action.group('ATYPE') == ' bets':
|
||||
hand.addBet( street, action.group('PNAME'), action.group('BET') )
|
||||
elif action.group('ATYPE') == ' folds':
|
||||
hand.addFold( street, action.group('PNAME'))
|
||||
elif action.group('ATYPE') == ' checks':
|
||||
hand.addCheck( street, action.group('PNAME'))
|
||||
elif action.group('ATYPE') == ' discards':
|
||||
hand.addDiscard(street, action.group('PNAME'), action.group('BET'), action.group('DISCARDED'))
|
||||
elif action.group('ATYPE') == ' stands pat':
|
||||
hand.addStandsPat( street, action.group('PNAME'))
|
||||
else:
|
||||
print "DEBUG: unimplemented readAction: '%s' '%s'" %(action.group('PNAME'),action.group('ATYPE'),)
|
||||
|
||||
|
||||
def readShowdownActions(self, hand):
|
||||
# TODO: pick up mucks also??
|
||||
for shows in self.re_ShowdownAction.finditer(hand.handText):
|
||||
cards = shows.group('CARDS').split(' ')
|
||||
#print "DEBUG: addShownCards(%s, %s)" %(cards, shows.group('PNAME'))
|
||||
hand.addShownCards(cards, shows.group('PNAME'))
|
||||
|
||||
def readCollectPot(self,hand):
|
||||
for m in self.re_CollectPot.finditer(hand.handText):
|
||||
#print "DEBUG: addCollectPot(%s, %s)" %(m.group('PNAME'), m.group('POT'))
|
||||
hand.addCollectPot(player=m.group('PNAME'),pot=m.group('POT'))
|
||||
|
||||
def readShownCards(self,hand):
|
||||
for m in self.re_ShownCards.finditer(hand.handText):
|
||||
if m.group('CARDS') is not None:
|
||||
cards = m.group('CARDS')
|
||||
cards = cards.split(' ') # needs to be a list, not a set--stud needs the order
|
||||
|
||||
(shown, mucked) = (False, False)
|
||||
if m.group('SHOWED') == "showed": shown = True
|
||||
elif m.group('SHOWED') == "mucked": mucked = True
|
||||
|
||||
hand.addShownCards(cards=cards, player=m.group('PNAME'), shown=shown, mucked=mucked)
|
||||
|
||||
if __name__ == "__main__":
|
||||
parser = OptionParser()
|
||||
parser.add_option("-i", "--input", dest="ipath", help="parse input hand history", default="regression-test-files/stars/horse/HH20090226 Natalie V - $0.10-$0.20 - HORSE.txt")
|
||||
parser.add_option("-o", "--output", dest="opath", help="output translation to", default="-")
|
||||
parser.add_option("-f", "--follow", dest="follow", help="follow (tail -f) the input", action="store_true", default=False)
|
||||
#parser.add_option("-q", "--quiet", action="store_const", const=logging.CRITICAL, dest="verbosity", default=logging.INFO)
|
||||
#parser.add_option("-v", "--verbose", action="store_const", const=logging.INFO, dest="verbosity")
|
||||
#parser.add_option("--vv", action="store_const", const=logging.DEBUG, dest="verbosity")
|
||||
|
||||
(options, args) = parser.parse_args()
|
||||
|
||||
e = PokerStars(in_path = options.ipath, out_path = options.opath, follow = options.follow)
|
||||
|
|
@ -17,6 +17,9 @@
|
|||
|
||||
"""pokerstars-specific summary parsing code"""
|
||||
|
||||
import L10n
|
||||
_ = L10n.get_translation()
|
||||
|
||||
from decimal import Decimal
|
||||
import datetime
|
||||
|
||||
|
|
@ -40,117 +43,110 @@ class PokerStarsSummary(TourneySummary):
|
|||
'5 Card Draw' : ('draw','fivedraw')
|
||||
}
|
||||
|
||||
re_TourNo = re.compile("\#[0-9]+,")
|
||||
re_Entries = re.compile("[0-9]+")
|
||||
re_Prizepool = re.compile("\$[0-9]+\.[0-9]+")
|
||||
re_Player = re.compile(u"""(?P<RANK>[0-9]+):\s(?P<NAME>.*)\s\(.*\),(\s)?(\$(?P<WINNINGS>[0-9]+\.[0-9]+))?(?P<STILLPLAYING>still\splaying)?""")
|
||||
re_BuyInFee = re.compile("(?P<BUYIN>[0-9]+\.[0-9]+).*(?P<FEE>[0-9]+\.[0-9]+)")
|
||||
re_FPP = re.compile("(?P<FPP>[0-9]+)\sFPP")
|
||||
#note: the dollar and cent in the below line are currency-agnostic
|
||||
re_Added = re.compile("(?P<DOLLAR>[0-9]+)\.(?P<CENT>[0-9]+)\s(?P<CURRENCY>[A-Z]+)(\sadded\sto\sthe\sprize\spool\sby\sPokerStars)")
|
||||
substitutions = {
|
||||
'LEGAL_ISO' : "USD|EUR|GBP|CAD|FPP", # legal ISO currency codes
|
||||
'LS' : "\$|\xe2\x82\xac|" # legal currency symbols - Euro(cp1252, utf-8)
|
||||
}
|
||||
|
||||
re_SplitTourneys = re.compile("PokerStars Tournament ")
|
||||
|
||||
re_TourNo = re.compile("\#(?P<TOURNO>[0-9]+),")
|
||||
|
||||
re_TourneyInfo = re.compile(u"""
|
||||
\#(?P<TOURNO>[0-9]+),\s
|
||||
(?P<LIMIT>No\sLimit|Limit|LIMIT|Pot\sLimit)\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+
|
||||
(?P<DESC>[ a-zA-Z]+\s+)?
|
||||
(Buy-In:\s\$(?P<BUYIN>[.0-9]+)(\/\$(?P<FEE>[.0-9]+))?\s+)?
|
||||
(?P<ENTRIES>[0-9]+)\splayers\s+
|
||||
(\$?(?P<ADDED>[.\d]+)\sadded\sto\sthe\sprize\spool\sby\sPokerStars\.com\s+)?
|
||||
(Total\sPrize\sPool:\s\$?(?P<PRIZEPOOL>[.0-9]+)\s+)?
|
||||
(Target\sTournament\s.*)?
|
||||
Tournament\sstarted\s-\s
|
||||
(?P<Y>[0-9]{4})\/(?P<M>[0-9]{2})\/(?P<D>[0-9]{2})[\-\s]+(?P<H>[0-9]+):(?P<MIN>[0-9]+):(?P<S>[0-9]+)\s?\(?(?P<TZ>[A-Z]+)\)\s
|
||||
""" % substitutions ,re.VERBOSE|re.MULTILINE|re.DOTALL)
|
||||
|
||||
re_Currency = re.compile(u"""(?P<CURRENCY>[%(LS)s]|FPP)""" % substitutions)
|
||||
|
||||
re_Player = re.compile(u"""(?P<RANK>[0-9]+):\s(?P<NAME>.*)\s\(.*\),(\s)?(\$(?P<WINNINGS>[0-9]+\.[0-9]+))?(?P<STILLPLAYING>still\splaying)?((?P<TICKET>Tournament\sTicket)\s\(WSOP\sStep\s(?P<LEVEL>\d)\))?(\s+)?""")
|
||||
|
||||
re_DateTime = re.compile("\[(?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]+)")
|
||||
re_DateTimeET = re.compile("(?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]+)")
|
||||
re_GameInfo = re.compile(u""".+(?P<LIMIT>No\sLimit|Limit|LIMIT|Pot\sLimit)\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)""")
|
||||
|
||||
codepage = ["utf-8"]
|
||||
|
||||
def parseSummary(self):
|
||||
lines=self.summaryText.splitlines()
|
||||
m = self.re_TourneyInfo.search(self.summaryText)
|
||||
if m == None:
|
||||
tmp = self.summaryText[0:200]
|
||||
log.error(_("parseSummary: Unable to recognise Tourney Info: '%s'") % tmp)
|
||||
log.error(_("parseSummary: Raising FpdbParseError"))
|
||||
raise FpdbParseError(_("Unable to recognise Tourney Info: '%s'") % tmp)
|
||||
|
||||
self.tourNo = self.re_TourNo.findall(lines[0])[0][1:-1] #ignore game and limit type as thats not recorded
|
||||
#print "DEBUG: m.groupdict(): %s" % m.groupdict()
|
||||
|
||||
result=self.re_GameInfo.search(lines[0])
|
||||
result=result.groupdict()
|
||||
self.gametype['limitType']=self.limits[result['LIMIT']]
|
||||
self.gametype['category']=self.games[result['GAME']][1]
|
||||
mg = m.groupdict()
|
||||
if 'TOURNO' in mg: self.tourNo = mg['TOURNO']
|
||||
if 'LIMIT' in mg: self.gametype['limitType'] = self.limits[mg['LIMIT']]
|
||||
if 'GAME' in mg: self.gametype['category'] = self.games[mg['GAME']][1]
|
||||
if mg['BUYIN'] != None:
|
||||
self.buyin = int(100*Decimal(mg['BUYIN']))
|
||||
if mg['FEE'] != None:
|
||||
self.fee = int(100*Decimal(mg['FEE']))
|
||||
if 'PRIZEPOOL' in mg: self.prizepool = mg['PRIZEPOOL']
|
||||
if 'ENTRIES' in mg: self.entries = mg['ENTRIES']
|
||||
|
||||
if lines[1].find("$")!=-1: #TODO: move this into a method and call that from PokerStarsToFpdb.py:269 if hand.buyinCurrency=="USD" etc.
|
||||
self.currency="USD"
|
||||
elif lines[1].find(u"€")!=-1:
|
||||
self.currency="EUR"
|
||||
elif lines[1].find("FPP")!=-1:
|
||||
self.currency="PSFP"
|
||||
else:
|
||||
raise FpdbParseError("didn't recognise buyin currency in:"+lines[1])
|
||||
datetimestr = "%s/%s/%s %s:%s:%s" % (mg['Y'], mg['M'], mg['D'], mg['H'], mg['MIN'], mg['S'])
|
||||
self.startTime = datetime.datetime.strptime(datetimestr, "%Y/%m/%d %H:%M:%S")
|
||||
|
||||
if self.currency=="USD" or self.currency=="EUR":
|
||||
result=self.re_BuyInFee.search(lines[1])
|
||||
result=result.groupdict()
|
||||
self.buyin=int(100*Decimal(result['BUYIN']))
|
||||
self.fee=int(100*Decimal(result['FEE']))
|
||||
elif self.currency=="PSFP":
|
||||
result=self.re_FPP.search(lines[1])
|
||||
result=result.groupdict()
|
||||
self.buyin=int(Decimal(result['FPP']))
|
||||
self.fee=0
|
||||
if 'TZ' in mg:
|
||||
self.startTime = HandHistoryConverter.changeTimezone(self.startTime, mg['TZ'], "UTC")
|
||||
|
||||
currentLine=2
|
||||
self.entries = self.re_Entries.findall(lines[currentLine])[0]
|
||||
currentLine+=1 #note that I chose to make the code keep state (the current line number)
|
||||
#as that means it'll fail rather than silently skip potentially valuable information
|
||||
#print "after entries lines[currentLine]", lines[currentLine]
|
||||
|
||||
result=self.re_Added.search(lines[currentLine])
|
||||
if result:
|
||||
result=result.groupdict()
|
||||
self.added=100*int(Decimal(result['DOLLAR']))+int(Decimal(result['CENT']))
|
||||
self.addedCurrency=result['CURRENCY']
|
||||
currentLine+=1
|
||||
else:
|
||||
self.added=0
|
||||
self.addedCurrency="NA"
|
||||
#print "after added/entries lines[currentLine]", lines[currentLine]
|
||||
m = self.re_Currency.search(self.summaryText)
|
||||
if m == None:
|
||||
log.error(_("parseSummary: Unable to locate currency"))
|
||||
log.error(_("parseSummary: Raising FpdbParseError"))
|
||||
raise FpdbParseError(_("Unable to locate currency"))
|
||||
#print "DEBUG: m.groupdict(): %s" % m.groupdict()
|
||||
|
||||
result=self.re_Prizepool.findall(lines[currentLine])
|
||||
if result:
|
||||
self.prizepool = result[0]
|
||||
self.prizepool = self.prizepool[1:-3]+self.prizepool[-2:]
|
||||
currentLine+=1
|
||||
#print "after prizepool lines[currentLine]", lines[currentLine]
|
||||
mg = m.groupdict()
|
||||
if mg['CURRENCY'] == "$": self.currency = "USD"
|
||||
elif mg['CURRENCY'] == u"€": self.currency="EUR"
|
||||
elif mg['CURRENCY'] == "FPP": self.currency="PSFP"
|
||||
|
||||
useET=False
|
||||
result=self.re_DateTime.search(lines[currentLine])
|
||||
if not result:
|
||||
print "in not result starttime"
|
||||
useET=True
|
||||
result=self.re_DateTimeET.search(lines[currentLine])
|
||||
result=result.groupdict()
|
||||
datetimestr = "%s/%s/%s %s:%s:%s" % (result['Y'], result['M'],result['D'],result['H'],result['MIN'],result['S'])
|
||||
self.startTime= datetime.datetime.strptime(datetimestr, "%Y/%m/%d %H:%M:%S") # also timezone at end, e.g. " ET"
|
||||
self.startTime = HandHistoryConverter.changeTimezone(self.startTime, "ET", "UTC")
|
||||
currentLine+=1
|
||||
m = self.re_Player.finditer(self.summaryText)
|
||||
for a in m:
|
||||
mg = a.groupdict()
|
||||
#print "DEBUG: a.groupdict(): %s" % mg
|
||||
name = mg['NAME']
|
||||
rank = mg['RANK']
|
||||
winnings = 0
|
||||
|
||||
if useET:
|
||||
result=self.re_DateTimeET.search(lines[currentLine])
|
||||
else:
|
||||
result=self.re_DateTime.search(lines[currentLine])
|
||||
if result:
|
||||
result=result.groupdict()
|
||||
datetimestr = "%s/%s/%s %s:%s:%s" % (result['Y'], result['M'],result['D'],result['H'],result['MIN'],result['S'])
|
||||
self.endTime= datetime.datetime.strptime(datetimestr, "%Y/%m/%d %H:%M:%S") # also timezone at end, e.g. " ET"
|
||||
self.endTime = HandHistoryConverter.changeTimezone(self.endTime, "ET", "UTC")
|
||||
currentLine+=1
|
||||
if 'WINNINGS' in mg and mg['WINNINGS'] != None:
|
||||
winnings = int(100*Decimal(mg['WINNINGS']))
|
||||
|
||||
if lines[currentLine].find("Tournament is still in progress")!=-1:
|
||||
currentLine+=1
|
||||
|
||||
for i in range(currentLine,len(lines)-2): #lines with rank and winnings info
|
||||
if lines[i].find(":")==-1:
|
||||
break
|
||||
result=self.re_Player.search(lines[i])
|
||||
result=result.groupdict()
|
||||
rank=result['RANK']
|
||||
name=result['NAME']
|
||||
winnings=result['WINNINGS']
|
||||
|
||||
if winnings:
|
||||
winnings=int(100*Decimal(winnings))
|
||||
else:
|
||||
winnings=0
|
||||
|
||||
if result['STILLPLAYING']:
|
||||
if 'STILLPLAYING' in mg and mg['STILLPLAYING'] != None:
|
||||
#print "stillplaying"
|
||||
rank=None
|
||||
winnings=None
|
||||
|
||||
self.addPlayer(rank, name, winnings, self.currency, None, None, None)#TODO: currency, ko/addon/rebuy count -> need examples!
|
||||
#end def parseSummary
|
||||
if 'TICKET' and mg['TICKET'] != None:
|
||||
#print "Tournament Ticket Level %s" % mg['LEVEL']
|
||||
step_values = {
|
||||
'1' : '750', # Step 1 - $7.50 USD
|
||||
'2' : '2750', # Step 2 - $27.00 USD
|
||||
'3' : '8200', # Step 3 - $82.00 USD
|
||||
'4' : '21500', # Step 4 - $215.00 USD
|
||||
'5' : '70000', # Step 5 - $700.00 USD
|
||||
'6' : '210000', # Step 6 - $2100.00 USD
|
||||
}
|
||||
winnings = step_values[mg['LEVEL']]
|
||||
|
||||
#TODO: currency, ko/addon/rebuy count -> need examples!
|
||||
#print "DEBUG: addPlayer(%s, %s, %s, %s, None, None, None)" %(rank, name, winnings, self.currency)
|
||||
#print "DEBUG: self.buyin: %s self.fee %s" %(self.buyin, self.fee)
|
||||
self.addPlayer(rank, name, winnings, self.currency, None, None, None)
|
||||
|
||||
#print self
|
||||
|
||||
#end class PokerStarsSummary
|
||||
|
|
|
|||
|
|
@ -18,6 +18,9 @@
|
|||
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
########################################################################
|
||||
|
||||
import L10n
|
||||
_ = L10n.get_translation()
|
||||
|
||||
# TODO: straighten out discards for draw games
|
||||
|
||||
import sys
|
||||
|
|
@ -36,7 +39,7 @@ class PokerStars(HandHistoryConverter):
|
|||
siteId = 2 # Needs to match id entry in Sites database
|
||||
|
||||
mixes = { 'HORSE': 'horse', '8-Game': '8game', 'HOSE': 'hose'} # Legal mixed games
|
||||
sym = {'USD': "\$", 'CAD': "\$", 'T$': "", "EUR": "\xe2\x82\xac", "GBP": "\xa3"} # ADD Euro, Sterling, etc HERE
|
||||
sym = {'USD': "\$", 'CAD': "\$", 'T$': "", "EUR": "\xe2\x82\xac", "GBP": "\xa3", "play": ""} # ADD Euro, Sterling, etc HERE
|
||||
substitutions = {
|
||||
'LEGAL_ISO' : "USD|EUR|GBP|CAD|FPP", # legal ISO currency codes
|
||||
'LS' : "\$|\xe2\x82\xac|" # legal currency symbols - Euro(cp1252, utf-8)
|
||||
|
|
@ -44,12 +47,21 @@ class PokerStars(HandHistoryConverter):
|
|||
|
||||
# translations from captured groups to fpdb info strings
|
||||
Lim_Blinds = { '0.04': ('0.01', '0.02'), '0.10': ('0.02', '0.05'), '0.20': ('0.05', '0.10'),
|
||||
'0.40': ('0.10', '0.20'), '0.50': ('0.10', '0.25'), '1.00': ('0.25', '0.50'),
|
||||
'2.00': ('0.50', '1.00'), '2': ('0.50', '1.00'), '4' : ('1.00', '2.00'),
|
||||
'4.00': ('1.00', '2.00'), '6': ('1.00', '3.00'), '6.00': ('1.00', '3.00'),
|
||||
'10.00': ('2.00', '5.00'), '20.00': ('5.00', '10.00'), '30.00': ('10.00', '15.00'),
|
||||
'60.00': ('15.00', '30.00'), '100.00': ('25.00', '50.00'), '200.00': ('50.00', '100.00'),
|
||||
'400.00': ('100.00', '200.00'), '1000.00': ('250.00', '500.00')}
|
||||
'0.40': ('0.10', '0.20'), '0.50': ('0.10', '0.25'),
|
||||
'1.00': ('0.25', '0.50'), '1': ('0.25', '0.50'),
|
||||
'2.00': ('0.50', '1.00'), '2': ('0.50', '1.00'),
|
||||
'4.00': ('1.00', '2.00'), '4': ('1.00', '2.00'),
|
||||
'6.00': ('1.00', '3.00'), '6': ('1.00', '3.00'),
|
||||
'8.00': ('2.00', '4.00'), '8': ('2.00', '4.00'),
|
||||
'10.00': ('2.00', '5.00'), '10': ('2.00', '5.00'),
|
||||
'20.00': ('5.00', '10.00'), '20': ('5.00', '10.00'),
|
||||
'30.00': ('10.00', '15.00'), '30': ('10.00', '15.00'),
|
||||
'60.00': ('15.00', '30.00'), '60': ('15.00', '30.00'),
|
||||
'100.00': ('25.00', '50.00'), '100': ('25.00', '50.00'),
|
||||
'200.00': ('50.00', '100.00'), '200': ('50.00', '100.00'),
|
||||
'400.00': ('100.00', '200.00'), '400': ('100.00', '200.00'),
|
||||
'1000.00': ('250.00', '500.00'),'1000': ('250.00', '500.00')
|
||||
}
|
||||
|
||||
limits = { 'No Limit':'nl', 'Pot Limit':'pl', 'Limit':'fl', 'LIMIT':'fl' }
|
||||
games = { # base, category
|
||||
|
|
@ -62,6 +74,7 @@ class PokerStars(HandHistoryConverter):
|
|||
'7 Card Stud Hi/Lo' : ('stud','studhilo'),
|
||||
'Badugi' : ('draw','badugi'),
|
||||
'Triple Draw 2-7 Lowball' : ('draw','27_3draw'),
|
||||
'Single Draw 2-7 Lowball' : ('draw','27_1draw'),
|
||||
'5 Card Draw' : ('draw','fivedraw')
|
||||
}
|
||||
currencies = { u'€':'EUR', '$':'USD', '':'T$' }
|
||||
|
|
@ -74,8 +87,8 @@ class PokerStars(HandHistoryConverter):
|
|||
# here's how I plan to use LS
|
||||
(?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
|
||||
(?P<MIXED>HORSE|8\-Game|HOSE|Mixed PLH/PLO)?\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|Single\sDraw\s2\-7\sLowball|5\sCard\sDraw)\s
|
||||
(?P<LIMIT>No\sLimit|Limit|LIMIT|Pot\sLimit)\)?,?\s
|
||||
(-\s)?
|
||||
(Match.*)? #TODO: waiting for reply from user as to what this means
|
||||
|
|
@ -148,6 +161,8 @@ class PokerStars(HandHistoryConverter):
|
|||
["ring", "stud", "fl"],
|
||||
|
||||
["ring", "draw", "fl"],
|
||||
["ring", "draw", "pl"],
|
||||
["ring", "draw", "nl"],
|
||||
|
||||
["tour", "hold", "nl"],
|
||||
["tour", "hold", "pl"],
|
||||
|
|
@ -157,23 +172,15 @@ class PokerStars(HandHistoryConverter):
|
|||
]
|
||||
|
||||
def determineGameType(self, handText):
|
||||
# inspect the handText and return the gametype dict
|
||||
# gametype dict is:
|
||||
# {'limitType': xxx, 'base': xxx, 'category': xxx}
|
||||
|
||||
info = {}
|
||||
m = self.re_GameInfo.search(handText)
|
||||
if not m:
|
||||
tmp = handText[0:100]
|
||||
log.error("determineGameType: Unable to recognise gametype from: '%s'" % tmp)
|
||||
log.error("determineGameType: Raising FpdbParseError")
|
||||
raise FpdbParseError("Unable to recognise gametype from: '%s'" % tmp)
|
||||
log.error(_("determineGameType: Unable to recognise gametype from: '%s'") % tmp)
|
||||
log.error(_("determineGameType: Raising FpdbParseError"))
|
||||
raise FpdbParseError(_("Unable to recognise gametype from: '%s'") % tmp)
|
||||
|
||||
mg = m.groupdict()
|
||||
# I don't think this is doing what we think. mg will always have all
|
||||
# the expected keys, but the ones that didn't match in the regex will
|
||||
# have a value of None. It is OK if it throws an exception when it
|
||||
# runs across an unknown game or limit or whatever.
|
||||
if 'LIMIT' in mg:
|
||||
info['limitType'] = self.limits[mg['LIMIT']]
|
||||
if 'GAME' in mg:
|
||||
|
|
@ -195,22 +202,22 @@ class PokerStars(HandHistoryConverter):
|
|||
info['sb'] = self.Lim_Blinds[mg['BB']][0]
|
||||
info['bb'] = self.Lim_Blinds[mg['BB']][1]
|
||||
except KeyError:
|
||||
log.error("determineGameType: Lim_Blinds has no lookup for '%s'" % mg['BB'])
|
||||
log.error("determineGameType: Raising FpdbParseError")
|
||||
raise FpdbParseError("Lim_Blinds has no lookup for '%s'" % mg['BB'])
|
||||
log.error(_("determineGameType: Lim_Blinds has no lookup for '%s'" % mg['BB']))
|
||||
log.error(_("determineGameType: Raising FpdbParseError"))
|
||||
raise FpdbParseError(_("Lim_Blinds has no lookup for '%s'") % mg['BB'])
|
||||
|
||||
return info
|
||||
|
||||
def readHandInfo(self, hand):
|
||||
info = {}
|
||||
m = self.re_HandInfo.search(hand.handText,re.DOTALL)
|
||||
if m:
|
||||
info.update(m.groupdict())
|
||||
else:
|
||||
pass # throw an exception here, eh?
|
||||
m = self.re_GameInfo.search(hand.handText)
|
||||
if m:
|
||||
info.update(m.groupdict())
|
||||
m = self.re_HandInfo.search(hand.handText,re.DOTALL)
|
||||
m2 = self.re_GameInfo.search(hand.handText)
|
||||
if m is None or m2 is None:
|
||||
log.error("Didn't match re_HandInfo")
|
||||
raise FpdbParseError(_("No match in readHandInfo."))
|
||||
|
||||
info.update(m.groupdict())
|
||||
info.update(m2.groupdict())
|
||||
|
||||
log.debug("readHandInfo: %s" % info)
|
||||
for key in info:
|
||||
|
|
@ -249,7 +256,7 @@ class PokerStars(HandHistoryConverter):
|
|||
hand.buyinCurrency="PSFP"
|
||||
else:
|
||||
#FIXME: handle other currencies, FPP, play money
|
||||
raise FpdbParseError("failed to detect currency")
|
||||
raise FpdbParseError(_("failed to detect currency"))
|
||||
|
||||
info['BIAMT'] = info['BIAMT'].strip(u'$€FPP')
|
||||
|
||||
|
|
@ -296,7 +303,7 @@ class PokerStars(HandHistoryConverter):
|
|||
if m:
|
||||
hand.buttonpos = int(m.group('BUTTON'))
|
||||
else:
|
||||
log.info('readButton: not found')
|
||||
log.info(_('readButton: not found'))
|
||||
|
||||
def readPlayerStacks(self, hand):
|
||||
log.debug("readPlayerStacks")
|
||||
|
|
@ -334,7 +341,7 @@ class PokerStars(HandHistoryConverter):
|
|||
hand.setCommunityCards(street, m.group('CARDS').split(' '))
|
||||
|
||||
def readAntes(self, hand):
|
||||
log.debug("reading antes")
|
||||
log.debug(_("reading antes"))
|
||||
m = self.re_Antes.finditer(hand.handText)
|
||||
for player in m:
|
||||
#~ logging.debug("hand.addAnte(%s,%s)" %(player.group('PNAME'), player.group('ANTE')))
|
||||
|
|
@ -416,7 +423,7 @@ class PokerStars(HandHistoryConverter):
|
|||
elif action.group('ATYPE') == ' stands pat':
|
||||
hand.addStandsPat( street, action.group('PNAME'))
|
||||
else:
|
||||
print "DEBUG: unimplemented readAction: '%s' '%s'" %(action.group('PNAME'),action.group('ATYPE'),)
|
||||
print _("DEBUG: unimplemented readAction: '%s' '%s'") %(action.group('PNAME'),action.group('ATYPE'),)
|
||||
|
||||
|
||||
def readShowdownActions(self, hand):
|
||||
|
|
@ -439,13 +446,14 @@ class PokerStars(HandHistoryConverter):
|
|||
if m.group('SHOWED') == "showed": shown = True
|
||||
elif m.group('SHOWED') == "mucked": mucked = True
|
||||
|
||||
#print "DEBUG: hand.addShownCards(%s, %s, %s, %s)" %(cards, m.group('PNAME'), shown, mucked)
|
||||
hand.addShownCards(cards=cards, player=m.group('PNAME'), shown=shown, mucked=mucked)
|
||||
|
||||
if __name__ == "__main__":
|
||||
parser = OptionParser()
|
||||
parser.add_option("-i", "--input", dest="ipath", help="parse input hand history", default="regression-test-files/stars/horse/HH20090226 Natalie V - $0.10-$0.20 - HORSE.txt")
|
||||
parser.add_option("-o", "--output", dest="opath", help="output translation to", default="-")
|
||||
parser.add_option("-f", "--follow", dest="follow", help="follow (tail -f) the input", action="store_true", default=False)
|
||||
parser.add_option("-i", "--input", dest="ipath", help=_("parse input hand history"), default="regression-test-files/stars/horse/HH20090226 Natalie V - $0.10-$0.20 - HORSE.txt")
|
||||
parser.add_option("-o", "--output", dest="opath", help=_("output translation to"), default="-")
|
||||
parser.add_option("-f", "--follow", dest="follow", help=_("follow (tail -f) the input"), action="store_true", default=False)
|
||||
#parser.add_option("-q", "--quiet", action="store_const", const=logging.CRITICAL, dest="verbosity", default=logging.INFO)
|
||||
#parser.add_option("-v", "--verbose", action="store_const", const=logging.INFO, dest="verbosity")
|
||||
#parser.add_option("--vv", action="store_const", const=logging.DEBUG, dest="verbosity")
|
||||
|
|
|
|||
158
pyfpdb/RazzStartHandGenerator.py
Normal file
158
pyfpdb/RazzStartHandGenerator.py
Normal file
|
|
@ -0,0 +1,158 @@
|
|||
#!/usr/bin/env python
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
"""Generate Razz startCards encoding and decoding for Card.py"""
|
||||
|
||||
import re
|
||||
|
||||
re_space = re.compile("([\(\)AKQJT0-9]+)\s+", re.MULTILINE)
|
||||
|
||||
razzlist = """(32)A (3A)2 (2A)3 (42)A (4A)2 (2A)4 (43)A (4A)3 (3A)4 (43)2
|
||||
(42)3 (32)4 (52)A (5A)2 (2A)5 (53)A (5A)3 (3A)5 (53)2 (52)3
|
||||
(32)5 (54)A (5A)4 (4A)5 (54)2 (52)4 (42)5 (54)3 (53)4 (43)5
|
||||
(62)A (6A)2 (2A)6 (63)A (6A)3 (3A)6 (63)2 (62)3 (32)6 (64)A
|
||||
(6A)4 (4A)6 (64)2 (62)4 (42)6 (64)3 (63)4 (43)6 (65)A (6A)5
|
||||
(5A)6 (65)2 (62)5 (52)6 (65)3 (63)5 (53)6 (65)4 (64)5 (54)6
|
||||
(72)A (7A)2 (2A)7 (73)A (7A)3 (3A)7 (73)2 (72)3 (32)7 (74)A
|
||||
(7A)4 (4A)7 (74)2 (72)4 (42)7 (74)3 (73)4 (43)7 (75)A (7A)5
|
||||
(5A)7 (75)2 (72)5 (52)7 (75)3 (73)5 (53)7 (75)4 (74)5 (54)7
|
||||
(76)A (7A)6 (6A)7 (76)2 (72)6 (62)7 (76)3 (73)6 (63)7 (76)4
|
||||
(74)6 (64)7 (76)5 (75)6 (65)7 (82)A (8A)2 (2A)8 (83)A (8A)3
|
||||
(3A)8 (83)2 (82)3 (32)8 (84)A (8A)4 (4A)8 (84)2 (82)4 (42)8
|
||||
(84)3 (83)4 (43)8 (85)A (8A)5 (5A)8 (85)2 (82)5 (52)8 (85)3
|
||||
(83)5 (53)8 (85)4 (84)5 (54)8 (86)A (8A)6 (6A)8 (86)2 (82)6
|
||||
(62)8 (86)3 (83)6 (63)8 (86)4 (84)6 (64)8 (86)5 (85)6 (65)8
|
||||
(87)A (8A)7 (7A)8 (87)2 (82)7 (72)8 (87)3 (83)7 (73)8 (87)4
|
||||
(84)7 (74)8 (87)5 (85)7 (75)8 (87)6 (86)7 (76)8 (92)A (9A)2
|
||||
(2A)9 (93)A (9A)3 (3A)9 (93)2 (92)3 (32)9 (94)A (9A)4 (4A)9
|
||||
(94)2 (92)4 (42)9 (94)3 (93)4 (43)9 (95)A (9A)5 (5A)9 (95)2
|
||||
(92)5 (52)9 (95)3 (93)5 (53)9 (95)4 (94)5 (54)9 (96)A (9A)6
|
||||
(6A)9 (96)2 (92)6 (62)9 (96)3 (93)6 (63)9 (96)4 (94)6 (64)9
|
||||
(96)5 (95)6 (65)9 (97)A (9A)7 (7A)9 (97)2 (92)7 (72)9 (97)3
|
||||
(93)7 (73)9 (97)4 (94)7 (74)9 (97)5 (95)7 (75)9 (97)6 (96)7
|
||||
(76)9 (98)A (9A)8 (8A)9 (98)2 (92)8 (82)9 (98)3 (93)8 (83)9
|
||||
(98)4 (94)8 (84)9 (98)5 (95)8 (85)9 (98)6 (96)8 (86)9 (98)7
|
||||
(97)8 (87)9 (T2)A (TA)2 (2A)T (T3)A (TA)3 (3A)T (T3)2 (T2)3
|
||||
(32)T (T4)A (TA)4 (4A)T (T4)2 (T2)4 (42)T (T4)3 (T3)4 (43)T
|
||||
(T5)A (TA)5 (5A)T (T5)2 (T2)5 (52)T (T5)3 (T3)5 (53)T (T5)4
|
||||
(T4)5 (54)T (T6)A (TA)6 (6A)T (T6)2 (T2)6 (62)T (T6)3 (T3)6
|
||||
(63)T (T6)4 (T4)6 (64)T (T6)5 (T5)6 (65)T (T7)A (TA)7 (7A)T
|
||||
(T7)2 (T2)7 (72)T (T7)3 (T3)7 (73)T (T7)4 (T4)7 (74)T (T7)5
|
||||
(T5)7 (75)T (T7)6 (T6)7 (76)T (T8)A (TA)8 (8A)T (T8)2 (T2)8
|
||||
(82)T (T8)3 (T3)8 (83)T (T8)4 (T4)8 (84)T (T8)5 (T5)8 (85)T
|
||||
(T8)6 (T6)8 (86)T (T8)7 (T7)8 (87)T (T9)A (TA)9 (9A)T (T9)2
|
||||
(T2)9 (92)T (T9)3 (T3)9 (93)T (T9)4 (T4)9 (94)T (T9)5 (T5)9
|
||||
(95)T (T9)6 (T6)9 (96)T (T9)7 (T7)9 (97)T (T9)8 (T8)9 (98)T
|
||||
(J2)A (JA)2 (2A)J (J3)A (JA)3 (3A)J (J3)2 (J2)3 (32)J (J4)A
|
||||
(JA)4 (4A)J (J4)2 (J2)4 (42)J (J4)3 (J3)4 (43)J (J5)A (JA)5
|
||||
(5A)J (J5)2 (J2)5 (52)J (J5)3 (J3)5 (53)J (J5)4 (J4)5 (54)J
|
||||
(J6)A (JA)6 (6A)J (J6)2 (J2)6 (62)J (J6)3 (J3)6 (63)J (J6)4
|
||||
(J4)6 (64)J (J6)5 (J5)6 (65)J (J7)A (JA)7 (7A)J (J7)2 (J2)7
|
||||
(72)J (J7)3 (J3)7 (73)J (J7)4 (J4)7 (74)J (J7)5 (J5)7 (75)J
|
||||
(J7)6 (J6)7 (76)J (J8)A (JA)8 (8A)J (J8)2 (J2)8 (82)J (J8)3
|
||||
(J3)8 (83)J (J8)4 (J4)8 (84)J (J8)5 (J5)8 (85)J (J8)6 (J6)8
|
||||
(86)J (J8)7 (J7)8 (87)J (J9)A (JA)9 (9A)J (J9)2 (J2)9 (92)J
|
||||
(J9)3 (J3)9 (93)J (J9)4 (J4)9 (94)J (J9)5 (J5)9 (95)J (J9)6
|
||||
(J6)9 (96)J (J9)7 (J7)9 (97)J (J9)8 (J8)9 (98)J (JT)A (JA)T
|
||||
(TA)J (JT)2 (J2)T (T2)J (JT)3 (J3)T (T3)J (JT)4 (J4)T (T4)J
|
||||
(JT)5 (J5)T (T5)J (JT)6 (J6)T (T6)J (JT)7 (J7)T (T7)J (JT)8
|
||||
(J8)T (T8)J (JT)9 (J9)T (T9)J (Q2)A (QA)2 (2A)Q (Q3)A (QA)3
|
||||
(3A)Q (Q3)2 (Q2)3 (32)Q (Q4)A (QA)4 (4A)Q (Q4)2 (Q2)4 (42)Q
|
||||
(Q4)3 (Q3)4 (43)Q (Q5)A (QA)5 (5A)Q (Q5)2 (Q2)5 (52)Q (Q5)3
|
||||
(Q3)5 (53)Q (Q5)4 (Q4)5 (54)Q (Q6)A (QA)6 (6A)Q (Q6)2 (Q2)6
|
||||
(62)Q (Q6)3 (Q3)6 (63)Q (Q6)4 (Q4)6 (64)Q (Q6)5 (Q5)6 (65)Q
|
||||
(Q7)A (QA)7 (7A)Q (Q7)2 (Q2)7 (72)Q (Q7)3 (Q3)7 (73)Q (Q7)4
|
||||
(Q4)7 (74)Q (Q7)5 (Q5)7 (75)Q (Q7)6 (Q6)7 (76)Q (Q8)A (QA)8
|
||||
(8A)Q (Q8)2 (Q2)8 (82)Q (Q8)3 (Q3)8 (83)Q (Q8)4 (Q4)8 (84)Q
|
||||
(Q8)5 (Q5)8 (85)Q (Q8)6 (Q6)8 (86)Q (Q8)7 (Q7)8 (87)Q (Q9)A
|
||||
(QA)9 (9A)Q (Q9)2 (Q2)9 (92)Q (Q9)3 (Q3)9 (93)Q (Q9)4 (Q4)9
|
||||
(94)Q (Q9)5 (Q5)9 (95)Q (Q9)6 (Q6)9 (96)Q (Q9)7 (Q7)9 (97)Q
|
||||
(Q9)8 (Q8)9 (98)Q (QT)A (QA)T (TA)Q (QT)2 (Q2)T (T2)Q (QT)3
|
||||
(Q3)T (T3)Q (QT)4 (Q4)T (T4)Q (QT)5 (Q5)T (T5)Q (QT)6 (Q6)T
|
||||
(T6)Q (QT)7 (Q7)T (T7)Q (QT)8 (Q8)T (T8)Q (QT)9 (Q9)T (T9)Q
|
||||
(QJ)A (QA)J (JA)Q (QJ)2 (Q2)J (J2)Q (QJ)3 (Q3)J (J3)Q (QJ)4
|
||||
(Q4)J (J4)Q (QJ)5 (Q5)J (J5)Q (QJ)6 (Q6)J (J6)Q (QJ)7 (Q7)J
|
||||
(J7)Q (QJ)8 (Q8)J (J8)Q (QJ)9 (Q9)J (J9)Q (QJ)T (QT)J (JT)Q
|
||||
(K2)A (KA)2 (2A)K (K3)A (KA)3 (3A)K (K3)2 (K2)3 (32)K (K4)A
|
||||
(KA)4 (4A)K (K4)2 (K2)4 (42)K (K4)3 (K3)4 (43)K (K5)A (KA)5
|
||||
(5A)K (K5)2 (K2)5 (52)K (K5)3 (K3)5 (53)K (K5)4 (K4)5 (54)K
|
||||
(K6)A (KA)6 (6A)K (K6)2 (K2)6 (62)K (K6)3 (K3)6 (63)K (K6)4
|
||||
(K4)6 (64)K (K6)5 (K5)6 (65)K (K7)A (KA)7 (7A)K (K7)2 (K2)7
|
||||
(72)K (K7)3 (K3)7 (73)K (K7)4 (K4)7 (74)K (K7)5 (K5)7 (75)K
|
||||
(K7)6 (K6)7 (76)K (K8)A (KA)8 (8A)K (K8)2 (K2)8 (82)K (K8)3
|
||||
(K3)8 (83)K (K8)4 (K4)8 (84)K (K8)5 (K5)8 (85)K (K8)6 (K6)8
|
||||
(86)K (K8)7 (K7)8 (87)K (K9)A (KA)9 (9A)K (K9)2 (K2)9 (92)K
|
||||
(K9)3 (K3)9 (93)K (K9)4 (K4)9 (94)K (K9)5 (K5)9 (95)K (K9)6
|
||||
(K6)9 (96)K (K9)7 (K7)9 (97)K (K9)8 (K8)9 (98)K (KT)A (KA)T
|
||||
(TA)K (KT)2 (K2)T (T2)K (KT)3 (K3)T (T3)K (KT)4 (K4)T (T4)K
|
||||
(KT)5 (K5)T (T5)K (KT)6 (K6)T (T6)K (KT)7 (K7)T (T7)K (KT)8
|
||||
(K8)T (T8)K (KT)9 (K9)T (T9)K (KJ)A (KA)J (JA)K (KJ)2 (K2)J
|
||||
(J2)K (KJ)3 (K3)J (J3)K (KJ)4 (K4)J (J4)K (KJ)5 (K5)J (J5)K
|
||||
(KJ)6 (K6)J (J6)K (KJ)7 (K7)J (J7)K (KJ)8 (K8)J (J8)K (KJ)9
|
||||
(K9)J (J9)K (KJ)T (KT)J (JT)K (KQ)A (KA)Q (QA)K (KQ)2 (K2)Q
|
||||
(Q2)K (KQ)3 (K3)Q (Q3)K (KQ)4 (K4)Q (Q4)K (KQ)5 (K5)Q (Q5)K
|
||||
(KQ)6 (K6)Q (Q6)K (KQ)7 (K7)Q (Q7)K (KQ)8 (K8)Q (Q8)K (KQ)9
|
||||
(K9)Q (Q9)K (KQ)T (KT)Q (QT)K (KQ)J (KJ)Q (QJ)K (2A)A (22)A
|
||||
(AA)2 (2A)2 (3A)A (33)A (AA)3 (3A)3 (32)2 (33)2 (22)3 (32)3
|
||||
(4A)A (44)A (AA)4 (4A)4 (42)2 (44)2 (22)4 (42)4 (43)3 (44)3
|
||||
(33)4 (43)4 (5A)A (55)A (AA)5 (5A)5 (52)2 (55)2 (22)5 (52)5
|
||||
(53)3 (55)3 (33)5 (53)5 (54)4 (55)4 (44)5 (54)5 (6A)A (66)A
|
||||
(AA)6 (6A)6 (62)2 (66)2 (22)6 (62)6 (63)3 (66)3 (33)6 (63)6
|
||||
(64)4 (66)4 (44)6 (64)6 (65)5 (66)5 (55)6 (65)6 (7A)A (77)A
|
||||
(AA)7 (7A)7 (72)2 (77)2 (22)7 (72)7 (73)3 (77)3 (33)7 (73)7
|
||||
(74)4 (77)4 (44)7 (74)7 (75)5 (77)5 (55)7 (75)7 (76)6 (77)6
|
||||
(66)7 (76)7 (8A)A (88)A (AA)8 (8A)8 (82)2 (88)2 (22)8 (82)8
|
||||
(83)3 (88)3 (33)8 (83)8 (84)4 (88)4 (44)8 (84)8 (85)5 (88)5
|
||||
(55)8 (85)8 (86)6 (88)6 (66)8 (86)8 (87)7 (88)7 (77)8 (87)8
|
||||
(9A)A (99)A (AA)9 (9A)9 (92)2 (99)2 (22)9 (92)9 (93)3 (99)3
|
||||
(33)9 (93)9 (94)4 (99)4 (44)9 (94)9 (95)5 (99)5 (55)9 (95)9
|
||||
(96)6 (99)6 (66)9 (96)9 (97)7 (99)7 (77)9 (97)9 (98)8 (99)8
|
||||
(88)9 (98)9 (TA)A (TT)A (AA)T (TA)T (T2)2 (TT)2 (22)T (T2)T
|
||||
(T3)3 (TT)3 (33)T (T3)T (T4)4 (TT)4 (44)T (T4)T (T5)5 (TT)5
|
||||
(55)T (T5)T (T6)6 (TT)6 (66)T (T6)T (T7)7 (TT)7 (77)T (T7)T
|
||||
(T8)8 (TT)8 (88)T (T8)T (T9)9 (TT)9 (99)T (T9)T (JA)A (JJ)A
|
||||
(AA)J (JA)J (J2)2 (JJ)2 (22)J (J2)J (J3)3 (JJ)3 (33)J (J3)J
|
||||
(J4)4 (JJ)4 (44)J (J4)J (J5)5 (JJ)5 (55)J (J5)J (J6)6 (JJ)6
|
||||
(66)J (J6)J (J7)7 (JJ)7 (77)J (J7)J (J8)8 (JJ)8 (88)J (J8)J
|
||||
(J9)9 (JJ)9 (99)J (J9)J (JT)T (JJ)T (TT)J (JT)J (QA)A (QQ)A
|
||||
(AA)Q (QA)Q (Q2)2 (QQ)2 (22)Q (Q2)Q (Q3)3 (QQ)3 (33)Q (Q3)Q
|
||||
(Q4)4 (QQ)4 (44)Q (Q4)Q (Q5)5 (QQ)5 (55)Q (Q5)Q (Q6)6 (QQ)6
|
||||
(66)Q (Q6)Q (Q7)7 (QQ)7 (77)Q (Q7)Q (Q8)8 (QQ)8 (88)Q (Q8)Q
|
||||
(Q9)9 (QQ)9 (99)Q (Q9)Q (QT)T (QQ)T (TT)Q (QT)Q (QJ)J (QQ)J
|
||||
(JJ)Q (QJ)Q (KA)A (KK)A (AA)K (KA)K (K2)2 (KK)2 (22)K (K2)K
|
||||
(K3)3 (KK)3 (33)K (K3)K (K4)4 (KK)4 (44)K (K4)K (K5)5 (KK)5
|
||||
(55)K (K5)K (K6)6 (KK)6 (66)K (K6)K (K7)7 (KK)7 (77)K (K7)K
|
||||
(K8)8 (KK)8 (88)K (K8)K (K9)9 (KK)9 (99)K (K9)K (KT)T (KK)T
|
||||
(TT)K (KT)K (KJ)J (KK)J (JJ)K (KJ)K (KQ)Q (KK)Q (QQ)K (KQ)K
|
||||
(AA)A (22)2 (33)3 (44)4 (55)5 (66)6 (77)7 (88)8 (99)9 (TT)T
|
||||
(JJ)J (QQ)Q (KK)K
|
||||
"""
|
||||
|
||||
count = 1
|
||||
string = ""
|
||||
|
||||
for a in re_space.finditer(razzlist):
|
||||
string = string + ("'%s':%s," %(a.group(1), count))
|
||||
count+=1
|
||||
if count%10 == 0:
|
||||
string = string + "\n"
|
||||
print "-------------------------"
|
||||
print "Razz encode list"
|
||||
print "------------------------ "
|
||||
print string
|
||||
|
||||
string = ""
|
||||
count = 1
|
||||
|
||||
for a in re_space.finditer(razzlist):
|
||||
string = string + ("%s:'%s'," %(count, a.group(1)))
|
||||
count+=1
|
||||
if count%10 == 0:
|
||||
string = string + "\n"
|
||||
|
||||
|
||||
print "-------------------------"
|
||||
print "Razz decode list"
|
||||
print "------------------------ "
|
||||
print string
|
||||
|
||||
435
pyfpdb/SQL.py
435
pyfpdb/SQL.py
|
|
@ -108,6 +108,72 @@ class Sql:
|
|||
self.query['createSettingsTable'] = """CREATE TABLE Settings
|
||||
(version INTEGER NOT NULL) """
|
||||
|
||||
################################
|
||||
# Create RawHands (this table is all but identical with RawTourneys)
|
||||
################################
|
||||
if db_server == 'mysql':
|
||||
self.query['createRawHands'] = """CREATE TABLE RawHands (
|
||||
id BIGINT UNSIGNED AUTO_INCREMENT NOT NULL, PRIMARY KEY (id),
|
||||
handId BIGINT NOT NULL,
|
||||
rawHand TEXT NOT NULL,
|
||||
complain BOOLEAN NOT NULL DEFAULT FALSE)
|
||||
ENGINE=INNODB"""
|
||||
elif db_server == 'postgresql':
|
||||
self.query['createRawHands'] = """CREATE TABLE RawHands (
|
||||
id BIGSERIAL, PRIMARY KEY (id),
|
||||
handId BIGINT NOT NULL,
|
||||
rawHand TEXT NOT NULL,
|
||||
complain BOOLEAN NOT NULL DEFAULT FALSE)"""
|
||||
elif db_server == 'sqlite':
|
||||
self.query['createRawHands'] = """CREATE TABLE RawHands (
|
||||
id INTEGER PRIMARY KEY,
|
||||
handId BIGINT NOT NULL,
|
||||
rawHand TEXT NOT NULL,
|
||||
complain BOOLEAN NOT NULL DEFAULT FALSE)"""
|
||||
|
||||
################################
|
||||
# Create RawTourneys (this table is all but identical with RawHands)
|
||||
################################
|
||||
if db_server == 'mysql':
|
||||
self.query['createRawTourneys'] = """CREATE TABLE RawTourneys (
|
||||
id BIGINT UNSIGNED AUTO_INCREMENT NOT NULL, PRIMARY KEY (id),
|
||||
tourneyId BIGINT NOT NULL,
|
||||
rawTourney TEXT NOT NULL,
|
||||
complain BOOLEAN NOT NULL DEFAULT FALSE)
|
||||
ENGINE=INNODB"""
|
||||
elif db_server == 'postgresql':
|
||||
self.query['createRawTourneys'] = """CREATE TABLE RawTourneys (
|
||||
id BIGSERIAL, PRIMARY KEY (id),
|
||||
tourneyId BIGINT NOT NULL,
|
||||
rawTourney TEXT NOT NULL,
|
||||
complain BOOLEAN NOT NULL DEFAULT FALSE)"""
|
||||
elif db_server == 'sqlite':
|
||||
self.query['createRawTourneys'] = """CREATE TABLE RawTourneys (
|
||||
id INTEGER PRIMARY KEY,
|
||||
tourneyId BIGINT NOT NULL,
|
||||
rawTourney TEXT NOT NULL,
|
||||
complain BOOLEAN NOT NULL DEFAULT FALSE)"""
|
||||
|
||||
################################
|
||||
# Create Actions
|
||||
################################
|
||||
|
||||
if db_server == 'mysql':
|
||||
self.query['createActionsTable'] = """CREATE TABLE Actions (
|
||||
id SMALLINT UNSIGNED AUTO_INCREMENT NOT NULL, PRIMARY KEY (id),
|
||||
name varchar(32) NOT NULL,
|
||||
code char(4) NOT NULL)
|
||||
ENGINE=INNODB"""
|
||||
elif db_server == 'postgresql':
|
||||
self.query['createActionsTable'] = """CREATE TABLE Actions (
|
||||
id SERIAL, PRIMARY KEY (id),
|
||||
name varchar(32),
|
||||
code char(4))"""
|
||||
elif db_server == 'sqlite':
|
||||
self.query['createActionsTable'] = """CREATE TABLE Actions (
|
||||
id INTEGER PRIMARY KEY,
|
||||
name TEXT NOT NULL,
|
||||
code TEXT NOT NULL)"""
|
||||
|
||||
################################
|
||||
# Create Sites
|
||||
|
|
@ -137,21 +203,21 @@ class Sql:
|
|||
if db_server == 'mysql':
|
||||
self.query['createBackingsTable'] = """CREATE TABLE Backings (
|
||||
id SMALLINT UNSIGNED AUTO_INCREMENT NOT NULL, PRIMARY KEY (id),
|
||||
tourneysPlayerId BIGINT UNSIGNED NOT NULL, FOREIGN KEY (tourneysPlayerId) REFERENCES TourneysPlayers(id),
|
||||
tourneysPlayersId BIGINT UNSIGNED NOT NULL, FOREIGN KEY (tourneysPlayersId) REFERENCES TourneysPlayers(id),
|
||||
playerId INT UNSIGNED NOT NULL, FOREIGN KEY (playerId) REFERENCES Players(id),
|
||||
buyInPercentage FLOAT UNSIGNED NOT NULL,
|
||||
payOffPercentage FLOAT UNSIGNED NOT NULL) ENGINE=INNODB"""
|
||||
elif db_server == 'postgresql':
|
||||
self.query['createBackingsTable'] = """CREATE TABLE Backings (
|
||||
id BIGSERIAL, PRIMARY KEY (id),
|
||||
tourneysPlayerId INT NOT NULL, FOREIGN KEY (tourneysPlayerId) REFERENCES TourneysPlayers(id),
|
||||
tourneysPlayersId INT NOT NULL, FOREIGN KEY (tourneysPlayersId) REFERENCES TourneysPlayers(id),
|
||||
playerId INT NOT NULL, FOREIGN KEY (playerId) REFERENCES Players(id),
|
||||
buyInPercentage FLOAT NOT NULL,
|
||||
payOffPercentage FLOAT NOT NULL)"""
|
||||
elif db_server == 'sqlite':
|
||||
self.query['createBackingsTable'] = """CREATE TABLE Backings (
|
||||
id INTEGER PRIMARY KEY,
|
||||
tourneysPlayerId INT NOT NULL,
|
||||
tourneysPlayersId INT NOT NULL,
|
||||
playerId INT NOT NULL,
|
||||
buyInPercentage REAL UNSIGNED NOT NULL,
|
||||
payOffPercentage REAL UNSIGNED NOT NULL)"""
|
||||
|
|
@ -918,7 +984,7 @@ class Sql:
|
|||
commentTs timestamp without time zone)"""
|
||||
elif db_server == 'sqlite':
|
||||
self.query['createTourneysPlayersTable'] = """CREATE TABLE TourneysPlayers (
|
||||
id INT PRIMARY KEY,
|
||||
id INTEGER PRIMARY KEY,
|
||||
tourneyId INT,
|
||||
playerId INT,
|
||||
rank INT,
|
||||
|
|
@ -944,11 +1010,14 @@ class Sql:
|
|||
handsPlayerId BIGINT UNSIGNED NOT NULL, FOREIGN KEY (handsPlayerId) REFERENCES HandsPlayers(id),
|
||||
street SMALLINT NOT NULL,
|
||||
actionNo SMALLINT NOT NULL,
|
||||
action CHAR(5) NOT NULL,
|
||||
allIn BOOLEAN NOT NULL,
|
||||
streetActionNo SMALLINT NOT NULL,
|
||||
actionId SMALLINT UNSIGNED NOT NULL, FOREIGN KEY (actionId) REFERENCES Actions(id),
|
||||
amount INT NOT NULL,
|
||||
comment TEXT,
|
||||
commentTs DATETIME)
|
||||
raiseTo INT NOT NULL,
|
||||
amountCalled INT NOT NULL,
|
||||
numDiscarded SMALLINT NOT NULL,
|
||||
cardsDiscarded varchar(14),
|
||||
allIn BOOLEAN NOT NULL)
|
||||
ENGINE=INNODB"""
|
||||
elif db_server == 'postgresql':
|
||||
self.query['createHandsActionsTable'] = """CREATE TABLE HandsActions (
|
||||
|
|
@ -956,23 +1025,30 @@ class Sql:
|
|||
handsPlayerId BIGINT, FOREIGN KEY (handsPlayerId) REFERENCES HandsPlayers(id),
|
||||
street SMALLINT,
|
||||
actionNo SMALLINT,
|
||||
action CHAR(5),
|
||||
allIn BOOLEAN,
|
||||
streetActionNo SMALLINT,
|
||||
actionId SMALLINT, FOREIGN KEY (actionId) REFERENCES Actions(id),
|
||||
amount INT,
|
||||
comment TEXT,
|
||||
commentTs timestamp without time zone)"""
|
||||
raiseTo INT,
|
||||
amountCalled INT,
|
||||
numDiscarded SMALLINT,
|
||||
cardsDiscarded varchar(14),
|
||||
allIn BOOLEAN)"""
|
||||
elif db_server == 'sqlite':
|
||||
self.query['createHandsActionsTable'] = """CREATE TABLE HandsActions (
|
||||
id INT PRIMARY KEY,
|
||||
id INTEGER PRIMARY KEY,
|
||||
handsPlayerId BIGINT,
|
||||
street SMALLINT,
|
||||
actionNo SMALLINT,
|
||||
action CHAR(5),
|
||||
allIn INT,
|
||||
streetActionNo SMALLINT,
|
||||
actionId SMALLINT,
|
||||
amount INT,
|
||||
comment TEXT,
|
||||
commentTs timestamp without time zone,
|
||||
FOREIGN KEY (handsPlayerId) REFERENCES HandsPlayers(id)
|
||||
raiseTo INT,
|
||||
amountCalled INT,
|
||||
numDiscarded SMALLINT,
|
||||
cardsDiscarded TEXT,
|
||||
allIn BOOLEAN,
|
||||
FOREIGN KEY (handsPlayerId) REFERENCES HandsPlayers(id),
|
||||
FOREIGN KEY (actionId) REFERENCES Actions(id) ON DELETE CASCADE
|
||||
)"""
|
||||
|
||||
|
||||
|
|
@ -1321,6 +1397,10 @@ class Sql:
|
|||
|
||||
self.query['get_last_hand'] = "select max(id) from Hands"
|
||||
|
||||
self.query['get_last_date'] = "SELECT MAX(startTime) FROM Hands"
|
||||
|
||||
self.query['get_first_date'] = "SELECT MIN(startTime) FROM Hands"
|
||||
|
||||
self.query['get_player_id'] = """
|
||||
select Players.id AS player_id
|
||||
from Players, Sites
|
||||
|
|
@ -1336,8 +1416,6 @@ class Sql:
|
|||
and (p.siteId = %s or %s = -1)
|
||||
"""
|
||||
|
||||
self.query['getSiteId'] = """SELECT id from Sites where name = %s"""
|
||||
|
||||
self.query['get_stats_from_hand'] = """
|
||||
SELECT hc.playerId AS player_id,
|
||||
hp.seatNo AS seat,
|
||||
|
|
@ -1400,6 +1478,7 @@ class Sql:
|
|||
sum(hc.foldToStreet4CBChance) AS f_cb_opp_4,
|
||||
sum(hc.foldToStreet4CBDone) AS f_cb_4,
|
||||
sum(hc.totalProfit) AS net,
|
||||
sum(gt.bigblind) AS bigblind,
|
||||
sum(hc.street1CheckCallRaiseChance) AS ccr_opp_1,
|
||||
sum(hc.street1CheckCallRaiseDone) AS ccr_1,
|
||||
sum(hc.street2CheckCallRaiseChance) AS ccr_opp_2,
|
||||
|
|
@ -1428,6 +1507,7 @@ class Sql:
|
|||
INNER JOIN HudCache hc ON ( hc.PlayerId = hp.PlayerId+0
|
||||
AND hc.gametypeId+0 = h.gametypeId+0)
|
||||
INNER JOIN Players p ON (p.id = hp.PlayerId+0)
|
||||
INNER JOIN Gametypes gt ON (gt.id = hc.gametypeId)
|
||||
WHERE h.id = %s
|
||||
AND hc.styleKey > %s
|
||||
/* styleKey is currently 'd' (for date) followed by a yyyymmdd
|
||||
|
|
@ -1499,6 +1579,7 @@ class Sql:
|
|||
sum(hc.foldToStreet4CBChance) AS f_cb_opp_4,
|
||||
sum(hc.foldToStreet4CBDone) AS f_cb_4,
|
||||
sum(hc.totalProfit) AS net,
|
||||
sum(gt.bigblind) AS bigblind,
|
||||
sum(hc.street1CheckCallRaiseChance) AS ccr_opp_1,
|
||||
sum(hc.street1CheckCallRaiseDone) AS ccr_1,
|
||||
sum(hc.street2CheckCallRaiseChance) AS ccr_opp_2,
|
||||
|
|
@ -1526,6 +1607,7 @@ class Sql:
|
|||
INNER JOIN HandsPlayers hp ON (hp.handId = h.id)
|
||||
INNER JOIN HudCache hc ON (hc.playerId = hp.playerId)
|
||||
INNER JOIN Players p ON (p.id = hc.playerId)
|
||||
INNER JOIN Gametypes gt ON (gt.id = hc.gametypeId)
|
||||
WHERE h.id = %s
|
||||
AND ( /* 2 separate parts for hero and opponents */
|
||||
( hp.playerId != %s
|
||||
|
|
@ -1625,6 +1707,7 @@ class Sql:
|
|||
cast(hp2.foldToStreet4CBChance as <signed>integer) AS f_cb_opp_4,
|
||||
cast(hp2.foldToStreet4CBDone as <signed>integer) AS f_cb_4,
|
||||
cast(hp2.totalProfit as <signed>integer) AS net,
|
||||
cast(gt.bigblind as <signed>integer) AS bigblind,
|
||||
cast(hp2.street1CheckCallRaiseChance as <signed>integer) AS ccr_opp_1,
|
||||
cast(hp2.street1CheckCallRaiseDone as <signed>integer) AS ccr_1,
|
||||
cast(hp2.street2CheckCallRaiseChance as <signed>integer) AS ccr_opp_2,
|
||||
|
|
@ -1654,6 +1737,7 @@ class Sql:
|
|||
INNER JOIN HandsPlayers hp ON (h.id = hp.handId) /* players in this hand */
|
||||
INNER JOIN HandsPlayers hp2 ON (hp2.playerId+0 = hp.playerId+0 AND (hp2.handId = h2.id+0)) /* other hands by these players */
|
||||
INNER JOIN Players p ON (p.id = hp2.PlayerId+0)
|
||||
INNER JOIN Gametypes gt ON (gt.id = h2.gametypeId)
|
||||
WHERE hp.handId = %s
|
||||
/* check activeseats once this data returned (don't want to do that here as it might
|
||||
assume a session ended just because the number of seats dipped for a few hands)
|
||||
|
|
@ -1727,6 +1811,7 @@ class Sql:
|
|||
cast(hp2.foldToStreet4CBChance as <signed>integer) AS f_cb_opp_4,
|
||||
cast(hp2.foldToStreet4CBDone as <signed>integer) AS f_cb_4,
|
||||
cast(hp2.totalProfit as <signed>integer) AS net,
|
||||
cast(gt.bigblind as <signed>integer) AS bigblind,
|
||||
cast(hp2.street1CheckCallRaiseChance as <signed>integer) AS ccr_opp_1,
|
||||
cast(hp2.street1CheckCallRaiseDone as <signed>integer) AS ccr_1,
|
||||
cast(hp2.street2CheckCallRaiseChance as <signed>integer) AS ccr_opp_2,
|
||||
|
|
@ -1757,6 +1842,7 @@ class Sql:
|
|||
INNER JOIN HandsPlayers hp2 ON ( hp2.playerId+0 = hp.playerId+0
|
||||
AND hp2.handId = h2.id) /* other hands by these players */
|
||||
INNER JOIN Players p ON (p.id = hp2.PlayerId+0)
|
||||
INNER JOIN Gametypes gt ON (gt.id = h2.gametypeId)
|
||||
WHERE h.id = %s
|
||||
/* check activeseats once this data returned (don't want to do that here as it might
|
||||
assume a session ended just because the number of seats dipped for a few hands)
|
||||
|
|
@ -1830,6 +1916,7 @@ class Sql:
|
|||
cast(hp2.foldToStreet4CBChance as <signed>integer) AS f_cb_opp_4,
|
||||
cast(hp2.foldToStreet4CBDone as <signed>integer) AS f_cb_4,
|
||||
cast(hp2.totalProfit as <signed>integer) AS net,
|
||||
cast(gt.bigblind as <signed>integer) AS bigblind,
|
||||
cast(hp2.street1CheckCallRaiseChance as <signed>integer) AS ccr_opp_1,
|
||||
cast(hp2.street1CheckCallRaiseDone as <signed>integer) AS ccr_1,
|
||||
cast(hp2.street2CheckCallRaiseChance as <signed>integer) AS ccr_opp_2,
|
||||
|
|
@ -1860,6 +1947,7 @@ class Sql:
|
|||
INNER JOIN HandsPlayers hp2 ON ( hp2.playerId+0 = hp.playerId+0
|
||||
AND hp2.handId = h2.id) /* other hands by these players */
|
||||
INNER JOIN Players p ON (p.id = hp2.PlayerId+0)
|
||||
INNER JOIN Gametypes gt ON (gt.id = h2.gametypeId)
|
||||
WHERE h.id = %s
|
||||
/* check activeseats once this data returned (don't want to do that here as it might
|
||||
assume a session ended just because the number of seats dipped for a few hands)
|
||||
|
|
@ -2000,8 +2088,6 @@ class Sql:
|
|||
self.query['getPlayerIdBySite'] = """SELECT id from Players where name = %s AND siteId = %s"""
|
||||
|
||||
# used in *Filters:
|
||||
self.query['getSiteId'] = """SELECT id from Sites where name = %s"""
|
||||
self.query['getGames'] = """SELECT DISTINCT category from Gametypes"""
|
||||
#self.query['getLimits'] = already defined further up
|
||||
self.query['getLimits2'] = """SELECT DISTINCT type, limitType, bigBlind
|
||||
from Gametypes
|
||||
|
|
@ -2019,6 +2105,7 @@ class Sql:
|
|||
, limitType
|
||||
, bigBlind as bb_or_buyin
|
||||
from Gametypes gt
|
||||
WHERE type = 'ring'
|
||||
order by type, limitType DESC, bb_or_buyin DESC"""
|
||||
|
||||
if db_server == 'mysql':
|
||||
|
|
@ -2392,7 +2479,7 @@ class Sql:
|
|||
select s.name AS siteName
|
||||
,t.tourneyTypeId AS tourneyTypeId
|
||||
,tt.currency AS currency
|
||||
,(CASE WHEN tt.currency = "USD" THEN tt.buyIn/100.0 ELSE tt.buyIn END) AS buyIn
|
||||
,(CASE WHEN tt.currency = 'USD' THEN tt.buyIn/100.0 ELSE tt.buyIn END) AS buyIn
|
||||
,tt.fee/100.0 AS fee
|
||||
,tt.category AS category
|
||||
,tt.limitType AS limitType
|
||||
|
|
@ -2400,11 +2487,11 @@ class Sql:
|
|||
,COUNT(1) AS tourneyCount
|
||||
,SUM(CASE WHEN tp.rank > 0 THEN 0 ELSE 1 END) AS unknownRank
|
||||
,SUM(CASE WHEN winnings > 0 THEN 1 ELSE 0 END)/(COUNT(1) - SUM(CASE WHEN tp.rank > 0 THEN 0 ELSE 1 END)) AS itm
|
||||
,SUM(CASE WHEN rank = 1 THEN 1 ELSE 0 END) AS 1st
|
||||
,SUM(CASE WHEN rank = 2 THEN 1 ELSE 0 END) AS 2nd
|
||||
,SUM(CASE WHEN rank = 3 THEN 1 ELSE 0 END) AS 3rd
|
||||
,SUM(CASE WHEN rank = 1 THEN 1 ELSE 0 END) AS _1st
|
||||
,SUM(CASE WHEN rank = 2 THEN 1 ELSE 0 END) AS _2nd
|
||||
,SUM(CASE WHEN rank = 3 THEN 1 ELSE 0 END) AS _3rd
|
||||
,SUM(tp.winnings)/100.0 AS won
|
||||
,SUM(CASE WHEN tt.currency = "USD" THEN (tt.buyIn+tt.fee)/100.0 ELSE tt.buyIn END) AS spent
|
||||
,SUM(CASE WHEN tt.currency = 'USD' THEN (tt.buyIn+tt.fee)/100.0 ELSE tt.buyIn END) AS spent
|
||||
,SUM(tp.winnings)/SUM(tt.buyin+tt.fee)*100.0-100 AS roi
|
||||
,SUM(tp.winnings-(tt.buyin+tt.fee))/100.0/(COUNT(1)-SUM(CASE WHEN tp.rank > 0 THEN 0 ELSE 1 END)) AS profitPerTourney
|
||||
from TourneysPlayers tp
|
||||
|
|
@ -2419,9 +2506,72 @@ class Sql:
|
|||
,playerName
|
||||
,siteName"""
|
||||
elif db_server == 'postgresql':
|
||||
self.query['tourneyPlayerDetailedStats'] = """TODO"""
|
||||
# sc: itm and profitPerTourney changed to "ELSE 0" to avoid divide by zero error as temp fix
|
||||
# proper fix should use coalesce() or case ... when ... to work in all circumstances
|
||||
self.query['tourneyPlayerDetailedStats'] = """
|
||||
select s.name AS siteName
|
||||
,t.tourneyTypeId AS tourneyTypeId
|
||||
,tt.currency AS currency
|
||||
,(CASE WHEN tt.currency = 'USD' THEN tt.buyIn/100.0 ELSE tt.buyIn END) AS buyIn
|
||||
,tt.fee/100.0 AS fee
|
||||
,tt.category AS category
|
||||
,tt.limitType AS limitType
|
||||
,p.name AS playerName
|
||||
,COUNT(1) AS tourneyCount
|
||||
,SUM(CASE WHEN tp.rank > 0 THEN 0 ELSE 1 END) AS unknownRank
|
||||
,SUM(CASE WHEN winnings > 0 THEN 1 ELSE 0 END)
|
||||
/(COUNT(1) - SUM(CASE WHEN tp.rank > 0 THEN 0 ELSE 0 END)) AS itm
|
||||
,SUM(CASE WHEN rank = 1 THEN 1 ELSE 0 END) AS _1st
|
||||
,SUM(CASE WHEN rank = 2 THEN 1 ELSE 0 END) AS _2nd
|
||||
,SUM(CASE WHEN rank = 3 THEN 1 ELSE 0 END) AS _3rd
|
||||
,SUM(tp.winnings)/100.0 AS won
|
||||
,SUM(CASE WHEN tt.currency = 'USD' THEN (tt.buyIn+tt.fee)/100.0 ELSE tt.buyIn END) AS spent
|
||||
,SUM(tp.winnings)/SUM(tt.buyin+tt.fee)*100.0-100 AS roi
|
||||
,SUM(tp.winnings-(tt.buyin+tt.fee))/100.0
|
||||
/(COUNT(1)-SUM(CASE WHEN tp.rank > 0 THEN 0 ELSE 0 END)) AS profitPerTourney
|
||||
from TourneysPlayers tp
|
||||
inner join Tourneys t on (t.id = tp.tourneyId)
|
||||
inner join TourneyTypes tt on (tt.Id = t.tourneyTypeId)
|
||||
inner join Sites s on (s.Id = tt.siteId)
|
||||
inner join Players p on (p.Id = tp.playerId)
|
||||
where tp.playerId in <nametest> <sitetest>
|
||||
and to_char(t.startTime, 'YYYY-MM-DD HH24:MI:SS') <datestest>
|
||||
group by tourneyTypeId, s.name, playerName, tt.currency, tt.buyin, tt.fee
|
||||
, tt.category, tt.limitType
|
||||
order by tourneyTypeId
|
||||
,playerName
|
||||
,siteName"""
|
||||
elif db_server == 'sqlite':
|
||||
self.query['tourneyPlayerDetailedStats'] = """TODO"""
|
||||
self.query['tourneyPlayerDetailedStats'] = """
|
||||
select s.name AS siteName
|
||||
,t.tourneyTypeId AS tourneyTypeId
|
||||
,tt.currency AS currency
|
||||
,(CASE WHEN tt.currency = 'USD' THEN tt.buyIn/100.0 ELSE tt.buyIn END) AS buyIn
|
||||
,tt.fee/100.0 AS fee
|
||||
,tt.category AS category
|
||||
,tt.limitType AS limitType
|
||||
,p.name AS playerName
|
||||
,COUNT(1) AS tourneyCount
|
||||
,SUM(CASE WHEN tp.rank > 0 THEN 0 ELSE 1 END) AS unknownRank
|
||||
,SUM(CASE WHEN winnings > 0 THEN 1 ELSE 0 END)/(COUNT(1) - SUM(CASE WHEN tp.rank > 0 THEN 0 ELSE 1 END)) AS itm
|
||||
,SUM(CASE WHEN rank = 1 THEN 1 ELSE 0 END) AS _1st
|
||||
,SUM(CASE WHEN rank = 2 THEN 1 ELSE 0 END) AS _2nd
|
||||
,SUM(CASE WHEN rank = 3 THEN 1 ELSE 0 END) AS _3rd
|
||||
,SUM(tp.winnings)/100.0 AS won
|
||||
,SUM(CASE WHEN tt.currency = 'USD' THEN (tt.buyIn+tt.fee)/100.0 ELSE tt.buyIn END) AS spent
|
||||
,SUM(tp.winnings)/SUM(tt.buyin+tt.fee)*100.0-100 AS roi
|
||||
,SUM(tp.winnings-(tt.buyin+tt.fee))/100.0/(COUNT(1)-SUM(CASE WHEN tp.rank > 0 THEN 0 ELSE 1 END)) AS profitPerTourney
|
||||
from TourneysPlayers tp
|
||||
inner join Tourneys t on (t.id = tp.tourneyId)
|
||||
inner join TourneyTypes tt on (tt.Id = t.tourneyTypeId)
|
||||
inner join Sites s on (s.Id = tt.siteId)
|
||||
inner join Players p on (p.Id = tp.playerId)
|
||||
where tp.playerId in <nametest> <sitetest>
|
||||
and datetime(t.startTime) <datestest>
|
||||
group by tourneyTypeId, playerName
|
||||
order by tourneyTypeId
|
||||
,playerName
|
||||
,siteName"""
|
||||
|
||||
if db_server == 'mysql':
|
||||
self.query['playerStats'] = """
|
||||
|
|
@ -2770,6 +2920,8 @@ class Sql:
|
|||
order by stats.category, stats.limitType, stats.bigBlindDesc desc
|
||||
<orderbyseats>, cast(stats.PlPosition as signed)
|
||||
"""
|
||||
elif db_server == 'sqlite':
|
||||
self.query['playerStatsByPosition'] = ""#TODO
|
||||
else: # assume postgresql
|
||||
self.query['playerStatsByPosition'] = """
|
||||
select /* stats from hudcache */
|
||||
|
|
@ -2907,9 +3059,10 @@ class Sql:
|
|||
order by stats.category, stats.limitType, stats.bigBlindDesc desc
|
||||
<orderbyseats>, cast(stats.PlPosition as smallint)
|
||||
"""
|
||||
#elif db_server == 'sqlite':
|
||||
# self.query['playerStatsByPosition'] = """ """
|
||||
|
||||
####################################
|
||||
# Cash Game Graph query
|
||||
####################################
|
||||
self.query['getRingProfitAllHandsPlayerIdSite'] = """
|
||||
SELECT hp.handId, hp.totalProfit, hp.sawShowdown
|
||||
FROM HandsPlayers hp
|
||||
|
|
@ -2926,6 +3079,62 @@ class Sql:
|
|||
GROUP BY h.startTime, hp.handId, hp.sawShowdown, hp.totalProfit
|
||||
ORDER BY h.startTime"""
|
||||
|
||||
self.query['getRingProfitAllHandsPlayerIdSiteInBB'] = """
|
||||
SELECT hp.handId, ( hp.totalProfit / ( gt.bigBlind * 2 ) ) * 100 , hp.sawShowdown
|
||||
FROM HandsPlayers hp
|
||||
INNER JOIN Players pl ON (pl.id = hp.playerId)
|
||||
INNER JOIN Hands h ON (h.id = hp.handId)
|
||||
INNER JOIN Gametypes gt ON (gt.id = h.gametypeId)
|
||||
WHERE pl.id in <player_test>
|
||||
AND pl.siteId in <site_test>
|
||||
AND h.startTime > '<startdate_test>'
|
||||
AND h.startTime < '<enddate_test>'
|
||||
<limit_test>
|
||||
<game_test>
|
||||
AND hp.tourneysPlayersId IS NULL
|
||||
GROUP BY h.startTime, hp.handId, hp.sawShowdown, hp.totalProfit
|
||||
ORDER BY h.startTime"""
|
||||
|
||||
self.query['getRingProfitAllHandsPlayerIdSiteInDollars'] = """
|
||||
SELECT hp.handId, hp.totalProfit, hp.sawShowdown
|
||||
FROM HandsPlayers hp
|
||||
INNER JOIN Players pl ON (pl.id = hp.playerId)
|
||||
INNER JOIN Hands h ON (h.id = hp.handId)
|
||||
INNER JOIN Gametypes gt ON (gt.id = h.gametypeId)
|
||||
WHERE pl.id in <player_test>
|
||||
AND pl.siteId in <site_test>
|
||||
AND h.startTime > '<startdate_test>'
|
||||
AND h.startTime < '<enddate_test>'
|
||||
<limit_test>
|
||||
<game_test>
|
||||
AND hp.tourneysPlayersId IS NULL
|
||||
GROUP BY h.startTime, hp.handId, hp.sawShowdown, hp.totalProfit
|
||||
ORDER BY h.startTime"""
|
||||
|
||||
|
||||
|
||||
####################################
|
||||
# Tourney Results query
|
||||
####################################
|
||||
self.query['tourneyResults'] = """
|
||||
SELECT tp.tourneyId, (coalesce(tp.winnings,0) - coalesce(tt.buyIn,0) - coalesce(tt.fee,0)) as profit, tp.koCount, tp.rebuyCount, tp.addOnCount, tt.buyIn, tt.fee, t.siteTourneyNo
|
||||
FROM TourneysPlayers tp
|
||||
INNER JOIN Players pl ON (pl.id = tp.playerId)
|
||||
INNER JOIN Tourneys t ON (t.id = tp.tourneyId)
|
||||
INNER JOIN TourneyTypes tt ON (tt.id = t.tourneyTypeId)
|
||||
WHERE pl.id in <player_test>
|
||||
AND pl.siteId in <site_test>
|
||||
AND t.startTime > '<startdate_test>'
|
||||
AND t.startTime < '<enddate_test>'
|
||||
GROUP BY t.startTime, tp.tourneyId, tp.winningsCurrency,
|
||||
tp.winnings, tp.koCount,
|
||||
tp.rebuyCount, tp.addOnCount,
|
||||
tt.buyIn, tt.fee
|
||||
ORDER BY t.startTime"""
|
||||
|
||||
#AND gt.type = 'ring'
|
||||
#<limit_test>
|
||||
#<game_test>
|
||||
|
||||
####################################
|
||||
# Session stats query
|
||||
|
|
@ -2940,7 +3149,7 @@ class Sql:
|
|||
INNER JOIN Players p on (p.Id = hp.playerId)
|
||||
WHERE hp.playerId in <player_test>
|
||||
AND date_format(h.startTime, '%Y-%m-%d') <datestest>
|
||||
AND gt.type is 'ring'
|
||||
AND gt.type LIKE 'ring'
|
||||
ORDER by time"""
|
||||
elif db_server == 'postgresql':
|
||||
self.query['sessionStats'] = """
|
||||
|
|
@ -2952,7 +3161,7 @@ class Sql:
|
|||
INNER JOIN Players p on (p.Id = hp.playerId)
|
||||
WHERE hp.playerId in <player_test>
|
||||
AND h.startTime <datestest>
|
||||
AND gt.type is 'ring'
|
||||
AND gt.type LIKE 'ring'
|
||||
ORDER by time"""
|
||||
elif db_server == 'sqlite':
|
||||
self.query['sessionStats'] = """
|
||||
|
|
@ -2981,15 +3190,22 @@ class Sql:
|
|||
,playerId
|
||||
,activeSeats
|
||||
,position
|
||||
,tourneyTypeId
|
||||
<tourney_insert_clause>
|
||||
,styleKey
|
||||
,HDs
|
||||
,wonWhenSeenStreet1
|
||||
,wonWhenSeenStreet2
|
||||
,wonWhenSeenStreet3
|
||||
,wonWhenSeenStreet4
|
||||
,wonAtSD
|
||||
,street0VPI
|
||||
,street0Aggr
|
||||
,street0_3BChance
|
||||
,street0_3BDone
|
||||
,street0_4BChance
|
||||
,street0_4BDone
|
||||
,other3BStreet0
|
||||
,other4BStreet0
|
||||
,street1Seen
|
||||
,street2Seen
|
||||
,street3Seen
|
||||
|
|
@ -2999,10 +3215,12 @@ class Sql:
|
|||
,street2Aggr
|
||||
,street3Aggr
|
||||
,street4Aggr
|
||||
,otherRaisedStreet0
|
||||
,otherRaisedStreet1
|
||||
,otherRaisedStreet2
|
||||
,otherRaisedStreet3
|
||||
,otherRaisedStreet4
|
||||
,foldToOtherRaisedStreet0
|
||||
,foldToOtherRaisedStreet1
|
||||
,foldToOtherRaisedStreet2
|
||||
,foldToOtherRaisedStreet3
|
||||
|
|
@ -3071,15 +3289,22 @@ class Sql:
|
|||
when hp.position = '9' then 'E'
|
||||
else 'E'
|
||||
end AS hc_position
|
||||
,t.tourneyTypeId
|
||||
<tourney_select_clause>
|
||||
,date_format(h.startTime, 'd%y%m%d')
|
||||
,count(1)
|
||||
,sum(wonWhenSeenStreet1)
|
||||
,sum(wonWhenSeenStreet2)
|
||||
,sum(wonWhenSeenStreet3)
|
||||
,sum(wonWhenSeenStreet4)
|
||||
,sum(wonAtSD)
|
||||
,sum(street0VPI)
|
||||
,sum(street0Aggr)
|
||||
,sum(street0_3BChance)
|
||||
,sum(street0_3BDone)
|
||||
,sum(street0_4BChance)
|
||||
,sum(street0_4BDone)
|
||||
,sum(other3BStreet0)
|
||||
,sum(other4BStreet0)
|
||||
,sum(street1Seen)
|
||||
,sum(street2Seen)
|
||||
,sum(street3Seen)
|
||||
|
|
@ -3089,10 +3314,12 @@ class Sql:
|
|||
,sum(street2Aggr)
|
||||
,sum(street3Aggr)
|
||||
,sum(street4Aggr)
|
||||
,sum(otherRaisedStreet0)
|
||||
,sum(otherRaisedStreet1)
|
||||
,sum(otherRaisedStreet2)
|
||||
,sum(otherRaisedStreet3)
|
||||
,sum(otherRaisedStreet4)
|
||||
,sum(foldToOtherRaisedStreet0)
|
||||
,sum(foldToOtherRaisedStreet1)
|
||||
,sum(foldToOtherRaisedStreet2)
|
||||
,sum(foldToOtherRaisedStreet3)
|
||||
|
|
@ -3145,14 +3372,13 @@ 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)
|
||||
<tourney_join_clause>
|
||||
<where_clause>
|
||||
GROUP BY h.gametypeId
|
||||
,hp.playerId
|
||||
,h.seats
|
||||
,hc_position
|
||||
,t.tourneyTypeId
|
||||
<tourney_group_clause>
|
||||
,date_format(h.startTime, 'd%y%m%d')
|
||||
"""
|
||||
elif db_server == 'postgresql':
|
||||
|
|
@ -3162,15 +3388,22 @@ class Sql:
|
|||
,playerId
|
||||
,activeSeats
|
||||
,position
|
||||
,tourneyTypeId
|
||||
<tourney_insert_clause>
|
||||
,styleKey
|
||||
,HDs
|
||||
,wonWhenSeenStreet1
|
||||
,wonWhenSeenStreet2
|
||||
,wonWhenSeenStreet3
|
||||
,wonWhenSeenStreet4
|
||||
,wonAtSD
|
||||
,street0VPI
|
||||
,street0Aggr
|
||||
,street0_3BChance
|
||||
,street0_3BDone
|
||||
,street0_4BChance
|
||||
,street0_4BDone
|
||||
,other3BStreet0
|
||||
,other4BStreet0
|
||||
,street1Seen
|
||||
,street2Seen
|
||||
,street3Seen
|
||||
|
|
@ -3180,10 +3413,12 @@ class Sql:
|
|||
,street2Aggr
|
||||
,street3Aggr
|
||||
,street4Aggr
|
||||
,otherRaisedStreet0
|
||||
,otherRaisedStreet1
|
||||
,otherRaisedStreet2
|
||||
,otherRaisedStreet3
|
||||
,otherRaisedStreet4
|
||||
,foldToOtherRaisedStreet0
|
||||
,foldToOtherRaisedStreet1
|
||||
,foldToOtherRaisedStreet2
|
||||
,foldToOtherRaisedStreet3
|
||||
|
|
@ -3252,15 +3487,22 @@ class Sql:
|
|||
when hp.position = '9' then 'E'
|
||||
else 'E'
|
||||
end AS hc_position
|
||||
,t.tourneyTypeId
|
||||
<tourney_select_clause>
|
||||
,'d' || to_char(h.startTime, 'YYMMDD')
|
||||
,count(1)
|
||||
,sum(wonWhenSeenStreet1)
|
||||
,sum(wonWhenSeenStreet2)
|
||||
,sum(wonWhenSeenStreet3)
|
||||
,sum(wonWhenSeenStreet4)
|
||||
,sum(wonAtSD)
|
||||
,sum(CAST(street0VPI as integer))
|
||||
,sum(CAST(street0Aggr as integer))
|
||||
,sum(CAST(street0_3BChance as integer))
|
||||
,sum(CAST(street0_3BDone as integer))
|
||||
,sum(CAST(street0_4BChance as integer))
|
||||
,sum(CAST(street0_4BDone as integer))
|
||||
,sum(CAST(other3BStreet0 as integer))
|
||||
,sum(CAST(other4BStreet0 as integer))
|
||||
,sum(CAST(street1Seen as integer))
|
||||
,sum(CAST(street2Seen as integer))
|
||||
,sum(CAST(street3Seen as integer))
|
||||
|
|
@ -3270,10 +3512,12 @@ class Sql:
|
|||
,sum(CAST(street2Aggr as integer))
|
||||
,sum(CAST(street3Aggr as integer))
|
||||
,sum(CAST(street4Aggr as integer))
|
||||
,sum(CAST(otherRaisedStreet0 as integer))
|
||||
,sum(CAST(otherRaisedStreet1 as integer))
|
||||
,sum(CAST(otherRaisedStreet2 as integer))
|
||||
,sum(CAST(otherRaisedStreet3 as integer))
|
||||
,sum(CAST(otherRaisedStreet4 as integer))
|
||||
,sum(CAST(foldToOtherRaisedStreet0 as integer))
|
||||
,sum(CAST(foldToOtherRaisedStreet1 as integer))
|
||||
,sum(CAST(foldToOtherRaisedStreet2 as integer))
|
||||
,sum(CAST(foldToOtherRaisedStreet3 as integer))
|
||||
|
|
@ -3326,14 +3570,13 @@ 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)
|
||||
<tourney_join_clause>
|
||||
<where_clause>
|
||||
GROUP BY h.gametypeId
|
||||
,hp.playerId
|
||||
,h.seats
|
||||
,hc_position
|
||||
,t.tourneyTypeId
|
||||
<tourney_group_clause>
|
||||
,to_char(h.startTime, 'YYMMDD')
|
||||
"""
|
||||
else: # assume sqlite
|
||||
|
|
@ -3343,15 +3586,22 @@ class Sql:
|
|||
,playerId
|
||||
,activeSeats
|
||||
,position
|
||||
,tourneyTypeId
|
||||
<tourney_insert_clause>
|
||||
,styleKey
|
||||
,HDs
|
||||
,wonWhenSeenStreet1
|
||||
,wonWhenSeenStreet2
|
||||
,wonWhenSeenStreet3
|
||||
,wonWhenSeenStreet4
|
||||
,wonAtSD
|
||||
,street0VPI
|
||||
,street0Aggr
|
||||
,street0_3BChance
|
||||
,street0_3BDone
|
||||
,street0_4BChance
|
||||
,street0_4BDone
|
||||
,other3BStreet0
|
||||
,other4BStreet0
|
||||
,street1Seen
|
||||
,street2Seen
|
||||
,street3Seen
|
||||
|
|
@ -3361,10 +3611,12 @@ class Sql:
|
|||
,street2Aggr
|
||||
,street3Aggr
|
||||
,street4Aggr
|
||||
,otherRaisedStreet0
|
||||
,otherRaisedStreet1
|
||||
,otherRaisedStreet2
|
||||
,otherRaisedStreet3
|
||||
,otherRaisedStreet4
|
||||
,foldToOtherRaisedStreet0
|
||||
,foldToOtherRaisedStreet1
|
||||
,foldToOtherRaisedStreet2
|
||||
,foldToOtherRaisedStreet3
|
||||
|
|
@ -3433,15 +3685,22 @@ class Sql:
|
|||
when hp.position = '9' then 'E'
|
||||
else 'E'
|
||||
end AS hc_position
|
||||
,t.tourneyTypeId
|
||||
<tourney_select_clause>
|
||||
,'d' || substr(strftime('%Y%m%d', h.startTime),3,7)
|
||||
,count(1)
|
||||
,sum(wonWhenSeenStreet1)
|
||||
,sum(wonWhenSeenStreet2)
|
||||
,sum(wonWhenSeenStreet3)
|
||||
,sum(wonWhenSeenStreet4)
|
||||
,sum(wonAtSD)
|
||||
,sum(CAST(street0VPI as integer))
|
||||
,sum(CAST(street0Aggr as integer))
|
||||
,sum(CAST(street0_3BChance as integer))
|
||||
,sum(CAST(street0_3BDone as integer))
|
||||
,sum(CAST(street0_4BChance as integer))
|
||||
,sum(CAST(street0_4BDone as integer))
|
||||
,sum(CAST(other3BStreet0 as integer))
|
||||
,sum(CAST(other4BStreet0 as integer))
|
||||
,sum(CAST(street1Seen as integer))
|
||||
,sum(CAST(street2Seen as integer))
|
||||
,sum(CAST(street3Seen as integer))
|
||||
|
|
@ -3451,10 +3710,12 @@ class Sql:
|
|||
,sum(CAST(street2Aggr as integer))
|
||||
,sum(CAST(street3Aggr as integer))
|
||||
,sum(CAST(street4Aggr as integer))
|
||||
,sum(CAST(otherRaisedStreet0 as integer))
|
||||
,sum(CAST(otherRaisedStreet1 as integer))
|
||||
,sum(CAST(otherRaisedStreet2 as integer))
|
||||
,sum(CAST(otherRaisedStreet3 as integer))
|
||||
,sum(CAST(otherRaisedStreet4 as integer))
|
||||
,sum(CAST(foldToOtherRaisedStreet0 as integer))
|
||||
,sum(CAST(foldToOtherRaisedStreet1 as integer))
|
||||
,sum(CAST(foldToOtherRaisedStreet2 as integer))
|
||||
,sum(CAST(foldToOtherRaisedStreet3 as integer))
|
||||
|
|
@ -3507,14 +3768,13 @@ 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)
|
||||
<tourney_join_clause>
|
||||
<where_clause>
|
||||
GROUP BY h.gametypeId
|
||||
,hp.playerId
|
||||
,h.seats
|
||||
,hc_position
|
||||
,t.tourneyTypeId
|
||||
<tourney_group_clause>
|
||||
,'d' || substr(strftime('%Y%m%d', h.startTime),3,7)
|
||||
"""
|
||||
|
||||
|
|
@ -3531,6 +3791,10 @@ class Sql:
|
|||
street0Aggr,
|
||||
street0_3BChance,
|
||||
street0_3BDone,
|
||||
street0_4BChance,
|
||||
street0_4BDone,
|
||||
other3BStreet0,
|
||||
other4BStreet0,
|
||||
street1Seen,
|
||||
street2Seen,
|
||||
street3Seen,
|
||||
|
|
@ -3540,15 +3804,20 @@ class Sql:
|
|||
street2Aggr,
|
||||
street3Aggr,
|
||||
street4Aggr,
|
||||
otherRaisedStreet0,
|
||||
otherRaisedStreet1,
|
||||
otherRaisedStreet2,
|
||||
otherRaisedStreet3,
|
||||
otherRaisedStreet4,
|
||||
foldToOtherRaisedStreet0,
|
||||
foldToOtherRaisedStreet1,
|
||||
foldToOtherRaisedStreet2,
|
||||
foldToOtherRaisedStreet3,
|
||||
foldToOtherRaisedStreet4,
|
||||
wonWhenSeenStreet1,
|
||||
wonWhenSeenStreet2,
|
||||
wonWhenSeenStreet3,
|
||||
wonWhenSeenStreet4,
|
||||
wonAtSD,
|
||||
raiseFirstInChance,
|
||||
raisedFirstIn,
|
||||
|
|
@ -3611,7 +3880,8 @@ class Sql:
|
|||
%s, %s, %s, %s, %s,
|
||||
%s, %s, %s, %s, %s,
|
||||
%s, %s, %s, %s, %s,
|
||||
%s)"""
|
||||
%s, %s, %s, %s, %s,
|
||||
%s, %s, %s, %s, %s)"""
|
||||
|
||||
self.query['update_hudcache'] = """
|
||||
UPDATE HudCache SET
|
||||
|
|
@ -3620,6 +3890,10 @@ class Sql:
|
|||
street0Aggr=street0Aggr+%s,
|
||||
street0_3BChance=street0_3BChance+%s,
|
||||
street0_3BDone=street0_3BDone+%s,
|
||||
street0_4BChance=street0_4BChance+%s,
|
||||
street0_4BDone=street0_4BDone+%s,
|
||||
other3BStreet0=other3BStreet0+%s,
|
||||
other4BStreet0=other4BStreet0+%s,
|
||||
street1Seen=street1Seen+%s,
|
||||
street2Seen=street2Seen+%s,
|
||||
street3Seen=street3Seen+%s,
|
||||
|
|
@ -3629,15 +3903,20 @@ class Sql:
|
|||
street2Aggr=street2Aggr+%s,
|
||||
street3Aggr=street3Aggr+%s,
|
||||
street4Aggr=street4Aggr+%s,
|
||||
otherRaisedStreet0=otherRaisedStreet0+%s,
|
||||
otherRaisedStreet1=otherRaisedStreet1+%s,
|
||||
otherRaisedStreet2=otherRaisedStreet2+%s,
|
||||
otherRaisedStreet3=otherRaisedStreet3+%s,
|
||||
otherRaisedStreet4=otherRaisedStreet4+%s,
|
||||
foldToOtherRaisedStreet0=foldToOtherRaisedStreet0+%s,
|
||||
foldToOtherRaisedStreet1=foldToOtherRaisedStreet1+%s,
|
||||
foldToOtherRaisedStreet2=foldToOtherRaisedStreet2+%s,
|
||||
foldToOtherRaisedStreet3=foldToOtherRaisedStreet3+%s,
|
||||
foldToOtherRaisedStreet4=foldToOtherRaisedStreet4+%s,
|
||||
wonWhenSeenStreet1=wonWhenSeenStreet1+%s,
|
||||
wonWhenSeenStreet2=wonWhenSeenStreet2+%s,
|
||||
wonWhenSeenStreet3=wonWhenSeenStreet3+%s,
|
||||
wonWhenSeenStreet4=wonWhenSeenStreet4+%s,
|
||||
wonAtSD=wonAtSD+%s,
|
||||
raiseFirstInChance=raiseFirstInChance+%s,
|
||||
raisedFirstIn=raisedFirstIn+%s,
|
||||
|
|
@ -3781,6 +4060,7 @@ class Sql:
|
|||
AND fee=%s
|
||||
AND category=%s
|
||||
AND limitType=%s
|
||||
AND maxSeats=%s
|
||||
AND knockout=%s
|
||||
AND rebuy=%s
|
||||
AND addOn=%s
|
||||
|
|
@ -3790,9 +4070,9 @@ class Sql:
|
|||
"""
|
||||
|
||||
self.query['insertTourneyType'] = """INSERT INTO TourneyTypes
|
||||
(siteId, currency, buyin, fee, category, limitType, buyInChips, knockout, koBounty, rebuy,
|
||||
(siteId, currency, buyin, fee, category, limitType, maxSeats, 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, %s)
|
||||
VALUES (%s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s)
|
||||
"""
|
||||
|
||||
self.query['getTourneyByTourneyNo'] = """SELECT t.*
|
||||
|
|
@ -3801,6 +4081,22 @@ class Sql:
|
|||
WHERE tt.siteId=%s AND t.siteTourneyNo=%s
|
||||
"""
|
||||
|
||||
self.query['getTourneyInfo'] = """SELECT tt.*, t.*
|
||||
FROM Tourneys t
|
||||
INNER JOIN TourneyTypes tt ON (t.tourneyTypeId = tt.id)
|
||||
INNER JOIN Sites s ON (tt.siteId = s.id)
|
||||
WHERE s.name=%s AND t.siteTourneyNo=%s
|
||||
"""
|
||||
|
||||
self.query['getTourneyPlayerInfo'] = """SELECT tp.*
|
||||
FROM Tourneys t
|
||||
INNER JOIN TourneyTypes tt ON (t.tourneyTypeId = tt.id)
|
||||
INNER JOIN Sites s ON (tt.siteId = s.id)
|
||||
INNER JOIN TourneysPlayers tp ON (tp.tourneyId = t.id)
|
||||
INNER JOIN Players p ON (p.id = tp.playerId)
|
||||
WHERE s.name=%s AND t.siteTourneyNo=%s AND p.name=%s
|
||||
"""
|
||||
|
||||
self.query['insertTourney'] = """INSERT INTO Tourneys
|
||||
(tourneyTypeId, siteTourneyNo, entries, prizepool,
|
||||
startTime, endTime, tourneyName, matrixIdProcessed,
|
||||
|
|
@ -3936,6 +4232,9 @@ class Sql:
|
|||
street3CBDone,
|
||||
street4CBDone,
|
||||
wonWhenSeenStreet1,
|
||||
wonWhenSeenStreet2,
|
||||
wonWhenSeenStreet3,
|
||||
wonWhenSeenStreet4,
|
||||
street0Calls,
|
||||
street1Calls,
|
||||
street2Calls,
|
||||
|
|
@ -3951,10 +4250,16 @@ class Sql:
|
|||
startCards,
|
||||
street0_3BChance,
|
||||
street0_3BDone,
|
||||
street0_4BChance,
|
||||
street0_4BDone,
|
||||
other3BStreet0,
|
||||
other4BStreet0,
|
||||
otherRaisedStreet0,
|
||||
otherRaisedStreet1,
|
||||
otherRaisedStreet2,
|
||||
otherRaisedStreet3,
|
||||
otherRaisedStreet4,
|
||||
foldToOtherRaisedStreet0,
|
||||
foldToOtherRaisedStreet1,
|
||||
foldToOtherRaisedStreet2,
|
||||
foldToOtherRaisedStreet3,
|
||||
|
|
@ -4003,6 +4308,26 @@ class Sql:
|
|||
%s, %s, %s, %s, %s,
|
||||
%s, %s, %s, %s, %s,
|
||||
%s, %s, %s, %s, %s,
|
||||
%s, %s, %s, %s, %s,
|
||||
%s, %s, %s, %s, %s,
|
||||
%s, %s, %s, %s, %s,
|
||||
%s, %s, %s, %s, %s
|
||||
)"""
|
||||
|
||||
self.query['store_hands_actions'] = """INSERT INTO HandsActions (
|
||||
handsPlayerId,
|
||||
street,
|
||||
actionNo,
|
||||
streetActionNo,
|
||||
actionId,
|
||||
amount,
|
||||
raiseTo,
|
||||
amountCalled,
|
||||
numDiscarded,
|
||||
cardsDiscarded,
|
||||
allIn
|
||||
)
|
||||
VALUES (
|
||||
%s, %s, %s, %s, %s,
|
||||
%s, %s, %s, %s, %s,
|
||||
%s
|
||||
|
|
@ -4011,14 +4336,14 @@ class Sql:
|
|||
################################
|
||||
# Counts for DB stats window
|
||||
################################
|
||||
self.query['getHandCount'] = "SELECT COUNT(id) FROM Hands"
|
||||
self.query['getTourneyCount'] = "SELECT COUNT(id) FROM Tourneys"
|
||||
self.query['getTourneyTypeCount'] = "SELECT COUNT(id) FROM TourneyTypes"
|
||||
self.query['getHandCount'] = "SELECT COUNT(*) FROM Hands"
|
||||
self.query['getTourneyCount'] = "SELECT COUNT(*) FROM Tourneys"
|
||||
self.query['getTourneyTypeCount'] = "SELECT COUNT(*) FROM TourneyTypes"
|
||||
|
||||
################################
|
||||
# queries for dumpDatabase
|
||||
################################
|
||||
for table in (u'Autorates', u'Backings', u'Gametypes', u'Hands', u'HandsActions', u'HandsPlayers', u'HudCache', u'Players', u'Settings', u'Sites', u'TourneyTypes', u'Tourneys', u'TourneysPlayers'):
|
||||
for table in (u'Autorates', u'Backings', u'Gametypes', u'Hands', u'HandsActions', u'HandsPlayers', u'HudCache', u'Players', u'RawHands', u'RawTourneys', u'Settings', u'Sites', u'TourneyTypes', u'Tourneys', u'TourneysPlayers'):
|
||||
self.query['get'+table] = u"SELECT * FROM "+table
|
||||
|
||||
################################
|
||||
|
|
|
|||
207
pyfpdb/SplitHandHistory.py
Normal file
207
pyfpdb/SplitHandHistory.py
Normal file
|
|
@ -0,0 +1,207 @@
|
|||
#!/usr/bin/python
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
#Copyright 2010 Chaz Littlejohn
|
||||
#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 L10n
|
||||
_ = L10n.get_translation()
|
||||
|
||||
# This code is based heavily on stars-support-hh-split.py by Mika Boström
|
||||
|
||||
import os
|
||||
import sys
|
||||
import re
|
||||
import codecs
|
||||
import Options
|
||||
import Configuration
|
||||
from Exceptions import *
|
||||
from cStringIO import StringIO
|
||||
|
||||
(options, argv) = Options.fpdb_options()
|
||||
|
||||
__ARCHIVE_PRE_HEADER_REGEX='^Hand #(\d+)\s*$|\*{20}\s#\s\d+\s\*+\s+'
|
||||
re_SplitArchive = re.compile(__ARCHIVE_PRE_HEADER_REGEX)
|
||||
codepage = ["utf-16", "utf-8", "cp1252"]
|
||||
|
||||
|
||||
class SplitHandHistory:
|
||||
def __init__(self, config, in_path = '-', out_path = None, hands = 100, filter = "PokerStarsToFpdb", archive = False):
|
||||
self.config = config
|
||||
self.in_path = in_path
|
||||
self.out_path = out_path
|
||||
if not self.out_path:
|
||||
self.out_path = os.path.dirname(self.in_path)
|
||||
self.hands = hands
|
||||
self.archive = archive
|
||||
self.re_SplitHands = None
|
||||
self.line_delimiter = None
|
||||
self.line_addendum = None
|
||||
self.filedone = False
|
||||
|
||||
#Acquire re_SplitHands for this hh
|
||||
filter_name = filter.replace("ToFpdb", "")
|
||||
mod = __import__(filter)
|
||||
obj = getattr(mod, filter_name, None)
|
||||
self.re_SplitHands = obj.re_SplitHands
|
||||
|
||||
#Determine line delimiter type if any
|
||||
if self.re_SplitHands.match('\n\n'):
|
||||
self.line_delimiter = '\n\n'
|
||||
if self.re_SplitHands.match('\n\n\n'):
|
||||
self.line_delimiter = '\n\n\n'
|
||||
|
||||
#Add new line addendum for sites which match SplitHand to next line as well
|
||||
if filter_name == 'OnGame':
|
||||
self.line_addendum = '*'
|
||||
if filter_name == 'Carbon':
|
||||
self.line_addendum = '<game'
|
||||
|
||||
#Open the gargantuan file
|
||||
for kodec in self.__listof(codepage):
|
||||
try:
|
||||
infile = codecs.open(self.in_path, 'r', kodec)
|
||||
except IOError:
|
||||
print _('File not found')
|
||||
sys.exit(2)
|
||||
|
||||
#Split with do_hands_per_file if archive and paragraphs if a regular hh
|
||||
if self.archive:
|
||||
nn = 0
|
||||
while True:
|
||||
nn += 1
|
||||
check = self.do_hands_per_file(infile, nn)
|
||||
if check is None:
|
||||
print _('%s processed' % self.in_path)
|
||||
break
|
||||
else:
|
||||
filenum = 0
|
||||
while not self.filedone:
|
||||
filenum += 1
|
||||
outfile = self.new_file(filenum)
|
||||
handnum = 0
|
||||
for hand in self.paragraphs(infile, None, self.line_addendum):
|
||||
outfile.write(hand)
|
||||
if self.line_delimiter:
|
||||
outfile.write(self.line_delimiter)
|
||||
handnum += 1
|
||||
if handnum >= self.hands:
|
||||
break
|
||||
outfile.close()
|
||||
|
||||
def new_file(self, fileno=-1):
|
||||
if fileno < 1:
|
||||
print _('Nope, will not work (fileno=%d)' % fileno)
|
||||
sys.exit(2)
|
||||
basename = os.path.splitext(os.path.basename(self.in_path))[0]
|
||||
name = os.path.join(self.out_path, basename+'-%06d.txt' % fileno)
|
||||
print '-> %s' % name
|
||||
newfile = file(name, 'w')
|
||||
return newfile
|
||||
|
||||
#Archive Hand Splitter
|
||||
def do_hands_per_file(self, infile, num=-1):
|
||||
done = False
|
||||
n = 0
|
||||
outfile = self.new_file(num)
|
||||
while n < self.hands:
|
||||
try:
|
||||
infile = self.next_hand(infile)
|
||||
infile = self.process_hand(infile, outfile)
|
||||
except FpdbEndOfFile:
|
||||
done = True
|
||||
break
|
||||
except:
|
||||
print _("Unexpected error processing file")
|
||||
sys.exit(2)
|
||||
n += 1
|
||||
outfile.close()
|
||||
if not done:
|
||||
return infile
|
||||
else:
|
||||
return None
|
||||
|
||||
#Non-Archive Hand Splitter
|
||||
def paragraphs(self, file, separator=None, addendum=None):
|
||||
if not callable(separator) and self.line_delimiter:
|
||||
def separator(line): return line == '\n'
|
||||
else:
|
||||
def separator(line): return self.re_SplitHands.search(line)
|
||||
file_str = StringIO()
|
||||
print file_str.getvalue()
|
||||
for line in file:
|
||||
if separator(line+addendum):
|
||||
if file_str.getvalue():
|
||||
if not self.line_delimiter:
|
||||
file_str.write(line)
|
||||
yield file_str.getvalue()
|
||||
file_str = None
|
||||
file_str = StringIO()
|
||||
else:
|
||||
file_str.write(line)
|
||||
if file_str.getvalue(): yield file_str.getvalue()
|
||||
self.filedone = True
|
||||
|
||||
|
||||
# Finds pre-hand header (Hand #<num>)
|
||||
def next_hand(self, infile):
|
||||
m = None
|
||||
while not m:
|
||||
l = infile.readline()
|
||||
#print l, len(l)
|
||||
# Catch EOF
|
||||
if len(l) == 0:
|
||||
raise FpdbEndOfFile(_("End of file reached"))
|
||||
m = re_SplitArchive.search(l)
|
||||
# There is an empty line after pre-hand header and actual HH entry
|
||||
l = infile.readline()
|
||||
|
||||
return infile
|
||||
|
||||
# Each individual hand is written separately
|
||||
def process_hand(self, infile=None, outfile=None):
|
||||
l = infile.readline()
|
||||
l = l.replace('\r\n', '\n')
|
||||
outfile.write(l)
|
||||
l = infile.readline()
|
||||
|
||||
while len(l) < 3:
|
||||
l = infile.readline()
|
||||
|
||||
while len(l) > 2:
|
||||
l = l.replace('\r\n', '\n')
|
||||
outfile.write(l)
|
||||
l = infile.readline()
|
||||
outfile.write(self.line_delimiter)
|
||||
return infile
|
||||
|
||||
def __listof(self, x):
|
||||
if isinstance(x, list) or isinstance(x, tuple):
|
||||
return x
|
||||
else:
|
||||
return [x]
|
||||
|
||||
def main(argv=None):
|
||||
if argv is None:
|
||||
argv = sys.argv[1:]
|
||||
|
||||
if not options.config:
|
||||
options.config = Configuration.Config(file = "HUD_config.test.xml")
|
||||
|
||||
if options.filename:
|
||||
SplitHH = SplitHandHistory(options.config, options.filename, options.outpath, options.hands,
|
||||
options.hhc, options.archive)
|
||||
|
||||
if __name__ == '__main__':
|
||||
sys.exit(main())
|
||||
705
pyfpdb/Stats.py
Executable file → Normal file
705
pyfpdb/Stats.py
Executable file → Normal file
File diff suppressed because it is too large
Load Diff
|
|
@ -1,12 +1,14 @@
|
|||
#!/usr/bin/env python
|
||||
# -*- coding: utf-8 -*-
|
||||
"""Discover_TableWindow.py
|
||||
"""Base class for interacting with poker client windows.
|
||||
|
||||
Inspects the currently open windows and finds those of interest to us--that is
|
||||
poker table windows from supported sites. Returns a list
|
||||
of Table_Window objects representing the windows found.
|
||||
There are currently subclasses for X and Windows.
|
||||
|
||||
The class queries the poker client window for data of interest, such as
|
||||
size and location. It also controls the signals to alert the HUD when the
|
||||
client has been resized, destroyed, etc.
|
||||
"""
|
||||
# Copyright 2008-2010, Ray E. Barker
|
||||
# Copyright 2008 - 2010, Ray E. Barker
|
||||
|
||||
# This program is free software; you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License as published by
|
||||
|
|
@ -25,37 +27,38 @@ of Table_Window objects representing the windows found.
|
|||
########################################################################
|
||||
|
||||
# Standard Library modules
|
||||
import os
|
||||
import sys
|
||||
import re
|
||||
|
||||
# pyGTK modules
|
||||
import pygtk
|
||||
import gtk
|
||||
import gobject
|
||||
|
||||
# FreePokerTools modules
|
||||
import Configuration
|
||||
#if os.name == "posix":
|
||||
# import XTables
|
||||
#elif os.name == "nt":
|
||||
# import WinTables
|
||||
from HandHistoryConverter import getTableTitleRe
|
||||
from HandHistoryConverter import getTableNoRe
|
||||
|
||||
# Global used for figuring out the current game being played from the title
|
||||
# The dict key is the fpdb name for the game
|
||||
# Global used for figuring out the current game being played from the title.
|
||||
# The dict key is a tuple of (limit type, category) for the game.
|
||||
# The list is the names for those games used by the supported poker sites
|
||||
# This is currently only used for HORSE, so it only needs to support those
|
||||
# This is currently only used for mixed games, so it only needs to support those
|
||||
# games on PokerStars and Full Tilt.
|
||||
game_names = { #fpdb name Stars Name FTP Name
|
||||
"holdem" : ("Hold\'em" , ),
|
||||
"omahahilo" : ("Omaha H/L" , ),
|
||||
"studhilo" : ("Stud H/L" , ),
|
||||
"razz" : ("Razz" , ),
|
||||
"studhi" : ("Stud" , "Stud Hi")
|
||||
nlpl_game_names = { #fpdb name Stars Name FTP Name (if different)
|
||||
("nl", "holdem" ) : ("No Limit Hold\'em" , ),
|
||||
("pl", "holdem" ) : ("Pot Limit Hold\'em" , ),
|
||||
("pl", "omahahi" ) : ("Pot Limit Omaha" ,"Pot Limit Omaha Hi" ),
|
||||
}
|
||||
limit_game_names = { #fpdb name Stars Name FTP Name
|
||||
("fl", "holdem" ) : ("Limit Hold\'em" , ),
|
||||
("fl", "omahahilo" ) : ("Limit Omaha H/L" , ),
|
||||
("fl", "studhilo" ) : ("Limit Stud H/L" , ),
|
||||
("fl", "razz" ) : ("Limit Razz" , ),
|
||||
("fl", "studhi" ) : ("Limit Stud" , "Stud Hi"),
|
||||
("fl", "27_3draw" ) : ("Limit Triple Draw 2-7 Lowball", )
|
||||
}
|
||||
|
||||
# A window title might have our table name + one of theses words/
|
||||
# A window title might have our table name + one of these words/
|
||||
# phrases. If it has this word in the title, it is not a table.
|
||||
bad_words = ('History for table:', 'HUD:', 'Chat:')
|
||||
bad_words = ('History for table:', 'HUD:', 'Chat:', 'FPDBHUD')
|
||||
|
||||
# Here are the custom signals we define for allowing the 'client watcher'
|
||||
# thread to communicate with the gui thread. Any time a poker client is
|
||||
|
|
@ -76,11 +79,19 @@ gobject.signal_new("client_destroyed", gtk.Window,
|
|||
gobject.TYPE_NONE,
|
||||
(gobject.TYPE_PYOBJECT,))
|
||||
|
||||
gobject.signal_new("game_changed", gtk.Window,
|
||||
gobject.SIGNAL_RUN_LAST,
|
||||
gobject.TYPE_NONE,
|
||||
(gobject.TYPE_PYOBJECT,))
|
||||
|
||||
gobject.signal_new("table_changed", gtk.Window,
|
||||
gobject.SIGNAL_RUN_LAST,
|
||||
gobject.TYPE_NONE,
|
||||
(gobject.TYPE_PYOBJECT,))
|
||||
|
||||
# Each TableWindow object must have the following attributes correctly populated:
|
||||
# tw.name = the table name from the title bar, which must to match the table name
|
||||
# from the corresponding hand history.
|
||||
# tw.site = the site name, e.g. PokerStars, FullTilt. This must match the site
|
||||
# name specified in the config file.
|
||||
# from the corresponding hand record in the db.
|
||||
# tw.number = This is the system id number for the client table window in the
|
||||
# format that the system presents it. This is Xid in Xwindows and
|
||||
# hwnd in Microsoft Windows.
|
||||
|
|
@ -92,60 +103,161 @@ gobject.signal_new("client_destroyed", gtk.Window,
|
|||
# to the top left of the display screen. This also does not include the
|
||||
# title bar and window borders. To put it another way, this is the
|
||||
# screen location of (0, 0) in the working window.
|
||||
# tournament = Tournament number for a tournament or None for a cash game.
|
||||
# table = Table number for a tournament.
|
||||
# gdkhandle =
|
||||
# window =
|
||||
# parent =
|
||||
# game =
|
||||
# search_string =
|
||||
|
||||
class Table_Window(object):
|
||||
def __init__(self, search_string, table_name = None, tournament = None, table_number = None):
|
||||
def __init__(self, config, site, table_name = None, tournament = None, table_number = None):
|
||||
|
||||
self.config = config
|
||||
self.site = site
|
||||
if tournament is not None and table_number is not None:
|
||||
print "tournament %s, table %s" % (tournament, table_number)
|
||||
self.tournament = int(tournament)
|
||||
self.table = int(table_number)
|
||||
self.name = "%s - %s" % (self.tournament, self.table)
|
||||
self.type = "tour"
|
||||
table_kwargs = dict(tournament = self.tournament, table_number = self.table)
|
||||
self.tableno_re = getTableNoRe(self.config, self.site, tournament = self.tournament)
|
||||
elif table_name is not None:
|
||||
# search_string = table_name
|
||||
self.name = table_name
|
||||
self.type = "cash"
|
||||
self.tournament = None
|
||||
table_kwargs = dict(table_name = table_name)
|
||||
|
||||
else:
|
||||
return None
|
||||
|
||||
self.find_table_parameters(search_string)
|
||||
self.search_string = getTableTitleRe(self.config, self.site, self.type, **table_kwargs)
|
||||
self.find_table_parameters()
|
||||
|
||||
geo = self.get_geometry()
|
||||
if geo is None: return None
|
||||
self.width = geo['width']
|
||||
self.height = geo['height']
|
||||
self.x = geo['x']
|
||||
self.y = geo['y']
|
||||
self.oldx = self.x # attn ray: remove these two lines and update Hud.py::update_table_position()
|
||||
self.oldy = self.y
|
||||
|
||||
self.game = self.get_game()
|
||||
|
||||
def __str__(self):
|
||||
# __str__ method for testing
|
||||
likely_attrs = ("site", "number", "title", "width", "height", "x", "y",
|
||||
"tournament", "table", "gdkhandle")
|
||||
likely_attrs = ("number", "title", "site", "width", "height", "x", "y",
|
||||
"tournament", "table", "gdkhandle", "window", "parent",
|
||||
"game", "search_string", "tableno_re")
|
||||
temp = 'TableWindow object\n'
|
||||
for a in likely_attrs:
|
||||
if getattr(self, a, 0):
|
||||
temp += " %s = %s\n" % (a, getattr(self, a))
|
||||
return temp
|
||||
|
||||
####################################################################
|
||||
# "get" methods. These query the table and return the info to get.
|
||||
# They don't change the data in the table and are generally used
|
||||
# by the "check" methods. Most of the get methods are in the
|
||||
# subclass because they are specific to X, Windows, etc.
|
||||
def get_game(self):
|
||||
title = self.get_window_title()
|
||||
print title
|
||||
for game, names in game_names.iteritems():
|
||||
# title = self.get_window_title()
|
||||
# if title is None:
|
||||
# return False
|
||||
title = self.title
|
||||
|
||||
# check for nl and pl games first, to avoid bad matches
|
||||
for game, names in nlpl_game_names.iteritems():
|
||||
for name in names:
|
||||
if name in title:
|
||||
return game
|
||||
return None
|
||||
for game, names in limit_game_names.iteritems():
|
||||
for name in names:
|
||||
if name in title:
|
||||
return game
|
||||
return False
|
||||
|
||||
def check_geometry(self):
|
||||
def get_table_no(self):
|
||||
new_title = self.get_window_title()
|
||||
if new_title is None:
|
||||
return False
|
||||
|
||||
try:
|
||||
mo = re.search(self.tableno_re, new_title)
|
||||
except AttributeError: #'Table' object has no attribute 'tableno_re'
|
||||
return False
|
||||
|
||||
if mo is not None:
|
||||
#print "get_table_no: mo=",mo.groups()
|
||||
return mo.group(1)
|
||||
return False
|
||||
|
||||
####################################################################
|
||||
# check_table() is meant to be called by the hud periodically to
|
||||
# determine if the client has been moved or resized. check_table()
|
||||
# also checks and signals if the client has been closed.
|
||||
def check_table(self, hud):
|
||||
result = self.check_size()
|
||||
if result != False:
|
||||
hud.parent.main_window.emit(result, hud)
|
||||
if result == "client_destroyed":
|
||||
return True
|
||||
|
||||
result = self.check_loc()
|
||||
if result != False:
|
||||
hud.parent.main_window.emit(result, hud)
|
||||
if result == "client_destroyed":
|
||||
return True
|
||||
return True
|
||||
|
||||
####################################################################
|
||||
# "check" methods. They use the corresponding get method, update the
|
||||
# table object and return the name of the signal to be emitted or
|
||||
# False if unchanged. These do not signal for destroyed
|
||||
# clients to prevent a race condition.
|
||||
|
||||
# These might be called by a Window.timeout, so they must not
|
||||
# return False, or the timeout will be cancelled.
|
||||
def check_game(self, hud):
|
||||
new_game = self.get_game()
|
||||
if new_game is not None and self.game != new_game:
|
||||
self.game = new_game
|
||||
hud.main_window.emit("game_changed", hud)
|
||||
return "game_changed"
|
||||
return True
|
||||
|
||||
def check_size(self):
|
||||
new_geo = self.get_geometry()
|
||||
|
||||
if new_geo is None: # window destroyed
|
||||
return "client_destroyed"
|
||||
|
||||
elif self.x != new_geo['x'] or self.y != new_geo['y']: # window moved
|
||||
self.x = new_geo['x']
|
||||
self.y = new_geo['y']
|
||||
return "client_moved"
|
||||
|
||||
elif self.width != new_geo['width'] or self.height != new_geo['height']: # window resized
|
||||
self.width = new_geo['width']
|
||||
self.height = new_geo['height']
|
||||
return "client_resized"
|
||||
return False # no change
|
||||
|
||||
else: return False # window not changed
|
||||
def check_loc(self):
|
||||
new_geo = self.get_geometry()
|
||||
if new_geo is None: # window destroyed
|
||||
return "client_destroyed"
|
||||
|
||||
if self.x != new_geo['x'] or self.y != new_geo['y']: # window moved
|
||||
print self.x, self.y, new_geo['x'], new_geo['y']
|
||||
self.x = new_geo['x']
|
||||
self.y = new_geo['y']
|
||||
return "client_moved"
|
||||
return False # no change
|
||||
|
||||
def check_table_no(self, hud):
|
||||
result = self.get_table_no()
|
||||
if result != False and result != self.table:
|
||||
self.table = result
|
||||
if hud is not None:
|
||||
hud.main_window.emit("table_changed", hud)
|
||||
return True
|
||||
|
||||
def check_bad_words(self, title):
|
||||
for word in bad_words:
|
||||
|
|
|
|||
438
pyfpdb/Tables.py
438
pyfpdb/Tables.py
|
|
@ -1,438 +0,0 @@
|
|||
#!/usr/bin/env python
|
||||
# -*- coding: utf-8 -*-
|
||||
"""Discover_Tables.py
|
||||
|
||||
Inspects the currently open windows and finds those of interest to us--that is
|
||||
poker table windows from supported sites. Returns a list
|
||||
of Table_Window objects representing the windows found.
|
||||
"""
|
||||
# Copyright 2008-2010, Ray E. Barker
|
||||
|
||||
# This program is free software; you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License as published by
|
||||
# the Free Software Foundation; either version 2 of the License, or
|
||||
# (at your option) any later version.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with this program; if not, write to the Free Software
|
||||
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
|
||||
########################################################################
|
||||
|
||||
# Standard Library modules
|
||||
import os
|
||||
import sys
|
||||
import re
|
||||
|
||||
# Win32 modules
|
||||
|
||||
if os.name == 'nt':
|
||||
import win32gui
|
||||
import win32process
|
||||
import win32api
|
||||
import win32con
|
||||
import win32security
|
||||
|
||||
# FreePokerTools modules
|
||||
import Configuration
|
||||
|
||||
# Each TableWindow object must have the following attributes correctly populated:
|
||||
# tw.name = the table name from the title bar, which must to match the table name
|
||||
# from the corresponding hand history.
|
||||
# tw.site = the site name, e.g. PokerStars, FullTilt. This must match the site
|
||||
# name specified in the config file.
|
||||
# tw.number = This is the system id number for the client table window in the
|
||||
# format that the system presents it. This is Xid in Xwindows and
|
||||
# hwnd in Microsoft Windows.
|
||||
# tw.title = The full title from the window title bar.
|
||||
# tw.width, tw.height = The width and height of the window in pixels. This is
|
||||
# the internal width and height, not including the title bar and
|
||||
# window borders.
|
||||
# tw.x, tw.y = The x, y (horizontal, vertical) location of the window relative
|
||||
# to the top left of the display screen. This also does not include the
|
||||
# title bar and window borders. To put it another way, this is the
|
||||
# screen location of (0, 0) in the working window.
|
||||
|
||||
class Table_Window:
|
||||
def __init__(self, info = {}):
|
||||
if 'number' in info: self.number = info['number']
|
||||
if 'exe' in info: self.exe = info['exe']
|
||||
if 'width' in info: self.width = info['width']
|
||||
if 'height' in info: self.height = info['height']
|
||||
if 'x' in info: self.x = info['x']
|
||||
if 'y' in info: self.y = info['y']
|
||||
if 'site' in info: self.site = info['site']
|
||||
if 'title' in info: self.title = info['title']
|
||||
if 'name' in info: self.name = info['name']
|
||||
self.gdkhandle = None
|
||||
|
||||
def __str__(self):
|
||||
# __str__ method for testing
|
||||
temp = 'TableWindow object\n'
|
||||
temp = temp + " name = %s\n site = %s\n number = %s\n title = %s\n" % (self.name, self.site, self.number, self.title)
|
||||
# temp = temp + " game = %s\n structure = %s\n max = %s\n" % (self.game, self.structure, self.max)
|
||||
temp = temp + " width = %d\n height = %d\n x = %d\n y = %d\n" % (self.width, self.height, self.x, self.y)
|
||||
if getattr(self, 'tournament', 0):
|
||||
temp = temp + " tournament = %d\n table = %d" % (self.tournament, self.table)
|
||||
return temp
|
||||
|
||||
############################################################################
|
||||
# Top-level discovery routines--these are the modules interface
|
||||
def discover(c):
|
||||
"""Dispatch routine for finding all potential poker client windows."""
|
||||
if os.name == 'posix':
|
||||
tables = discover_posix(c)
|
||||
elif os.name == 'nt':
|
||||
tables = discover_nt(c)
|
||||
elif os.name == 'mac':
|
||||
tables = discover_mac(c)
|
||||
else:
|
||||
tables = {}
|
||||
return tables
|
||||
|
||||
def discover_table_by_name(c, tablename):
|
||||
"""Dispatch routine for finding poker client windows with the given name."""
|
||||
if os.name == 'posix':
|
||||
info = discover_posix_by_name(c, tablename)
|
||||
elif os.name == 'nt':
|
||||
info = discover_nt_by_name(c, tablename)
|
||||
elif os.name == 'mac':
|
||||
info = discover_mac_by_name(c, tablename)
|
||||
else:
|
||||
return None
|
||||
if info is None:
|
||||
return None
|
||||
return Table_Window(info)
|
||||
|
||||
def discover_tournament_table(c, tour_number, tab_number):
|
||||
"""Dispatch routine for finding poker clients with tour and table number."""
|
||||
if os.name == 'posix':
|
||||
info = discover_posix_tournament(c, tour_number, tab_number)
|
||||
elif os.name == 'nt':
|
||||
info = discover_nt_tournament(c, tour_number, tab_number)
|
||||
elif os.name == 'mac':
|
||||
info = discover_mac_tournament(c, tour_number, tab_number)
|
||||
else:
|
||||
return None
|
||||
if info:
|
||||
return Table_Window(info)
|
||||
return None
|
||||
|
||||
#############################################################################
|
||||
# Posix (= XWindows) specific routines
|
||||
def discover_posix(c):
|
||||
"""Poker client table window finder for posix/Linux = XWindows."""
|
||||
tables = {}
|
||||
for listing in os.popen('xwininfo -root -tree').readlines():
|
||||
# xwininfo -root -tree -id 0xnnnnn gets the info on a single window
|
||||
for s in c.get_supported_sites():
|
||||
params = c.get_site_parameters(s)
|
||||
|
||||
# TODO: We need to make a list of phrases, shared between the WIndows and Unix code!!!!!!
|
||||
if re.search(params['table_finder'], listing):
|
||||
if 'Lobby' in listing: continue
|
||||
if 'Instant Hand History' in listing: continue
|
||||
# if '\"Full Tilt Poker\"' in listing: continue
|
||||
if 'History for table:' in listing: continue
|
||||
if 'has no name' in listing: continue
|
||||
info = decode_xwininfo(c, listing)
|
||||
if info['site'] is None: continue
|
||||
if info['title'] == info['exe']: continue
|
||||
# this appears to be a poker client, so make a table object for it
|
||||
tw = Table_Window(info)
|
||||
eval("%s(tw)" % params['decoder'])
|
||||
tables[tw.name] = tw
|
||||
return tables
|
||||
|
||||
def discover_posix_by_name(c, tablename):
|
||||
"""Find an XWindows poker client of the given name."""
|
||||
for listing in os.popen('xwininfo -root -tree').readlines():
|
||||
if tablename in listing:
|
||||
if 'History for table:' in listing: continue
|
||||
info = decode_xwininfo(c, listing)
|
||||
if not info['name'] == tablename: continue
|
||||
return info
|
||||
return None
|
||||
|
||||
def discover_posix_tournament(c, t_number, s_number):
|
||||
"""Finds the X window for a client, given tournament and table nos."""
|
||||
search_string = "%s.+Table.+%s" % (t_number, s_number)
|
||||
for listing in os.popen('xwininfo -root -tree').readlines():
|
||||
if re.search(search_string, listing):
|
||||
return decode_xwininfo(c, listing)
|
||||
return None
|
||||
|
||||
def decode_xwininfo(c, info_string):
|
||||
"""Gets window parameters from xwinifo string--XWindows."""
|
||||
info = {}
|
||||
mo = re.match('\s+([\dxabcdef]+) (.+):\s\(\"([a-zA-Z.]+)\".+ (\d+)x(\d+)\+\d+\+\d+ \+(\d+)\+(\d+)', info_string)
|
||||
if not mo:
|
||||
return None
|
||||
else:
|
||||
info['number'] = int( mo.group(1), 0)
|
||||
info['exe'] = mo.group(3)
|
||||
info['width'] = int( mo.group(4) )
|
||||
info['height'] = int( mo.group(5) )
|
||||
info['x'] = int( mo.group(6) )
|
||||
info['y'] = int( mo.group(7) )
|
||||
info['site'] = get_site_from_exe(c, info['exe'])
|
||||
info['title'] = re.sub('\"', '', mo.group(2))
|
||||
title_bits = re.split(' - ', info['title'])
|
||||
info['name'] = clean_title(title_bits[0])
|
||||
return info
|
||||
|
||||
##############################################################################
|
||||
# NT (= Windows) specific routines
|
||||
def discover_nt(c):
|
||||
""" Poker client table window finder for Windows."""
|
||||
#
|
||||
# I cannot figure out how to get the inside dimensions of the poker table
|
||||
# windows. So I just assume all borders are 3 thick and all title bars
|
||||
# are 29 high. No doubt this will be off when used with certain themes.
|
||||
#
|
||||
b_width = 3
|
||||
tb_height = 29
|
||||
titles = {}
|
||||
tables = {}
|
||||
win32gui.EnumWindows(win_enum_handler, titles)
|
||||
for hwnd in titles:
|
||||
if 'Logged In as' in titles[hwnd] and not 'Lobby' in titles[hwnd]:
|
||||
if 'Full Tilt Poker' in titles[hwnd]:
|
||||
continue
|
||||
tw = Table_Window()
|
||||
tw.number = hwnd
|
||||
(x, y, width, height) = win32gui.GetWindowRect(hwnd)
|
||||
tw.title = titles[hwnd]
|
||||
tw.width = int( width ) - 2*b_width
|
||||
tw.height = int( height ) - b_width - tb_height
|
||||
tw.x = int( x ) + b_width
|
||||
tw.y = int( y ) + tb_height
|
||||
|
||||
# TODO: Isn't the site being determined by the EXE name it belongs to? is this section of code even useful? cleaning it anyway
|
||||
if 'Logged In as' in titles[hwnd]:
|
||||
tw.site = "PokerStars"
|
||||
elif 'Logged In As' in titles[hwnd]:
|
||||
tw.site = "Full Tilt"
|
||||
else:
|
||||
tw.site = "Unknown"
|
||||
sys.stderr.write("Found unknown table = %s" % tw.title)
|
||||
if tw.site != "Unknown":
|
||||
eval("%s(tw)" % c.supported_sites[tw.site].decoder)
|
||||
else:
|
||||
tw.name = "Unknown"
|
||||
tables[len(tables)] = tw
|
||||
return tables
|
||||
|
||||
def discover_nt_by_name(c, tablename):
|
||||
"""Finds poker client window with the given table name."""
|
||||
titles = {}
|
||||
win32gui.EnumWindows(win_enum_handler, titles)
|
||||
|
||||
for hwnd in titles:
|
||||
#print "Tables.py: tablename =", tablename, "title =", titles[hwnd]
|
||||
try:
|
||||
# maybe it's better to make global titles[hwnd] decoding?
|
||||
# this can blow up in XP on some windows, eg firefox displaying http://docs.python.org/tutorial/classes.html
|
||||
if not tablename.lower() in titles[hwnd].decode(Configuration.LOCALE_ENCODING).lower():
|
||||
continue
|
||||
except:
|
||||
continue
|
||||
if 'History for table:' in titles[hwnd]: continue # Everleaf Network HH viewer window
|
||||
if 'HUD:' in titles[hwnd]: continue # FPDB HUD window
|
||||
if 'Chat:' in titles[hwnd]: continue # Some sites (FTP? PS? Others?) have seperable or seperately constructed chat windows
|
||||
if ' - Table ' in titles[hwnd]: continue # Absolute table Chat window.. sigh. TODO: Can we tell what site we're trying to discover for somehow in here, so i can limit this check just to AP searches?
|
||||
temp = decode_windows(c, titles[hwnd], hwnd)
|
||||
print "attach to window", temp
|
||||
return temp
|
||||
return None
|
||||
|
||||
def discover_nt_tournament(c, tour_number, tab_number):
|
||||
"""Finds the Windows window handle for the given tournament/table."""
|
||||
search_string = "%s.+%s" % (tour_number, tab_number)
|
||||
|
||||
titles ={}
|
||||
win32gui.EnumWindows(win_enum_handler, titles)
|
||||
for hwnd in titles:
|
||||
# Some sites (FTP? PS? Others?) have seperable or seperately constructed chat windows
|
||||
if 'Chat:' in titles[hwnd]: continue
|
||||
# Everleaf Network HH viewer window
|
||||
if 'History for table:' in titles[hwnd]: continue
|
||||
# FPDB HUD window
|
||||
if 'HUD:' in titles[hwnd]: continue
|
||||
|
||||
if re.search(search_string, titles[hwnd]):
|
||||
return decode_windows(c, titles[hwnd], hwnd)
|
||||
return None
|
||||
|
||||
def get_nt_exe(hwnd):
|
||||
"""Finds the name of the executable that the given window handle belongs to."""
|
||||
|
||||
# Request privileges to enable "debug process", so we can later use
|
||||
# PROCESS_VM_READ, retardedly required to GetModuleFileNameEx()
|
||||
priv_flags = win32security.TOKEN_ADJUST_PRIVILEGES | win32security.TOKEN_QUERY
|
||||
hToken = win32security.OpenProcessToken (win32api.GetCurrentProcess(),
|
||||
priv_flags)
|
||||
# enable "debug process"
|
||||
privilege_id = win32security.LookupPrivilegeValue(None,
|
||||
win32security.SE_DEBUG_NAME)
|
||||
old_privs = win32security.AdjustTokenPrivileges(hToken, 0,
|
||||
[(privilege_id,
|
||||
win32security.SE_PRIVILEGE_ENABLED)])
|
||||
|
||||
# Open the process, and query it's filename
|
||||
processid = win32process.GetWindowThreadProcessId(hwnd)
|
||||
pshandle = win32api.OpenProcess(win32con.PROCESS_QUERY_INFORMATION |
|
||||
win32con.PROCESS_VM_READ, False,
|
||||
processid[1])
|
||||
try:
|
||||
exename = win32process.GetModuleFileNameEx(pshandle, 0)
|
||||
except pywintypes.error:
|
||||
# insert code to call GetProcessImageName if we can find it..
|
||||
# returning None from here will hopefully break all following code
|
||||
exename = None
|
||||
finally:
|
||||
# clean up
|
||||
win32api.CloseHandle(pshandle)
|
||||
win32api.CloseHandle(hToken)
|
||||
|
||||
return exename
|
||||
|
||||
def decode_windows(c, title, hwnd):
|
||||
"""Gets window parameters from the window title and handle--Windows."""
|
||||
|
||||
# I cannot figure out how to get the inside dimensions of the poker table
|
||||
# windows. So I just assume all borders are 3 thick and all title bars
|
||||
# are 29 high. No doubt this will be off when used with certain themes.
|
||||
b_width = 3
|
||||
tb_height = 29
|
||||
|
||||
info = {}
|
||||
info['number'] = hwnd
|
||||
info['title'] = re.sub('\"', '', title)
|
||||
(x, y, width, height) = win32gui.GetWindowRect(hwnd)
|
||||
|
||||
info['x'] = int(x) + b_width
|
||||
info['y'] = int( y ) + tb_height
|
||||
info['width'] = int( width ) - 2*b_width
|
||||
info['height'] = int( height ) - b_width - tb_height
|
||||
info['exe'] = get_nt_exe(hwnd)
|
||||
print "get_nt_exe returned ", info['exe']
|
||||
# TODO: 'width' here is all sorts of screwed up.
|
||||
|
||||
title_bits = re.split(' - ', info['title'])
|
||||
info['name'] = title_bits[0]
|
||||
info['site'] = get_site_from_exe(c, info['exe'])
|
||||
|
||||
return info
|
||||
|
||||
def win_enum_handler(hwnd, titles):
|
||||
str = win32gui.GetWindowText(hwnd)
|
||||
if str != "":
|
||||
titles[hwnd] = win32gui.GetWindowText(hwnd)
|
||||
|
||||
###################################################################
|
||||
# Utility routines used by all the discoverers.
|
||||
def get_site_from_exe(c, exe):
|
||||
"""Look up the site from config, given the exe."""
|
||||
for s in c.get_supported_sites():
|
||||
params = c.get_site_parameters(s)
|
||||
if re.search(params['table_finder'], exe):
|
||||
return params['site_name']
|
||||
return None
|
||||
|
||||
def everleaf_decode_table(tw):
|
||||
# 2 - Tournament ID: 573256 - NL Hold'em - 150/300 blinds - Good luck <username>! - [Connection is ...]
|
||||
pass
|
||||
|
||||
def pokerstars_decode_table(tw):
|
||||
# Extract poker information from the window title. This is not needed for
|
||||
# fpdb, since all that information is available in the db via new_hand_number.
|
||||
# This is needed only when using the HUD with a backend less integrated.
|
||||
title_bits = re.split(' - ', tw.title)
|
||||
name = title_bits[0]
|
||||
mo = re.search('Tournament (\d+) Table (\d+)', name)
|
||||
if mo:
|
||||
tw.tournament = int( mo.group(1) )
|
||||
tw.table = int( mo.group(2) )
|
||||
tw.name = name
|
||||
else:
|
||||
tw.tournament = None
|
||||
tw.name = clean_title(name)
|
||||
mo = re.search('(Razz|Stud H/L|Stud|Omaha H/L|Omaha|Hold\'em|5-Card Draw|Triple Draw 2-7 Lowball|Badugi)', tw.title)
|
||||
|
||||
tw.game = mo.group(1).lower()
|
||||
tw.game = re.sub('\'', '', tw.game)
|
||||
tw.game = re.sub('h/l', 'hi/lo', tw.game)
|
||||
|
||||
mo = re.search('(No Limit|Pot Limit)', tw.title)
|
||||
if mo:
|
||||
tw.structure = mo.group(1).lower()
|
||||
else:
|
||||
tw.structure = 'limit'
|
||||
|
||||
tw.max = None
|
||||
if tw.game in ('razz', 'stud', 'stud hi/lo'):
|
||||
tw.max = 8
|
||||
elif tw.game in ('5-card draw', 'triple draw 2-7 lowball'):
|
||||
tw.max = 6
|
||||
elif tw.game == 'holdem':
|
||||
pass
|
||||
elif tw.game in ('omaha', 'omaha hi/lo'):
|
||||
pass
|
||||
|
||||
def fulltilt_decode_table(tw):
|
||||
# Extract poker information from the window title. This is not needed for
|
||||
# fpdb, since all that information is available in the db via new_hand_number.
|
||||
# This is needed only when using the HUD with a backend less integrated.
|
||||
title_bits = re.split(' - ', tw.title)
|
||||
name = title_bits[0]
|
||||
tw.tournament = None
|
||||
tw.name = clean_title(name)
|
||||
|
||||
def clean_title(name):
|
||||
"""Clean the little info strings from the table name."""
|
||||
# these strings could go in a config file
|
||||
for pattern in [' \(6 max\)', ' \(heads up\)', ' \(deep\)',
|
||||
' \(deep hu\)', ' \(deep 6\)', '\(6 max, deep\)', ' \(2\)',
|
||||
' \(edu\)', ' \(edu, 6 max\)', ' \(6\)',
|
||||
' \(speed\)', 'special', 'newVPP',
|
||||
' no all-in', ' fast', ',', ' 50BB min', '50bb min', '\s+$']:
|
||||
name = re.sub(pattern, '', name)
|
||||
name = name.rstrip()
|
||||
return name
|
||||
|
||||
###########################################################################
|
||||
# Mac specific routines....all stubs for now
|
||||
def discover_mac_tournament(c, tour_number, tab_number):
|
||||
"""Mac users need help."""
|
||||
return None
|
||||
|
||||
def discover_mac(c):
|
||||
"""Poker client table window finder for Macintosh."""
|
||||
tables = {}
|
||||
return tables
|
||||
|
||||
def discover_mac_by_name(c, tablename):
|
||||
"""Oh, the humanity."""
|
||||
# again, i have no mac to test this on, sorry -eric
|
||||
return None
|
||||
|
||||
###########################################################################
|
||||
# Main function used for testing
|
||||
if __name__=="__main__":
|
||||
c = Configuration.Config()
|
||||
|
||||
print discover_table_by_name(c, "Torino")
|
||||
# print discover_tournament_table(c, "118942908", "3")
|
||||
|
||||
tables = discover(c)
|
||||
for t in tables.keys():
|
||||
print tables[t]
|
||||
|
||||
print "press enter to continue"
|
||||
sys.stdin.readline()
|
||||
|
|
@ -22,19 +22,19 @@ Main program module to test/demo the Tables subclasses.
|
|||
|
||||
########################################################################
|
||||
|
||||
import L10n
|
||||
_ = L10n.get_translation()
|
||||
|
||||
# Standard Library modules
|
||||
import sys
|
||||
import os
|
||||
import re
|
||||
|
||||
# pyGTK modules
|
||||
import pygtk
|
||||
import gtk
|
||||
import gobject
|
||||
|
||||
# fpdb/free poker tools modules
|
||||
import Configuration
|
||||
from HandHistoryConverter import getTableTitleRe
|
||||
|
||||
# get the correct module for the current os
|
||||
if os.name == 'posix':
|
||||
|
|
@ -57,30 +57,37 @@ if __name__=="__main__":
|
|||
self.main_window.connect("destroy", self.client_destroyed)
|
||||
self.label = gtk.Label('Fake Fake Fake Fake\nFake\nFake\nFake')
|
||||
self.main_window.add(self.label)
|
||||
self.main_window.set_title("Fake HUD Main Window")
|
||||
self.main_window.set_title(_("Fake HUD Main Window"))
|
||||
self.main_window.move(table.x + dx, table.y + dy)
|
||||
self.main_window.show_all()
|
||||
table.topify(self)
|
||||
|
||||
# These are the currently defined signals. Do this in the HUD.
|
||||
self.main_window.connect("client_moved", self.client_moved)
|
||||
self.main_window.connect("client_resized", self.client_resized)
|
||||
self.main_window.connect("client_destroyed", self.client_destroyed)
|
||||
self.main_window.connect("game_changed", self.game_changed)
|
||||
self.main_window.connect("table_changed", self.table_changed)
|
||||
|
||||
# And these of the handlers that go with those signals.
|
||||
# These would live inside the HUD code.
|
||||
def client_moved(self, widget, hud):
|
||||
self.main_window.move(self.table.x + self.dx, self.table.y + self.dy)
|
||||
|
||||
def client_resized(self, *args):
|
||||
print "client resized"
|
||||
print "Client resized"
|
||||
|
||||
def client_destroyed(self, *args): # call back for terminating the main eventloop
|
||||
print "Client destroyed."
|
||||
gtk.main_quit()
|
||||
|
||||
def check_on_table(table, hud):
|
||||
result = table.check_geometry()
|
||||
if result != False:
|
||||
hud.main_window.emit(result, hud)
|
||||
return True
|
||||
def game_changed(self, *args):
|
||||
print "Game Changed."
|
||||
|
||||
print "enter table name to find: ",
|
||||
def table_changed(self, *args):
|
||||
print "Table Changed."
|
||||
|
||||
print _("enter table name to find: "),
|
||||
table_name = sys.stdin.readline()
|
||||
if "," in table_name: # tournament
|
||||
print "tournament"
|
||||
|
|
@ -95,16 +102,12 @@ if __name__=="__main__":
|
|||
type = "cash"
|
||||
table_kwargs = dict(table_name = table_name)
|
||||
|
||||
search_string = getTableTitleRe(config, "Full Tilt Poker", type, **table_kwargs)
|
||||
table = Tables.Table(search_string, **table_kwargs)
|
||||
table.gdk_handle = gtk.gdk.window_foreign_new(table.number)
|
||||
|
||||
print "table =", table
|
||||
# print "game =", table.get_game()
|
||||
table = Tables.Table(config, "Full Tilt Poker", **table_kwargs)
|
||||
print table
|
||||
|
||||
fake = fake_hud(table)
|
||||
print "fake =", fake
|
||||
# gobject.timeout_add(100, check_on_table, table, fake)
|
||||
gobject.timeout_add(1000, table.check_game, fake)
|
||||
gobject.timeout_add(100, table.check_table, fake)
|
||||
print "calling main"
|
||||
gtk.main()
|
||||
|
||||
|
|
|
|||
233
pyfpdb/TestHandsPlayers.py
Executable file
233
pyfpdb/TestHandsPlayers.py
Executable file
|
|
@ -0,0 +1,233 @@
|
|||
#!/usr/bin/env python
|
||||
# -*- coding: utf-8 -*-
|
||||
#
|
||||
# Copyright 2010, Carl Gherardi
|
||||
#
|
||||
# This program is free software; you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License as published by
|
||||
# the Free Software Foundation; either version 2 of the License, or
|
||||
# (at your option) any later version.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with this program; if not, write to the Free Software
|
||||
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
########################################################################
|
||||
|
||||
import sys
|
||||
import os
|
||||
import codecs
|
||||
import pprint
|
||||
import PokerStarsToFpdb
|
||||
from Hand import *
|
||||
import Configuration
|
||||
import Database
|
||||
import SQL
|
||||
import fpdb_import
|
||||
|
||||
|
||||
class FpdbError:
|
||||
def __init__(self, sitename):
|
||||
self.site = sitename
|
||||
self.errorcount = 0
|
||||
self.histogram = {}
|
||||
self.statcount = {}
|
||||
|
||||
def error_report(self, filename, hand, stat, ghash, testhash, player):
|
||||
print "Regression Test Error:"
|
||||
print "\tFile: %s" % filename
|
||||
print "\tStat: %s" % stat
|
||||
print "\tPlayer: %s" % player
|
||||
if filename in self.histogram:
|
||||
self.histogram[filename] += 1
|
||||
else:
|
||||
self.histogram[filename] = 1
|
||||
|
||||
if stat in self.statcount:
|
||||
self.statcount[stat] += 1
|
||||
else:
|
||||
self.statcount[stat] = 1
|
||||
self.errorcount += 1
|
||||
|
||||
def print_histogram(self):
|
||||
print "%s:" % self.site
|
||||
for f in self.histogram:
|
||||
idx = f.find('regression')
|
||||
print "(%3d) : %s" %(self.histogram[f], f[idx:])
|
||||
|
||||
def compare(leaf, importer, errors, site):
|
||||
filename = leaf
|
||||
#print "DEBUG: fileanme: %s" % filename
|
||||
|
||||
# Test if this is a hand history file
|
||||
if filename.endswith('.txt'):
|
||||
# test if there is a .hp version of the file
|
||||
importer.addBulkImportImportFileOrDir(filename, site=site)
|
||||
(stored, dups, partial, errs, ttime) = importer.runImport()
|
||||
|
||||
if os.path.isfile(filename + '.hp') and errs < 1:
|
||||
# Compare them
|
||||
hashfilename = filename + '.hp'
|
||||
|
||||
in_fh = codecs.open(hashfilename, 'r', 'utf8')
|
||||
whole_file = in_fh.read()
|
||||
in_fh.close()
|
||||
|
||||
testhash = eval(whole_file)
|
||||
|
||||
hhc = importer.getCachedHHC()
|
||||
handlist = hhc.getProcessedHands()
|
||||
#We _really_ only want to deal with a single hand here.
|
||||
for hand in handlist:
|
||||
ghash = hand.stats.getHandsPlayers()
|
||||
for p in ghash:
|
||||
#print "DEBUG: player: '%s'" % p
|
||||
pstat = ghash[p]
|
||||
teststat = testhash[p]
|
||||
|
||||
for stat in pstat:
|
||||
#print "pstat[%s][%s]: %s == %s" % (p, stat, pstat[stat], teststat[stat])
|
||||
try:
|
||||
if pstat[stat] == teststat[stat]:
|
||||
# The stats match - continue
|
||||
pass
|
||||
else:
|
||||
# Stats don't match - Doh!
|
||||
errors.error_report(filename, hand, stat, ghash, testhash, p)
|
||||
except KeyError, e:
|
||||
errors.error_report(filename, False, "KeyError: '%s'" % stat, False, False, p)
|
||||
if errs > 0:
|
||||
errors.error_report(filename, False, "Parse", False, False, False)
|
||||
|
||||
importer.clearFileList()
|
||||
|
||||
|
||||
|
||||
def walk_testfiles(dir, function, importer, errors, site):
|
||||
"""Walks a directory, and executes a callback on each file """
|
||||
dir = os.path.abspath(dir)
|
||||
for file in [file for file in os.listdir(dir) if not file in [".",".."]]:
|
||||
nfile = os.path.join(dir,file)
|
||||
if os.path.isdir(nfile):
|
||||
walk_testfiles(nfile, compare, importer, errors, site)
|
||||
else:
|
||||
compare(nfile, importer, errors, site)
|
||||
|
||||
def main(argv=None):
|
||||
if argv is None:
|
||||
argv = sys.argv[1:]
|
||||
|
||||
config = Configuration.Config(file = "HUD_config.test.xml")
|
||||
db = Database.Database(config)
|
||||
sql = SQL.Sql(db_server = 'sqlite')
|
||||
settings = {}
|
||||
settings.update(config.get_db_parameters())
|
||||
settings.update(config.get_import_parameters())
|
||||
settings.update(config.get_default_paths())
|
||||
db.recreate_tables()
|
||||
importer = fpdb_import.Importer(False, settings, config, None)
|
||||
importer.setDropIndexes("don't drop")
|
||||
importer.setFailOnError(True)
|
||||
importer.setThreads(-1)
|
||||
importer.setCallHud(False)
|
||||
importer.setFakeCacheHHC(True)
|
||||
|
||||
PokerStarsErrors = FpdbError('PokerStars')
|
||||
FTPErrors = FpdbError('Full Tilt Poker')
|
||||
PartyPokerErrors = FpdbError('Party Poker')
|
||||
BetfairErrors = FpdbError('Betfair')
|
||||
OnGameErrors = FpdbError('OnGame')
|
||||
AbsoluteErrors = FpdbError('Absolute Poker')
|
||||
EverleafErrors = FpdbError('Everleaf Poker')
|
||||
CarbonErrors = FpdbError('Carbon')
|
||||
PKRErrors = FpdbError('PKR')
|
||||
iPokerErrors = FpdbError('iPoker')
|
||||
WinamaxErrors = FpdbError('Winamax')
|
||||
|
||||
ErrorsList = [
|
||||
PokerStarsErrors, FTPErrors, PartyPokerErrors,
|
||||
BetfairErrors, OnGameErrors, AbsoluteErrors,
|
||||
EverleafErrors, CarbonErrors, PKRErrors,
|
||||
iPokerErrors, WinamaxErrors
|
||||
]
|
||||
|
||||
sites = {
|
||||
'PokerStars' : True,
|
||||
'Full Tilt Poker' : True,
|
||||
'PartyPoker' : True,
|
||||
'Betfair' : True,
|
||||
'OnGame' : True,
|
||||
'Absolute' : True,
|
||||
'Everleaf' : True,
|
||||
'Carbon' : True,
|
||||
'PKR' : False,
|
||||
'iPoker' : True,
|
||||
'Winamax' : True,
|
||||
}
|
||||
|
||||
if sites['PokerStars'] == True:
|
||||
walk_testfiles("regression-test-files/cash/Stars/", compare, importer, PokerStarsErrors, "PokerStars")
|
||||
walk_testfiles("regression-test-files/tour/Stars/", compare, importer, PokerStarsErrors, "PokerStars")
|
||||
if sites['Full Tilt Poker'] == True:
|
||||
walk_testfiles("regression-test-files/cash/FTP/", compare, importer, FTPErrors, "Full Tilt Poker")
|
||||
walk_testfiles("regression-test-files/tour/FTP/", compare, importer, FTPErrors, "Full Tilt Poker")
|
||||
if sites['PartyPoker'] == True:
|
||||
walk_testfiles("regression-test-files/cash/PartyPoker/", compare, importer, PartyPokerErrors, "PartyPoker")
|
||||
walk_testfiles("regression-test-files/tour/PartyPoker/", compare, importer, PartyPokerErrors, "PartyPoker")
|
||||
if sites['Betfair'] == True:
|
||||
walk_testfiles("regression-test-files/cash/Betfair/", compare, importer, BetfairErrors, "Betfair")
|
||||
if sites['OnGame'] == True:
|
||||
walk_testfiles("regression-test-files/cash/OnGame/", compare, importer, OnGameErrors, "OnGame")
|
||||
if sites['Absolute'] == True:
|
||||
walk_testfiles("regression-test-files/cash/Absolute/", compare, importer, AbsoluteErrors, "Absolute")
|
||||
if sites['Everleaf'] == True:
|
||||
walk_testfiles("regression-test-files/cash/Everleaf/", compare, importer, EverleafErrors, "Everleaf")
|
||||
if sites['Carbon'] == True:
|
||||
walk_testfiles("regression-test-files/cash/Carbon/", compare, importer, CarbonErrors, "Carbon")
|
||||
if sites['PKR'] == True:
|
||||
walk_testfiles("regression-test-files/cash/PKR/", compare, importer, PKRErrors, "PKR")
|
||||
if sites['iPoker'] == True:
|
||||
walk_testfiles("regression-test-files/cash/iPoker/", compare, importer, iPokerErrors, "iPoker")
|
||||
if sites['Winamax'] == True:
|
||||
walk_testfiles("regression-test-files/cash/Winamax/", compare, importer, WinamaxErrors, "Winamax")
|
||||
|
||||
totalerrors = 0
|
||||
|
||||
for i, site in enumerate(ErrorsList):
|
||||
totalerrors += ErrorsList[i].errorcount
|
||||
|
||||
print "---------------------"
|
||||
print "Total Errors: %d" % totalerrors
|
||||
print "---------------------"
|
||||
for i, site in enumerate(ErrorsList):
|
||||
ErrorsList[i].print_histogram()
|
||||
|
||||
# Merge the dicts of stats from the various error objects
|
||||
statdict = {}
|
||||
for i, site in enumerate(ErrorsList):
|
||||
tmp = ErrorsList[i].statcount
|
||||
for stat in tmp:
|
||||
if stat in statdict:
|
||||
statdict[stat] += tmp[stat]
|
||||
else:
|
||||
statdict[stat] = tmp[stat]
|
||||
|
||||
print "\n"
|
||||
print "---------------------"
|
||||
print "Errors by stat:"
|
||||
print "---------------------"
|
||||
#for stat in statdict:
|
||||
# print "(%3d) : %s" %(statdict[stat], stat)
|
||||
|
||||
sortedstats = sorted([(value,key) for (key,value) in statdict.items()])
|
||||
for num, stat in sortedstats:
|
||||
print "(%3d) : %s" %(num, stat)
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
sys.exit(main())
|
||||
|
||||
|
|
@ -21,6 +21,9 @@
|
|||
|
||||
########################################################################
|
||||
|
||||
import L10n
|
||||
_ = L10n.get_translation()
|
||||
|
||||
# to do allow window resizing
|
||||
# to do hud to echo, but ignore non numbers
|
||||
# to do no stat window for hero
|
||||
|
|
@ -35,7 +38,7 @@ import traceback
|
|||
(options, argv) = Options.fpdb_options()
|
||||
|
||||
if not options.errorsToConsole:
|
||||
print "Note: error output is being diverted to fpdb-error-log.txt and HUD-error.txt. Any major error will be reported there _only_."
|
||||
print _("Note: error output is being diverted to fpdb-error-log.txt and HUD-error.txt. Any major error will be reported there _only_.")
|
||||
errorFile = open('tourneyerror.txt', 'w', 0)
|
||||
sys.stderr = errorFile
|
||||
|
||||
|
|
@ -96,10 +99,10 @@ class Tournament:
|
|||
self.window.show() # isn't there a better way to bring something to the front? not that GTK focus works right anyway, ever
|
||||
else:
|
||||
self.window = gtk.Window(gtk.WINDOW_TOPLEVEL)
|
||||
print "tournament edit window=", self.window
|
||||
print _("tournament edit window="), self.window
|
||||
self.window.connect("delete_event", self.delete_event)
|
||||
self.window.connect("destroy", self.destroy)
|
||||
self.window.set_title("FPDB Tournament Entry")
|
||||
self.window.set_title(_("FPDB Tournament Entry"))
|
||||
self.window.set_border_width(1)
|
||||
self.window.set_default_size(480,640)
|
||||
self.window.set_resizable(True)
|
||||
|
|
@ -139,14 +142,14 @@ class ttracker_main(object):
|
|||
self.main_window = gtk.Window()
|
||||
self.main_window.connect("destroy", self.destroy)
|
||||
self.vb = gtk.VBox()
|
||||
self.label = gtk.Label('Closing this window will stop the Tournament Tracker')
|
||||
self.label = gtk.Label(_('Closing this window will stop the Tournament Tracker'))
|
||||
self.vb.add(self.label)
|
||||
self.addbutton = gtk.Button(label="Enter Tournament")
|
||||
self.addbutton = gtk.Button(label=_("Enter Tournament"))
|
||||
self.addbutton.connect("clicked", self.addClicked, "add tournament")
|
||||
self.vb.add(self.addbutton)
|
||||
|
||||
self.main_window.add(self.vb)
|
||||
self.main_window.set_title("FPDB Tournament Tracker")
|
||||
self.main_window.set_title(_("FPDB Tournament Tracker"))
|
||||
self.main_window.show_all()
|
||||
|
||||
def addClicked(self, widget, data): # what is "data"? i'm guessing anything i pass in after the function name in connect() but unsure because the documentation sucks
|
||||
|
|
@ -157,10 +160,10 @@ class ttracker_main(object):
|
|||
self.tourney_list.append(t)
|
||||
mylabel = gtk.Label("%s - %s - %s - %s - %s %s - %s - %s - %s - %s - %s" % (t.site, t.id, t.starttime, t.endtime, t.structure, t.game, t.buyin, t.fee, t.numrebuys, t.numplayers, t.prizepool))
|
||||
print "new label=", mylabel
|
||||
editbutton = gtk.Button(label="Edit")
|
||||
editbutton = gtk.Button(label=_("Edit"))
|
||||
print "new button=", editbutton
|
||||
editbutton.connect("clicked", t.openwindow)
|
||||
rebuybutton = gtk.Button(label="Rebuy")
|
||||
rebuybutton = gtk.Button(label=_("Rebuy"))
|
||||
rebuybutton.connect("clicked", t.addrebuy)
|
||||
self.vb.add(rebuybutton)
|
||||
self.vb.add(editbutton) # These should probably be put in.. a.. h-box? i don't know..
|
||||
|
|
@ -259,9 +262,9 @@ class ttracker_main(object):
|
|||
cards['common'] = comm_cards['common']
|
||||
except Exception, err:
|
||||
err = traceback.extract_tb(sys.exc_info()[2])[-1]
|
||||
print "db error: skipping "+str(new_hand_id)+" "+err[2]+"("+str(err[1])+"): "+str(sys.exc_info()[1])
|
||||
print _("db error: skipping ")+str(new_hand_id)+" "+err[2]+"("+str(err[1])+"): "+str(sys.exc_info()[1])
|
||||
if new_hand_id: # new_hand_id is none if we had an error prior to the store
|
||||
sys.stderr.write("Database error %s in hand %d. Skipping.\n" % (err, int(new_hand_id)))
|
||||
sys.stderr.write(_("Database error %s in hand %d. Skipping.\n") % (err, int(new_hand_id)))
|
||||
continue
|
||||
|
||||
if type == "tour": # hand is from a tournament
|
||||
|
|
@ -270,8 +273,8 @@ class ttracker_main(object):
|
|||
(tour_number, tab_number) = mat_obj.group(1, 2)
|
||||
temp_key = tour_number
|
||||
else: # tourney, but can't get number and table
|
||||
print "could not find tournament: skipping "
|
||||
sys.stderr.write("Could not find tournament %d in hand %d. Skipping.\n" % (int(tour_number), int(new_hand_id)))
|
||||
print _("could not find tournament: skipping")
|
||||
sys.stderr.write(_("Could not find tournament %d in hand %d. Skipping.\n") % (int(tour_number), int(new_hand_id)))
|
||||
continue
|
||||
|
||||
else:
|
||||
|
|
@ -294,15 +297,15 @@ class ttracker_main(object):
|
|||
# If no client window is found on the screen, complain and continue
|
||||
if type == "tour":
|
||||
table_name = "%s %s" % (tour_number, tab_number)
|
||||
sys.stderr.write("table name "+table_name+" not found, skipping.\n")
|
||||
sys.stderr.write(_("table name %s not found, skipping.\n")% table_name)
|
||||
else:
|
||||
self.create_HUD(new_hand_id, tablewindow, temp_key, max, poker_game, stat_dict, cards)
|
||||
self.db_connection.connection.rollback()
|
||||
|
||||
if __name__== "__main__":
|
||||
|
||||
sys.stderr.write("tournament tracker starting\n")
|
||||
sys.stderr.write("Using db name = %s\n" % (options.dbname))
|
||||
sys.stderr.write(_("tournament tracker starting\n"))
|
||||
sys.stderr.write(_("Using db name = %s\n") % (options.dbname))
|
||||
|
||||
# start the HUD_main object
|
||||
hm = ttracker_main(db_name = options.dbname)
|
||||
|
|
|
|||
|
|
@ -15,6 +15,9 @@
|
|||
#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 L10n
|
||||
_ = L10n.get_translation()
|
||||
|
||||
import threading
|
||||
import pygtk
|
||||
pygtk.require('2.0')
|
||||
|
|
@ -29,7 +32,6 @@ from time import gmtime, mktime, strftime, strptime
|
|||
import logging #logging has been set up in fpdb.py or HUD_main.py, use their settings:
|
||||
log = logging.getLogger("filter")
|
||||
|
||||
|
||||
#import Configuration
|
||||
#import Database
|
||||
#import SQL
|
||||
|
|
@ -45,9 +47,9 @@ class TourneyFilters(Filters.Filters):
|
|||
self.conf = db.config
|
||||
self.display = display
|
||||
|
||||
self.filterText = {'playerstitle':'Hero:', 'sitestitle':'Sites:', 'seatstitle':'Number of Players:',
|
||||
'seatsbetween':'Between:', 'seatsand':'And:', 'datestitle':'Date:',
|
||||
'tourneyTypesTitle':'Tourney Type'}
|
||||
self.filterText = {'playerstitle':_('Hero:'), 'sitestitle':_('Sites:'), 'seatstitle':_('Number of Players:'),
|
||||
'seatsbetween':_('Between:'), 'seatsand':_('And:'), 'datestitle':_('Date:'),
|
||||
'tourneyTypesTitle':_('Tourney Type')}
|
||||
|
||||
gen = self.conf.get_general_params()
|
||||
self.day_start = 0
|
||||
|
|
@ -74,7 +76,7 @@ class TourneyFilters(Filters.Filters):
|
|||
self.numTourneys = int(w.get_text())
|
||||
except:
|
||||
self.numTourneys = 0
|
||||
print "setting numTourneys:", self.numTourneys
|
||||
print _("setting numTourneys:"), self.numTourneys
|
||||
#end def __set_num_tourneys
|
||||
|
||||
def __toggle_box(self, widget, entry): #identical with Filters
|
||||
|
|
@ -102,7 +104,7 @@ class TourneyFilters(Filters.Filters):
|
|||
if len(result) == 1:
|
||||
self.siteid[site] = result[0][0]
|
||||
else:
|
||||
print "Either 0 or more than one site matched (%s) - EEK" % site
|
||||
print _("Either 0 or more than one site matched (%s) - EEK") % site
|
||||
|
||||
# For use in date ranges.
|
||||
self.start_date = gtk.Entry(max=12)
|
||||
|
|
|
|||
|
|
@ -17,6 +17,9 @@
|
|||
|
||||
"""parses and stores summary sections from e.g. eMail or summary files"""
|
||||
|
||||
import L10n
|
||||
_ = L10n.get_translation()
|
||||
|
||||
# TODO: check to keep only the needed modules
|
||||
|
||||
import re
|
||||
|
|
@ -30,6 +33,7 @@ import operator
|
|||
import time,datetime
|
||||
from copy import deepcopy
|
||||
from Exceptions import *
|
||||
|
||||
import pprint
|
||||
import DerivedStats
|
||||
import Card
|
||||
|
|
@ -61,10 +65,10 @@ class TourneySummary(object):
|
|||
self.endTime = None
|
||||
self.tourNo = None
|
||||
self.currency = None
|
||||
self.buyin = None
|
||||
self.fee = None
|
||||
self.buyin = 0
|
||||
self.fee = 0
|
||||
self.hero = None
|
||||
self.maxseats = None
|
||||
self.maxseats = 0
|
||||
self.entries = 0
|
||||
self.speed = "Normal"
|
||||
self.prizepool = 0 # Make it a dict in order to deal (eventually later) with non-money winnings : {'MONEY' : amount, 'OTHER' : Value ??}
|
||||
|
|
@ -112,65 +116,68 @@ class TourneySummary(object):
|
|||
self.sym = None
|
||||
|
||||
if builtFrom=="IMAP":
|
||||
self.parseSummary()
|
||||
self.insertOrUpdate()
|
||||
# Fix line endings?
|
||||
pass
|
||||
|
||||
self.parseSummary()
|
||||
self.insertOrUpdate()
|
||||
#end def __init__
|
||||
|
||||
def __str__(self):
|
||||
#TODO : Update
|
||||
vars = ( ("SITE", self.siteName),
|
||||
("START TIME", self.startTime),
|
||||
("END TIME", self.endTime),
|
||||
("TOURNEY NAME", self.tourneyName),
|
||||
("TOURNEY NO", self.tourNo),
|
||||
("TOURNEY TYPE ID", self.tourneyTypeId),
|
||||
("TOURNEY ID", self.tourneyId),
|
||||
("BUYIN", self.buyin),
|
||||
("FEE", self.fee),
|
||||
("CURRENCY", self.currency),
|
||||
("HERO", self.hero),
|
||||
("MAXSEATS", self.maxseats),
|
||||
("ENTRIES", self.entries),
|
||||
("SPEED", self.speed),
|
||||
("PRIZE POOL", self.prizepool),
|
||||
("STARTING CHIP COUNT", self.buyInChips),
|
||||
("MIXED", self.mixed),
|
||||
("REBUY", self.isRebuy),
|
||||
("ADDON", self.isAddOn),
|
||||
("KO", self.isKO),
|
||||
("MATRIX", self.isMatrix),
|
||||
("MATRIX ID PROCESSED", self.matrixIdProcessed),
|
||||
("SHOOTOUT", self.isShootout),
|
||||
("MATRIX MATCH ID", self.matrixMatchId),
|
||||
("SUB TOURNEY BUY IN", self.subTourneyBuyin),
|
||||
("SUB TOURNEY FEE", self.subTourneyFee),
|
||||
("REBUY CHIPS", self.rebuyChips),
|
||||
("ADDON CHIPS", self.addOnChips),
|
||||
("REBUY COST", self.rebuyCost),
|
||||
("ADDON COST", self.addOnCost),
|
||||
("TOTAL REBUYS", self.totalRebuyCount),
|
||||
("TOTAL ADDONS", self.totalAddOnCount),
|
||||
("KO BOUNTY", self.koBounty),
|
||||
("TOURNEY COMMENT", self.tourneyComment),
|
||||
("SNG", self.isSng),
|
||||
("SATELLITE", self.isSatellite),
|
||||
("DOUBLE OR NOTHING", self.isDoubleOrNothing),
|
||||
("GUARANTEE", self.guarantee),
|
||||
("ADDED", self.added),
|
||||
("ADDED CURRENCY", self.addedCurrency),
|
||||
("COMMENT", self.comment),
|
||||
("COMMENT TIMESTAMP", self.commentTs)
|
||||
vars = ( (_("SITE"), self.siteName),
|
||||
(_("START TIME"), self.startTime),
|
||||
(_("END TIME"), self.endTime),
|
||||
(_("TOURNEY NAME"), self.tourneyName),
|
||||
(_("TOURNEY NO"), self.tourNo),
|
||||
(_("TOURNEY TYPE ID"), self.tourneyTypeId),
|
||||
(_("TOURNEY ID"), self.tourneyId),
|
||||
(_("BUYIN"), self.buyin),
|
||||
(_("FEE"), self.fee),
|
||||
(_("CURRENCY"), self.currency),
|
||||
(_("HERO"), self.hero),
|
||||
(_("MAXSEATS"), self.maxseats),
|
||||
(_("ENTRIES"), self.entries),
|
||||
(_("SPEED"), self.speed),
|
||||
(_("PRIZE POOL"), self.prizepool),
|
||||
(_("STARTING CHIP COUNT"), self.buyInChips),
|
||||
(_("MIXED"), self.mixed),
|
||||
(_("REBUY"), self.isRebuy),
|
||||
(_("ADDON"), self.isAddOn),
|
||||
(_("KO"), self.isKO),
|
||||
(_("MATRIX"), self.isMatrix),
|
||||
(_("MATRIX ID PROCESSED"), self.matrixIdProcessed),
|
||||
(_("SHOOTOUT"), self.isShootout),
|
||||
(_("MATRIX MATCH ID"), self.matrixMatchId),
|
||||
(_("SUB TOURNEY BUY IN"), self.subTourneyBuyin),
|
||||
(_("SUB TOURNEY FEE"), self.subTourneyFee),
|
||||
(_("REBUY CHIPS"), self.rebuyChips),
|
||||
(_("ADDON CHIPS"), self.addOnChips),
|
||||
(_("REBUY COST"), self.rebuyCost),
|
||||
(_("ADDON COST"), self.addOnCost),
|
||||
(_("TOTAL REBUYS"), self.totalRebuyCount),
|
||||
(_("TOTAL ADDONS"), self.totalAddOnCount),
|
||||
(_("KO BOUNTY"), self.koBounty),
|
||||
(_("TOURNEY COMMENT"), self.tourneyComment),
|
||||
(_("SNG"), self.isSng),
|
||||
(_("SATELLITE"), self.isSatellite),
|
||||
(_("DOUBLE OR NOTHING"), self.isDoubleOrNothing),
|
||||
(_("GUARANTEE"), self.guarantee),
|
||||
(_("ADDED"), self.added),
|
||||
(_("ADDED CURRENCY"), self.addedCurrency),
|
||||
(_("COMMENT"), self.comment),
|
||||
(_("COMMENT TIMESTAMP"), self.commentTs)
|
||||
)
|
||||
|
||||
structs = ( ("PLAYER IDS", self.playerIds),
|
||||
("PLAYERS", self.players),
|
||||
("TOURNEYS PLAYERS IDS", self.tourneysPlayersIds),
|
||||
("RANKS", self.ranks),
|
||||
("WINNINGS", self.winnings),
|
||||
("WINNINGS CURRENCY", self.winningsCurrency),
|
||||
("COUNT REBUYS", self.rebuyCounts),
|
||||
("COUNT ADDONS", self.addOnCounts),
|
||||
("NB OF KO", self.koCounts)
|
||||
structs = ( (_("PLAYER IDS"), self.playerIds),
|
||||
(_("PLAYERS"), self.players),
|
||||
(_("TOURNEYS PLAYERS IDS"), self.tourneysPlayersIds),
|
||||
(_("RANKS"), self.ranks),
|
||||
(_("WINNINGS"), self.winnings),
|
||||
(_("WINNINGS CURRENCY"), self.winningsCurrency),
|
||||
(_("COUNT REBUYS"), self.rebuyCounts),
|
||||
(_("COUNT ADDONS"), self.addOnCounts),
|
||||
(_("NB OF KO"), self.koCounts)
|
||||
)
|
||||
str = ''
|
||||
for (name, var) in vars:
|
||||
|
|
@ -217,7 +224,7 @@ class TourneySummary(object):
|
|||
self.tourneysPlayersIds = self.db.createOrUpdateTourneysPlayers(self, "TS")
|
||||
self.db.commit()
|
||||
|
||||
logging.debug("Tourney Insert/Update done")
|
||||
logging.debug(_("Tourney Insert/Update done"))
|
||||
|
||||
# TO DO : Return what has been done (tourney created, updated, nothing)
|
||||
# ?? stored = 1 if tourney is fully created / duplicates = 1, if everything was already here and correct / partial=1 if some things were already here (between tourney, tourneysPlayers and handsPlayers)
|
||||
|
|
@ -237,7 +244,7 @@ rank (int) indicating the finishing rank (can be -1 if unknown)
|
|||
name (string) player name
|
||||
winnings (decimal) the money the player ended the tourney with (can be 0, or -1 if unknown)
|
||||
"""
|
||||
log.debug("addPlayer: rank:%s - name : '%s' - Winnings (%s)" % (rank, name, winnings))
|
||||
log.debug(_("addPlayer: rank:%s - name : '%s' - Winnings (%s)") % (rank, name, winnings))
|
||||
self.players.append(name)
|
||||
if rank:
|
||||
self.ranks.update( { name : Decimal(rank) } )
|
||||
|
|
@ -264,7 +271,7 @@ winnings (decimal) the money the player ended the tourney with (can be 0, or
|
|||
#end def addPlayer
|
||||
|
||||
def incrementPlayerWinnings(self, name, additionnalWinnings):
|
||||
log.debug("incrementPlayerWinnings: name : '%s' - Add Winnings (%s)" % (name, additionnalWinnings))
|
||||
log.debug(_("incrementPlayerWinnings: name : '%s' - Add Winnings (%s)") % (name, additionnalWinnings))
|
||||
oldWins = 0
|
||||
if self.winnings.has_key(name):
|
||||
oldWins = self.winnings[name]
|
||||
|
|
|
|||
424
pyfpdb/TreeViewTooltips.py
Normal file
424
pyfpdb/TreeViewTooltips.py
Normal file
|
|
@ -0,0 +1,424 @@
|
|||
# Copyright (c) 2006, Daniel J. Popowich
|
||||
#
|
||||
# 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.
|
||||
#
|
||||
# Send bug reports and contributions to:
|
||||
#
|
||||
# dpopowich AT astro dot umass dot edu
|
||||
#
|
||||
# This version of the file is part of fpdb, contact: fpdb-main@lists.sourceforge.net
|
||||
|
||||
'''
|
||||
TreeViewTooltips.py
|
||||
|
||||
Provides TreeViewTooltips, a class which presents tooltips for cells,
|
||||
columns and rows in a gtk.TreeView.
|
||||
|
||||
------------------------------------------------------------
|
||||
This file includes a demo. Just execute the file:
|
||||
|
||||
python TreeViewTooltips.py
|
||||
------------------------------------------------------------
|
||||
|
||||
To use, first subclass TreeViewTooltips and implement the get_tooltip()
|
||||
method; see below. Then add any number of gtk.TreeVew widgets to a
|
||||
TreeViewTooltips instance by calling the add_view() method. Overview
|
||||
of the steps:
|
||||
|
||||
# 1. subclass TreeViewTooltips
|
||||
class MyTooltips(TreeViewTooltips):
|
||||
|
||||
# 2. overriding get_tooltip()
|
||||
def get_tooltip(...):
|
||||
...
|
||||
|
||||
# 3. create an instance
|
||||
mytips = MyTooltips()
|
||||
|
||||
# 4. Build up your gtk.TreeView.
|
||||
myview = gtk.TreeView()
|
||||
...# create columns, set the model, etc.
|
||||
|
||||
# 5. Add the view to the tooltips
|
||||
mytips.add_view(myview)
|
||||
|
||||
How it works: the add_view() method connects the TreeView to the
|
||||
"motion-notify" event with the callback set to a private method.
|
||||
Whenever the mouse moves across the TreeView the callback will call
|
||||
get_tooltip() with the following arguments:
|
||||
|
||||
get_tooltip(view, column, path)
|
||||
|
||||
where,
|
||||
|
||||
view: the gtk.TreeView instance.
|
||||
column: the gtk.TreeViewColumn instance that the mouse is
|
||||
currently over.
|
||||
path: the path to the row that the mouse is currently over.
|
||||
|
||||
Based on whether or not column and path are checked for specific
|
||||
values, get_tooltip can return tooltips for a cell, column, row or the
|
||||
whole view:
|
||||
|
||||
Column Checked Path Checked Tooltip For...
|
||||
Y Y cell
|
||||
Y N column
|
||||
N Y row
|
||||
N N view
|
||||
|
||||
get_tooltip() should return None if no tooltip should be displayed.
|
||||
Otherwise the return value will be coerced to a string (with the str()
|
||||
builtin) and stripped; if non-empty, the result will be displayed as
|
||||
the tooltip. By default, the tooltip popup window will be displayed
|
||||
centered and just below the pointer and will remain shown until the
|
||||
pointer leaves the cell (or column, or row, or view, depending on how
|
||||
get_tooltip() is implemented).
|
||||
|
||||
'''
|
||||
|
||||
|
||||
import pygtk
|
||||
pygtk.require('2.0')
|
||||
|
||||
import gtk
|
||||
import gtk.gdk
|
||||
import gobject
|
||||
|
||||
if gtk.gtk_version < (2, 8):
|
||||
import warnings
|
||||
|
||||
msg = (_('''This module was developed and tested with version 2.8.18 of gtk. You are using version %d.%d.%d. Your milage may vary.''')
|
||||
% gtk.gtk_version)
|
||||
warnings.warn(msg)
|
||||
|
||||
|
||||
# major, minor, patch
|
||||
version = 1, 0, 0
|
||||
|
||||
class TreeViewTooltips:
|
||||
|
||||
def __init__(self):
|
||||
|
||||
'''
|
||||
Initialize the tooltip. After initialization there are two
|
||||
attributes available for advanced control:
|
||||
|
||||
window: the popup window that holds the tooltip text, an
|
||||
instance of gtk.Window.
|
||||
label: a gtk.Label that is packed into the window. The
|
||||
tooltip text is set in the label with the
|
||||
set_label() method, so the text can be plain or
|
||||
markup text.
|
||||
|
||||
Be default, the tooltip is enabled. See the enabled/disabled
|
||||
methods.
|
||||
'''
|
||||
|
||||
# create the window
|
||||
self.window = window = gtk.Window(gtk.WINDOW_POPUP)
|
||||
window.set_name('gtk-tooltips')
|
||||
window.set_resizable(False)
|
||||
window.set_border_width(4)
|
||||
window.set_app_paintable(True)
|
||||
window.connect("expose-event", self.__on_expose_event)
|
||||
|
||||
|
||||
# create the label
|
||||
self.label = label = gtk.Label()
|
||||
label.set_line_wrap(True)
|
||||
label.set_alignment(0.5, 0.5)
|
||||
label.set_use_markup(True)
|
||||
label.show()
|
||||
window.add(label)
|
||||
|
||||
# by default, the tooltip is enabled
|
||||
self.__enabled = True
|
||||
# saves the current cell
|
||||
self.__save = None
|
||||
# the timer id for the next tooltip to be shown
|
||||
self.__next = None
|
||||
# flag on whether the tooltip window is shown
|
||||
self.__shown = False
|
||||
|
||||
def enable(self):
|
||||
'Enable the tooltip'
|
||||
|
||||
self.__enabled = True
|
||||
|
||||
def disable(self):
|
||||
'Disable the tooltip'
|
||||
|
||||
self.__enabled = False
|
||||
|
||||
def __show(self, tooltip, x, y):
|
||||
|
||||
'''show the tooltip popup with the text/markup given by
|
||||
tooltip.
|
||||
|
||||
tooltip: the text/markup for the tooltip.
|
||||
x, y: the coord. (root window based) of the pointer.
|
||||
'''
|
||||
|
||||
window = self.window
|
||||
|
||||
# set label
|
||||
self.label.set_label(tooltip)
|
||||
# resize window
|
||||
w, h = window.size_request()
|
||||
# move the window
|
||||
window.move(*self.location(x,y,w,h))
|
||||
# show it
|
||||
window.show()
|
||||
self.__shown = True
|
||||
|
||||
def __hide(self):
|
||||
'hide the tooltip'
|
||||
|
||||
self.__queue_next()
|
||||
self.window.hide()
|
||||
self.__shown = False
|
||||
|
||||
def __leave_handler(self, view, event):
|
||||
'when the pointer leaves the view, hide the tooltip'
|
||||
|
||||
self.__hide()
|
||||
|
||||
def __motion_handler(self, view, event):
|
||||
'As the pointer moves across the view, show a tooltip.'
|
||||
|
||||
path = view.get_path_at_pos(int(event.x), int(event.y))
|
||||
|
||||
if self.__enabled and path:
|
||||
path, col, x, y = path
|
||||
tooltip = self.get_tooltip(view, col, path)
|
||||
if tooltip is not None:
|
||||
tooltip = str(tooltip).strip()
|
||||
if tooltip:
|
||||
self.__queue_next((path, col), tooltip,
|
||||
int(event.x_root),
|
||||
int(event.y_root))
|
||||
return
|
||||
|
||||
self.__hide()
|
||||
|
||||
def __queue_next(self, *args):
|
||||
|
||||
'queue next request to show a tooltip'
|
||||
|
||||
# if args is non-empty it means a request was made to show a
|
||||
# tooltip. if empty, no request is being made, but any
|
||||
# pending requests should be cancelled anyway.
|
||||
|
||||
cell = None
|
||||
|
||||
# if called with args, break them out
|
||||
if args:
|
||||
cell, tooltip, x, y = args
|
||||
|
||||
# if it's the same cell as previously shown, just return
|
||||
if self.__save == cell:
|
||||
return
|
||||
|
||||
# if we have something queued up, cancel it
|
||||
if self.__next:
|
||||
gobject.source_remove(self.__next)
|
||||
self.__next = None
|
||||
|
||||
# if there was a request...
|
||||
if cell:
|
||||
# if the tooltip is already shown, show the new one
|
||||
# immediately
|
||||
if self.__shown:
|
||||
self.__show(tooltip, x, y)
|
||||
# else queue it up in 1/2 second
|
||||
else:
|
||||
self.__next = gobject.timeout_add(500, self.__show,
|
||||
tooltip, x, y)
|
||||
|
||||
# save this cell
|
||||
self.__save = cell
|
||||
|
||||
|
||||
def __on_expose_event(self, window, event):
|
||||
|
||||
# this magic is required so the window appears with a 1-pixel
|
||||
# black border (default gtk Style). This code is a
|
||||
# transliteration of the C implementation of gtk.Tooltips.
|
||||
w, h = window.size_request()
|
||||
window.style.paint_flat_box(window.window, gtk.STATE_NORMAL,
|
||||
gtk.SHADOW_OUT, None, window,
|
||||
'tooltip', 0, 0, w, h)
|
||||
|
||||
def location(self, x, y, w, h):
|
||||
|
||||
'''Given the x,y coordinates of the pointer and the width and
|
||||
height (w,h) demensions of the tooltip window, return the x, y
|
||||
coordinates of the tooltip window.
|
||||
|
||||
The default location is to center the window on the pointer
|
||||
and 4 pixels below it.
|
||||
'''
|
||||
|
||||
return x - w/2, y + 4
|
||||
|
||||
def add_view(self, view):
|
||||
|
||||
'add a gtk.TreeView to the tooltip'
|
||||
|
||||
assert isinstance(view, gtk.TreeView), \
|
||||
('This handler should only be connected to '
|
||||
'instances of gtk.TreeView')
|
||||
|
||||
view.connect("motion-notify-event", self.__motion_handler)
|
||||
view.connect("leave-notify-event", self.__leave_handler)
|
||||
|
||||
def get_tooltip(self, view, column, path):
|
||||
'See the module doc string for a description of this method'
|
||||
|
||||
raise NotImplemented, 'Subclass must implement get_tooltip()'
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
|
||||
############################################################
|
||||
# DEMO
|
||||
############################################################
|
||||
|
||||
# First, subclass TreeViewTooltips
|
||||
|
||||
class DemoTips(TreeViewTooltips):
|
||||
|
||||
def __init__(self, customer_column):
|
||||
# customer_column is an instance of gtk.TreeViewColumn and
|
||||
# is being used in the gtk.TreeView to show customer names.
|
||||
self.cust_col = customer_column
|
||||
|
||||
# call base class init
|
||||
TreeViewTooltips.__init__(self)
|
||||
|
||||
def get_tooltip(self, view, column, path):
|
||||
|
||||
# we have a two column view: customer, phone; we'll make
|
||||
# tooltips cell-based for the customer column, but generic
|
||||
# column-based for the phone column.
|
||||
|
||||
# customer
|
||||
if column is self.cust_col:
|
||||
|
||||
# By checking both column and path we have a
|
||||
# cell-based tooltip.
|
||||
model = view.get_model()
|
||||
customer = model[path][2]
|
||||
return '<big>%s %s</big>\n<i>%s</i>' % (customer.fname,
|
||||
customer.lname,
|
||||
customer.notes)
|
||||
# phone
|
||||
else:
|
||||
return ('<big><u>Generic Column Tooltip</u></big>\n'
|
||||
'Unless otherwise noted, all\narea codes are 888')
|
||||
|
||||
def XX_location(self, x, y, w, h):
|
||||
# rename me to "location" so I override the base class
|
||||
# method. This will demonstrate being able to change
|
||||
# where the tooltip window popups, relative to the
|
||||
# pointer.
|
||||
|
||||
# this will place the tooltip above and to the right
|
||||
return x + 10, y - (h + 10)
|
||||
|
||||
# Here's our customer
|
||||
class Customer:
|
||||
|
||||
def __init__(self, fname, lname, phone, notes):
|
||||
self.fname = fname
|
||||
self.lname = lname
|
||||
self.phone = phone
|
||||
self.notes = notes
|
||||
|
||||
# create a bunch of customers
|
||||
customers = []
|
||||
for fname, lname, phone, notes in [
|
||||
('Joe', 'Schmoe', '555-1212', 'Likes to Morris dance.'),
|
||||
('Jane', 'Doe', '555-2323',
|
||||
'Wonders what the hell\nMorris dancing is.'),
|
||||
('Phred', 'Phantastic', '900-555-1212', 'Dreams of Betty.'),
|
||||
('Betty', 'Boop', '555-3434', 'Dreams in b&w.'),
|
||||
('Red Sox', 'Fan', '555-4545',
|
||||
"Still livin' 2004!\nEspecially after 2006.")]:
|
||||
customers.append(Customer(fname, lname, phone, notes))
|
||||
|
||||
# Build our model and view
|
||||
model = gtk.ListStore(str, str, object)
|
||||
for c in customers:
|
||||
model.append(['%s %s' % (c.fname, c.lname), c.phone, c])
|
||||
|
||||
view = gtk.TreeView(model)
|
||||
view.get_selection().set_mode(gtk.SELECTION_NONE)
|
||||
|
||||
# two columns, name and phone
|
||||
cell = gtk.CellRendererText()
|
||||
cell.set_property('xpad', 20)
|
||||
namecol = gtk.TreeViewColumn('Customer Name', cell, text=0)
|
||||
namecol.set_min_width(200)
|
||||
view.append_column(namecol)
|
||||
|
||||
cell = gtk.CellRendererText()
|
||||
phonecol = gtk.TreeViewColumn('Phone', cell, text=1)
|
||||
view.append_column(phonecol)
|
||||
|
||||
# finally, connect the tooltip, specifying the name column as the
|
||||
# column we want the tooltip to popup over.
|
||||
tips = DemoTips(namecol)
|
||||
tips.add_view(view)
|
||||
|
||||
# We're going to demonstrate enable/disable. First we need a
|
||||
# callback function to connect to the toggled signal.
|
||||
def toggle(button):
|
||||
if button.get_active():
|
||||
tips.disable()
|
||||
else:
|
||||
tips.enable()
|
||||
|
||||
# create a checkbutton and connect our handler
|
||||
check = gtk.CheckButton('Check to disable view tooltips')
|
||||
check.connect('toggled', toggle)
|
||||
|
||||
# a standard gtk.Tooltips to compare to
|
||||
tt = gtk.Tooltips()
|
||||
tt.set_tip(check, ('This is a standard gtk tooltip.\n'
|
||||
'Compare me to the tooltips above.'))
|
||||
|
||||
# create a VBox to pack the view and checkbutton
|
||||
vbox = gtk.VBox()
|
||||
vbox.pack_start(view)
|
||||
vbox.pack_start(check, False)
|
||||
vbox.show_all()
|
||||
|
||||
# pack the vbox into a simple dialog and run it
|
||||
dialog = gtk.Dialog('TreeViewTooltips Demo')
|
||||
close = dialog.add_button(gtk.STOCK_CLOSE, gtk.RESPONSE_NONE)
|
||||
|
||||
# add a tooltip for the close button
|
||||
tt.set_tip(close, 'Click to end the demo.')
|
||||
|
||||
dialog.set_default_size(400,400)
|
||||
dialog.vbox.pack_start(vbox)
|
||||
dialog.run()
|
||||
|
|
@ -18,6 +18,9 @@
|
|||
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
########################################################################
|
||||
|
||||
import L10n
|
||||
_ = L10n.get_translation()
|
||||
|
||||
import sys
|
||||
from HandHistoryConverter import *
|
||||
|
||||
|
|
@ -39,7 +42,7 @@ in_path (default '-' = sys.stdin)
|
|||
out_path (default '-' = sys.stdout)
|
||||
follow : whether to tail -f the input"""
|
||||
HandHistoryConverter.__init__(self, in_path, out_path, sitename="UltimateBet", follow=follow, index=index)
|
||||
logging.info("Initialising UltimateBetconverter class")
|
||||
logging.info(_("Initialising UltimateBetconverter class"))
|
||||
self.filetype = "text"
|
||||
self.codepage = "cp1252"
|
||||
self.siteId = 6 # Needs to match id entry in Sites database
|
||||
|
|
@ -141,7 +144,7 @@ follow : whether to tail -f the input"""
|
|||
if m:
|
||||
hand.buttonpos = int(m.group('BUTTON'))
|
||||
else:
|
||||
logging.info('readButton: not found')
|
||||
logging.info(_('readButton: not found'))
|
||||
|
||||
def readPlayerStacks(self, hand):
|
||||
logging.debug("readPlayerStacks")
|
||||
|
|
@ -180,7 +183,7 @@ follow : whether to tail -f the input"""
|
|||
hand.setCommunityCards(street, m.group('CARDS').split(' '))
|
||||
|
||||
def readAntes(self, hand):
|
||||
logging.debug("reading antes")
|
||||
logging.debug(_("reading antes"))
|
||||
m = self.re_Antes.finditer(hand.handText)
|
||||
for player in m:
|
||||
#~ logging.debug("hand.addAnte(%s,%s)" %(player.group('PNAME'), player.group('ANTE')))
|
||||
|
|
@ -290,7 +293,7 @@ follow : whether to tail -f the input"""
|
|||
#elif action.group('ATYPE') == ' stands pat':
|
||||
# hand.addStandsPat( street, action.group('PNAME'))
|
||||
else:
|
||||
print "DEBUG: unimplemented readAction: '%s' '%s'" %(action.group('PNAME'),action.group('ATYPE'),)
|
||||
print _("DEBUG: unimplemented readAction: '%s' '%s'" %(action.group('PNAME'),action.group('ATYPE'),))
|
||||
|
||||
|
||||
def readShowdownActions(self, hand):
|
||||
|
|
@ -312,9 +315,9 @@ follow : whether to tail -f the input"""
|
|||
|
||||
if __name__ == "__main__":
|
||||
parser = OptionParser()
|
||||
parser.add_option("-i", "--input", dest="ipath", help="parse input hand history", default="regression-test-files/pokerstars/HH20090226 Natalie V - $0.10-$0.20 - HORSE.txt")
|
||||
parser.add_option("-o", "--output", dest="opath", help="output translation to", default="-")
|
||||
parser.add_option("-f", "--follow", dest="follow", help="follow (tail -f) the input", action="store_true", default=False)
|
||||
parser.add_option("-i", "--input", dest="ipath", help=_("parse input hand history"), default="regression-test-files/pokerstars/HH20090226 Natalie V - $0.10-$0.20 - HORSE.txt")
|
||||
parser.add_option("-o", "--output", dest="opath", help=_("output translation to"), default="-")
|
||||
parser.add_option("-f", "--follow", dest="follow", help=_("follow (tail -f) the input"), action="store_true", default=False)
|
||||
parser.add_option("-q", "--quiet",
|
||||
action="store_const", const=logging.CRITICAL, dest="verbosity", default=logging.INFO)
|
||||
parser.add_option("-v", "--verbose",
|
||||
|
|
|
|||
|
|
@ -18,6 +18,9 @@
|
|||
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
########################################################################
|
||||
|
||||
import L10n
|
||||
_ = L10n.get_translation()
|
||||
|
||||
import sys
|
||||
import datetime
|
||||
from HandHistoryConverter import *
|
||||
|
|
@ -88,8 +91,10 @@ class Win2day(HandHistoryConverter):
|
|||
|
||||
m = self.re_GameInfo.search(handText)
|
||||
if not m:
|
||||
print "determineGameType:", handText
|
||||
return None
|
||||
tmp = handText[0:100]
|
||||
log.error(_("determineGameType: Unable to recognise gametype from: '%s'") % tmp)
|
||||
log.error(_("determineGameType: Raising FpdbParseError"))
|
||||
raise FpdbParseError(_("Unable to recognise gametype from: '%s'") % tmp)
|
||||
|
||||
mg = m.groupdict()
|
||||
|
||||
|
|
@ -98,7 +103,8 @@ class Win2day(HandHistoryConverter):
|
|||
limits = { 'NL':'nl', 'PL':'pl'}
|
||||
games = { # base, category
|
||||
"GAME_THM" : ('hold','holdem'),
|
||||
# 'Omaha' : ('hold','omahahi'),
|
||||
"GAME_OMA" : ('hold','omahahi'),
|
||||
|
||||
#'Omaha Hi/Lo' : ('hold','omahahilo'),
|
||||
# 'Razz' : ('stud','razz'),
|
||||
#'7 Card Stud' : ('stud','studhi'),
|
||||
|
|
@ -153,7 +159,7 @@ class Win2day(HandHistoryConverter):
|
|||
hand.buttonpos = player[0]
|
||||
break
|
||||
else:
|
||||
logging.info('readButton: not found')
|
||||
logging.info(_('readButton: not found'))
|
||||
|
||||
def readPlayerStacks(self, hand):
|
||||
logging.debug("readPlayerStacks")
|
||||
|
|
@ -182,19 +188,19 @@ class Win2day(HandHistoryConverter):
|
|||
if street in ('FLOP','TURN','RIVER'): # a list of streets which get dealt community cards (i.e. all but PREFLOP)
|
||||
#print "DEBUG readCommunityCards:", street, hand.streets.group(street)
|
||||
|
||||
boardCards = set([])
|
||||
boardCards = []
|
||||
if street == 'FLOP':
|
||||
m = self.re_Card.findall(hand.streets[street])
|
||||
for card in m:
|
||||
boardCards.add(self.convertWin2dayCards(card))
|
||||
boardCards.append(self.convertWin2dayCards(card))
|
||||
else:
|
||||
m = self.re_BoardLast.search(hand.streets[street])
|
||||
boardCards.add(self.convertWin2dayCards(m.group('CARD')))
|
||||
boardCards.append(self.convertWin2dayCards(m.group('CARD')))
|
||||
|
||||
hand.setCommunityCards(street, boardCards)
|
||||
|
||||
def readAntes(self, hand):
|
||||
logging.debug("reading antes")
|
||||
logging.debug(_("reading antes"))
|
||||
m = self.re_Antes.finditer(hand.handText)
|
||||
for player in m:
|
||||
#~ logging.debug("hand.addAnte(%s,%s)" %(player.group('PNAME'), player.group('ANTE')))
|
||||
|
|
@ -225,7 +231,7 @@ class Win2day(HandHistoryConverter):
|
|||
for found in m:
|
||||
hand.hero = found.group('PNAME')
|
||||
for card in self.re_Card.finditer(found.group('CARDS')):
|
||||
print self.convertWin2dayCards(card.group('CARD'))
|
||||
#print self.convertWin2dayCards(card.group('CARD'))
|
||||
newcards.append(self.convertWin2dayCards(card.group('CARD')))
|
||||
|
||||
#hand.addHoleCards(holeCards, m.group('PNAME'))
|
||||
|
|
@ -267,13 +273,13 @@ class Win2day(HandHistoryConverter):
|
|||
newcards = player.group('NEWCARDS')
|
||||
oldcards = player.group('OLDCARDS')
|
||||
if newcards == None:
|
||||
newcards = set()
|
||||
newcards = []
|
||||
else:
|
||||
newcards = set(newcards.split(' '))
|
||||
newcards = newcards.split(' ')
|
||||
if oldcards == None:
|
||||
oldcards = set()
|
||||
oldcards = []
|
||||
else:
|
||||
oldcards = set(oldcards.split(' '))
|
||||
oldcards = oldcards.split(' ')
|
||||
hand.addDrawHoleCards(newcards, oldcards, player.group('PNAME'), street)
|
||||
|
||||
|
||||
|
|
@ -332,15 +338,15 @@ class Win2day(HandHistoryConverter):
|
|||
elif action.group('ATYPE') == 'ACTION_STAND':
|
||||
hand.addStandsPat( street, action.group('PNAME'))
|
||||
else:
|
||||
print "DEBUG: unimplemented readAction: '%s' '%s'" %(action.group('PNAME'),action.group('ATYPE'),)
|
||||
print _("DEBUG: unimplemented readAction: '%s' '%s'" %(action.group('PNAME'),action.group('ATYPE'),))
|
||||
|
||||
|
||||
def readShowdownActions(self, hand):
|
||||
for shows in self.re_ShowdownAction.finditer(hand.handText):
|
||||
showdownCards = set([])
|
||||
showdownCards = []
|
||||
for card in self.re_Card.finditer(shows.group('CARDS')):
|
||||
#print "DEBUG:", card, card.group('CARD'), self.convertWin2dayCards(card.group('CARD'))
|
||||
showdownCards.add(self.convertWin2dayCards(card.group('CARD')))
|
||||
showdownCards.append(self.convertWin2dayCards(card.group('CARD')))
|
||||
|
||||
hand.addShownCards(showdownCards, shows.group('PNAME'))
|
||||
|
||||
|
|
@ -354,14 +360,14 @@ class Win2day(HandHistoryConverter):
|
|||
for m in self.re_ShownCards.finditer(hand.handText):
|
||||
if m.group('CARDS') is not None:
|
||||
cards = m.group('CARDS')
|
||||
cards = set(cards.split(' '))
|
||||
cards = cards.split(' ')
|
||||
hand.addShownCards(cards=cards, player=m.group('PNAME'))
|
||||
|
||||
if __name__ == "__main__":
|
||||
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="-")
|
||||
parser.add_option("-f", "--follow", dest="follow", help="follow (tail -f) the input", action="store_true", default=False)
|
||||
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="-")
|
||||
parser.add_option("-f", "--follow", dest="follow", help=_("follow (tail -f) the input"), action="store_true", default=False)
|
||||
parser.add_option("-q", "--quiet",
|
||||
action="store_const", const=logging.CRITICAL, dest="verbosity", default=logging.INFO)
|
||||
parser.add_option("-v", "--verbose",
|
||||
|
|
|
|||
|
|
@ -1,10 +1,8 @@
|
|||
#!/usr/bin/env python
|
||||
# -*- coding: utf-8 -*-
|
||||
"""WinTables.py
|
||||
|
||||
Routines for detecting and handling poker client windows for MS Windows.
|
||||
"""Routines for detecting and handling poker client windows for MS Windows.
|
||||
"""
|
||||
# Copyright 2008-2010, Ray E. Barker
|
||||
# Copyright 2008 - 2010, Ray E. Barker
|
||||
|
||||
# This program is free software; you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License as published by
|
||||
|
|
@ -22,6 +20,9 @@ Routines for detecting and handling poker client windows for MS Windows.
|
|||
|
||||
########################################################################
|
||||
|
||||
import L10n
|
||||
_ = L10n.get_translation()
|
||||
|
||||
# Standard Library modules
|
||||
import re
|
||||
|
||||
|
|
@ -48,87 +49,80 @@ from TableWindow import Table_Window
|
|||
b_width = 3
|
||||
tb_height = 29
|
||||
|
||||
|
||||
class Table(Table_Window):
|
||||
|
||||
def find_table_parameters(self, search_string):
|
||||
def find_table_parameters(self):
|
||||
"""Finds poker client window with the given table name."""
|
||||
titles = {}
|
||||
win32gui.EnumWindows(win_enum_handler, titles)
|
||||
for hwnd in titles:
|
||||
if titles[hwnd] == "": continue
|
||||
# print "searching ", search_string, " in ", titles[hwnd]
|
||||
if re.search(search_string, titles[hwnd]):
|
||||
if 'History for table:' in titles[hwnd]: continue # Everleaf Network HH viewer window
|
||||
if 'HUD:' in titles[hwnd]: continue # FPDB HUD window
|
||||
if 'Chat:' in titles[hwnd]: continue # Some sites (FTP? PS? Others?) have seperable or seperately constructed chat windows
|
||||
if 'FPDBHUD' in titles[hwnd]: continue # can't attach to ourselves!
|
||||
if titles[hwnd] == "":
|
||||
continue
|
||||
if re.search(self.search_string, titles[hwnd]):
|
||||
if self.check_bad_words(titles[hwnd]):
|
||||
continue
|
||||
self.window = hwnd
|
||||
break
|
||||
|
||||
try:
|
||||
if self.window == None:
|
||||
log.error( "Window %s not found. Skipping." % search_string )
|
||||
log.error(_("Window %s not found. Skipping." % self.search_string))
|
||||
return None
|
||||
except AttributeError:
|
||||
log.error( "self.window doesn't exist? why?" )
|
||||
log.error(_("self.window doesn't exist? why?"))
|
||||
return None
|
||||
|
||||
(x, y, width, height) = win32gui.GetWindowRect(hwnd)
|
||||
log.debug("x = %s y = %s width = %s height = %s" % (x, y, width, height))
|
||||
self.x = int(x) + b_width
|
||||
self.y = int(y) + tb_height
|
||||
self.width = width - x
|
||||
self.height = height - y
|
||||
log.debug("x = %s y = %s width = %s height = %s" % (self.x, self.y, self.width, self.height))
|
||||
#self.height = int(height) - b_width - tb_height
|
||||
#self.width = int(width) - 2*b_width
|
||||
|
||||
self.exe = self.get_nt_exe(hwnd)
|
||||
self.title = titles[hwnd]
|
||||
self.site = ""
|
||||
self.hud = None
|
||||
self.title = titles[hwnd]
|
||||
self.hud = None
|
||||
self.number = hwnd
|
||||
self.gdkhandle = gtk.gdk.window_foreign_new(long(self.window))
|
||||
|
||||
def get_geometry(self):
|
||||
if not win32gui.IsWindow(self.number): # window closed
|
||||
return None
|
||||
|
||||
try:
|
||||
(x, y, width, height) = win32gui.GetWindowRect(self.number)
|
||||
width = width - x
|
||||
height = height - y
|
||||
return {'x' : int(x) + b_width,
|
||||
if win32gui.IsWindow(self.number):
|
||||
(x, y, width, height) = win32gui.GetWindowRect(self.number)
|
||||
# this apparently returns x = far left side of window, width = far right side of window, y = top of window, height = bottom of window
|
||||
# so apparently we have to subtract x from "width" to get actual width, and y from "height" to get actual height ?
|
||||
# it definitely gives slightly different results than the GTK code that does the same thing.
|
||||
#print "x=", x, "y=", y, "width=", width, "height=", height
|
||||
width = width - x
|
||||
height = height - y
|
||||
return {
|
||||
'x' : int(x) + b_width,
|
||||
'y' : int(y) + tb_height,
|
||||
'width' : int(height) - b_width - tb_height,
|
||||
'height' : int(width) - 2*b_width
|
||||
}
|
||||
except:
|
||||
'height' : int(height) - y,
|
||||
'width' : int(width) - x
|
||||
}
|
||||
except AttributeError:
|
||||
return None
|
||||
|
||||
def get_window_title(self):
|
||||
return win32gui.GetWindowText(self.window)
|
||||
try: # after window is destroyed, self.window = attribute error
|
||||
return win32gui.GetWindowText(self.window)
|
||||
except AttributeError:
|
||||
return ""
|
||||
|
||||
def get_nt_exe(self, hwnd):
|
||||
"""Finds the name of the executable that the given window handle belongs to."""
|
||||
# def get_nt_exe(self, hwnd):
|
||||
# """Finds the name of the executable that the given window handle belongs to."""
|
||||
#
|
||||
# # Request privileges to enable "debug process", so we can later use PROCESS_VM_READ, retardedly required to GetModuleFileNameEx()
|
||||
# priv_flags = win32security.TOKEN_ADJUST_PRIVILEGES | win32security.TOKEN_QUERY
|
||||
# hToken = win32security.OpenProcessToken (win32api.GetCurrentProcess(), priv_flags)
|
||||
# # enable "debug process"
|
||||
# privilege_id = win32security.LookupPrivilegeValue (None, win32security.SE_DEBUG_NAME)
|
||||
# old_privs = win32security.AdjustTokenPrivileges (hToken, 0, [(privilege_id, win32security.SE_PRIVILEGE_ENABLED)])
|
||||
#
|
||||
# # Open the process, and query it's filename
|
||||
# processid = win32process.GetWindowThreadProcessId(hwnd)
|
||||
# pshandle = win32api.OpenProcess(win32con.PROCESS_QUERY_INFORMATION | win32con.PROCESS_VM_READ, False, processid[1])
|
||||
# exename = win32process.GetModuleFileNameEx(pshandle, 0)
|
||||
#
|
||||
# # clean up
|
||||
# win32api.CloseHandle(pshandle)
|
||||
# win32api.CloseHandle(hToken)
|
||||
#
|
||||
# return exename
|
||||
|
||||
# Request privileges to enable "debug process", so we can later use PROCESS_VM_READ, retardedly required to GetModuleFileNameEx()
|
||||
priv_flags = win32security.TOKEN_ADJUST_PRIVILEGES | win32security.TOKEN_QUERY
|
||||
hToken = win32security.OpenProcessToken (win32api.GetCurrentProcess(), priv_flags)
|
||||
# enable "debug process"
|
||||
privilege_id = win32security.LookupPrivilegeValue (None, win32security.SE_DEBUG_NAME)
|
||||
old_privs = win32security.AdjustTokenPrivileges (hToken, 0, [(privilege_id, win32security.SE_PRIVILEGE_ENABLED)])
|
||||
|
||||
# Open the process, and query it's filename
|
||||
processid = win32process.GetWindowThreadProcessId(hwnd)
|
||||
pshandle = win32api.OpenProcess(win32con.PROCESS_QUERY_INFORMATION | win32con.PROCESS_VM_READ, False, processid[1])
|
||||
exename = win32process.GetModuleFileNameEx(pshandle, 0)
|
||||
|
||||
# clean up
|
||||
win32api.CloseHandle(pshandle)
|
||||
win32api.CloseHandle(hToken)
|
||||
|
||||
return exename
|
||||
def topify(self, hud):
|
||||
"""Set the specified gtk window to stayontop in MS Windows."""
|
||||
|
||||
|
|
@ -147,10 +141,10 @@ class Table(Table_Window):
|
|||
# hud.main_window.gdkhandle = gtk.gdk.window_foreign_new(w[0])
|
||||
hud.main_window.gdkhandle = hud.main_window.window
|
||||
hud.main_window.gdkhandle.set_transient_for(self.gdkhandle)
|
||||
rect = self.gdkhandle.get_frame_extents()
|
||||
(innerx, innery) = self.gdkhandle.get_origin()
|
||||
b_width = rect.x - innerx
|
||||
tb_height = rect.y - innery
|
||||
# rect = self.gdkhandle.get_frame_extents()
|
||||
# (innerx, innery) = self.gdkhandle.get_origin()
|
||||
# b_width = rect.x - innerx
|
||||
# tb_height = rect.y - innery
|
||||
#
|
||||
# style = win32gui.GetWindowLong(self.number, win32con.GWL_EXSTYLE)
|
||||
# style |= win32con.WS_CLIPCHILDREN
|
||||
|
|
@ -159,5 +153,6 @@ class Table(Table_Window):
|
|||
|
||||
# hud.main_window.set_title(real_name)
|
||||
|
||||
|
||||
def win_enum_handler(hwnd, titles):
|
||||
titles[hwnd] = win32gui.GetWindowText(hwnd)
|
||||
|
|
|
|||
388
pyfpdb/WinamaxToFpdb.py
Normal file
388
pyfpdb/WinamaxToFpdb.py
Normal file
|
|
@ -0,0 +1,388 @@
|
|||
#!/usr/bin/env python
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
# Copyright 2008-2010, Carl Gherardi
|
||||
#
|
||||
# This program is free software; you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License as published by
|
||||
# the Free Software Foundation; either version 2 of the License, or
|
||||
# (at your option) any later version.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with this program; if not, write to the Free Software
|
||||
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
########################################################################
|
||||
|
||||
import L10n
|
||||
_ = L10n.get_translation()
|
||||
|
||||
import sys
|
||||
import exceptions
|
||||
|
||||
import logging
|
||||
# logging has been set up in fpdb.py or HUD_main.py, use their settings:
|
||||
|
||||
import Configuration
|
||||
from HandHistoryConverter import *
|
||||
from decimal import Decimal
|
||||
import time
|
||||
|
||||
# Winamax HH Format
|
||||
|
||||
class Winamax(HandHistoryConverter):
|
||||
def Trace(f):
|
||||
def my_f(*args, **kwds):
|
||||
print ( "entering " + f.__name__)
|
||||
result= f(*args, **kwds)
|
||||
print ( "exiting " + f.__name__)
|
||||
return result
|
||||
my_f.__name = f.__name__
|
||||
my_f.__doc__ = f.__doc__
|
||||
return my_f
|
||||
|
||||
filter = "Winamax"
|
||||
siteName = "Winamax"
|
||||
filetype = "text"
|
||||
codepage = ("utf8", "cp1252")
|
||||
siteId = 14 # Needs to match id entry in Sites database
|
||||
|
||||
mixes = { } # Legal mixed games
|
||||
sym = {'USD': "\$", 'CAD': "\$", 'T$': "", "EUR": "\xe2\x82\xac", "GBP": "\xa3"} # ADD Euro, Sterling, etc HERE
|
||||
substitutions = {
|
||||
'LEGAL_ISO' : "USD|EUR|GBP|CAD|FPP", # legal ISO currency codes
|
||||
'LS' : "\$|\xe2\x82\xac|" # legal currency symbols - Euro(cp1252, utf-8)
|
||||
}
|
||||
|
||||
limits = { 'no limit':'nl', 'pot limit' : 'pl','LIMIT':'fl'}
|
||||
|
||||
games = { # base, category
|
||||
"Holdem" : ('hold','holdem'),
|
||||
'Omaha' : ('hold','omahahi'),
|
||||
# 'Omaha Hi/Lo' : ('hold','omahahilo'),
|
||||
# 'Razz' : ('stud','razz'),
|
||||
# 'RAZZ' : ('stud','razz'),
|
||||
# '7 Card Stud' : ('stud','studhi'),
|
||||
# 'SEVEN_CARD_STUD_HI_LO' : ('stud','studhilo'),
|
||||
# 'Badugi' : ('draw','badugi'),
|
||||
# 'Triple Draw 2-7 Lowball' : ('draw','27_3draw'),
|
||||
# '5 Card Draw' : ('draw','fivedraw')
|
||||
}
|
||||
|
||||
# Static regexes
|
||||
# ***** End of hand R5-75443872-57 *****
|
||||
re_SplitHands = re.compile(r'\n\n')
|
||||
|
||||
|
||||
|
||||
# Winamax Poker - CashGame - HandId: #279823-223-1285031451 - Holdem no limit (0.02€/0.05€) - 2010/09/21 03:10:51 UTC
|
||||
# Table: 'Charenton-le-Pont' 9-max (real money) Seat #5 is the button
|
||||
re_HandInfo = re.compile(u"""
|
||||
\s*Winamax\sPoker\s-\sCashGame\s-\sHandId:\s\#(?P<HID1>\d+)-(?P<HID2>\d+)-(?P<HID3>\d+).*\s
|
||||
(?P<GAME>Holdem|Omaha)\s
|
||||
(?P<LIMIT>no\slimit|pot\slimit)\s
|
||||
\(
|
||||
((%(LS)s)?(?P<SB>[.0-9]+)(%(LS)s)?)/
|
||||
((%(LS)s)?(?P<BB>[.0-9]+)(%(LS)s)?)
|
||||
\)\s-\s
|
||||
(?P<DATETIME>.*)
|
||||
Table:\s\'(?P<TABLE>[^']+)\'\s(?P<MAXPLAYER>\d+)\-max
|
||||
""" % substitutions, re.MULTILINE|re.DOTALL|re.VERBOSE)
|
||||
|
||||
re_TailSplitHands = re.compile(r'\n\s*\n')
|
||||
re_Button = re.compile(r'Seat\s#(?P<BUTTON>\d+)\sis\sthe\sbutton')
|
||||
re_Board = re.compile(r"\[(?P<CARDS>.+)\]")
|
||||
|
||||
# 2010/09/21 03:10:51 UTC
|
||||
re_DateTime = re.compile("""
|
||||
(?P<Y>[0-9]{4})/
|
||||
(?P<M>[0-9]+)/
|
||||
(?P<D>[0-9]+)\s
|
||||
(?P<H>[0-9]+):(?P<MIN>[0-9]+):(?P<S>[0-9]+)\s
|
||||
UTC
|
||||
""", re.MULTILINE|re.VERBOSE)
|
||||
|
||||
# Seat 1: some_player (5€)
|
||||
# Seat 2: some_other_player21 (6.33€)
|
||||
|
||||
re_PlayerInfo = re.compile(u'Seat\s(?P<SEAT>[0-9]+):\s(?P<PNAME>.*)\s\((%(LS)s)?(?P<CASH>[.0-9]+)(%(LS)s)?\)' % substitutions)
|
||||
|
||||
def compilePlayerRegexs(self, hand):
|
||||
players = set([player[1] for player in hand.players])
|
||||
if not players <= self.compiledPlayers: # x <= y means 'x is subset of y'
|
||||
# we need to recompile the player regexs.
|
||||
# TODO: should probably rename re_HeroCards and corresponding method,
|
||||
# since they are used to find all cards on lines starting with "Dealt to:"
|
||||
# They still identify the hero.
|
||||
self.compiledPlayers = players
|
||||
#ANTES/BLINDS
|
||||
#helander2222 posts blind ($0.25), lopllopl posts blind ($0.50).
|
||||
player_re = "(?P<PNAME>" + "|".join(map(re.escape, players)) + ")"
|
||||
subst = {'PLYR': player_re, 'CUR': self.sym[hand.gametype['currency']]}
|
||||
self.re_PostSB = re.compile('%(PLYR)s posts small blind (%(CUR)s)?(?P<SB>[\.0-9]+)(%(CUR)s)?' % subst, re.MULTILINE)
|
||||
self.re_PostBB = re.compile('%(PLYR)s posts big blind (%(CUR)s)?(?P<BB>[\.0-9]+)(%(CUR)s)?' % subst, re.MULTILINE)
|
||||
self.re_DenySB = re.compile('(?P<PNAME>.*) deny SB' % subst, re.MULTILINE)
|
||||
self.re_Antes = re.compile(r"^%(PLYR)s: posts the ante (%(CUR)s)?(?P<ANTE>[\.0-9]+)(%(CUR)s)?" % subst, re.MULTILINE)
|
||||
self.re_BringIn = re.compile(r"^%(PLYR)s: brings[- ]in( low|) for (%(CUR)s)?(?P<BRINGIN>[\.0-9]+(%(CUR)s)?)" % subst, re.MULTILINE)
|
||||
self.re_PostBoth = re.compile('(?P<PNAME>.*): posts small \& big blind \( (%(CUR)s)?(?P<SBBB>[\.0-9]+)(%(CUR)s)?\)' % subst)
|
||||
self.re_PostDead = re.compile('(?P<PNAME>.*) posts dead blind \((%(CUR)s)?(?P<DEAD>[\.0-9]+)(%(CUR)s)?\)' % subst, re.MULTILINE)
|
||||
self.re_HeroCards = re.compile('Dealt\sto\s%(PLYR)s\s\[(?P<CARDS>.*)\]' % subst)
|
||||
|
||||
self.re_Action = re.compile('(, )?(?P<PNAME>.*?)(?P<ATYPE> bets| checks| raises| calls| folds)( (%(CUR)s)?(?P<BET>[\d\.]+)(%(CUR)s)?)?( and is all-in)?' % subst)
|
||||
self.re_ShowdownAction = re.compile('(?P<PNAME>[^\(\)\n]*) (\((small blind|big blind|button)\) )?shows \[(?P<CARDS>.+)\]')
|
||||
|
||||
self.re_CollectPot = re.compile('\s*(?P<PNAME>.*)\scollected\s(%(CUR)s)?(?P<POT>[\.\d]+)(%(CUR)s)?.*' % subst)
|
||||
self.re_ShownCards = re.compile("^Seat (?P<SEAT>[0-9]+): %(PLYR)s showed \[(?P<CARDS>.*)\].*" % subst, re.MULTILINE)
|
||||
self.re_sitsOut = re.compile('(?P<PNAME>.*) sits out')
|
||||
|
||||
def readSupportedGames(self):
|
||||
return [
|
||||
["ring", "hold", "fl"],
|
||||
["ring", "hold", "nl"],
|
||||
["ring", "hold", "pl"],
|
||||
]
|
||||
|
||||
def determineGameType(self, handText):
|
||||
# Inspect the handText and return the gametype dict
|
||||
# gametype dict is: {'limitType': xxx, 'base': xxx, 'category': xxx}
|
||||
info = {}
|
||||
|
||||
m = self.re_HandInfo.search(handText)
|
||||
if not m:
|
||||
tmp = handText[0:100]
|
||||
log.error(_("determineGameType: Unable to recognise gametype from: '%s'") % tmp)
|
||||
log.error(_("determineGameType: Raising FpdbParseError"))
|
||||
raise FpdbParseError(_("Unable to recognise gametype from: '%s'") % tmp)
|
||||
|
||||
mg = m.groupdict()
|
||||
|
||||
info['type'] = 'ring'
|
||||
info['currency'] = 'EUR'
|
||||
|
||||
if 'LIMIT' in mg:
|
||||
if mg['LIMIT'] in self.limits:
|
||||
info['limitType'] = self.limits[mg['LIMIT']]
|
||||
else:
|
||||
tmp = handText[0:100]
|
||||
log.error(_("determineGameType: limit not found in self.limits(%s). hand: '%s'") % (str(mg),tmp))
|
||||
log.error(_("determineGameType: Raising FpdbParseError"))
|
||||
raise FpdbParseError(_("limit not found in self.limits(%s). hand: '%s'") % (str(mg),tmp))
|
||||
if 'GAME' in mg:
|
||||
(info['base'], info['category']) = self.games[mg['GAME']]
|
||||
if 'SB' in mg:
|
||||
info['sb'] = mg['SB']
|
||||
if 'BB' in mg:
|
||||
info['bb'] = mg['BB']
|
||||
|
||||
return info
|
||||
|
||||
def readHandInfo(self, hand):
|
||||
info = {}
|
||||
m = self.re_HandInfo.search(hand.handText)
|
||||
|
||||
if m:
|
||||
info.update(m.groupdict())
|
||||
|
||||
#log.debug("readHandInfo: %s" % info)
|
||||
for key in info:
|
||||
if key == 'DATETIME':
|
||||
a = self.re_DateTime.search(info[key])
|
||||
if a:
|
||||
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'))
|
||||
tzoffset = str(-time.timezone/3600)
|
||||
else:
|
||||
datetimestr = "2010/Jan/01 01:01:01"
|
||||
log.error(_("readHandInfo: DATETIME not matched: '%s'" % info[key]))
|
||||
# print "DEBUG: readHandInfo: DATETIME not matched: '%s'" % info[key]
|
||||
# TODO: Manually adjust time against OFFSET
|
||||
hand.startTime = datetime.datetime.strptime(datetimestr, "%Y/%m/%d %H:%M:%S") # also timezone at end, e.g. " ET"
|
||||
hand.startTime = HandHistoryConverter.changeTimezone(hand.startTime, "CET", "UTC")
|
||||
if key == 'HID1':
|
||||
hand.handid = "1%.4d%s%s"%(int(info['HID2']),info['HID1'],info['HID3'])
|
||||
# Need to remove non-alphanumerics for MySQL
|
||||
if key == 'TABLE':
|
||||
hand.tablename = info[key]
|
||||
|
||||
# TODO: These
|
||||
hand.buttonpos = 1
|
||||
hand.maxseats = 10 # Set to None - Hand.py will guessMaxSeats()
|
||||
hand.mixed = None
|
||||
|
||||
def readPlayerStacks(self, hand):
|
||||
log.debug(_("readplayerstacks: re is '%s'" % self.re_PlayerInfo))
|
||||
m = self.re_PlayerInfo.finditer(hand.handText)
|
||||
for a in m:
|
||||
hand.addPlayer(int(a.group('SEAT')), a.group('PNAME'), a.group('CASH'))
|
||||
|
||||
|
||||
def markStreets(self, hand):
|
||||
m = re.search(r"\*\*\* ANTE\/BLINDS \*\*\*(?P<PREFLOP>.+(?=\*\*\* FLOP \*\*\*)|.+)"
|
||||
r"(\*\*\* FLOP \*\*\*(?P<FLOP> \[\S\S \S\S \S\S\].+(?=\*\*\* TURN \*\*\*)|.+))?"
|
||||
r"(\*\*\* TURN \*\*\* \[\S\S \S\S \S\S](?P<TURN>\[\S\S\].+(?=\*\*\* RIVER \*\*\*)|.+))?"
|
||||
r"(\*\*\* RIVER \*\*\* \[\S\S \S\S \S\S \S\S](?P<RIVER>\[\S\S\].+))?", hand.handText,re.DOTALL)
|
||||
|
||||
try:
|
||||
hand.addStreets(m)
|
||||
# print "adding street", m.group(0)
|
||||
# print "---"
|
||||
except:
|
||||
print (_("Failed to add streets. handtext=%s"))
|
||||
|
||||
#Needs to return a list in the format
|
||||
# ['player1name', 'player2name', ...] where player1name is the sb and player2name is bb,
|
||||
# addtional players are assumed to post a bb oop
|
||||
|
||||
def readButton(self, hand):
|
||||
m = self.re_Button.search(hand.handText)
|
||||
if m:
|
||||
hand.buttonpos = int(m.group('BUTTON'))
|
||||
log.debug(_('readButton: button on pos %d'%hand.buttonpos))
|
||||
else:
|
||||
log.warning(_('readButton: not found'))
|
||||
|
||||
# def readCommunityCards(self, hand, street):
|
||||
# #print hand.streets.group(street)
|
||||
# if street in ('FLOP','TURN','RIVER'): # a list of streets which get dealt community cards (i.e. all but PREFLOP)
|
||||
# m = self.re_Board.search(hand.streets.group(street))
|
||||
# hand.setCommunityCards(street, m.group('CARDS').split(','))
|
||||
|
||||
def readCommunityCards(self, hand, street): # street has been matched by markStreets, so exists in this hand
|
||||
if street in ('FLOP','TURN','RIVER'): # a list of streets which get dealt community cards (i.e. all but PREFLOP)
|
||||
#print "DEBUG readCommunityCards:", street, hand.streets.group(street)
|
||||
m = self.re_Board.search(hand.streets[street])
|
||||
hand.setCommunityCards(street, m.group('CARDS').split(' '))
|
||||
|
||||
def readBlinds(self, hand):
|
||||
if not self.re_DenySB.search(hand.handText):
|
||||
try:
|
||||
m = self.re_PostSB.search(hand.handText)
|
||||
hand.addBlind(m.group('PNAME'), 'small blind', m.group('SB'))
|
||||
except exceptions.AttributeError: # no small blind
|
||||
log.warning( _("readBlinds in noSB exception - no SB created")+str(sys.exc_info()) )
|
||||
#hand.addBlind(None, None, None)
|
||||
for a in self.re_PostBB.finditer(hand.handText):
|
||||
hand.addBlind(a.group('PNAME'), 'big blind', a.group('BB'))
|
||||
for a in self.re_PostDead.finditer(hand.handText):
|
||||
#print "DEBUG: Found dead blind: addBlind(%s, 'secondsb', %s)" %(a.group('PNAME'), a.group('DEAD'))
|
||||
hand.addBlind(a.group('PNAME'), 'secondsb', a.group('DEAD'))
|
||||
for a in self.re_PostBoth.finditer(hand.handText):
|
||||
hand.addBlind(a.group('PNAME'), 'small & big blinds', a.group('SBBB'))
|
||||
|
||||
def readAntes(self, hand):
|
||||
log.debug(_("reading antes"))
|
||||
m = self.re_Antes.finditer(hand.handText)
|
||||
for player in m:
|
||||
#~ logging.debug("hand.addAnte(%s,%s)" %(player.group('PNAME'), player.group('ANTE')))
|
||||
hand.addAnte(player.group('PNAME'), player.group('ANTE'))
|
||||
|
||||
def readBringIn(self, hand):
|
||||
m = self.re_BringIn.search(hand.handText,re.DOTALL)
|
||||
if m:
|
||||
#~ logging.debug("readBringIn: %s for %s" %(m.group('PNAME'), m.group('BRINGIN')))
|
||||
hand.addBringIn(m.group('PNAME'), m.group('BRINGIN'))
|
||||
|
||||
def readHeroCards(self, hand):
|
||||
# streets PREFLOP, PREDRAW, and THIRD are special cases beacause
|
||||
# we need to grab hero's cards
|
||||
for street in ('PREFLOP', 'DEAL', 'BLINDSANTES'):
|
||||
if street in hand.streets.keys():
|
||||
m = self.re_HeroCards.finditer(hand.streets[street])
|
||||
if m == []:
|
||||
log.debug(_("No hole cards found for %s"%street))
|
||||
for found in m:
|
||||
hand.hero = found.group('PNAME')
|
||||
newcards = found.group('CARDS').split(' ')
|
||||
# print "DEBUG: addHoleCards(%s, %s, %s)" %(street, hand.hero, newcards)
|
||||
hand.addHoleCards(street, hand.hero, closed=newcards, shown=False, mucked=False, dealt=True)
|
||||
log.debug(_("Hero cards %s: %s"%(hand.hero, newcards)))
|
||||
|
||||
def readAction(self, hand, street):
|
||||
m = self.re_Action.finditer(hand.streets[street])
|
||||
for action in m:
|
||||
acts = action.groupdict()
|
||||
if action.group('ATYPE') == ' raises':
|
||||
hand.addRaiseBy( street, action.group('PNAME'), action.group('BET') )
|
||||
elif action.group('ATYPE') == ' calls':
|
||||
hand.addCall( street, action.group('PNAME'), action.group('BET') )
|
||||
elif action.group('ATYPE') == ' bets':
|
||||
hand.addBet( street, action.group('PNAME'), action.group('BET') )
|
||||
elif action.group('ATYPE') == ' folds':
|
||||
hand.addFold( street, action.group('PNAME'))
|
||||
elif action.group('ATYPE') == ' checks':
|
||||
hand.addCheck( street, action.group('PNAME'))
|
||||
elif action.group('ATYPE') == ' discards':
|
||||
hand.addDiscard(street, action.group('PNAME'), action.group('BET'), action.group('DISCARDED'))
|
||||
elif action.group('ATYPE') == ' stands pat':
|
||||
hand.addStandsPat( street, action.group('PNAME'))
|
||||
else:
|
||||
log.fatal(_("DEBUG: unimplemented readAction: '%s' '%s'")) %(action.group('PNAME'),action.group('ATYPE'),)
|
||||
# print "Processed %s"%acts
|
||||
# print "committed=",hand.pot.committed
|
||||
|
||||
def readShowdownActions(self, hand):
|
||||
for shows in self.re_ShowdownAction.finditer(hand.handText):
|
||||
log.debug(_("add show actions %s"%shows))
|
||||
cards = shows.group('CARDS')
|
||||
cards = cards.split(' ')
|
||||
# print "DEBUG: addShownCards(%s, %s)" %(cards, shows.group('PNAME'))
|
||||
hand.addShownCards(cards, shows.group('PNAME'))
|
||||
|
||||
def readCollectPot(self,hand):
|
||||
# Winamax has unfortunately thinks that a sidepot is created
|
||||
# when there is uncalled money in the pot - something that can
|
||||
# only happen when a player is all-in
|
||||
|
||||
# Becuase of this, we need to do the same calculations as class Pot()
|
||||
# and determine if the amount returned is the same as the amount collected
|
||||
# if so then the collected line is invalid
|
||||
|
||||
total = sum(hand.pot.committed.values()) + sum(hand.pot.common.values())
|
||||
|
||||
# Return any uncalled bet.
|
||||
committed = sorted([ (v,k) for (k,v) in hand.pot.committed.items()])
|
||||
#print "DEBUG: committed: %s" % committed
|
||||
#ERROR below. lastbet is correct in most cases, but wrong when
|
||||
# additional money is committed to the pot in cash games
|
||||
# due to an additional sb being posted. (Speculate that
|
||||
# posting sb+bb is also potentially wrong)
|
||||
returned = {}
|
||||
lastbet = committed[-1][0] - committed[-2][0]
|
||||
if lastbet > 0: # uncalled
|
||||
returnto = committed[-1][1]
|
||||
#print "DEBUG: returning %f to %s" % (lastbet, returnto)
|
||||
total -= lastbet
|
||||
returned[returnto] = lastbet
|
||||
|
||||
collectees = []
|
||||
|
||||
for m in self.re_CollectPot.finditer(hand.handText):
|
||||
collectees.append([m.group('PNAME'), m.group('POT')])
|
||||
|
||||
for plyr, p in collectees:
|
||||
if plyr in returned.keys() and Decimal(p) - returned[plyr] == 0:
|
||||
p = Decimal(p) - returned[plyr]
|
||||
if p > 0:
|
||||
print "DEBUG: addCollectPot(%s,%s)" %(plyr, p)
|
||||
hand.addCollectPot(player=plyr,pot=p)
|
||||
|
||||
def readShownCards(self,hand):
|
||||
for m in self.re_ShownCards.finditer(hand.handText):
|
||||
log.debug(_("Read shown cards: %s"%m.group(0)))
|
||||
cards = m.group('CARDS')
|
||||
cards = cards.split(' ') # needs to be a list, not a set--stud needs the order
|
||||
(shown, mucked) = (False, False)
|
||||
if m.group('CARDS') is not None:
|
||||
shown = True
|
||||
hand.addShownCards(cards=cards, player=m.group('PNAME'), shown=shown, mucked=mucked)
|
||||
|
||||
if __name__ == "__main__":
|
||||
c = Configuration.Config()
|
||||
if len(sys.argv) == 1:
|
||||
testfile = "regression-test-files/ongame/nlhe/ong NLH handhq_0.txt"
|
||||
else:
|
||||
testfile = sys.argv[1]
|
||||
e = Winamax(c, testfile)
|
||||
|
|
@ -1,12 +1,8 @@
|
|||
#!/usr/bin/env python
|
||||
# -*- coding: utf-8 -*-
|
||||
"""Discover_Tables.py
|
||||
|
||||
Inspects the currently open windows and finds those of interest to us--that is
|
||||
poker table windows from supported sites. Returns a list
|
||||
of Table_Window objects representing the windows found.
|
||||
"""XWindows specific methods for TableWindows Class.
|
||||
"""
|
||||
# Copyright 2008-2010, Ray E. Barker
|
||||
# Copyright 2008 - 2010, Ray E. Barker
|
||||
|
||||
# This program is free software; you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License as published by
|
||||
|
|
@ -24,102 +20,62 @@ of Table_Window objects representing the windows found.
|
|||
|
||||
########################################################################
|
||||
|
||||
import L10n
|
||||
_ = L10n.get_translation()
|
||||
|
||||
# Standard Library modules
|
||||
import re
|
||||
import os
|
||||
|
||||
# pyGTK modules
|
||||
import pygtk
|
||||
import gtk
|
||||
|
||||
# Other Library modules
|
||||
import Xlib
|
||||
import Xlib.display
|
||||
|
||||
# FreePokerTools modules
|
||||
# FPDB modules
|
||||
from TableWindow import Table_Window
|
||||
|
||||
# We might as well do this once and make them globals
|
||||
disp = Xlib.display.Display()
|
||||
root = disp.screen().root
|
||||
name_atom = disp.get_atom("WM_NAME", 1)
|
||||
|
||||
class Table(Table_Window):
|
||||
|
||||
def find_table_parameters(self, search_string):
|
||||
# self.window = None
|
||||
# done_looping = False
|
||||
# for outside in root.query_tree().children:
|
||||
# for inside in outside.query_tree().children:
|
||||
# if done_looping: break
|
||||
# prop = inside.get_property(name_atom, Xlib.Xatom.STRING, 0, 1000)
|
||||
# print prop
|
||||
# if prop is None: continue
|
||||
# if prop.value and re.search(search_string, prop.value):
|
||||
# if self.check_bad_words(prop.value): continue
|
||||
## if inside.get_wm_name() and re.search(search_string, inside.get_wm_name()):
|
||||
## if self.check_bad_words(inside.get_wm_name()):
|
||||
## print "bad word =", inside.get_wm_name()
|
||||
## continue
|
||||
# self.window = inside
|
||||
# self.parent = outside
|
||||
# done_looping = True
|
||||
# break
|
||||
def find_table_parameters(self):
|
||||
|
||||
window_number = None
|
||||
self.number = None
|
||||
for listing in os.popen('xwininfo -root -tree').readlines():
|
||||
if re.search(search_string, listing):
|
||||
# print listing
|
||||
if re.search(self.search_string, listing):
|
||||
mo = re.match('\s+([\dxabcdef]+) (.+):\s\(\"([a-zA-Z0-9\-.]+)\".+ (\d+)x(\d+)\+\d+\+\d+ \+(\d+)\+(\d+)', listing)
|
||||
title = re.sub('\"', '', mo.group(2))
|
||||
if self.check_bad_words(title): continue
|
||||
self.number = int( mo.group(1), 0)
|
||||
self.width = int( mo.group(4) )
|
||||
self.height = int( mo.group(5) )
|
||||
self.x = int( mo.group(6) )
|
||||
self.y = int( mo.group(7) )
|
||||
self.title = re.sub('\"', '', mo.group(2))
|
||||
self.exe = "" # not used?
|
||||
self.hud = None
|
||||
# done_looping = False
|
||||
# for outside in root.query_tree().children:
|
||||
# for inside in outside.query_tree().children:
|
||||
# if done_looping: break
|
||||
# if inside.id == window_number:
|
||||
# self.window = inside
|
||||
# self.parent = outside
|
||||
# done_looping = True
|
||||
# break
|
||||
self.title = title
|
||||
self.hud = None # specified later
|
||||
break
|
||||
|
||||
if window_number is None:
|
||||
if self.number is None:
|
||||
return None
|
||||
|
||||
# my_geo = self.window.get_geometry()
|
||||
# pa_geo = self.parent.get_geometry()
|
||||
#
|
||||
# self.x = pa_geo.x + my_geo.x
|
||||
# self.y = pa_geo.y + my_geo.y
|
||||
# self.width = my_geo.width
|
||||
# self.height = my_geo.height
|
||||
# self.exe = self.window.get_wm_class()[0]
|
||||
# self.title = self.window.get_wm_name()
|
||||
# self.site = ""
|
||||
# self.hud = None
|
||||
self.window = self.get_window_from_xid(self.number)
|
||||
self.parent = self.window.query_tree().parent
|
||||
|
||||
# window_string = str(self.window)
|
||||
mo = re.match('Xlib\.display\.Window\(([\dxabcdef]+)', window_string)
|
||||
if not mo:
|
||||
print "Not matched"
|
||||
self.gdk_handle = None
|
||||
else:
|
||||
self.number = int( mo.group(1), 0)
|
||||
print "number =", self.number
|
||||
# self.gdk_handle = gtk.gdk.window_foreign_new(int(self.number))
|
||||
def get_window_from_xid(self, id):
|
||||
for outside in root.query_tree().children:
|
||||
if outside.id == id:
|
||||
return outside
|
||||
for inside in outside.query_tree().children:
|
||||
if inside.id == id:
|
||||
return inside
|
||||
return None
|
||||
|
||||
def get_geometry(self):
|
||||
try:
|
||||
my_geo = self.window.get_geometry()
|
||||
pa_geo = self.parent.get_geometry()
|
||||
return {'x' : pa_geo.x + my_geo.x,
|
||||
'y' : pa_geo.y + my_geo.y,
|
||||
return {'x' : my_geo.x + pa_geo.x,
|
||||
'y' : my_geo.y + pa_geo.y,
|
||||
'width' : my_geo.width,
|
||||
'height' : my_geo.height
|
||||
}
|
||||
|
|
@ -127,7 +83,13 @@ class Table(Table_Window):
|
|||
return None
|
||||
|
||||
def get_window_title(self):
|
||||
return self.window.get_wm_name()
|
||||
s = os.popen("xwininfo -wm -id %d" % self.number).read()
|
||||
mo = re.search('"(.+)"', s)
|
||||
try:
|
||||
return mo.group(1)
|
||||
except AttributeError:
|
||||
return None
|
||||
|
||||
|
||||
def topify(self, hud):
|
||||
hud.main_window.gdkhandle = gtk.gdk.window_foreign_new(hud.main_window.window.xid)
|
||||
|
|
|
|||
426
pyfpdb/fpdb.pyw
426
pyfpdb/fpdb.pyw
|
|
@ -15,6 +15,9 @@
|
|||
#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 L10n
|
||||
_ = L10n.get_translation()
|
||||
|
||||
import os
|
||||
import sys
|
||||
import re
|
||||
|
|
@ -22,26 +25,26 @@ import Queue
|
|||
|
||||
# if path is set to use an old version of python look for a new one:
|
||||
# (does this work in linux?)
|
||||
if os.name == 'nt' and sys.version[0:3] not in ('2.5', '2.6') and '-r' not in sys.argv:
|
||||
if os.name == 'nt' and sys.version[0:3] not in ('2.5', '2.6', '2.7') and '-r' not in sys.argv:
|
||||
#print "old path =", os.environ['PATH']
|
||||
dirs = re.split(os.pathsep, os.environ['PATH'])
|
||||
# remove any trailing / or \ chars from dirs:
|
||||
dirs = [re.sub('[\\/]$','',p) for p in dirs]
|
||||
# remove any dirs containing 'python' apart from those ending in 'python25', 'python26' or 'python':
|
||||
dirs = [p for p in dirs if not re.search('python', p, re.I) or re.search('python25$', p, re.I) or re.search('python26$', p, re.I)]
|
||||
dirs = [p for p in dirs if not re.search('python', p, re.I) or re.search('python25$', p, re.I) or re.search('python26$', p, re.I) or re.search('python27$', p, re.I)]
|
||||
tmppath = ";".join(dirs)
|
||||
#print "new path =", tmppath
|
||||
if re.search('python', tmppath, re.I):
|
||||
os.environ['PATH'] = tmppath
|
||||
print "Python " + sys.version[0:3] + ' - press return to continue\n'
|
||||
print "Python " + sys.version[0:3] + _(' - press return to continue\n')
|
||||
sys.stdin.readline()
|
||||
if os.name=='nt':
|
||||
os.execvpe('pythonw.exe', ('pythonw.exe', 'fpdb.pyw', '-r'), os.environ) # first arg is ignored (name of program being run)
|
||||
else:
|
||||
os.execvpe('python', ('python', 'fpdb.pyw', '-r'), os.environ) # first arg is ignored (name of program being run)
|
||||
else:
|
||||
print "\npython 2.5 not found, please install python 2.5 or 2.6 for fpdb\n"
|
||||
raw_input("Press ENTER to continue.")
|
||||
print _("\npython 2.5-2.7 not found, please install python 2.5, 2.6 or 2.7 for fpdb\n")
|
||||
raw_input(_("Press ENTER to continue."))
|
||||
exit()
|
||||
else:
|
||||
pass
|
||||
|
|
@ -52,8 +55,8 @@ if os.name == 'nt':
|
|||
import win32api
|
||||
import win32con
|
||||
except ImportError:
|
||||
print "We appear to be running in Windows, but the Windows Python Extensions are not loading. Please install the PYWIN32 package from http://sourceforge.net/projects/pywin32/"
|
||||
raw_input("Press ENTER to continue.")
|
||||
print _("We appear to be running in Windows, but the Windows Python Extensions are not loading. Please install the PYWIN32 package from http://sourceforge.net/projects/pywin32/")
|
||||
raw_input(_("Press ENTER to continue."))
|
||||
exit()
|
||||
|
||||
print "Python " + sys.version[0:3] + '...'
|
||||
|
|
@ -74,8 +77,8 @@ try:
|
|||
import gtk
|
||||
import pango
|
||||
except:
|
||||
print "Unable to load PYGTK modules required for GUI. Please install PyCairo, PyGObject, and PyGTK from www.pygtk.org."
|
||||
raw_input("Press ENTER to continue.")
|
||||
print _("Unable to load PyGTK modules required for GUI. Please install PyCairo, PyGObject, and PyGTK from www.pygtk.org.")
|
||||
raw_input(_("Press ENTER to continue."))
|
||||
exit()
|
||||
|
||||
import interlocks
|
||||
|
|
@ -103,12 +106,14 @@ import GuiPrefs
|
|||
import GuiLogView
|
||||
import GuiDatabase
|
||||
import GuiBulkImport
|
||||
import ImapFetcher
|
||||
import GuiImapFetcher
|
||||
import GuiRingPlayerStats
|
||||
import GuiTourneyPlayerStats
|
||||
import GuiTourneyViewer
|
||||
import GuiPositionalStats
|
||||
import GuiAutoImport
|
||||
import GuiGraphViewer
|
||||
import GuiTourneyGraphViewer
|
||||
import GuiSessionViewer
|
||||
import SQL
|
||||
import Database
|
||||
|
|
@ -116,7 +121,7 @@ import Configuration
|
|||
import Exceptions
|
||||
import Stats
|
||||
|
||||
VERSION = "0.20.903 plus git"
|
||||
VERSION = "0.20.906 plus git"
|
||||
|
||||
|
||||
class fpdb:
|
||||
|
|
@ -231,19 +236,19 @@ class 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("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_copyright(_("Copyright 2008-2010, Steffen, Eratosthenes, Carl Gherardi, Eric Blade, _mt, sqlcoder, Bostik, and others"))
|
||||
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',
|
||||
'Eric Blade', '_mt', 'sqlcoder', 'Bostik', 'and others'])
|
||||
'Eric Blade', '_mt', 'sqlcoder', 'Bostik', _('and others')])
|
||||
dia.set_program_name("Free Poker Database (FPDB)")
|
||||
|
||||
db_version = ""
|
||||
#if self.db is not None:
|
||||
# db_version = self.db.get_version()
|
||||
nums = [ ('Operating System', os.name)
|
||||
nums = [ (_('Operating System'), os.name)
|
||||
, ('Python', sys.version[0:3])
|
||||
, ('GTK+', '.'.join([str(x) for x in gtk.gtk_version]))
|
||||
, ('PyGTK', '.'.join([str(x) for x in gtk.pygtk_version]))
|
||||
|
|
@ -251,7 +256,8 @@ class fpdb:
|
|||
, ('numpy', numpy_version)
|
||||
, ('sqlite3', sqlite3_version)
|
||||
, ('sqlite', sqlite_version)
|
||||
, ('database', self.settings['db-server'] + db_version)
|
||||
, ('fpdb version', VERSION)
|
||||
, ('database used', self.settings['db-server'])
|
||||
]
|
||||
versions = gtk.TextBuffer()
|
||||
w = 20 # width used for module names and version numbers
|
||||
|
|
@ -263,24 +269,24 @@ class fpdb:
|
|||
view.show()
|
||||
dia.vbox.pack_end(view, True, True, 2)
|
||||
|
||||
l = gtk.Label("Your config file is: "+self.config.file)
|
||||
l = gtk.Label(_("Your config file is: ")+self.config.file)
|
||||
l.set_alignment(0.5, 0.5)
|
||||
l.show()
|
||||
dia.vbox.pack_end(l, True, True, 2)
|
||||
|
||||
l = gtk.Label('Version Information:')
|
||||
l = gtk.Label(_('Version Information:'))
|
||||
l.set_alignment(0.5, 0.5)
|
||||
l.show()
|
||||
dia.vbox.pack_end(l, True, True, 2)
|
||||
|
||||
dia.run()
|
||||
dia.destroy()
|
||||
log.debug("Threads: ")
|
||||
log.debug(_("Threads: "))
|
||||
for t in self.threads:
|
||||
log.debug("........." + str(t.__class__))
|
||||
|
||||
def dia_preferences(self, widget, data=None):
|
||||
dia = gtk.Dialog("Preferences",
|
||||
dia = gtk.Dialog(_("Preferences"),
|
||||
self.window,
|
||||
gtk.DIALOG_MODAL | gtk.DIALOG_DESTROY_WITH_PARENT,
|
||||
(gtk.STOCK_CANCEL, gtk.RESPONSE_REJECT,
|
||||
|
|
@ -298,8 +304,7 @@ class fpdb:
|
|||
dia.destroy()
|
||||
else:
|
||||
dia.destroy() # destroy prefs before raising warning, otherwise parent is dia rather than self.window
|
||||
self.warning_box("Updated preferences have not been loaded because "
|
||||
+ "windows are open. Re-start fpdb to load them.")
|
||||
self.warning_box(_("Updated preferences have not been loaded because windows are open. Re-start fpdb to load them."))
|
||||
else:
|
||||
dia.destroy()
|
||||
|
||||
|
|
@ -309,7 +314,7 @@ class fpdb:
|
|||
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
|
||||
dia = gtk.Dialog("Maintain Databases",
|
||||
dia = gtk.Dialog(_("Maintain Databases"),
|
||||
self.window,
|
||||
gtk.DIALOG_MODAL | gtk.DIALOG_DESTROY_WITH_PARENT,
|
||||
(gtk.STOCK_CANCEL, gtk.RESPONSE_REJECT,
|
||||
|
|
@ -319,27 +324,26 @@ class fpdb:
|
|||
prefs = GuiDatabase.GuiDatabase(self.config, self.window, dia)
|
||||
response = dia.run()
|
||||
if response == gtk.RESPONSE_ACCEPT:
|
||||
log.info('saving updated db data')
|
||||
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))
|
||||
log.info(_('guidb response was ')+str(response))
|
||||
|
||||
self.release_global_lock()
|
||||
|
||||
dia.destroy()
|
||||
else:
|
||||
self.warning_box("Cannot open Database Maintenance window because "
|
||||
+ "other windows have been opened. Re-start fpdb to use this option.")
|
||||
self.warning_box(_("Cannot open Database Maintenance window because other windows have been opened. Re-start fpdb to use this option."))
|
||||
|
||||
def dia_database_stats(self, widget, data=None):
|
||||
self.warning_box(str="Number of Hands: "+str(self.db.getHandCount())+
|
||||
"\nNumber of Tourneys: "+str(self.db.getTourneyCount())+
|
||||
"\nNumber of TourneyTypes: "+str(self.db.getTourneyTypeCount()),
|
||||
diatitle="Database Statistics")
|
||||
self.warning_box(str=_("Number of Hands: ")+str(self.db.getHandCount())+
|
||||
_("\nNumber of Tourneys: ")+str(self.db.getTourneyCount())+
|
||||
_("\nNumber of TourneyTypes: ")+str(self.db.getTourneyTypeCount()),
|
||||
diatitle=_("Database Statistics"))
|
||||
#end def dia_database_stats
|
||||
|
||||
def diaHudConfigurator(self, widget, data=None):
|
||||
|
|
@ -348,13 +352,13 @@ class fpdb:
|
|||
self.hudConfiguratorColumns=None
|
||||
self.hudConfiguratorGame=None
|
||||
|
||||
diaSelections = gtk.Dialog("HUD Configurator - choose category",
|
||||
diaSelections = gtk.Dialog(_("HUD Configurator - choose category"),
|
||||
self.window,
|
||||
gtk.DIALOG_MODAL | gtk.DIALOG_DESTROY_WITH_PARENT,
|
||||
(gtk.STOCK_OK, gtk.RESPONSE_ACCEPT,
|
||||
gtk.STOCK_CANCEL, gtk.RESPONSE_REJECT))
|
||||
|
||||
label=gtk.Label("Please select the game category for which you want to configure HUD stats:")
|
||||
label=gtk.Label(_("Please select the game category for which you want to configure HUD stats:"))
|
||||
diaSelections.vbox.add(label)
|
||||
label.show()
|
||||
|
||||
|
|
@ -406,25 +410,25 @@ class fpdb:
|
|||
"""shows dialogue with Table of ComboBoxes to allow choosing of HUD stats"""
|
||||
#TODO: add notices to hud configurator: no duplicates, no empties, display options
|
||||
#TODO: show explanation of what each stat means
|
||||
diaHudTable = gtk.Dialog("HUD Configurator - please choose your stats",
|
||||
diaHudTable = gtk.Dialog(_("HUD Configurator - please choose your stats"),
|
||||
self.window,
|
||||
gtk.DIALOG_MODAL | gtk.DIALOG_DESTROY_WITH_PARENT,
|
||||
(gtk.STOCK_SAVE, gtk.RESPONSE_ACCEPT,
|
||||
gtk.STOCK_CANCEL, gtk.RESPONSE_REJECT))
|
||||
|
||||
label=gtk.Label("Please choose the stats you wish to use in the below table.")
|
||||
label=gtk.Label(_("Please choose the stats you wish to use in the below table."))
|
||||
diaHudTable.vbox.add(label)
|
||||
label.show()
|
||||
|
||||
label=gtk.Label("Note that you may not select any stat more than once or it will crash.")
|
||||
label=gtk.Label(_("Note that you may not select any stat more than once or it will crash."))
|
||||
diaHudTable.vbox.add(label)
|
||||
label.show()
|
||||
|
||||
label=gtk.Label("It is not currently possible to select \"empty\" or anything else to that end.")
|
||||
label=gtk.Label(_("It is not currently possible to select \"empty\" or anything else to that end."))
|
||||
diaHudTable.vbox.add(label)
|
||||
label.show()
|
||||
|
||||
label=gtk.Label("To configure things like colouring you will still have to manually edit your HUD_config.xml.")
|
||||
label=gtk.Label(_("To configure things like colouring you will still have to use the Preferences dialogue or manually edit your HUD_config.xml."))
|
||||
diaHudTable.vbox.add(label)
|
||||
label.show()
|
||||
|
||||
|
|
@ -502,9 +506,6 @@ class fpdb:
|
|||
dumpFile.close()
|
||||
#end def dia_database_stats
|
||||
|
||||
def dia_licensing(self, widget, data=None):
|
||||
self.warning_box("Unimplemented: Licensing")
|
||||
|
||||
def dia_load_profile(self, widget, data=None):
|
||||
"""Dialogue to select a file to load a profile from"""
|
||||
if self.obtain_global_lock("fpdb.dia_load_profile"): # returns true if successful
|
||||
|
|
@ -534,9 +535,10 @@ class fpdb:
|
|||
|
||||
#lock_released = False
|
||||
dia_confirm = gtk.MessageDialog(parent=self.window, flags=gtk.DIALOG_DESTROY_WITH_PARENT, type=gtk.MESSAGE_WARNING,
|
||||
buttons=(gtk.BUTTONS_YES_NO), message_format="Confirm deleting and recreating tables")
|
||||
diastring = "Please confirm that you want to (re-)create the tables. If there already are tables in the database " \
|
||||
+self.db.database+" on "+self.db.host+" they will be deleted.\nThis may take a while."
|
||||
buttons=(gtk.BUTTONS_YES_NO), message_format=_("Confirm deleting and recreating tables"))
|
||||
diastring = _("Please confirm that you want to (re-)create the tables.") \
|
||||
+ (_(" If there already are tables in the database %s on %s they will be deleted and you will have to re-import your histories.\n") % (self.db.database, self.db.host)) \
|
||||
+ _("This may take a while.")
|
||||
dia_confirm.format_secondary_text(diastring)#todo: make above string with bold for db, host and deleted
|
||||
# disable windowclose, do not want the the underlying processing interrupted mid-process
|
||||
dia_confirm.set_deletable(False)
|
||||
|
|
@ -561,14 +563,14 @@ class fpdb:
|
|||
# self.fdb_lock.fdb.recreate_tables()
|
||||
elif response == gtk.RESPONSE_NO:
|
||||
self.release_global_lock()
|
||||
print 'User cancelled recreating tables'
|
||||
print _('User cancelled recreating tables')
|
||||
#if not lock_released:
|
||||
#end def dia_recreate_tables
|
||||
|
||||
def dia_recreate_hudcache(self, widget, data=None):
|
||||
if self.obtain_global_lock("dia_recreate_hudcache"):
|
||||
self.dia_confirm = gtk.MessageDialog(parent=self.window, flags=gtk.DIALOG_DESTROY_WITH_PARENT, type=gtk.MESSAGE_WARNING, buttons=(gtk.BUTTONS_YES_NO), message_format="Confirm recreating HUD cache")
|
||||
diastring = "Please confirm that you want to re-create the HUD cache."
|
||||
diastring = _("Please confirm that you want to re-create the HUD cache.")
|
||||
self.dia_confirm.format_secondary_text(diastring)
|
||||
# disable windowclose, do not want the the underlying processing interrupted mid-process
|
||||
self.dia_confirm.set_deletable(False)
|
||||
|
|
@ -576,7 +578,7 @@ class fpdb:
|
|||
hb1 = gtk.HBox(True, 1)
|
||||
self.h_start_date = gtk.Entry(max=12)
|
||||
self.h_start_date.set_text( self.db.get_hero_hudcache_start() )
|
||||
lbl = gtk.Label(" Hero's cache starts: ")
|
||||
lbl = gtk.Label(_(" Hero's cache starts: "))
|
||||
btn = gtk.Button()
|
||||
btn.set_image(gtk.image_new_from_stock(gtk.STOCK_INDEX, gtk.ICON_SIZE_BUTTON))
|
||||
btn.connect('clicked', self.__calendar_dialog, self.h_start_date)
|
||||
|
|
@ -590,7 +592,7 @@ class fpdb:
|
|||
hb2 = gtk.HBox(True, 1)
|
||||
self.start_date = gtk.Entry(max=12)
|
||||
self.start_date.set_text( self.db.get_hero_hudcache_start() )
|
||||
lbl = gtk.Label(" Villains' cache starts: ")
|
||||
lbl = gtk.Label(_(" Villains' cache starts: "))
|
||||
btn = gtk.Button()
|
||||
btn.set_image(gtk.image_new_from_stock(gtk.STOCK_INDEX, gtk.ICON_SIZE_BUTTON))
|
||||
btn.connect('clicked', self.__calendar_dialog, self.start_date)
|
||||
|
|
@ -603,7 +605,7 @@ class fpdb:
|
|||
|
||||
response = self.dia_confirm.run()
|
||||
if response == gtk.RESPONSE_YES:
|
||||
lbl = gtk.Label(" Rebuilding HUD Cache ... ")
|
||||
lbl = gtk.Label(_(" Rebuilding HUD Cache ... "))
|
||||
self.dia_confirm.vbox.add(lbl)
|
||||
lbl.show()
|
||||
while gtk.events_pending():
|
||||
|
|
@ -611,7 +613,7 @@ class fpdb:
|
|||
|
||||
self.db.rebuild_hudcache( self.h_start_date.get_text(), self.start_date.get_text() )
|
||||
elif response == gtk.RESPONSE_NO:
|
||||
print 'User cancelled rebuilding hud cache'
|
||||
print _('User cancelled rebuilding hud cache')
|
||||
|
||||
self.dia_confirm.destroy()
|
||||
|
||||
|
|
@ -623,8 +625,8 @@ class fpdb:
|
|||
,flags=gtk.DIALOG_DESTROY_WITH_PARENT
|
||||
,type=gtk.MESSAGE_WARNING
|
||||
,buttons=(gtk.BUTTONS_YES_NO)
|
||||
,message_format="Confirm rebuilding database indexes")
|
||||
diastring = "Please confirm that you want to rebuild the database indexes."
|
||||
,message_format=_("Confirm rebuilding database indexes"))
|
||||
diastring = _("Please confirm that you want to rebuild the database indexes.")
|
||||
self.dia_confirm.format_secondary_text(diastring)
|
||||
# disable windowclose, do not want the the underlying processing interrupted mid-process
|
||||
self.dia_confirm.set_deletable(False)
|
||||
|
|
@ -632,24 +634,24 @@ class fpdb:
|
|||
response = self.dia_confirm.run()
|
||||
if response == gtk.RESPONSE_YES:
|
||||
#FIXME these progress messages do not seem to work in *nix
|
||||
lbl = gtk.Label(" Rebuilding Indexes ... ")
|
||||
lbl = gtk.Label(_(" Rebuilding Indexes ... "))
|
||||
self.dia_confirm.vbox.add(lbl)
|
||||
lbl.show()
|
||||
while gtk.events_pending():
|
||||
gtk.main_iteration_do(False)
|
||||
self.db.rebuild_indexes()
|
||||
|
||||
lbl.set_text(" Cleaning Database ... ")
|
||||
lbl.set_text(_(" Cleaning Database ... "))
|
||||
while gtk.events_pending():
|
||||
gtk.main_iteration_do(False)
|
||||
self.db.vacuumDB()
|
||||
|
||||
lbl.set_text(" Analyzing Database ... ")
|
||||
lbl.set_text(_(" Analyzing Database ... "))
|
||||
while gtk.events_pending():
|
||||
gtk.main_iteration_do(False)
|
||||
self.db.analyzeDB()
|
||||
elif response == gtk.RESPONSE_NO:
|
||||
print 'User cancelled rebuilding db indexes'
|
||||
print _('User cancelled rebuilding db indexes')
|
||||
|
||||
self.dia_confirm.destroy()
|
||||
|
||||
|
|
@ -710,13 +712,13 @@ class fpdb:
|
|||
d.set_destroy_with_parent(True)
|
||||
d.set_modal(True)
|
||||
|
||||
d.set_title('Pick a date')
|
||||
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 = gtk.Button(_('Done'))
|
||||
btn.connect('clicked', self.__get_date, cal, entry, d)
|
||||
|
||||
vb.pack_start(btn, expand=False, padding=4)
|
||||
|
|
@ -743,31 +745,8 @@ class fpdb:
|
|||
win.destroy()
|
||||
self.dia_confirm.set_modal(True)
|
||||
|
||||
def dia_regression_test(self, widget, data=None):
|
||||
self.warning_box("Unimplemented: Regression Test")
|
||||
#self.obtain_global_lock("dia_regression_test")
|
||||
#self.release_global_lock()
|
||||
|
||||
def dia_save_profile(self, widget, data=None):
|
||||
self.warning_box("Unimplemented: Save Profile (try saving a HUD layout, that should do it)")
|
||||
|
||||
def diaSetupWizard(self, path):
|
||||
diaSetupWizard = gtk.Dialog(title="Fatal Error - Config File Missing", parent=None, flags=0, buttons=(gtk.STOCK_QUIT,gtk.RESPONSE_OK))
|
||||
|
||||
label = gtk.Label("Please copy the config file from the docs folder to:")
|
||||
diaSetupWizard.vbox.add(label)
|
||||
label.show()
|
||||
|
||||
label = gtk.Label(path)
|
||||
diaSetupWizard.vbox.add(label)
|
||||
label.show()
|
||||
|
||||
label = gtk.Label("and edit it according to the install documentation at http://fpdb.sourceforge.net")
|
||||
diaSetupWizard.vbox.add(label)
|
||||
label.show()
|
||||
|
||||
response = diaSetupWizard.run()
|
||||
sys.exit(1)
|
||||
self.warning_box(_("Unimplemented: Save Profile (try saving a HUD layout, that should do it)"))
|
||||
|
||||
def get_menu(self, window):
|
||||
"""returns the menu for this program"""
|
||||
|
|
@ -783,17 +762,18 @@ class fpdb:
|
|||
<menuitem action="Quit"/>
|
||||
</menu>
|
||||
<menu action="import">
|
||||
<menuitem action="sethharchive"/>
|
||||
<menuitem action="bulkimp"/>
|
||||
<menuitem action="imapsummaries"/>
|
||||
<menuitem action="imapimport"/>
|
||||
<menuitem action="autoimp"/>
|
||||
</menu>
|
||||
<menu action="viewers">
|
||||
<menuitem action="autoimp"/>
|
||||
<menuitem action="hudConfigurator"/>
|
||||
<menuitem action="graphs"/>
|
||||
<menuitem action="tourneygraphs"/>
|
||||
<menuitem action="ringplayerstats"/>
|
||||
<menuitem action="tourneyplayerstats"/>
|
||||
<menuitem action="tourneyviewer"/>
|
||||
<menuitem action="posnstats"/>
|
||||
<menuitem action="sessionstats"/>
|
||||
</menu>
|
||||
|
|
@ -818,35 +798,36 @@ class fpdb:
|
|||
actiongroup = gtk.ActionGroup('UIManagerExample')
|
||||
|
||||
# Create actions
|
||||
actiongroup.add_actions([('main', None, '_Main'),
|
||||
('Quit', gtk.STOCK_QUIT, '_Quit', None, 'Quit the Program', self.quit),
|
||||
('LoadProf', None, '_Load Profile (broken)', '<control>L', 'Load your profile', self.dia_load_profile),
|
||||
('SaveProf', None, '_Save Profile (todo)', '<control>S', 'Save your profile', self.dia_save_profile),
|
||||
('Preferences', None, 'Pre_ferences', '<control>F', 'Edit your preferences', self.dia_preferences),
|
||||
('import', None, '_Import'),
|
||||
('sethharchive', None, '_Set HandHistory Archive Directory', None, 'Set HandHistory Archive Directory', self.select_hhArchiveBase),
|
||||
('bulkimp', None, '_Bulk Import', '<control>B', 'Bulk Import', self.tab_bulk_import),
|
||||
('imapsummaries', None, '_Import Tourney Summaries through eMail/IMAP', '<control>I', 'Auto Import and HUD', self.import_imap_summaries),
|
||||
('viewers', None, '_Viewers'),
|
||||
('autoimp', None, '_Auto Import and HUD', '<control>A', 'Auto Import and HUD', self.tab_auto_import),
|
||||
('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, 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),
|
||||
('database', None, '_Database'),
|
||||
('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),
|
||||
('databasestats', None, '_Statistics', None, 'View Database Statistics', self.dia_database_stats),
|
||||
('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, License, Copying', None, 'About the program', self.dia_about),
|
||||
actiongroup.add_actions([('main', None, _('_Main')),
|
||||
('Quit', gtk.STOCK_QUIT, _('_Quit'), None, 'Quit the Program', self.quit),
|
||||
('LoadProf', None, _('_Load Profile (broken)'), _('<control>L'), 'Load your profile', self.dia_load_profile),
|
||||
('SaveProf', None, _('_Save Profile (todo)'), _('<control>S'), 'Save your profile', self.dia_save_profile),
|
||||
('Preferences', None, _('Pre_ferences'), _('<control>F'), 'Edit your preferences', self.dia_preferences),
|
||||
('import', None, _('_Import')),
|
||||
('bulkimp', None, _('_Bulk Import'), _('<control>B'), 'Bulk Import', self.tab_bulk_import),
|
||||
('imapimport', None, _('_Import through eMail/IMAP'), _('<control>I'), 'Import through eMail/IMAP', self.tab_imap_import),
|
||||
('viewers', None, _('_Viewers')),
|
||||
('autoimp', None, _('_Auto Import and HUD'), _('<control>A'), 'Auto Import and HUD', self.tab_auto_import),
|
||||
('hudConfigurator', None, _('_HUD Configurator'), _('<control>H'), 'HUD Configurator', self.diaHudConfigurator),
|
||||
('graphs', None, _('_Graphs'), _('<control>G'), 'Graphs', self.tabGraphViewer),
|
||||
('tourneygraphs', None, _('Tourney Graphs'), None, 'TourneyGraphs', self.tabTourneyGraphViewer),
|
||||
('ringplayerstats', None, _('Ring _Player Stats (tabulated view, not on pgsql)'), _('<control>P'), 'Ring Player Stats (tabulated view)', self.tab_ring_player_stats),
|
||||
('tourneyplayerstats', None, _('_Tourney Player Stats (tabulated view, not on pgsql)'), _('<control>T'), 'Tourney Player Stats (tabulated view, mysql only)', self.tab_tourney_player_stats),
|
||||
('tourneyviewer', None, _('Tourney _Viewer'), None, 'Tourney Viewer)', self.tab_tourney_viewer_stats),
|
||||
('posnstats', None, _('P_ositional Stats (tabulated view, not on sqlite)'), _('<control>O'), 'Positional Stats (tabulated view)', self.tab_positional_stats),
|
||||
('sessionstats', None, _('Session Stats'), None, 'Session Stats', self.tab_session_stats),
|
||||
('database', None, _('_Database')),
|
||||
('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),
|
||||
('databasestats', None, _('_Statistics'), None, 'View Database Statistics', self.dia_database_stats),
|
||||
('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, License, Copying'), None, 'About the program', self.dia_about),
|
||||
])
|
||||
actiongroup.get_action('Quit').set_property('short-label', '_Quit')
|
||||
actiongroup.get_action('Quit').set_property('short-label', _('_Quit'))
|
||||
|
||||
uimanager.insert_action_group(actiongroup, 0)
|
||||
merge_id = uimanager.add_ui_from_string(fpdbmenu)
|
||||
|
|
@ -857,27 +838,22 @@ class fpdb:
|
|||
return menubar
|
||||
#end def get_menu
|
||||
|
||||
def import_imap_summaries(self, widget, data=None):
|
||||
result=ImapFetcher.run(self.config, self.db)
|
||||
#print "import imap summaries result:", result
|
||||
#end def import_imap_summaries
|
||||
|
||||
def load_profile(self, create_db = False):
|
||||
"""Loads profile from the provided path name."""
|
||||
self.config = Configuration.Config(file=options.config, dbname=options.dbname)
|
||||
if self.config.file_error:
|
||||
self.warning_box( "There is an error in your config file\n" + self.config.file
|
||||
+ "\n\nError is: " + str(self.config.file_error)
|
||||
, diatitle="CONFIG FILE ERROR" )
|
||||
self.warning_box(_("There is an error in your config file\n") + self.config.file
|
||||
+ _("\n\nError is: ") + str(self.config.file_error)
|
||||
, diatitle=_("CONFIG FILE ERROR"))
|
||||
sys.exit()
|
||||
|
||||
log = Configuration.get_logger("logging.conf", "fpdb", log_dir=self.config.dir_log)
|
||||
print "Logfile is " + os.path.join(self.config.dir_log, self.config.log_file) + "\n"
|
||||
print (_("Logfile is %s\n") % os.path.join(self.config.dir_log, self.config.log_file))
|
||||
if self.config.example_copy:
|
||||
self.info_box( "Config file"
|
||||
, "has been created at:\n%s.\n" % self.config.file
|
||||
+ "Edit your screen_name and hand history path in the supported_sites "
|
||||
+ "section of the Preferences window (Main menu) before trying to import hands.")
|
||||
self.info_box(_("Config file")
|
||||
, _("has been created at:\n%s.\n") % self.config.file
|
||||
+ _("Edit your screen_name and hand history path in the supported_sites section of the Preferences window (Main menu) before trying to import hands."))
|
||||
self.settings = {}
|
||||
self.settings['global_lock'] = self.lock
|
||||
if (os.sep=="/"):
|
||||
|
|
@ -887,11 +863,10 @@ class fpdb:
|
|||
|
||||
self.settings.update({'cl_options': cl_options})
|
||||
self.settings.update(self.config.get_db_parameters())
|
||||
self.settings.update(self.config.get_tv_parameters())
|
||||
self.settings.update(self.config.get_import_parameters())
|
||||
self.settings.update(self.config.get_default_paths())
|
||||
|
||||
if self.db is not None and self.db.connected:
|
||||
if self.db is not None and self.db.is_connected():
|
||||
self.db.disconnect()
|
||||
|
||||
self.sql = SQL.Sql(db_server = self.settings['db-server'])
|
||||
|
|
@ -900,20 +875,22 @@ class fpdb:
|
|||
self.db = Database.Database(self.config, sql = self.sql)
|
||||
if self.db.get_backend_name() == 'SQLite':
|
||||
# tell sqlite users where the db file is
|
||||
print "Connected to SQLite: %(database)s" % {'database':self.db.db_path}
|
||||
print (_("Connected to SQLite: %s") % self.db.db_path)
|
||||
except Exceptions.FpdbMySQLAccessDenied:
|
||||
err_msg = "MySQL Server reports: Access denied. Are your permissions set correctly?"
|
||||
err_msg = _("MySQL Server reports: Access denied. Are your permissions set correctly?")
|
||||
except Exceptions.FpdbMySQLNoDatabase:
|
||||
err_msg = "MySQL client reports: 2002 or 2003 error. Unable to connect - " \
|
||||
+ "Please check that the MySQL service has been started"
|
||||
err_msg = _("MySQL client reports: 2002 or 2003 error. Unable to connect - ") \
|
||||
+ _("Please check that the MySQL service has been started")
|
||||
except Exceptions.FpdbPostgresqlAccessDenied:
|
||||
err_msg = "Postgres Server reports: Access denied. Are your permissions set correctly?"
|
||||
err_msg = _("PostgreSQL Server reports: Access denied. Are your permissions set correctly?")
|
||||
except Exceptions.FpdbPostgresqlNoDatabase:
|
||||
err_msg = "Postgres client reports: Unable to connect - " \
|
||||
+ "Please check that the Postgres service has been started"
|
||||
err_msg = _("PostgreSQL client reports: Unable to connect - ") \
|
||||
+ _("Please check that the PostgreSQL service has been started")
|
||||
if err_msg is not None:
|
||||
self.db = None
|
||||
self.warning_box(err_msg)
|
||||
if self.db is not None and not self.db.is_connected():
|
||||
self.db = None
|
||||
|
||||
# except FpdbMySQLFailedError:
|
||||
# self.warning_box("Unable to connect to MySQL! Is the MySQL server running?!", "FPDB ERROR")
|
||||
|
|
@ -932,17 +909,17 @@ class fpdb:
|
|||
# sys.stderr.write("Failed to connect to %s database with username %s." % (self.settings['db-server'], self.settings['db-user']))
|
||||
|
||||
if self.db is not None and self.db.wrongDbVersion:
|
||||
diaDbVersionWarning = gtk.Dialog(title="Strong Warning - Invalid database version", parent=None, flags=0, buttons=(gtk.STOCK_OK,gtk.RESPONSE_OK))
|
||||
diaDbVersionWarning = gtk.Dialog(title=_("Strong Warning - Invalid database version"), parent=None, flags=0, buttons=(gtk.STOCK_OK,gtk.RESPONSE_OK))
|
||||
|
||||
label = gtk.Label("An invalid DB version or missing tables have been detected.")
|
||||
label = gtk.Label(_("An invalid DB version or missing tables have been detected."))
|
||||
diaDbVersionWarning.vbox.add(label)
|
||||
label.show()
|
||||
|
||||
label = gtk.Label("This error is not necessarily fatal but it is strongly recommended that you recreate the tables by using the Database menu.")
|
||||
label = gtk.Label(_("This error is not necessarily fatal but it is strongly recommended that you recreate the tables by using the Database menu."))
|
||||
diaDbVersionWarning.vbox.add(label)
|
||||
label.show()
|
||||
|
||||
label = gtk.Label("Not doing this will likely lead to misbehaviour including fpdb crashes, corrupt data etc.")
|
||||
label = gtk.Label(_("Not doing this will likely lead to misbehaviour including fpdb crashes, corrupt data etc."))
|
||||
diaDbVersionWarning.vbox.add(label)
|
||||
label.show()
|
||||
|
||||
|
|
@ -954,24 +931,21 @@ class fpdb:
|
|||
self.main_vbox.pack_end(self.status_bar, False, True, 0)
|
||||
self.status_bar.show()
|
||||
|
||||
if self.db is not None and self.db.connected:
|
||||
self.status_bar.set_text("Status: Connected to %s database named %s on host %s"
|
||||
if self.db is not None and self.db.is_connected():
|
||||
self.status_bar.set_text(_("Status: Connected to %s database named %s on host %s")
|
||||
% (self.db.get_backend_name(),self.db.database, self.db.host))
|
||||
# rollback to make sure any locks are cleared:
|
||||
self.db.rollback()
|
||||
|
||||
self.validate_config()
|
||||
|
||||
def not_implemented(self, widget, data=None):
|
||||
self.warning_box("Unimplemented menu entry")
|
||||
|
||||
def obtain_global_lock(self, source):
|
||||
ret = self.lock.acquire(source=source) # will return false if lock is already held
|
||||
if ret:
|
||||
print "\nGlobal lock taken by", source
|
||||
print (_("\nGlobal lock taken by %s") % source)
|
||||
self.lockTakenBy=source
|
||||
else:
|
||||
print "\nFailed to get global lock, it is currently held by", source
|
||||
print (_("\nFailed to get global lock, it is currently held by %s") % source)
|
||||
return ret
|
||||
# need to release it later:
|
||||
# self.lock.release()
|
||||
|
|
@ -981,19 +955,20 @@ class fpdb:
|
|||
#FIXME get two "quitting normally" messages, following the addition of the self.window.destroy() call
|
||||
# ... because self.window.destroy() leads to self.destroy() which calls this!
|
||||
if not self.quitting:
|
||||
print "Quitting normally"
|
||||
print _("Quitting normally")
|
||||
self.quitting = True
|
||||
# TODO: check if current settings differ from profile, if so offer to save or abort
|
||||
|
||||
if self.db!=None:
|
||||
if self.db.backend==self.db.MYSQL_INNODB:
|
||||
try:
|
||||
if self.db is not None and self.db.connected():
|
||||
import _mysql_exceptions
|
||||
if self.db is not None and self.db.is_connected():
|
||||
self.db.disconnect()
|
||||
except _mysql_exceptions.OperationalError: # oh, damn, we're already disconnected
|
||||
pass
|
||||
else:
|
||||
if self.db is not None and self.db.connected():
|
||||
if self.db is not None and self.db.is_connected():
|
||||
self.db.disconnect()
|
||||
else:
|
||||
pass
|
||||
|
|
@ -1005,70 +980,93 @@ class fpdb:
|
|||
def release_global_lock(self):
|
||||
self.lock.release()
|
||||
self.lockTakenBy=None
|
||||
print "Global lock released.\n"
|
||||
print _("Global lock released.\n")
|
||||
|
||||
def tab_auto_import(self, widget, data=None):
|
||||
"""opens the auto import tab"""
|
||||
new_aimp_thread = GuiAutoImport.GuiAutoImport(self.settings, self.config, self.sql, self.window)
|
||||
self.threads.append(new_aimp_thread)
|
||||
aimp_tab=new_aimp_thread.get_vbox()
|
||||
self.add_and_display_tab(aimp_tab, "Auto Import")
|
||||
self.add_and_display_tab(aimp_tab, _("Auto Import"))
|
||||
|
||||
def tab_bulk_import(self, widget, data=None):
|
||||
"""opens a tab for bulk importing"""
|
||||
new_import_thread = GuiBulkImport.GuiBulkImport(self.settings, self.config, self.sql)
|
||||
new_import_thread = GuiBulkImport.GuiBulkImport(self.settings, self.config, self.sql, self.window)
|
||||
self.threads.append(new_import_thread)
|
||||
bulk_tab=new_import_thread.get_vbox()
|
||||
self.add_and_display_tab(bulk_tab, "Bulk Import")
|
||||
self.add_and_display_tab(bulk_tab, _("Bulk Import"))
|
||||
|
||||
def tab_imap_import(self, widget, data=None):
|
||||
new_thread = GuiImapFetcher.GuiImapFetcher(self.config, self.db, self.sql, self.window)
|
||||
self.threads.append(new_thread)
|
||||
tab=new_thread.get_vbox()
|
||||
self.add_and_display_tab(tab, _("eMail Import"))
|
||||
#end def tab_import_imap_summaries
|
||||
|
||||
def tab_ring_player_stats(self, widget, data=None):
|
||||
new_ps_thread = GuiRingPlayerStats.GuiRingPlayerStats(self.config, self.sql, self.window)
|
||||
self.threads.append(new_ps_thread)
|
||||
ps_tab=new_ps_thread.get_vbox()
|
||||
self.add_and_display_tab(ps_tab, "Ring Player Stats")
|
||||
self.add_and_display_tab(ps_tab, _("Ring Player Stats"))
|
||||
|
||||
def tab_tourney_player_stats(self, widget, data=None):
|
||||
new_ps_thread = GuiTourneyPlayerStats.GuiTourneyPlayerStats(self.config, self.db, self.sql, self.window)
|
||||
self.threads.append(new_ps_thread)
|
||||
ps_tab=new_ps_thread.get_vbox()
|
||||
self.add_and_display_tab(ps_tab, "Tourney Player Stats")
|
||||
self.add_and_display_tab(ps_tab, _("Tourney Player Stats"))
|
||||
|
||||
def tab_tourney_viewer_stats(self, widget, data=None):
|
||||
new_thread = GuiTourneyViewer.GuiTourneyViewer(self.config, self.db, self.sql, self.window)
|
||||
self.threads.append(new_thread)
|
||||
tab=new_thread.get_vbox()
|
||||
self.add_and_display_tab(tab, _("Tourney Viewer"))
|
||||
|
||||
def tab_positional_stats(self, widget, data=None):
|
||||
new_ps_thread = GuiPositionalStats.GuiPositionalStats(self.config, self.sql)
|
||||
self.threads.append(new_ps_thread)
|
||||
ps_tab=new_ps_thread.get_vbox()
|
||||
self.add_and_display_tab(ps_tab, "Positional Stats")
|
||||
self.add_and_display_tab(ps_tab, _("Positional Stats"))
|
||||
|
||||
def tab_session_stats(self, widget, data=None):
|
||||
new_ps_thread = GuiSessionViewer.GuiSessionViewer(self.config, self.sql, self.window)
|
||||
self.threads.append(new_ps_thread)
|
||||
ps_tab=new_ps_thread.get_vbox()
|
||||
self.add_and_display_tab(ps_tab, "Session Stats")
|
||||
self.add_and_display_tab(ps_tab, _("Session Stats"))
|
||||
|
||||
def tab_main_help(self, widget, data=None):
|
||||
"""Displays a tab with the main fpdb help screen"""
|
||||
mh_tab=gtk.Label("""Welcome to Fpdb!
|
||||
mh_tab=gtk.Label(_("""Fpdb needs translators!
|
||||
If you speak another language and have a few minutes or more to spare get in touch by emailing steffen@schaumburger.info
|
||||
|
||||
Welcome to Fpdb!
|
||||
To be notified of new snapshots and releases go to https://lists.sourceforge.net/lists/listinfo/fpdb-announce and subscribe.
|
||||
If you want to follow development more closely go to https://lists.sourceforge.net/lists/listinfo/fpdb-main and subscribe.
|
||||
|
||||
This program is currently in an alpha-state, so our database format is still sometimes changed.
|
||||
You should therefore always keep your hand history files so that you can re-import after an update, if necessary.
|
||||
|
||||
For documentation please visit our website at http://fpdb.sourceforge.net/.
|
||||
For documentation please visit our website/wiki at http://fpdb.sourceforge.net/.
|
||||
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.
|
||||
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")
|
||||
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 tabGraphViewer(self, widget, data=None):
|
||||
"""opens a graph viewer tab"""
|
||||
new_gv_thread = GuiGraphViewer.GuiGraphViewer(self.sql, self.config, self.window)
|
||||
self.threads.append(new_gv_thread)
|
||||
gv_tab = new_gv_thread.get_vbox()
|
||||
self.add_and_display_tab(gv_tab, "Graphs")
|
||||
self.add_and_display_tab(gv_tab, _("Graphs"))
|
||||
|
||||
def tabTourneyGraphViewer(self, widget, data=None):
|
||||
"""opens a graph viewer tab"""
|
||||
new_gv_thread = GuiTourneyGraphViewer.GuiTourneyGraphViewer(self.sql, self.config, self.window)
|
||||
self.threads.append(new_gv_thread)
|
||||
gv_tab = new_gv_thread.get_vbox()
|
||||
self.add_and_display_tab(gv_tab, _("Tourney Graphs"))
|
||||
|
||||
def __init__(self):
|
||||
# no more than 1 process can this lock at a time:
|
||||
|
|
@ -1077,6 +1075,7 @@ You can find the full license texts in agpl-3.0.txt, gpl-2.0.txt, gpl-3.0.txt an
|
|||
self.status_bar = None
|
||||
self.quitting = False
|
||||
|
||||
self.visible = False
|
||||
self.window = gtk.Window(gtk.WINDOW_TOPLEVEL)
|
||||
self.window.connect("delete_event", self.delete_event)
|
||||
self.window.connect("destroy", self.destroy)
|
||||
|
|
@ -1114,12 +1113,13 @@ You can find the full license texts in agpl-3.0.txt, gpl-2.0.txt, gpl-3.0.txt an
|
|||
self.tab_main_help(None, None)
|
||||
|
||||
self.window.show()
|
||||
self.visible = True # Flip on
|
||||
self.load_profile(create_db = True)
|
||||
|
||||
if not options.errorsToConsole:
|
||||
fileName = os.path.join(self.config.dir_log, 'fpdb-errors.txt')
|
||||
print "\nNote: error output is being diverted to fpdb-errors.txt and HUD-errors.txt in:\n" \
|
||||
+ self.config.dir_log + "\nAny major error will be reported there _only_.\n"
|
||||
print (_("\nNote: error output is being diverted to fpdb-errors.txt and HUD-errors.txt in: %s") % self.config.dir_log) \
|
||||
+ _("\nAny major error will be reported there _only_.\n")
|
||||
errorFile = open(fileName, 'w', 0)
|
||||
sys.stderr = errorFile
|
||||
|
||||
|
|
@ -1128,10 +1128,13 @@ You can find the full license texts in agpl-3.0.txt, gpl-2.0.txt, gpl-3.0.txt an
|
|||
cards = os.path.join(os.getcwd(), '..','gfx','fpdb-cards.png')
|
||||
if os.path.exists(cards):
|
||||
self.statusIcon.set_from_file(cards)
|
||||
self.window.set_icon_from_file(cards)
|
||||
elif os.path.exists('/usr/share/pixmaps/fpdb-cards.png'):
|
||||
self.statusIcon.set_from_file('/usr/share/pixmaps/fpdb-cards.png')
|
||||
self.window.set_icon_from_file('/usr/share/pixmaps/fpdb-cards.png')
|
||||
else:
|
||||
self.statusIcon.set_from_stock(gtk.STOCK_HOME)
|
||||
self.window.set_icon_stock(gtk.STOCK_HOME)
|
||||
self.statusIcon.set_tooltip("Free Poker Database")
|
||||
self.statusIcon.connect('activate', self.statusicon_activate)
|
||||
self.statusMenu = gtk.Menu()
|
||||
|
|
@ -1147,23 +1150,33 @@ You can find the full license texts in agpl-3.0.txt, gpl-2.0.txt, gpl-3.0.txt an
|
|||
self.statusIcon.set_visible(True)
|
||||
|
||||
self.window.connect('window-state-event', self.window_state_event_cb)
|
||||
sys.stderr.write("fpdb starting ...")
|
||||
sys.stderr.write(_("fpdb starting ..."))
|
||||
|
||||
|
||||
def __iconify(self):
|
||||
self.visible = False
|
||||
self.window.set_skip_taskbar_hint(True)
|
||||
self.window.set_skip_pager_hint(True)
|
||||
|
||||
def __deiconify(self):
|
||||
self.visible = True
|
||||
self.window.set_skip_taskbar_hint(False)
|
||||
self.window.set_skip_pager_hint(False)
|
||||
|
||||
def window_state_event_cb(self, window, event):
|
||||
# Deal with iconification first
|
||||
if event.changed_mask & gtk.gdk.WINDOW_STATE_ICONIFIED:
|
||||
# -20 = GWL_EXSTYLE can't find it in the pywin32 libs
|
||||
#bits = win32api.GetWindowLong(self.window.window.handle, -20)
|
||||
#bits = bits ^ (win32con.WS_EX_TOOLWINDOW | win32con.WS_EX_APPWINDOW)
|
||||
|
||||
#win32api.SetWindowLong(self.window.window.handle, -20, bits)
|
||||
|
||||
if event.new_window_state & gtk.gdk.WINDOW_STATE_ICONIFIED:
|
||||
self.window.hide()
|
||||
self.window.set_skip_taskbar_hint(True)
|
||||
self.window.set_skip_pager_hint(True)
|
||||
self.__iconify()
|
||||
else:
|
||||
self.window.set_skip_taskbar_hint(False)
|
||||
self.window.set_skip_pager_hint(False)
|
||||
self.__deiconify()
|
||||
if not event.new_window_state & gtk.gdk.WINDOW_STATE_WITHDRAWN:
|
||||
return True
|
||||
# And then the tray icon click
|
||||
if event.new_window_state & gtk.gdk.WINDOW_STATE_WITHDRAWN:
|
||||
self.__iconify()
|
||||
else:
|
||||
self.__deiconify()
|
||||
# Tell GTK not to propagate this signal any further
|
||||
return True
|
||||
|
||||
|
|
@ -1181,11 +1194,9 @@ You can find the full license texts in agpl-3.0.txt, gpl-2.0.txt, gpl-3.0.txt an
|
|||
def statusicon_activate(self, widget, data = None):
|
||||
# Let's allow the tray icon to toggle window visibility, the way
|
||||
# most other apps work
|
||||
shown = self.window.get_property('visible')
|
||||
if shown:
|
||||
if self.visible:
|
||||
self.window.hide()
|
||||
else:
|
||||
self.window.show()
|
||||
self.window.present()
|
||||
|
||||
def info_box(self, str1, str2):
|
||||
|
|
@ -1196,7 +1207,7 @@ You can find the full license texts in agpl-3.0.txt, gpl-2.0.txt, gpl-3.0.txt an
|
|||
diapath.destroy()
|
||||
return response
|
||||
|
||||
def warning_box(self, str, diatitle="FPDB WARNING"):
|
||||
def warning_box(self, str, diatitle=_("FPDB WARNING")):
|
||||
diaWarning = gtk.Dialog(title=diatitle, parent=self.window, flags=gtk.DIALOG_DESTROY_WITH_PARENT, buttons=(gtk.STOCK_OK,gtk.RESPONSE_OK))
|
||||
|
||||
label = gtk.Label(str)
|
||||
|
|
@ -1208,6 +1219,7 @@ You can find the full license texts in agpl-3.0.txt, gpl-2.0.txt, gpl-3.0.txt an
|
|||
return response
|
||||
|
||||
def validate_config(self):
|
||||
# can this be removed now?
|
||||
if self.config.get_import_parameters().get('saveStarsHH'):
|
||||
hhbase = self.config.get_import_parameters().get("hhArchiveBase")
|
||||
hhbase = os.path.expanduser(hhbase)
|
||||
|
|
@ -1215,7 +1227,7 @@ You can find the full license texts in agpl-3.0.txt, gpl-2.0.txt, gpl-3.0.txt an
|
|||
hhdir = hhbase
|
||||
if not os.path.isdir(hhdir):
|
||||
diapath = gtk.MessageDialog(parent=None, flags=0, type=gtk.MESSAGE_WARNING, buttons=(gtk.BUTTONS_YES_NO), message_format="Setup hh dir")
|
||||
diastring = "WARNING: Unable to find output hh directory %s\n\n Press YES to create this directory, or NO to select a new one." % hhdir
|
||||
diastring = _("WARNING: Unable to find output hand history directory %s\n\n Press YES to create this directory, or NO to select a new one.") % hhdir
|
||||
diapath.format_secondary_text(diastring)
|
||||
response = diapath.run()
|
||||
diapath.destroy()
|
||||
|
|
@ -1223,19 +1235,53 @@ You can find the full license texts in agpl-3.0.txt, gpl-2.0.txt, gpl-3.0.txt an
|
|||
try:
|
||||
os.makedirs(hhdir)
|
||||
except:
|
||||
self.warning_box("WARNING: Unable to create hand output directory. Importing is not likely to work until this is fixed.")
|
||||
self.warning_box(_("WARNING: Unable to create hand output directory. Importing is not likely to work until this is fixed."))
|
||||
elif response == gtk.RESPONSE_NO:
|
||||
self.select_hhArchiveBase()
|
||||
|
||||
def select_hhArchiveBase(self, widget=None):
|
||||
fc = gtk.FileChooserDialog(title="Select HH Output Directory", parent=None, action=gtk.FILE_CHOOSER_ACTION_SELECT_FOLDER, buttons=(gtk.STOCK_OPEN,gtk.RESPONSE_OK), backend=None)
|
||||
fc.run()
|
||||
# TODO: We need to put in a Cancel button, and handle if the user presses that or the "Close" box without selecting anything as a cancel, and return to the prior setting
|
||||
#self.warning_box("You selected %s" % fc.get_filename())
|
||||
self.config.set_hhArchiveBase(fc.get_filename())
|
||||
self.config.save()
|
||||
self.load_profile() # we can't do this at the end of this func because load_profile calls this func
|
||||
fc.destroy() # TODO: loop this to make sure we get valid data back from it, because the open directory thing in GTK lets you select files and not select things and other stupid bullshit
|
||||
# check if sites in config file are in DB
|
||||
for site in self.config.get_supported_sites(True): # get site names from config file
|
||||
try:
|
||||
self.config.get_site_id(site) # and check against list from db
|
||||
except KeyError , exc:
|
||||
log.warning("site %s missing from db" % site)
|
||||
dia = gtk.MessageDialog(parent=None, flags=0, type=gtk.MESSAGE_WARNING, buttons=(gtk.BUTTONS_YES_NO), message_format="Unknown Site")
|
||||
diastring = _("WARNING: Unable to find site '%s'\n\nPress YES to add this site to the database.") % site
|
||||
dia.format_secondary_text(diastring)
|
||||
response = dia.run()
|
||||
dia.destroy()
|
||||
if response == gtk.RESPONSE_YES:
|
||||
self.add_site(site)
|
||||
|
||||
def add_site(self, site):
|
||||
dia = gtk.Dialog( title="Add Site", parent=self.window
|
||||
, flags=gtk.DIALOG_DESTROY_WITH_PARENT
|
||||
, buttons=(gtk.STOCK_SAVE, gtk.RESPONSE_ACCEPT
|
||||
,gtk.STOCK_CANCEL, gtk.RESPONSE_REJECT)
|
||||
)
|
||||
|
||||
h = gtk.HBox()
|
||||
dia.vbox.pack_start(h, padding=5) # sets horizontal padding
|
||||
label = gtk.Label( _("\nEnter short code for %s\n(up to 3 characters):\n") % site )
|
||||
h.pack_start(label, padding=20) # sets horizontal padding
|
||||
#label.set_alignment(1.0, 0.5)
|
||||
|
||||
h = gtk.HBox()
|
||||
dia.vbox.add(h)
|
||||
e_code = gtk.Entry(max=3)
|
||||
e_code.set_width_chars(5)
|
||||
h.pack_start(e_code, True, False, padding=5)
|
||||
|
||||
label = gtk.Label( "" )
|
||||
dia.vbox.add(label) # create space below entry, maybe padding arg above makes this redundant?
|
||||
|
||||
dia.show_all()
|
||||
response = dia.run()
|
||||
site_code = e_code.get_text()
|
||||
if response == gtk.RESPONSE_ACCEPT and site_code is not None and site_code != "":
|
||||
self.db.add_site(site, site_code)
|
||||
self.db.commit()
|
||||
dia.destroy()
|
||||
|
||||
def main(self):
|
||||
gtk.main()
|
||||
|
|
|
|||
|
|
@ -15,6 +15,9 @@
|
|||
#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 L10n
|
||||
_ = L10n.get_translation()
|
||||
|
||||
# Standard Library modules
|
||||
|
||||
import os # todo: remove this once import_dir is in fpdb_import
|
||||
|
|
@ -36,7 +39,6 @@ import pygtk
|
|||
import gtk
|
||||
|
||||
# fpdb/FreePokerTools modules
|
||||
|
||||
import Database
|
||||
import Configuration
|
||||
import Exceptions
|
||||
|
|
@ -46,25 +48,26 @@ import Exceptions
|
|||
try:
|
||||
import MySQLdb
|
||||
except ImportError:
|
||||
log.debug("Import database module: MySQLdb not found")
|
||||
log.debug(_("Import database module: MySQLdb not found"))
|
||||
else:
|
||||
mysqlLibFound = True
|
||||
|
||||
try:
|
||||
import psycopg2
|
||||
except ImportError:
|
||||
log.debug("Import database module: psycopg2 not found")
|
||||
log.debug(_("Import database module: psycopg2 not found"))
|
||||
else:
|
||||
import psycopg2.extensions
|
||||
psycopg2.extensions.register_type(psycopg2.extensions.UNICODE)
|
||||
|
||||
class Importer:
|
||||
def __init__(self, caller, settings, config, sql = None):
|
||||
def __init__(self, caller, settings, config, sql = None, parent = None):
|
||||
"""Constructor"""
|
||||
self.settings = settings
|
||||
self.caller = caller
|
||||
self.config = config
|
||||
self.sql = sql
|
||||
self.parent = parent
|
||||
|
||||
#log = Configuration.get_logger("logging.conf", "importer", log_dir=self.config.dir_log)
|
||||
self.filelist = {}
|
||||
|
|
@ -91,6 +94,9 @@ class Importer:
|
|||
self.settings.setdefault("dropIndexes", "don't drop")
|
||||
self.settings.setdefault("dropHudCache", "don't drop")
|
||||
self.settings.setdefault("starsArchive", False)
|
||||
self.settings.setdefault("ftpArchive", False)
|
||||
self.settings.setdefault("testData", False)
|
||||
self.settings.setdefault("cacheHHC", False)
|
||||
|
||||
self.writeq = None
|
||||
self.database = Database.Database(self.config, sql = self.sql)
|
||||
|
|
@ -135,6 +141,18 @@ class Importer:
|
|||
def setStarsArchive(self, value):
|
||||
self.settings['starsArchive'] = value
|
||||
|
||||
def setFTPArchive(self, value):
|
||||
self.settings['ftpArchive'] = value
|
||||
|
||||
def setPrintTestData(self, value):
|
||||
self.settings['testData'] = value
|
||||
|
||||
def setFakeCacheHHC(self, value):
|
||||
self.settings['cacheHHC'] = value
|
||||
|
||||
def getCachedHHC(self):
|
||||
return self.handhistoryconverter
|
||||
|
||||
# def setWatchTime(self):
|
||||
# self.updated = time()
|
||||
|
||||
|
|
@ -164,9 +182,9 @@ class Importer:
|
|||
self.siteIds[site] = result[0][0]
|
||||
else:
|
||||
if len(result) == 0:
|
||||
log.error("Database ID for %s not found" % site)
|
||||
log.error(_("Database ID for %s not found") % site)
|
||||
else:
|
||||
log.error("[ERROR] More than 1 Database ID found for %s - Multiple currencies not implemented yet" % site)
|
||||
log.error(_("[ERROR] More than 1 Database ID found for %s - Multiple currencies not implemented yet") % site)
|
||||
|
||||
|
||||
# Called from GuiBulkImport to add a file or directory.
|
||||
|
|
@ -202,7 +220,7 @@ class Importer:
|
|||
#print " adding file ", file
|
||||
self.addImportFile(os.path.join(dir, file), site, filter)
|
||||
else:
|
||||
log.warning("Attempted to add non-directory: '%s' as an import directory" % str(dir))
|
||||
log.warning(_("Attempted to add non-directory '%s' as an import directory") % str(dir))
|
||||
|
||||
def runImport(self):
|
||||
""""Run full import on self.filelist. This is called from GuiBulkImport.py"""
|
||||
|
|
@ -212,7 +230,7 @@ class Importer:
|
|||
# Initial setup
|
||||
start = datetime.datetime.now()
|
||||
starttime = time()
|
||||
log.info("Started at %s -- %d files to import. indexes: %s" % (start, len(self.filelist), self.settings['dropIndexes']))
|
||||
log.info(_("Started at %s -- %d files to import. indexes: %s") % (start, len(self.filelist), self.settings['dropIndexes']))
|
||||
if self.settings['dropIndexes'] == 'auto':
|
||||
self.settings['dropIndexes'] = self.calculate_auto2(self.database, 12.0, 500.0)
|
||||
if 'dropHudCache' in self.settings and self.settings['dropHudCache'] == 'auto':
|
||||
|
|
@ -221,7 +239,7 @@ class Importer:
|
|||
if self.settings['dropIndexes'] == 'drop':
|
||||
self.database.prepareBulkImport()
|
||||
else:
|
||||
log.debug("No need to drop indexes.")
|
||||
log.info(_("No need to drop indexes."))
|
||||
#print "dropInd =", self.settings['dropIndexes'], " dropHudCache =", self.settings['dropHudCache']
|
||||
|
||||
if self.settings['threads'] <= 0:
|
||||
|
|
@ -240,10 +258,10 @@ class Importer:
|
|||
(totstored, totdups, totpartial, toterrors) = self.importFiles(self.database, self.writeq)
|
||||
|
||||
if self.writeq.empty():
|
||||
print "writers finished already"
|
||||
print _("writers finished already")
|
||||
pass
|
||||
else:
|
||||
print "waiting for writers to finish ..."
|
||||
print _("waiting for writers to finish ...")
|
||||
#for t in threading.enumerate():
|
||||
# print " "+str(t)
|
||||
#self.writeq.join()
|
||||
|
|
@ -253,17 +271,17 @@ class Importer:
|
|||
while gtk.events_pending(): # see http://faq.pygtk.org/index.py?req=index for more hints (3.7)
|
||||
gtk.main_iteration(False)
|
||||
sleep(0.5)
|
||||
print " ... writers finished"
|
||||
print _(" ... writers finished")
|
||||
|
||||
# Tidying up after import
|
||||
if self.settings['dropIndexes'] == 'drop':
|
||||
self.database.afterBulkImport()
|
||||
else:
|
||||
print "No need to rebuild indexes."
|
||||
log.info (_("No need to rebuild indexes."))
|
||||
if 'dropHudCache' in self.settings and self.settings['dropHudCache'] == 'drop':
|
||||
self.database.rebuild_hudcache()
|
||||
else:
|
||||
print "No need to rebuild hudcache."
|
||||
log.info (_("No need to rebuild hudcache."))
|
||||
self.database.analyzeDB()
|
||||
endtime = time()
|
||||
return (totstored, totdups, totpartial, toterrors, endtime-starttime)
|
||||
|
|
@ -279,7 +297,14 @@ class Importer:
|
|||
totpartial = 0
|
||||
toterrors = 0
|
||||
tottime = 0
|
||||
|
||||
#prepare progress popup window
|
||||
ProgressDialog = ProgressBar(len(self.filelist), self.parent)
|
||||
|
||||
for file in self.filelist:
|
||||
|
||||
ProgressDialog.progress_update()
|
||||
|
||||
(stored, duplicates, partial, errors, ttime) = self.import_file_dict(db, file
|
||||
,self.filelist[file][0], self.filelist[file][1], q)
|
||||
totstored += stored
|
||||
|
|
@ -287,10 +312,13 @@ class Importer:
|
|||
totpartial += partial
|
||||
toterrors += errors
|
||||
|
||||
del ProgressDialog
|
||||
|
||||
for i in xrange( self.settings['threads'] ):
|
||||
print "sending finish msg qlen =", q.qsize()
|
||||
print _("sending finish message queue length ="), q.qsize()
|
||||
db.send_finish_msg(q)
|
||||
|
||||
|
||||
return (totstored, totdups, totpartial, toterrors)
|
||||
# end def importFiles
|
||||
|
||||
|
|
@ -362,7 +390,7 @@ class Importer:
|
|||
#rulog.writelines("path exists ")
|
||||
if file in self.updatedsize: # we should be able to assume that if we're in size, we're in time as well
|
||||
if stat_info.st_size > self.updatedsize[file] or stat_info.st_mtime > self.updatedtime[file]:
|
||||
# print "file",counter," updated", os.path.basename(file), stat_info.st_size, self.updatedsize[file], stat_info.st_mtime, self.updatedtime[file]
|
||||
# print "file",file," updated", os.path.basename(file), stat_info.st_size, self.updatedsize[file], stat_info.st_mtime, self.updatedtime[file]
|
||||
try:
|
||||
if not os.path.isdir(file):
|
||||
self.caller.addText("\n"+os.path.basename(file))
|
||||
|
|
@ -414,9 +442,9 @@ class Importer:
|
|||
|
||||
# Load filter, process file, pass returned filename to import_fpdb_file
|
||||
if self.settings['threads'] > 0 and self.writeq is not None:
|
||||
log.info("Converting " + file + " (" + str(q.qsize()) + ")")
|
||||
log.info((_("Converting %s") % file) + " (" + str(q.qsize()) + ")")
|
||||
else:
|
||||
log.info("Converting " + file)
|
||||
log.info(_("Converting %s") % file)
|
||||
hhbase = self.config.get_import_parameters().get("hhArchiveBase")
|
||||
hhbase = os.path.expanduser(hhbase)
|
||||
hhdir = os.path.join(hhbase,site)
|
||||
|
|
@ -435,7 +463,9 @@ class Importer:
|
|||
idx = self.pos_in_file[file]
|
||||
else:
|
||||
self.pos_in_file[file] = 0
|
||||
hhc = obj(self.config, in_path = file, out_path = out_path, index = idx, starsArchive = self.settings['starsArchive'])
|
||||
hhc = obj( self.config, in_path = file, out_path = out_path, index = idx
|
||||
, starsArchive = self.settings['starsArchive'], ftpArchive = self.settings['ftpArchive'],
|
||||
sitename = site )
|
||||
if hhc.getStatus():
|
||||
handlist = hhc.getProcessedHands()
|
||||
self.pos_in_file[file] = hhc.getLastCharacterRead()
|
||||
|
|
@ -445,14 +475,14 @@ class Importer:
|
|||
if hand is not None:
|
||||
hand.prepInsert(self.database)
|
||||
try:
|
||||
hand.insert(self.database)
|
||||
hand.insert(self.database, printtest = self.settings['testData'])
|
||||
except Exceptions.FpdbHandDuplicate:
|
||||
duplicates += 1
|
||||
else:
|
||||
if self.callHud and hand.dbid_hands != 0:
|
||||
to_hud.append(hand.dbid_hands)
|
||||
else: # TODO: Treat empty as an error, or just ignore?
|
||||
log.error("Hand processed but empty")
|
||||
log.error(_("Hand processed but empty"))
|
||||
|
||||
# Call hudcache update if not in bulk import mode
|
||||
# FIXME: Need to test for bulk import that isn't rebuilding the cache
|
||||
|
|
@ -465,21 +495,25 @@ class Importer:
|
|||
#pipe the Hands.id out to the HUD
|
||||
for hid in to_hud:
|
||||
try:
|
||||
print "fpdb_import: sending hand to hud", hand.dbid_hands, "pipe =", self.caller.pipe_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)
|
||||
except IOError, e:
|
||||
log.error("Failed to send hand to HUD: %s" % e)
|
||||
log.error(_("Failed to send hand to HUD: %s") % e)
|
||||
|
||||
errors = getattr(hhc, 'numErrors')
|
||||
stored = getattr(hhc, 'numHands')
|
||||
stored -= duplicates
|
||||
stored -= errors
|
||||
# Really ugly hack to allow testing Hands within the HHC from someone
|
||||
# with only an Importer objec
|
||||
if self.settings['cacheHHC']:
|
||||
self.handhistoryconverter = hhc
|
||||
else:
|
||||
# conversion didn't work
|
||||
# TODO: appropriate response?
|
||||
return (0, 0, 0, 1, time() - ttime)
|
||||
else:
|
||||
log.warning("Unknown filter filter_name:'%s' in filter:'%s'" %(filter_name, filter))
|
||||
log.warning(_("Unknown filter filter_name:'%s' in filter:'%s'") %(filter_name, filter))
|
||||
return (0, 0, 0, 1, time() - ttime)
|
||||
|
||||
ttime = time() - ttime
|
||||
|
|
@ -490,16 +524,92 @@ class Importer:
|
|||
|
||||
def printEmailErrorMessage(self, errors, filename, line):
|
||||
traceback.print_exc(file=sys.stderr)
|
||||
print "Error No.",errors,", please send the hand causing this to fpdb-main@lists.sourceforge.net so we can fix the problem."
|
||||
print "Filename:", filename
|
||||
print "Here is the first line of the hand so you can identify it. Please mention that the error was a ValueError:"
|
||||
print (_("Error No.%s please send the hand causing this to fpdb-main@lists.sourceforge.net so we can fix the problem.") % errors)
|
||||
print _("Filename:"), filename
|
||||
print _("Here is the first line of the hand so you can identify it. Please mention that the error was a ValueError:")
|
||||
print self.hand[0]
|
||||
print "Hand logged to hand-errors.txt"
|
||||
print _("Hand logged to hand-errors.txt")
|
||||
logfile = open('hand-errors.txt', 'a')
|
||||
for s in self.hand:
|
||||
logfile.write(str(s) + "\n")
|
||||
logfile.write("\n")
|
||||
logfile.close()
|
||||
|
||||
|
||||
class ProgressBar:
|
||||
|
||||
"""
|
||||
Popup window to show progress
|
||||
|
||||
Init method sets up total number of expected iterations
|
||||
If no parent is passed to init, command line
|
||||
mode assumed, and does not create a progress bar
|
||||
"""
|
||||
|
||||
def __del__(self):
|
||||
|
||||
if self.parent:
|
||||
self.progress.destroy()
|
||||
|
||||
|
||||
def progress_update(self):
|
||||
|
||||
if not self.parent:
|
||||
#nothing to do
|
||||
return
|
||||
|
||||
self.fraction += 1
|
||||
#update sum if fraction exceeds expected total number of iterations
|
||||
if self.fraction > self.sum:
|
||||
sum = self.fraction
|
||||
|
||||
#progress bar total set to 1 plus the number of items,to prevent it
|
||||
#reaching 100% prior to processing fully completing
|
||||
|
||||
progress_percent = float(self.fraction) / (float(self.sum) + 1.0)
|
||||
progress_text = (self.title + " "
|
||||
+ str(self.fraction) + " / " + str(self.sum))
|
||||
|
||||
self.pbar.set_fraction(progress_percent)
|
||||
self.pbar.set_text(progress_text)
|
||||
|
||||
|
||||
def __init__(self, sum, parent):
|
||||
|
||||
self.parent = parent
|
||||
if not self.parent:
|
||||
#no parent is passed, assume this is being run from the
|
||||
#command line, so return immediately
|
||||
return
|
||||
|
||||
self.fraction = 0
|
||||
self.sum = sum
|
||||
self.title = _("Importing")
|
||||
|
||||
self.progress = gtk.Window(gtk.WINDOW_TOPLEVEL)
|
||||
|
||||
self.progress.set_resizable(False)
|
||||
self.progress.set_modal(True)
|
||||
self.progress.set_transient_for(self.parent)
|
||||
self.progress.set_decorated(True)
|
||||
self.progress.set_deletable(False)
|
||||
self.progress.set_title(self.title)
|
||||
|
||||
vbox = gtk.VBox(False, 5)
|
||||
vbox.set_border_width(10)
|
||||
self.progress.add(vbox)
|
||||
vbox.show()
|
||||
|
||||
align = gtk.Alignment(0.5, 0.5, 0, 0)
|
||||
vbox.pack_start(align, True, True, 2)
|
||||
align.show()
|
||||
|
||||
self.pbar = gtk.ProgressBar()
|
||||
align.add(self.pbar)
|
||||
self.pbar.show()
|
||||
|
||||
self.progress.show()
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
print "CLI for fpdb_import is now available as CliFpdb.py"
|
||||
print _("CLI for fpdb_import is now available as CliFpdb.py")
|
||||
|
|
|
|||
307
pyfpdb/iPokerToFpdb.py
Normal file
307
pyfpdb/iPokerToFpdb.py
Normal file
|
|
@ -0,0 +1,307 @@
|
|||
#!/usr/bin/env python
|
||||
# -*- coding: utf-8 -*-
|
||||
#
|
||||
# Copyright 2010, Carl Gherardi
|
||||
#
|
||||
# This program is free software; you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License as published by
|
||||
# the Free Software Foundation; either version 2 of the License, or
|
||||
# (at your option) any later version.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with this program; if not, write to the Free Software
|
||||
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
|
||||
########################################################################
|
||||
|
||||
import L10n
|
||||
_ = L10n.get_translation()
|
||||
|
||||
# This code is based on CarbonToFpdb.py by Matthew Boss
|
||||
#
|
||||
# TODO:
|
||||
#
|
||||
# -- No support for tournaments (see also the last item below)
|
||||
# -- Assumes that the currency of ring games is USD
|
||||
# -- No support for a bring-in or for antes (is the latter in fact unnecessary
|
||||
# for hold 'em on Carbon?)
|
||||
# -- hand.maxseats can only be guessed at
|
||||
# -- The last hand in a history file will often be incomplete and is therefore
|
||||
# rejected
|
||||
# -- Is behaviour currently correct when someone shows an uncalled hand?
|
||||
# -- Information may be lost when the hand ID is converted from the native form
|
||||
# xxxxxxxx-yyy(y*) to xxxxxxxxyyy(y*) (in principle this should be stored as
|
||||
# a string, but the database does not support this). Is there a possibility
|
||||
# of collision between hand IDs that ought to be distinct?
|
||||
# -- Cannot parse tables that run it twice (nor is this likely ever to be
|
||||
# possible)
|
||||
# -- Cannot parse hands in which someone is all in in one of the blinds. Until
|
||||
# this is corrected tournaments will be unparseable
|
||||
|
||||
import sys
|
||||
import logging
|
||||
from HandHistoryConverter import *
|
||||
from decimal import Decimal
|
||||
|
||||
|
||||
class iPoker(HandHistoryConverter):
|
||||
|
||||
sitename = "iPoker"
|
||||
filetype = "text"
|
||||
codepage = "cp1252"
|
||||
siteID = 13
|
||||
|
||||
# Static regexes
|
||||
re_SplitHands = re.compile(r'</game>')
|
||||
re_TailSplitHands = re.compile(r'(</game>)')
|
||||
re_GameInfo = re.compile(r'<gametype>(?P<GAME>[a-zA-Z0-9 ]+) \$(?P<SB>[.0-9]+)/\$(?P<BB>[.0-9]+)</gametype>', re.MULTILINE)
|
||||
re_HandInfo = re.compile(r'gamecode="(?P<HID>[0-9]+)">\s+<general>\s+<startdate>(?P<DATETIME>[-: 0-9]+)</startdate>', re.MULTILINE)
|
||||
re_Button = re.compile(r'<players dealer="(?P<BUTTON>[0-9]+)">')
|
||||
re_PlayerInfo = re.compile(r'<player seat="(?P<SEAT>[0-9]+)" name="(?P<PNAME>[^"]+)" chips="\$(?P<CASH>[.0-9]+)" dealer="(?P<DEALTIN>(0|1))" (?P<WIN>win="\$[^"]+") (bet="\$(?P<BET>[^"]+))?', re.MULTILINE)
|
||||
re_Board = re.compile(r'<cards type="COMMUNITY" cards="(?P<CARDS>[^"]+)"', re.MULTILINE)
|
||||
re_EndOfHand = re.compile(r'<round id="END_OF_GAME"', re.MULTILINE)
|
||||
|
||||
re_PostSB = re.compile(r'<event sequence="[0-9]+" type="(SMALL_BLIND|RETURN_BLIND)" player="(?P<PSEAT>[0-9])" amount="(?P<SB>[.0-9]+)"/>', re.MULTILINE)
|
||||
re_PostBB = re.compile(r'<event sequence="[0-9]+" type="(BIG_BLIND|INITIAL_BLIND)" player="(?P<PSEAT>[0-9])" amount="(?P<BB>[.0-9]+)"/>', re.MULTILINE)
|
||||
re_PostBoth = re.compile(r'<event sequence="[0-9]+" type="(RETURN_BLIND)" player="(?P<PSEAT>[0-9])" amount="(?P<SBBB>[.0-9]+)"/>', re.MULTILINE)
|
||||
re_HeroCards = re.compile(r'<cards type="HOLE" cards="(?P<CARDS>.+)" player="(?P<PSEAT>[0-9])"', re.MULTILINE)
|
||||
re_Action = re.compile(r'<action no="[0-9]+" player="(?P<PNAME>[^"]+)" type="(?P<ATYPE>\d+)" sum="\$(?P<BET>[.0-9]+)"', re.MULTILINE)
|
||||
re_Ante = re.compile(r'<action no="[0-9]+" player="(?P<PNAME>[^"]+)" type="(?P<ATYPE>15)" sum="\$(?P<BET>[.0-9]+)" cards="', re.MULTILINE)
|
||||
re_ShowdownAction = re.compile(r'<cards type="SHOWN" cards="(?P<CARDS>..,..)" player="(?P<PSEAT>[0-9])"/>', re.MULTILINE)
|
||||
re_CollectPot = re.compile(r'<winner amount="(?P<POT>[.0-9]+)" uncalled="(true|false)" potnumber="[0-9]+" player="(?P<PSEAT>[0-9])"', re.MULTILINE)
|
||||
re_SitsOut = re.compile(r'<event sequence="[0-9]+" type="SIT_OUT" player="(?P<PSEAT>[0-9])"/>', re.MULTILINE)
|
||||
re_ShownCards = re.compile(r'<cards type="(SHOWN|MUCKED)" cards="(?P<CARDS>..,..)" player="(?P<PSEAT>[0-9])"/>', re.MULTILINE)
|
||||
|
||||
def compilePlayerRegexs(self, hand):
|
||||
pass
|
||||
|
||||
def playerNameFromSeatNo(self, seatNo, hand):
|
||||
# This special function is required because Carbon Poker records
|
||||
# actions by seat number, not by the player's name
|
||||
for p in hand.players:
|
||||
if p[0] == int(seatNo):
|
||||
return p[1]
|
||||
|
||||
def readSupportedGames(self):
|
||||
return [
|
||||
["ring", "stud", "fl"],
|
||||
#["ring", "hold", "nl"],
|
||||
#["tour", "hold", "nl"]
|
||||
]
|
||||
|
||||
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 """
|
||||
|
||||
m = self.re_GameInfo.search(handText)
|
||||
if not m:
|
||||
# Information about the game type appears only at the beginning of
|
||||
# a hand history file; hence it is not supplied with the second
|
||||
# and subsequent hands. In these cases we use the value previously
|
||||
# stored.
|
||||
try:
|
||||
self.info
|
||||
return self.info
|
||||
except AttributeError:
|
||||
tmp = handText[0:100]
|
||||
log.error(_("determineGameType: Unable to recognise gametype from: '%s'") % tmp)
|
||||
log.error(_("determineGameType: Raising FpdbParseError"))
|
||||
raise FpdbParseError(_("Unable to recognise gametype from: '%s'") % tmp)
|
||||
|
||||
self.info = {}
|
||||
mg = m.groupdict()
|
||||
#print "DEBUG: m.groupdict(): %s" % mg
|
||||
|
||||
limits = { 'No Limit':'nl', 'Limit':'fl' }
|
||||
games = { # base, category
|
||||
'7 Card Stud L' : ('stud','studhilo'),
|
||||
}
|
||||
|
||||
if 'LIMIT' in mg:
|
||||
self.info['limitType'] = limits[mg['LIMIT']]
|
||||
self.info['limitType'] = 'fl'
|
||||
if 'GAME' in mg:
|
||||
(self.info['base'], self.info['category']) = games[mg['GAME']]
|
||||
if 'SB' in mg:
|
||||
self.info['sb'] = mg['SB']
|
||||
if 'BB' in mg:
|
||||
self.info['bb'] = mg['BB']
|
||||
if mg['GAME'] == 'Holdem Tournament':
|
||||
self.info['type'] = 'tour'
|
||||
self.info['currency'] = 'T$'
|
||||
else:
|
||||
self.info['type'] = 'ring'
|
||||
self.info['currency'] = 'USD'
|
||||
|
||||
return self.info
|
||||
|
||||
def readHandInfo(self, hand):
|
||||
m = self.re_HandInfo.search(hand.handText)
|
||||
if m is None:
|
||||
logging.error(_("Didn't match re_HandInfo"))
|
||||
logging.info(hand.handText)
|
||||
raise FpdbParseError(_("Didn't match re_HandInfo"))
|
||||
mg = m.groupdict()
|
||||
#print "DEBUG: m.groupdict(): %s" % mg
|
||||
hand.handid = m.group('HID')
|
||||
#hand.tablename = m.group('TABLE')[:-1]
|
||||
hand.maxseats = None
|
||||
hand.startTime = datetime.datetime.strptime(m.group('DATETIME'), '%Y-%m-%d %H:%M:%S')
|
||||
|
||||
def readPlayerStacks(self, hand):
|
||||
print "DEBUG: readPlayerStacks"
|
||||
m = self.re_PlayerInfo.finditer(hand.handText)
|
||||
for a in m:
|
||||
ag = a.groupdict()
|
||||
#print "DEBUG: re_PlayerInfo: %s" %ag
|
||||
seatno = int(a.group('SEAT'))
|
||||
# It may be necessary to adjust 'hand.maxseats', which is an
|
||||
# educated guess, starting with 2 (indicating a heads-up table) and
|
||||
# adjusted upwards in steps to 6, then 9, then 10. An adjustment is
|
||||
# made whenever a player is discovered whose seat number is
|
||||
# currently above the maximum allowable for the table.
|
||||
if seatno >= hand.maxseats:
|
||||
if seatno > 8:
|
||||
hand.maxseats = 10
|
||||
elif seatno > 5:
|
||||
hand.maxseats = 9
|
||||
else:
|
||||
hand.maxseats = 6
|
||||
|
||||
hand.addPlayer(seatno, a.group('PNAME'), a.group('CASH'))
|
||||
|
||||
def markStreets(self, hand):
|
||||
if hand.gametype['base'] in ('stud'):
|
||||
m = re.search(r'(?P<ANTES>.+(?=<round no="2">)|.+)'
|
||||
r'(<round no="2">(?P<THIRD>.+(?=<round no="3">)|.+))?'
|
||||
r'(<round no="3">(?P<FOURTH>.+(?=<round no="4">)|.+))?'
|
||||
r'(<round no="4">(?P<FIFTH>.+(?=<round no="5">)|.+))?'
|
||||
r'(<round no="5">(?P<SIXTH>.+(?=<round no="6">)|.+))?'
|
||||
r'(<round no="6">(?P<SEVENTH>.+))?', hand.handText,re.DOTALL)
|
||||
|
||||
hand.addStreets(m)
|
||||
|
||||
def readCommunityCards(self, hand, street):
|
||||
m = self.re_Board.search(hand.streets[street])
|
||||
if street == 'FLOP':
|
||||
hand.setCommunityCards(street, m.group('CARDS').split(','))
|
||||
elif street in ('TURN','RIVER'):
|
||||
hand.setCommunityCards(street, [m.group('CARDS').split(',')[-1]])
|
||||
|
||||
def readAntes(self, hand):
|
||||
m = self.re_Ante.finditer(hand.handText)
|
||||
for a in m:
|
||||
#print "DEBUG: addAnte(%s, %s)" %(a.group('PNAME'), a.group('BET'))
|
||||
hand.addAnte(a.group('PNAME'), a.group('BET'))
|
||||
|
||||
def readBringIn(self, hand):
|
||||
pass
|
||||
|
||||
def readBlinds(self, hand):
|
||||
m = self.re_PostSB.search(hand.handText)
|
||||
hand.addBlind(m.group('PNAME'), 'small blind', m.group('SB'))
|
||||
for a in self.re_PostBB.finditer(hand.handText):
|
||||
hand.addBlind(m.group('PNAME'), 'big blind', a.group('BB'))
|
||||
#for a in self.re_PostBoth.finditer(hand.handText):
|
||||
|
||||
def readButton(self, hand):
|
||||
hand.buttonpos = int(self.re_Button.search(hand.handText).group('BUTTON'))
|
||||
|
||||
def readHeroCards(self, hand):
|
||||
m = self.re_HeroCards.search(hand.handText)
|
||||
if m:
|
||||
hand.hero = self.playerNameFromSeatNo(m.group('PSEAT'), hand)
|
||||
cards = m.group('CARDS').split(',')
|
||||
hand.addHoleCards('PREFLOP', hand.hero, closed=cards, shown=False,
|
||||
mucked=False, dealt=True)
|
||||
|
||||
def readAction(self, hand, street):
|
||||
logging.debug("readAction (%s)" % street)
|
||||
m = self.re_Action.finditer(hand.streets[street])
|
||||
for action in m:
|
||||
ag = action.groupdict()
|
||||
#print "DEBUG: action.groupdict: %s" % ag
|
||||
logging.debug("%s %s" % (action.group('ATYPE'),
|
||||
action.groupdict()))
|
||||
if action.group('ATYPE') == 'RAISE': # Still no example for raise (i think?)
|
||||
hand.addCallandRaise(street, player, action.group('BET'))
|
||||
elif action.group('ATYPE') == '3': # Believe this is 'call'
|
||||
#print "DEBUG: addCall(%s, %s, %s)" %(street, action.group('PNAME'), action.group('BET'))
|
||||
hand.addCall(street, action.group('PNAME'), action.group('BET'))
|
||||
elif action.group('ATYPE') == '5':
|
||||
#print "DEBUG: addBet(%s, %s, %s)" %(street, action.group('PNAME'), action.group('BET'))
|
||||
hand.addBet(street, action.group('PNAME'), action.group('BET'))
|
||||
elif action.group('ATYPE') == '0': # Belive this is 'fold'
|
||||
#print "DEBUG: addFold(%s, %s)" %(street, action.group('PNAME'))
|
||||
hand.addFold(street, action.group('PNAME'))
|
||||
elif action.group('ATYPE') == '4':
|
||||
#print "DEBUG: addCheck(%s, %s)" %(street, action.group('PNAME'))
|
||||
hand.addCheck(street, action.group('PNAME'))
|
||||
#elif action.group('ATYPE') == 'ALL_IN':
|
||||
# hand.addAllIn(street, player, action.group('BET'))
|
||||
elif action.group('ATYPE') == '16': #BringIn
|
||||
#print "DEBUG: addBringIn(%s, %s)" %(action.group('PNAME'), action.group('BET'))
|
||||
hand.addBringIn(action.group('PNAME'), action.group('BET'))
|
||||
else:
|
||||
logging.error(_("Unimplemented readAction: %s" % (ag)))
|
||||
|
||||
def readShowdownActions(self, hand):
|
||||
for shows in self.re_ShowdownAction.finditer(hand.handText):
|
||||
cards = shows.group('CARDS').split(',')
|
||||
hand.addShownCards(cards,
|
||||
self.playerNameFromSeatNo(shows.group('PSEAT'),
|
||||
hand))
|
||||
|
||||
def readCollectPot(self, hand):
|
||||
pots = [Decimal(0) for n in range(hand.maxseats)]
|
||||
for m in self.re_CollectPot.finditer(hand.handText):
|
||||
pots[int(m.group('PSEAT'))] += Decimal(m.group('POT'))
|
||||
# Regarding the processing logic for "committed", see Pot.end() in
|
||||
# Hand.py
|
||||
committed = sorted([(v,k) for (k,v) in hand.pot.committed.items()])
|
||||
for p in range(hand.maxseats):
|
||||
pname = self.playerNameFromSeatNo(p, hand)
|
||||
if committed[-1][1] == pname:
|
||||
pots[p] -= committed[-1][0] - committed[-2][0]
|
||||
if pots[p] > 0:
|
||||
hand.addCollectPot(player=pname, pot=pots[p])
|
||||
|
||||
def readShownCards(self, hand):
|
||||
for m in self.re_ShownCards.finditer(hand.handText):
|
||||
cards = m.group('CARDS').split(',')
|
||||
hand.addShownCards(cards=cards, player=self.playerNameFromSeatNo(m.group('PSEAT'), hand))
|
||||
|
||||
if __name__ == "__main__":
|
||||
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="-")
|
||||
parser.add_option("-f", "--follow", dest="follow", help=_("follow (tail -f) the input"), action="store_true", default=False)
|
||||
parser.add_option("-q", "--quiet", action="store_const", const=logging.CRITICAL, dest="verbosity", default=logging.INFO)
|
||||
parser.add_option("-v", "--verbose", action="store_const", const=logging.INFO, dest="verbosity")
|
||||
parser.add_option("--vv", action="store_const", const=logging.DEBUG, dest="verbosity")
|
||||
|
||||
(options, args) = parser.parse_args()
|
||||
|
||||
LOG_FILENAME = './logging.out'
|
||||
logging.basicConfig(filename=LOG_FILENAME, level=options.verbosity)
|
||||
|
||||
e = Carbon(in_path = options.ipath,
|
||||
out_path = options.opath,
|
||||
follow = options.follow,
|
||||
autostart = True)
|
||||
|
||||
|
|
@ -3,6 +3,9 @@
|
|||
# Code from http://ender.snowburst.org:4747/~jjohns/interlocks.py
|
||||
# Thanks JJ!
|
||||
|
||||
import L10n
|
||||
_ = L10n.get_translation()
|
||||
|
||||
import sys
|
||||
import os, os.path
|
||||
import subprocess
|
||||
|
|
@ -46,7 +49,7 @@ class InterProcessLockBase:
|
|||
if source == None:
|
||||
source="Unknown"
|
||||
if self._has_lock: # make sure 2nd acquire in same process fails
|
||||
print "lock already held by:",self.heldBy
|
||||
print _("lock already held by:"),self.heldBy
|
||||
return False
|
||||
while not self._has_lock:
|
||||
try:
|
||||
|
|
|
|||
BIN
pyfpdb/locale/de/LC_MESSAGES/fpdb.mo
Normal file
BIN
pyfpdb/locale/de/LC_MESSAGES/fpdb.mo
Normal file
Binary file not shown.
3451
pyfpdb/locale/fpdb-de_DE.po
Normal file
3451
pyfpdb/locale/fpdb-de_DE.po
Normal file
File diff suppressed because it is too large
Load Diff
3274
pyfpdb/locale/fpdb-en_GB.pot
Normal file
3274
pyfpdb/locale/fpdb-en_GB.pot
Normal file
File diff suppressed because it is too large
Load Diff
3462
pyfpdb/locale/fpdb-fr_FR.po
Normal file
3462
pyfpdb/locale/fpdb-fr_FR.po
Normal file
File diff suppressed because it is too large
Load Diff
3687
pyfpdb/locale/fpdb-hu_HU.po
Normal file
3687
pyfpdb/locale/fpdb-hu_HU.po
Normal file
File diff suppressed because it is too large
Load Diff
BIN
pyfpdb/locale/fr/LC_MESSAGES/fpdb.mo
Normal file
BIN
pyfpdb/locale/fr/LC_MESSAGES/fpdb.mo
Normal file
Binary file not shown.
BIN
pyfpdb/locale/hu/LC_MESSAGES/fpdb.mo
Normal file
BIN
pyfpdb/locale/hu/LC_MESSAGES/fpdb.mo
Normal file
Binary file not shown.
17
pyfpdb/locale/localise.sh
Executable file
17
pyfpdb/locale/localise.sh
Executable file
|
|
@ -0,0 +1,17 @@
|
|||
cd ..
|
||||
rm *.pyc
|
||||
|
||||
echo "creating template po file"
|
||||
python /usr/share/doc/python-2.6*/examples/Tools/i18n/pygettext.py --output-dir=locale --default-domain=fpdb --output=fpdb-en_GB.pot *.py*
|
||||
|
||||
echo "merging template with existing translations"
|
||||
msgmerge --update locale/fpdb-de_DE.po locale/fpdb-en_GB.pot
|
||||
msgmerge --update locale/fpdb-fr_FR.po locale/fpdb-en_GB.pot
|
||||
msgmerge --update locale/fpdb-hu_HU.po locale/fpdb-en_GB.pot
|
||||
|
||||
echo "compiling mo files"
|
||||
python /usr/share/doc/python-2.6*/examples/Tools/i18n/msgfmt.py --output-file=locale/de/LC_MESSAGES/fpdb.mo locale/fpdb-de_DE.po
|
||||
python /usr/share/doc/python-2.6*/examples/Tools/i18n/msgfmt.py --output-file=locale/fr/LC_MESSAGES/fpdb.mo locale/fpdb-fr_FR.po
|
||||
python /usr/share/doc/python-2.6*/examples/Tools/i18n/msgfmt.py --output-file=locale/hu/LC_MESSAGES/fpdb.mo locale/fpdb-hu_HU.po
|
||||
|
||||
pocount locale/*.po
|
||||
|
|
@ -0,0 +1,91 @@
|
|||
Stage #1300000000: Seven Card Hi/Lo Normal $0.02/$0.04 - 2009-03-18 19:10:00 (ET)
|
||||
Seat 1 - PLAYER1 ($0.17 in chips)
|
||||
Seat 2 - PLAYER2 ($0.36 in chips)
|
||||
Seat 3 - PLAYER3 ($3.46 in chips)
|
||||
Seat 5 - PLAYER4 ($1 in chips)
|
||||
Seat 6 - PLAYER5 ($1.07 in chips)
|
||||
Seat 7 - PLAYER6 ($2.31 in chips)
|
||||
Seat 8 - PLAYER7 ($0.93 in chips)
|
||||
Player1 - Ante $0.01
|
||||
PLAYER5 - Ante $0.01
|
||||
PLAYER6 - Ante $0.01
|
||||
PLAYER3 - Ante $0.01
|
||||
PLAYER7 - Ante $0.01
|
||||
PLAYER2 - Ante $0.01
|
||||
PLAYER4 - Ante $0.01
|
||||
*** 3rd STREET ***
|
||||
Player1 - Pocket [H H Js]
|
||||
PLAYER2 - Pocket [H H 7h]
|
||||
PLAYER3 - Pocket [H H 6s]
|
||||
PLAYER4 - Pocket [10c 5c 7s]
|
||||
PLAYER5 - Pocket [H H Qh]
|
||||
PLAYER6 - Pocket [H H 9c]
|
||||
PLAYER7 - Pocket [H H 3s]
|
||||
PLAYER7 - Bring-In $0.01
|
||||
Player1 - Calls $0.01
|
||||
PLAYER2 - Folds
|
||||
PLAYER3 - Calls $0.01
|
||||
PLAYER4 - Folds
|
||||
PLAYER5 - Folds
|
||||
PLAYER6 - Calls $0.01
|
||||
*** 4TH STREET ***
|
||||
Player1 - Pocket [H H Js 10d]
|
||||
PLAYER3 - Pocket [H H 6s Ah]
|
||||
PLAYER4 - Pocket [10c 5c 7s]
|
||||
PLAYER6 - Pocket [H H 9c Ks]
|
||||
PLAYER7 - Pocket [H H 3s Qc]
|
||||
PLAYER3 - Checks
|
||||
PLAYER6 - Checks
|
||||
PLAYER7 - Checks
|
||||
Player1 - Checks
|
||||
*** 5TH STREET ***
|
||||
Player1 - Pocket [H H Js 10d Kh]
|
||||
PLAYER3 - Pocket [H H 6s Ah 8c]
|
||||
PLAYER4 - Pocket [10c 5c 7s]
|
||||
PLAYER6 - Pocket [H H 9c Ks 10s]
|
||||
PLAYER7 - Pocket [H H 3s Qc 6c]
|
||||
PLAYER3 - Bets $0.04
|
||||
PLAYER6 - Calls $0.04
|
||||
PLAYER7 - Calls $0.04
|
||||
Player1 - Calls $0.04
|
||||
*** 6TH STREET ***
|
||||
Player1 - Pocket [H H Js 10d Kh 2c]
|
||||
PLAYER3 - Pocket [H H 6s Ah 8c Jc]
|
||||
PLAYER4 - Pocket [10c 5c 7s]
|
||||
PLAYER6 - Pocket [H H 9c Ks 10s 8h]
|
||||
PLAYER7 - Pocket [H H 3s Qc 6c Qs]
|
||||
PLAYER7 - Checks
|
||||
Player1 - Checks
|
||||
PLAYER3 - Bets $0.04
|
||||
PLAYER6 - Calls $0.04
|
||||
PLAYER7 - Calls $0.04
|
||||
Player1 - Calls $0.04
|
||||
*** RIVER ***
|
||||
Player1 - Pocket [H H Js 10d Kh 2c H]
|
||||
PLAYER3 - Pocket [H H 6s Ah 8c Jc H]
|
||||
PLAYER4 - Pocket [10c 5c 7s]
|
||||
PLAYER6 - Pocket [H H 9c Ks 10s 8h H]
|
||||
PLAYER7 - Pocket [H H 3s Qc 6c Qs H]
|
||||
PLAYER7 - Checks
|
||||
Player1 - Checks
|
||||
PLAYER3 - Checks
|
||||
PLAYER6 - Checks
|
||||
*** SHOW DOWN ***
|
||||
PLAYER7 - Shows [5s 8d 3s Qc 6c Qs 9s] (One pair, queens)
|
||||
Player1 - Shows [Jh 3h Js 10d Kh 2c 2h] (Two Pair, jacks and twos)
|
||||
PLAYER3 - Shows [3d 5d 6s Ah 8c Jc As] (One pair, aces)
|
||||
PLAYER6 - Shows [Kc 10h 9c Ks 10s 8h 2s] (Two Pair, kings and tens)
|
||||
PLAYER3 Collects $0.19 from main pot
|
||||
PLAYER6 Collects $0.20 from main pot
|
||||
*** SUMMARY ***
|
||||
Total Pot($0.43) | Rake ($0.04)
|
||||
Seat 1: Player1 HI:lost with Two Pair, jacks and twos [Jh 3h Js 10d Kh 2c 2h - B:Js,P:Jh,P:2h,B:2c,B:Kh]
|
||||
Seat 2: PLAYER2 Folded on the 3rd STREET
|
||||
Seat 3: PLAYER3 won Total ($0.19) HI:with One pair, aces [3d 5d 6s Ah 8c Jc As - P:As,B:Ah,B:Jc,B:8c,B:6s] LO:($0.19) [B:Ah,P:3d,P:5d,B:6s,B:8c]
|
||||
Seat 5: PLAYER4 Folded on the 3rd STREET
|
||||
Seat 6: PLAYER5 Folded on the 3rd STREET
|
||||
Seat 7: PLAYER6 won Total ($0.20) HI:($0.20) with Two Pair, kings and tens [Kc 10h 9c Ks 10s 8h 2s - B:Ks,P:Kc,B:10s,P:10h,B:9c]
|
||||
Seat 8: PLAYER7 HI:lost with One pair, queens [5s 8d 3s Qc 6c Qs 9s - B:Qs,B:Qc,P:9s,P:8d,B:6c]
|
||||
|
||||
|
||||
|
||||
|
|
@ -0,0 +1,53 @@
|
|||
<description type="Holdem" stakes="No Limit ($0.25/$0.50)"/>
|
||||
<game id="15245216-1000" starttime="20081013150000" numholecards="2" gametype="2" realmoney="true" data="20081013|Niagara Falls (15245216)|15245216|15245216-1000|false">
|
||||
<players dealer="8">
|
||||
<player seat="3" nickname="Player1" balance="$34.13" dealtin="true" />
|
||||
<player seat="2" nickname="Player2" balance="$49.25" dealtin="true" />
|
||||
<player seat="1" nickname="Player3" balance="$55.64" dealtin="true" />
|
||||
<player seat="0" nickname="Player4" balance="$19.72" dealtin="true" />
|
||||
<player seat="7" nickname="Player5" balance="$25.16" dealtin="true" />
|
||||
<player seat="6" nickname="Player6" balance="$56.44" dealtin="false" />
|
||||
<player seat="5" nickname="Player7" balance="$43.52" dealtin="true" />
|
||||
<player seat="4" nickname="Player8" balance="$28.67" dealtin="true" />
|
||||
<player seat="8" nickname="Player9" balance="$9.25" dealtin="true" />
|
||||
</players>
|
||||
<round id="BLINDS" sequence="1">
|
||||
<event sequence="1" type="SMALL_BLIND" player="0" amount="0.25"/>
|
||||
<event sequence="2" type="BIG_BLIND" player="1" amount="0.50"/>
|
||||
</round>
|
||||
<round id="PREFLOP" sequence="2">
|
||||
<event sequence="3" type="FOLD" player="2"/>
|
||||
<event sequence="4" type="FOLD" player="3"/>
|
||||
<event sequence="5" type="RAISE" player="4" amount="1.00"/>
|
||||
<event sequence="6" type="FOLD" player="5"/>
|
||||
<event sequence="7" type="CALL" player="7" amount="1.00"/>
|
||||
<event sequence="8" type="FOLD" player="8"/>
|
||||
<event sequence="9" type="FOLD" player="0"/>
|
||||
<event sequence="10" type="RAISE" player="1" amount="5.00"/>
|
||||
<event sequence="11" type="CALL" player="4" amount="4.50"/>
|
||||
<event sequence="12" type="FOLD" player="7"/>
|
||||
<cards type="HOLE" cards="Ah,8s" player="2" hand="Ace High"/>
|
||||
</round>
|
||||
<round id="POSTFLOP" sequence="3">
|
||||
<event sequence="13" type="BET" player="1" amount="7.00"/>
|
||||
<event sequence="14" type="CALL" player="4" amount="7.00"/>
|
||||
<cards type="COMMUNITY" cards="5h,3c,Kd" hand="Ace High"/>
|
||||
</round>
|
||||
<round id="POSTTURN" sequence="4">
|
||||
<event sequence="15" type="BET" player="1" amount="18.00"/>
|
||||
<event sequence="16" type="ALL_IN" player="4" amount="16.17"/>
|
||||
<event sequence="17" type="SHOW" player="1"/>
|
||||
<event sequence="18" type="SHOW" player="4"/>
|
||||
<cards type="COMMUNITY" cards="5h,3c,Kd,3d" hand="Pair of Threes"/>
|
||||
<cards type="SHOWN" cards="Ad,3s" player="1"/>
|
||||
<cards type="SHOWN" cards="Qd,Qs" player="4"/>
|
||||
</round>
|
||||
<round id="POSTRIVER" sequence="5">
|
||||
<cards type="COMMUNITY" cards="5h,3c,Kd,3d,Ks" hand="Two Pair Kings and Threes"/>
|
||||
</round>
|
||||
<round id="END_OF_GAME" sequence="6">
|
||||
<winner amount="55.67" uncalled="false" potnumber="1" player="1" hand="Full House - Threes over Kings" pottype="n"/>
|
||||
<winner amount="1.83" uncalled="true" potnumber="2" player="1" hand="Full House - Threes over Kings" pottype="n"/>
|
||||
</round>
|
||||
</game>
|
||||
|
||||
|
|
@ -0,0 +1,752 @@
|
|||
{ u'Player1': { 'card1': 0,
|
||||
'card2': 0,
|
||||
'card3': 0,
|
||||
'card4': 0,
|
||||
'card5': 0,
|
||||
'card6': 0,
|
||||
'card7': 0,
|
||||
'foldBbToStealChance': False,
|
||||
'foldSbToStealChance': False,
|
||||
'foldToOtherRaisedStreet0': False,
|
||||
'foldToOtherRaisedStreet1': False,
|
||||
'foldToOtherRaisedStreet2': False,
|
||||
'foldToOtherRaisedStreet3': False,
|
||||
'foldToOtherRaisedStreet4': False,
|
||||
'foldToStreet1CBChance': False,
|
||||
'foldToStreet1CBDone': False,
|
||||
'foldToStreet2CBChance': False,
|
||||
'foldToStreet2CBDone': False,
|
||||
'foldToStreet3CBChance': False,
|
||||
'foldToStreet3CBDone': False,
|
||||
'foldToStreet4CBChance': False,
|
||||
'foldToStreet4CBDone': False,
|
||||
'foldedBbToSteal': False,
|
||||
'foldedSbToSteal': False,
|
||||
'other3BStreet0': False,
|
||||
'other4BStreet0': False,
|
||||
'otherRaisedStreet0': False,
|
||||
'otherRaisedStreet1': False,
|
||||
'otherRaisedStreet2': False,
|
||||
'otherRaisedStreet3': False,
|
||||
'otherRaisedStreet4': False,
|
||||
'position': 4,
|
||||
'raiseFirstInChance': True,
|
||||
'raisedFirstIn': False,
|
||||
'rake': 0,
|
||||
'sawShowdown': False,
|
||||
'seatNo': 3,
|
||||
'sitout': False,
|
||||
'startCards': 0,
|
||||
'startCash': 3413,
|
||||
'street0Aggr': False,
|
||||
'street0Bets': 0,
|
||||
'street0Calls': 0,
|
||||
'street0Raises': 0,
|
||||
'street0VPI': False,
|
||||
'street0_3BChance': False,
|
||||
'street0_3BDone': False,
|
||||
'street0_4BChance': False,
|
||||
'street0_4BDone': False,
|
||||
'street1Aggr': False,
|
||||
'street1Bets': 0,
|
||||
'street1CBChance': False,
|
||||
'street1CBDone': False,
|
||||
'street1Calls': 0,
|
||||
'street1CheckCallRaiseChance': False,
|
||||
'street1CheckCallRaiseDone': False,
|
||||
'street1Raises': 0,
|
||||
'street1Seen': False,
|
||||
'street2Aggr': False,
|
||||
'street2Bets': 0,
|
||||
'street2CBChance': False,
|
||||
'street2CBDone': False,
|
||||
'street2Calls': 0,
|
||||
'street2CheckCallRaiseChance': False,
|
||||
'street2CheckCallRaiseDone': False,
|
||||
'street2Raises': 0,
|
||||
'street2Seen': False,
|
||||
'street3Aggr': False,
|
||||
'street3Bets': 0,
|
||||
'street3CBChance': False,
|
||||
'street3CBDone': False,
|
||||
'street3Calls': 0,
|
||||
'street3CheckCallRaiseChance': False,
|
||||
'street3CheckCallRaiseDone': False,
|
||||
'street3Raises': 0,
|
||||
'street3Seen': False,
|
||||
'street4Aggr': False,
|
||||
'street4Bets': 0,
|
||||
'street4CBChance': False,
|
||||
'street4CBDone': False,
|
||||
'street4Calls': 0,
|
||||
'street4CheckCallRaiseChance': False,
|
||||
'street4CheckCallRaiseDone': False,
|
||||
'street4Raises': 0,
|
||||
'street4Seen': False,
|
||||
'totalProfit': 0,
|
||||
'tourneyTypeId': None,
|
||||
'tourneysPlayersIds': None,
|
||||
'winnings': 0,
|
||||
'wonAtSD': 0.0,
|
||||
'wonWhenSeenStreet1': 0.0,
|
||||
'wonWhenSeenStreet2': 0.0,
|
||||
'wonWhenSeenStreet3': 0.0,
|
||||
'wonWhenSeenStreet4': 0.0},
|
||||
u'Player2': { 'card1': 13,
|
||||
'card2': 46,
|
||||
'card3': 0,
|
||||
'card4': 0,
|
||||
'card5': 0,
|
||||
'card6': 0,
|
||||
'card7': 0,
|
||||
'foldBbToStealChance': False,
|
||||
'foldSbToStealChance': False,
|
||||
'foldToOtherRaisedStreet0': False,
|
||||
'foldToOtherRaisedStreet1': False,
|
||||
'foldToOtherRaisedStreet2': False,
|
||||
'foldToOtherRaisedStreet3': False,
|
||||
'foldToOtherRaisedStreet4': False,
|
||||
'foldToStreet1CBChance': False,
|
||||
'foldToStreet1CBDone': False,
|
||||
'foldToStreet2CBChance': False,
|
||||
'foldToStreet2CBDone': False,
|
||||
'foldToStreet3CBChance': False,
|
||||
'foldToStreet3CBDone': False,
|
||||
'foldToStreet4CBChance': False,
|
||||
'foldToStreet4CBDone': False,
|
||||
'foldedBbToSteal': False,
|
||||
'foldedSbToSteal': False,
|
||||
'other3BStreet0': False,
|
||||
'other4BStreet0': False,
|
||||
'otherRaisedStreet0': False,
|
||||
'otherRaisedStreet1': False,
|
||||
'otherRaisedStreet2': False,
|
||||
'otherRaisedStreet3': False,
|
||||
'otherRaisedStreet4': False,
|
||||
'position': 5,
|
||||
'raiseFirstInChance': True,
|
||||
'raisedFirstIn': False,
|
||||
'rake': 0,
|
||||
'sawShowdown': False,
|
||||
'seatNo': 2,
|
||||
'sitout': False,
|
||||
'startCards': 91,
|
||||
'startCash': 4925,
|
||||
'street0Aggr': False,
|
||||
'street0Bets': 0,
|
||||
'street0Calls': 0,
|
||||
'street0Raises': 0,
|
||||
'street0VPI': False,
|
||||
'street0_3BChance': False,
|
||||
'street0_3BDone': False,
|
||||
'street0_4BChance': False,
|
||||
'street0_4BDone': False,
|
||||
'street1Aggr': False,
|
||||
'street1Bets': 0,
|
||||
'street1CBChance': False,
|
||||
'street1CBDone': False,
|
||||
'street1Calls': 0,
|
||||
'street1CheckCallRaiseChance': False,
|
||||
'street1CheckCallRaiseDone': False,
|
||||
'street1Raises': 0,
|
||||
'street1Seen': False,
|
||||
'street2Aggr': False,
|
||||
'street2Bets': 0,
|
||||
'street2CBChance': False,
|
||||
'street2CBDone': False,
|
||||
'street2Calls': 0,
|
||||
'street2CheckCallRaiseChance': False,
|
||||
'street2CheckCallRaiseDone': False,
|
||||
'street2Raises': 0,
|
||||
'street2Seen': False,
|
||||
'street3Aggr': False,
|
||||
'street3Bets': 0,
|
||||
'street3CBChance': False,
|
||||
'street3CBDone': False,
|
||||
'street3Calls': 0,
|
||||
'street3CheckCallRaiseChance': False,
|
||||
'street3CheckCallRaiseDone': False,
|
||||
'street3Raises': 0,
|
||||
'street3Seen': False,
|
||||
'street4Aggr': False,
|
||||
'street4Bets': 0,
|
||||
'street4CBChance': False,
|
||||
'street4CBDone': False,
|
||||
'street4Calls': 0,
|
||||
'street4CheckCallRaiseChance': False,
|
||||
'street4CheckCallRaiseDone': False,
|
||||
'street4Raises': 0,
|
||||
'street4Seen': False,
|
||||
'totalProfit': 0,
|
||||
'tourneyTypeId': None,
|
||||
'tourneysPlayersIds': None,
|
||||
'winnings': 0,
|
||||
'wonAtSD': 0.0,
|
||||
'wonWhenSeenStreet1': 0.0,
|
||||
'wonWhenSeenStreet2': 0.0,
|
||||
'wonWhenSeenStreet3': 0.0,
|
||||
'wonWhenSeenStreet4': 0.0},
|
||||
u'Player3': { 'card1': 26,
|
||||
'card2': 41,
|
||||
'card3': 0,
|
||||
'card4': 0,
|
||||
'card5': 0,
|
||||
'card6': 0,
|
||||
'card7': 0,
|
||||
'foldBbToStealChance': False,
|
||||
'foldSbToStealChance': False,
|
||||
'foldToOtherRaisedStreet0': False,
|
||||
'foldToOtherRaisedStreet1': False,
|
||||
'foldToOtherRaisedStreet2': False,
|
||||
'foldToOtherRaisedStreet3': False,
|
||||
'foldToOtherRaisedStreet4': False,
|
||||
'foldToStreet1CBChance': False,
|
||||
'foldToStreet1CBDone': False,
|
||||
'foldToStreet2CBChance': False,
|
||||
'foldToStreet2CBDone': False,
|
||||
'foldToStreet3CBChance': False,
|
||||
'foldToStreet3CBDone': False,
|
||||
'foldToStreet4CBChance': False,
|
||||
'foldToStreet4CBDone': False,
|
||||
'foldedBbToSteal': False,
|
||||
'foldedSbToSteal': False,
|
||||
'other3BStreet0': False,
|
||||
'other4BStreet0': False,
|
||||
'otherRaisedStreet0': False,
|
||||
'otherRaisedStreet1': False,
|
||||
'otherRaisedStreet2': False,
|
||||
'otherRaisedStreet3': False,
|
||||
'otherRaisedStreet4': False,
|
||||
'position': 'B',
|
||||
'raiseFirstInChance': False,
|
||||
'raisedFirstIn': False,
|
||||
'rake': 292,
|
||||
'sawShowdown': True,
|
||||
'seatNo': 1,
|
||||
'sitout': False,
|
||||
'startCards': 26,
|
||||
'startCash': 5564,
|
||||
'street0Aggr': True,
|
||||
'street0Bets': 0,
|
||||
'street0Calls': 0,
|
||||
'street0Raises': 0,
|
||||
'street0VPI': True,
|
||||
'street0_3BChance': True,
|
||||
'street0_3BDone': True,
|
||||
'street0_4BChance': False,
|
||||
'street0_4BDone': False,
|
||||
'street1Aggr': True,
|
||||
'street1Bets': 1,
|
||||
'street1CBChance': True,
|
||||
'street1CBDone': True,
|
||||
'street1Calls': 0,
|
||||
'street1CheckCallRaiseChance': False,
|
||||
'street1CheckCallRaiseDone': False,
|
||||
'street1Raises': 0,
|
||||
'street1Seen': True,
|
||||
'street2Aggr': True,
|
||||
'street2Bets': 1,
|
||||
'street2CBChance': True,
|
||||
'street2CBDone': True,
|
||||
'street2Calls': 0,
|
||||
'street2CheckCallRaiseChance': False,
|
||||
'street2CheckCallRaiseDone': False,
|
||||
'street2Raises': 0,
|
||||
'street2Seen': True,
|
||||
'street3Aggr': False,
|
||||
'street3Bets': 0,
|
||||
'street3CBChance': False,
|
||||
'street3CBDone': False,
|
||||
'street3Calls': 0,
|
||||
'street3CheckCallRaiseChance': False,
|
||||
'street3CheckCallRaiseDone': False,
|
||||
'street3Raises': 0,
|
||||
'street3Seen': False,
|
||||
'street4Aggr': False,
|
||||
'street4Bets': 0,
|
||||
'street4CBChance': False,
|
||||
'street4CBDone': False,
|
||||
'street4Calls': 0,
|
||||
'street4CheckCallRaiseChance': False,
|
||||
'street4CheckCallRaiseDone': False,
|
||||
'street4Raises': 0,
|
||||
'street4Seen': False,
|
||||
'totalProfit': 2700,
|
||||
'tourneyTypeId': None,
|
||||
'tourneysPlayersIds': None,
|
||||
'winnings': 5567,
|
||||
'wonAtSD': 1.0,
|
||||
'wonWhenSeenStreet1': 1.0,
|
||||
'wonWhenSeenStreet2': 1.0,
|
||||
'wonWhenSeenStreet3': 1.0,
|
||||
'wonWhenSeenStreet4': 0.0},
|
||||
u'Player4': { 'card1': 0,
|
||||
'card2': 0,
|
||||
'card3': 0,
|
||||
'card4': 0,
|
||||
'card5': 0,
|
||||
'card6': 0,
|
||||
'card7': 0,
|
||||
'foldBbToStealChance': False,
|
||||
'foldSbToStealChance': False,
|
||||
'foldToOtherRaisedStreet0': False,
|
||||
'foldToOtherRaisedStreet1': False,
|
||||
'foldToOtherRaisedStreet2': False,
|
||||
'foldToOtherRaisedStreet3': False,
|
||||
'foldToOtherRaisedStreet4': False,
|
||||
'foldToStreet1CBChance': False,
|
||||
'foldToStreet1CBDone': False,
|
||||
'foldToStreet2CBChance': False,
|
||||
'foldToStreet2CBDone': False,
|
||||
'foldToStreet3CBChance': False,
|
||||
'foldToStreet3CBDone': False,
|
||||
'foldToStreet4CBChance': False,
|
||||
'foldToStreet4CBDone': False,
|
||||
'foldedBbToSteal': False,
|
||||
'foldedSbToSteal': False,
|
||||
'other3BStreet0': False,
|
||||
'other4BStreet0': False,
|
||||
'otherRaisedStreet0': False,
|
||||
'otherRaisedStreet1': False,
|
||||
'otherRaisedStreet2': False,
|
||||
'otherRaisedStreet3': False,
|
||||
'otherRaisedStreet4': False,
|
||||
'position': 'S',
|
||||
'raiseFirstInChance': False,
|
||||
'raisedFirstIn': False,
|
||||
'rake': 0,
|
||||
'sawShowdown': False,
|
||||
'seatNo': 0,
|
||||
'sitout': False,
|
||||
'startCards': 0,
|
||||
'startCash': 1972,
|
||||
'street0Aggr': False,
|
||||
'street0Bets': 0,
|
||||
'street0Calls': 0,
|
||||
'street0Raises': 0,
|
||||
'street0VPI': False,
|
||||
'street0_3BChance': True,
|
||||
'street0_3BDone': False,
|
||||
'street0_4BChance': False,
|
||||
'street0_4BDone': False,
|
||||
'street1Aggr': False,
|
||||
'street1Bets': 0,
|
||||
'street1CBChance': False,
|
||||
'street1CBDone': False,
|
||||
'street1Calls': 0,
|
||||
'street1CheckCallRaiseChance': False,
|
||||
'street1CheckCallRaiseDone': False,
|
||||
'street1Raises': 0,
|
||||
'street1Seen': False,
|
||||
'street2Aggr': False,
|
||||
'street2Bets': 0,
|
||||
'street2CBChance': False,
|
||||
'street2CBDone': False,
|
||||
'street2Calls': 0,
|
||||
'street2CheckCallRaiseChance': False,
|
||||
'street2CheckCallRaiseDone': False,
|
||||
'street2Raises': 0,
|
||||
'street2Seen': False,
|
||||
'street3Aggr': False,
|
||||
'street3Bets': 0,
|
||||
'street3CBChance': False,
|
||||
'street3CBDone': False,
|
||||
'street3Calls': 0,
|
||||
'street3CheckCallRaiseChance': False,
|
||||
'street3CheckCallRaiseDone': False,
|
||||
'street3Raises': 0,
|
||||
'street3Seen': False,
|
||||
'street4Aggr': False,
|
||||
'street4Bets': 0,
|
||||
'street4CBChance': False,
|
||||
'street4CBDone': False,
|
||||
'street4Calls': 0,
|
||||
'street4CheckCallRaiseChance': False,
|
||||
'street4CheckCallRaiseDone': False,
|
||||
'street4Raises': 0,
|
||||
'street4Seen': False,
|
||||
'totalProfit': -25,
|
||||
'tourneyTypeId': None,
|
||||
'tourneysPlayersIds': None,
|
||||
'winnings': 0,
|
||||
'wonAtSD': 0.0,
|
||||
'wonWhenSeenStreet1': 0.0,
|
||||
'wonWhenSeenStreet2': 0.0,
|
||||
'wonWhenSeenStreet3': 0.0,
|
||||
'wonWhenSeenStreet4': 0.0},
|
||||
u'Player5': { 'card1': 0,
|
||||
'card2': 0,
|
||||
'card3': 0,
|
||||
'card4': 0,
|
||||
'card5': 0,
|
||||
'card6': 0,
|
||||
'card7': 0,
|
||||
'foldBbToStealChance': False,
|
||||
'foldSbToStealChance': False,
|
||||
'foldToOtherRaisedStreet0': False,
|
||||
'foldToOtherRaisedStreet1': False,
|
||||
'foldToOtherRaisedStreet2': False,
|
||||
'foldToOtherRaisedStreet3': False,
|
||||
'foldToOtherRaisedStreet4': False,
|
||||
'foldToStreet1CBChance': False,
|
||||
'foldToStreet1CBDone': False,
|
||||
'foldToStreet2CBChance': False,
|
||||
'foldToStreet2CBDone': False,
|
||||
'foldToStreet3CBChance': False,
|
||||
'foldToStreet3CBDone': False,
|
||||
'foldToStreet4CBChance': False,
|
||||
'foldToStreet4CBDone': False,
|
||||
'foldedBbToSteal': False,
|
||||
'foldedSbToSteal': False,
|
||||
'other3BStreet0': False,
|
||||
'other4BStreet0': False,
|
||||
'otherRaisedStreet0': False,
|
||||
'otherRaisedStreet1': False,
|
||||
'otherRaisedStreet2': False,
|
||||
'otherRaisedStreet3': False,
|
||||
'otherRaisedStreet4': False,
|
||||
'position': 1,
|
||||
'raiseFirstInChance': False,
|
||||
'raisedFirstIn': False,
|
||||
'rake': 0,
|
||||
'sawShowdown': False,
|
||||
'seatNo': 7,
|
||||
'sitout': False,
|
||||
'startCards': 0,
|
||||
'startCash': 2516,
|
||||
'street0Aggr': False,
|
||||
'street0Bets': 0,
|
||||
'street0Calls': 1,
|
||||
'street0Raises': 0,
|
||||
'street0VPI': True,
|
||||
'street0_3BChance': True,
|
||||
'street0_3BDone': False,
|
||||
'street0_4BChance': True,
|
||||
'street0_4BDone': False,
|
||||
'street1Aggr': False,
|
||||
'street1Bets': 0,
|
||||
'street1CBChance': False,
|
||||
'street1CBDone': False,
|
||||
'street1Calls': 0,
|
||||
'street1CheckCallRaiseChance': False,
|
||||
'street1CheckCallRaiseDone': False,
|
||||
'street1Raises': 0,
|
||||
'street1Seen': False,
|
||||
'street2Aggr': False,
|
||||
'street2Bets': 0,
|
||||
'street2CBChance': False,
|
||||
'street2CBDone': False,
|
||||
'street2Calls': 0,
|
||||
'street2CheckCallRaiseChance': False,
|
||||
'street2CheckCallRaiseDone': False,
|
||||
'street2Raises': 0,
|
||||
'street2Seen': False,
|
||||
'street3Aggr': False,
|
||||
'street3Bets': 0,
|
||||
'street3CBChance': False,
|
||||
'street3CBDone': False,
|
||||
'street3Calls': 0,
|
||||
'street3CheckCallRaiseChance': False,
|
||||
'street3CheckCallRaiseDone': False,
|
||||
'street3Raises': 0,
|
||||
'street3Seen': False,
|
||||
'street4Aggr': False,
|
||||
'street4Bets': 0,
|
||||
'street4CBChance': False,
|
||||
'street4CBDone': False,
|
||||
'street4Calls': 0,
|
||||
'street4CheckCallRaiseChance': False,
|
||||
'street4CheckCallRaiseDone': False,
|
||||
'street4Raises': 0,
|
||||
'street4Seen': False,
|
||||
'totalProfit': -100,
|
||||
'tourneyTypeId': None,
|
||||
'tourneysPlayersIds': None,
|
||||
'winnings': 0,
|
||||
'wonAtSD': 0.0,
|
||||
'wonWhenSeenStreet1': 0.0,
|
||||
'wonWhenSeenStreet2': 0.0,
|
||||
'wonWhenSeenStreet3': 0.0,
|
||||
'wonWhenSeenStreet4': 0.0},
|
||||
u'Player7': { 'card1': 0,
|
||||
'card2': 0,
|
||||
'card3': 0,
|
||||
'card4': 0,
|
||||
'card5': 0,
|
||||
'card6': 0,
|
||||
'card7': 0,
|
||||
'foldBbToStealChance': False,
|
||||
'foldSbToStealChance': False,
|
||||
'foldToOtherRaisedStreet0': False,
|
||||
'foldToOtherRaisedStreet1': False,
|
||||
'foldToOtherRaisedStreet2': False,
|
||||
'foldToOtherRaisedStreet3': False,
|
||||
'foldToOtherRaisedStreet4': False,
|
||||
'foldToStreet1CBChance': False,
|
||||
'foldToStreet1CBDone': False,
|
||||
'foldToStreet2CBChance': False,
|
||||
'foldToStreet2CBDone': False,
|
||||
'foldToStreet3CBChance': False,
|
||||
'foldToStreet3CBDone': False,
|
||||
'foldToStreet4CBChance': False,
|
||||
'foldToStreet4CBDone': False,
|
||||
'foldedBbToSteal': False,
|
||||
'foldedSbToSteal': False,
|
||||
'other3BStreet0': False,
|
||||
'other4BStreet0': False,
|
||||
'otherRaisedStreet0': False,
|
||||
'otherRaisedStreet1': False,
|
||||
'otherRaisedStreet2': False,
|
||||
'otherRaisedStreet3': False,
|
||||
'otherRaisedStreet4': False,
|
||||
'position': 2,
|
||||
'raiseFirstInChance': False,
|
||||
'raisedFirstIn': False,
|
||||
'rake': 0,
|
||||
'sawShowdown': False,
|
||||
'seatNo': 5,
|
||||
'sitout': False,
|
||||
'startCards': 0,
|
||||
'startCash': 4352,
|
||||
'street0Aggr': False,
|
||||
'street0Bets': 0,
|
||||
'street0Calls': 0,
|
||||
'street0Raises': 0,
|
||||
'street0VPI': False,
|
||||
'street0_3BChance': True,
|
||||
'street0_3BDone': False,
|
||||
'street0_4BChance': False,
|
||||
'street0_4BDone': False,
|
||||
'street1Aggr': False,
|
||||
'street1Bets': 0,
|
||||
'street1CBChance': False,
|
||||
'street1CBDone': False,
|
||||
'street1Calls': 0,
|
||||
'street1CheckCallRaiseChance': False,
|
||||
'street1CheckCallRaiseDone': False,
|
||||
'street1Raises': 0,
|
||||
'street1Seen': False,
|
||||
'street2Aggr': False,
|
||||
'street2Bets': 0,
|
||||
'street2CBChance': False,
|
||||
'street2CBDone': False,
|
||||
'street2Calls': 0,
|
||||
'street2CheckCallRaiseChance': False,
|
||||
'street2CheckCallRaiseDone': False,
|
||||
'street2Raises': 0,
|
||||
'street2Seen': False,
|
||||
'street3Aggr': False,
|
||||
'street3Bets': 0,
|
||||
'street3CBChance': False,
|
||||
'street3CBDone': False,
|
||||
'street3Calls': 0,
|
||||
'street3CheckCallRaiseChance': False,
|
||||
'street3CheckCallRaiseDone': False,
|
||||
'street3Raises': 0,
|
||||
'street3Seen': False,
|
||||
'street4Aggr': False,
|
||||
'street4Bets': 0,
|
||||
'street4CBChance': False,
|
||||
'street4CBDone': False,
|
||||
'street4Calls': 0,
|
||||
'street4CheckCallRaiseChance': False,
|
||||
'street4CheckCallRaiseDone': False,
|
||||
'street4Raises': 0,
|
||||
'street4Seen': False,
|
||||
'totalProfit': 0,
|
||||
'tourneyTypeId': None,
|
||||
'tourneysPlayersIds': None,
|
||||
'winnings': 0,
|
||||
'wonAtSD': 0.0,
|
||||
'wonWhenSeenStreet1': 0.0,
|
||||
'wonWhenSeenStreet2': 0.0,
|
||||
'wonWhenSeenStreet3': 0.0,
|
||||
'wonWhenSeenStreet4': 0.0},
|
||||
u'Player8': { 'card1': 24,
|
||||
'card2': 50,
|
||||
'card3': 0,
|
||||
'card4': 0,
|
||||
'card5': 0,
|
||||
'card6': 0,
|
||||
'card7': 0,
|
||||
'foldBbToStealChance': False,
|
||||
'foldSbToStealChance': False,
|
||||
'foldToOtherRaisedStreet0': False,
|
||||
'foldToOtherRaisedStreet1': False,
|
||||
'foldToOtherRaisedStreet2': False,
|
||||
'foldToOtherRaisedStreet3': False,
|
||||
'foldToOtherRaisedStreet4': False,
|
||||
'foldToStreet1CBChance': False,
|
||||
'foldToStreet1CBDone': False,
|
||||
'foldToStreet2CBChance': False,
|
||||
'foldToStreet2CBDone': False,
|
||||
'foldToStreet3CBChance': False,
|
||||
'foldToStreet3CBDone': False,
|
||||
'foldToStreet4CBChance': False,
|
||||
'foldToStreet4CBDone': False,
|
||||
'foldedBbToSteal': False,
|
||||
'foldedSbToSteal': False,
|
||||
'other3BStreet0': False,
|
||||
'other4BStreet0': False,
|
||||
'otherRaisedStreet0': False,
|
||||
'otherRaisedStreet1': True,
|
||||
'otherRaisedStreet2': True,
|
||||
'otherRaisedStreet3': False,
|
||||
'otherRaisedStreet4': False,
|
||||
'position': 3,
|
||||
'raiseFirstInChance': True,
|
||||
'raisedFirstIn': True,
|
||||
'rake': 0,
|
||||
'sawShowdown': True,
|
||||
'seatNo': 4,
|
||||
'sitout': False,
|
||||
'startCards': 141,
|
||||
'startCash': 2867,
|
||||
'street0Aggr': True,
|
||||
'street0Bets': 0,
|
||||
'street0Calls': 1,
|
||||
'street0Raises': 0,
|
||||
'street0VPI': True,
|
||||
'street0_3BChance': False,
|
||||
'street0_3BDone': False,
|
||||
'street0_4BChance': True,
|
||||
'street0_4BDone': False,
|
||||
'street1Aggr': False,
|
||||
'street1Bets': 0,
|
||||
'street1CBChance': False,
|
||||
'street1CBDone': False,
|
||||
'street1Calls': 1,
|
||||
'street1CheckCallRaiseChance': False,
|
||||
'street1CheckCallRaiseDone': False,
|
||||
'street1Raises': 0,
|
||||
'street1Seen': True,
|
||||
'street2Aggr': False,
|
||||
'street2Bets': 0,
|
||||
'street2CBChance': False,
|
||||
'street2CBDone': False,
|
||||
'street2Calls': 1,
|
||||
'street2CheckCallRaiseChance': False,
|
||||
'street2CheckCallRaiseDone': False,
|
||||
'street2Raises': 0,
|
||||
'street2Seen': True,
|
||||
'street3Aggr': False,
|
||||
'street3Bets': 0,
|
||||
'street3CBChance': False,
|
||||
'street3CBDone': False,
|
||||
'street3Calls': 0,
|
||||
'street3CheckCallRaiseChance': False,
|
||||
'street3CheckCallRaiseDone': False,
|
||||
'street3Raises': 0,
|
||||
'street3Seen': False,
|
||||
'street4Aggr': False,
|
||||
'street4Bets': 0,
|
||||
'street4CBChance': False,
|
||||
'street4CBDone': False,
|
||||
'street4Calls': 0,
|
||||
'street4CheckCallRaiseChance': False,
|
||||
'street4CheckCallRaiseDone': False,
|
||||
'street4Raises': 0,
|
||||
'street4Seen': False,
|
||||
'totalProfit': -2867,
|
||||
'tourneyTypeId': None,
|
||||
'tourneysPlayersIds': None,
|
||||
'winnings': 0,
|
||||
'wonAtSD': 0.0,
|
||||
'wonWhenSeenStreet1': 0.0,
|
||||
'wonWhenSeenStreet2': 0.0,
|
||||
'wonWhenSeenStreet3': 0.0,
|
||||
'wonWhenSeenStreet4': 0.0},
|
||||
u'Player9': { 'card1': 0,
|
||||
'card2': 0,
|
||||
'card3': 0,
|
||||
'card4': 0,
|
||||
'card5': 0,
|
||||
'card6': 0,
|
||||
'card7': 0,
|
||||
'foldBbToStealChance': False,
|
||||
'foldSbToStealChance': False,
|
||||
'foldToOtherRaisedStreet0': False,
|
||||
'foldToOtherRaisedStreet1': False,
|
||||
'foldToOtherRaisedStreet2': False,
|
||||
'foldToOtherRaisedStreet3': False,
|
||||
'foldToOtherRaisedStreet4': False,
|
||||
'foldToStreet1CBChance': False,
|
||||
'foldToStreet1CBDone': False,
|
||||
'foldToStreet2CBChance': False,
|
||||
'foldToStreet2CBDone': False,
|
||||
'foldToStreet3CBChance': False,
|
||||
'foldToStreet3CBDone': False,
|
||||
'foldToStreet4CBChance': False,
|
||||
'foldToStreet4CBDone': False,
|
||||
'foldedBbToSteal': False,
|
||||
'foldedSbToSteal': False,
|
||||
'other3BStreet0': False,
|
||||
'other4BStreet0': False,
|
||||
'otherRaisedStreet0': False,
|
||||
'otherRaisedStreet1': False,
|
||||
'otherRaisedStreet2': False,
|
||||
'otherRaisedStreet3': False,
|
||||
'otherRaisedStreet4': False,
|
||||
'position': 0,
|
||||
'raiseFirstInChance': False,
|
||||
'raisedFirstIn': False,
|
||||
'rake': 0,
|
||||
'sawShowdown': False,
|
||||
'seatNo': 8,
|
||||
'sitout': False,
|
||||
'startCards': 0,
|
||||
'startCash': 925,
|
||||
'street0Aggr': False,
|
||||
'street0Bets': 0,
|
||||
'street0Calls': 0,
|
||||
'street0Raises': 0,
|
||||
'street0VPI': False,
|
||||
'street0_3BChance': True,
|
||||
'street0_3BDone': False,
|
||||
'street0_4BChance': False,
|
||||
'street0_4BDone': False,
|
||||
'street1Aggr': False,
|
||||
'street1Bets': 0,
|
||||
'street1CBChance': False,
|
||||
'street1CBDone': False,
|
||||
'street1Calls': 0,
|
||||
'street1CheckCallRaiseChance': False,
|
||||
'street1CheckCallRaiseDone': False,
|
||||
'street1Raises': 0,
|
||||
'street1Seen': False,
|
||||
'street2Aggr': False,
|
||||
'street2Bets': 0,
|
||||
'street2CBChance': False,
|
||||
'street2CBDone': False,
|
||||
'street2Calls': 0,
|
||||
'street2CheckCallRaiseChance': False,
|
||||
'street2CheckCallRaiseDone': False,
|
||||
'street2Raises': 0,
|
||||
'street2Seen': False,
|
||||
'street3Aggr': False,
|
||||
'street3Bets': 0,
|
||||
'street3CBChance': False,
|
||||
'street3CBDone': False,
|
||||
'street3Calls': 0,
|
||||
'street3CheckCallRaiseChance': False,
|
||||
'street3CheckCallRaiseDone': False,
|
||||
'street3Raises': 0,
|
||||
'street3Seen': False,
|
||||
'street4Aggr': False,
|
||||
'street4Bets': 0,
|
||||
'street4CBChance': False,
|
||||
'street4CBDone': False,
|
||||
'street4Calls': 0,
|
||||
'street4CheckCallRaiseChance': False,
|
||||
'street4CheckCallRaiseDone': False,
|
||||
'street4Raises': 0,
|
||||
'street4Seen': False,
|
||||
'totalProfit': 0,
|
||||
'tourneyTypeId': None,
|
||||
'tourneysPlayersIds': None,
|
||||
'winnings': 0,
|
||||
'wonAtSD': 0.0,
|
||||
'wonWhenSeenStreet1': 0.0,
|
||||
'wonWhenSeenStreet2': 0.0,
|
||||
'wonWhenSeenStreet3': 0.0,
|
||||
'wonWhenSeenStreet4': 0.0}}
|
||||
File diff suppressed because it is too large
Load Diff
|
|
@ -0,0 +1,40 @@
|
|||
Everleaf Gaming Game #190070009
|
||||
***** Hand history for game #190070009 *****
|
||||
Blinds $0.01/$0.02 NL Hold'em - 2010/08/03 - 17:00:00
|
||||
Table Los Angeles XV
|
||||
Seat 2 is the button
|
||||
Total number of players: 8
|
||||
Seat 1: Player1 ( $ 0.98 USD )
|
||||
Seat 2: Player2 ( $ 1.95 USD )
|
||||
Seat 3: Player3 ( $ 0.94 USD )
|
||||
Seat 4: Player4 ( $ 1.80 USD )
|
||||
Seat 5: Player5 ( $ 0.40 USD )
|
||||
Seat 8: Player6 ( $ 1.51 USD )
|
||||
Seat 9: Player7 ( $ 0.03 USD )
|
||||
Seat 10: Player8 ( $ 4.19 USD )
|
||||
Player3: posts small blind [$ 0.01 USD]
|
||||
Player4: posts big blind [$ 0.02 USD]
|
||||
** Dealing down cards **
|
||||
Player5 calls [$ 0.02 USD]
|
||||
Player6 folds
|
||||
Player7 calls [$ 0.02 USD]
|
||||
Player8 folds
|
||||
Player1 calls [$ 0.02 USD]
|
||||
Player2 folds
|
||||
Player3 calls [$ 0.01 USD]
|
||||
Player4 raises [$ 0.18 USD]
|
||||
Player5 folds
|
||||
Player7 calls [$ 0.01 USD]
|
||||
Player1 raises [$ 0.96 USD]
|
||||
Player3 folds
|
||||
Player4 calls [$ 0.78 USD]
|
||||
** Dealing Flop ** [ 6d, Jc, Js ]
|
||||
** Dealing Turn ** [ 3d ]
|
||||
** Dealing River ** [ 9d ]
|
||||
Player1 shows [ 4c, 4d ] two pairs, jacks and fours
|
||||
Player4 shows [ 8c, 8h ] two pairs, jacks and eights
|
||||
Player7 shows [ 5s, Td ] a pair of jacks
|
||||
Player4 wins $ 0.13 USD from main pot with two pairs, jacks and
|
||||
eights [ Jc, Js, 9d, 8c, 8h ]
|
||||
Player4 wins $ 1.81 USD from side pot with two pairs, jacks and
|
||||
eights [ Jc, Js, 9d, 8c, 8h ]
|
||||
|
|
@ -0,0 +1,752 @@
|
|||
{ u'Player1': { 'card1': 29,
|
||||
'card2': 16,
|
||||
'card3': 0,
|
||||
'card4': 0,
|
||||
'card5': 0,
|
||||
'card6': 0,
|
||||
'card7': 0,
|
||||
'foldBbToStealChance': False,
|
||||
'foldSbToStealChance': False,
|
||||
'foldToOtherRaisedStreet0': False,
|
||||
'foldToOtherRaisedStreet1': False,
|
||||
'foldToOtherRaisedStreet2': False,
|
||||
'foldToOtherRaisedStreet3': False,
|
||||
'foldToOtherRaisedStreet4': False,
|
||||
'foldToStreet1CBChance': False,
|
||||
'foldToStreet1CBDone': False,
|
||||
'foldToStreet2CBChance': False,
|
||||
'foldToStreet2CBDone': False,
|
||||
'foldToStreet3CBChance': False,
|
||||
'foldToStreet3CBDone': False,
|
||||
'foldToStreet4CBChance': False,
|
||||
'foldToStreet4CBDone': False,
|
||||
'foldedBbToSteal': False,
|
||||
'foldedSbToSteal': False,
|
||||
'other3BStreet0': False,
|
||||
'other4BStreet0': False,
|
||||
'otherRaisedStreet0': False,
|
||||
'otherRaisedStreet1': False,
|
||||
'otherRaisedStreet2': False,
|
||||
'otherRaisedStreet3': False,
|
||||
'otherRaisedStreet4': False,
|
||||
'position': 1,
|
||||
'raiseFirstInChance': False,
|
||||
'raisedFirstIn': False,
|
||||
'rake': 0,
|
||||
'sawShowdown': True,
|
||||
'seatNo': 1,
|
||||
'sitout': False,
|
||||
'startCards': 29,
|
||||
'startCash': 98,
|
||||
'street0Aggr': True,
|
||||
'street0Bets': 0,
|
||||
'street0Calls': 1,
|
||||
'street0Raises': 0,
|
||||
'street0VPI': True,
|
||||
'street0_3BChance': True,
|
||||
'street0_3BDone': True,
|
||||
'street0_4BChance': False,
|
||||
'street0_4BDone': False,
|
||||
'street1Aggr': False,
|
||||
'street1Bets': 0,
|
||||
'street1CBChance': False,
|
||||
'street1CBDone': False,
|
||||
'street1Calls': 0,
|
||||
'street1CheckCallRaiseChance': False,
|
||||
'street1CheckCallRaiseDone': False,
|
||||
'street1Raises': 0,
|
||||
'street1Seen': False,
|
||||
'street2Aggr': False,
|
||||
'street2Bets': 0,
|
||||
'street2CBChance': False,
|
||||
'street2CBDone': False,
|
||||
'street2Calls': 0,
|
||||
'street2CheckCallRaiseChance': False,
|
||||
'street2CheckCallRaiseDone': False,
|
||||
'street2Raises': 0,
|
||||
'street2Seen': False,
|
||||
'street3Aggr': False,
|
||||
'street3Bets': 0,
|
||||
'street3CBChance': False,
|
||||
'street3CBDone': False,
|
||||
'street3Calls': 0,
|
||||
'street3CheckCallRaiseChance': False,
|
||||
'street3CheckCallRaiseDone': False,
|
||||
'street3Raises': 0,
|
||||
'street3Seen': False,
|
||||
'street4Aggr': False,
|
||||
'street4Bets': 0,
|
||||
'street4CBChance': False,
|
||||
'street4CBDone': False,
|
||||
'street4Calls': 0,
|
||||
'street4CheckCallRaiseChance': False,
|
||||
'street4CheckCallRaiseDone': False,
|
||||
'street4Raises': 0,
|
||||
'street4Seen': False,
|
||||
'totalProfit': -98,
|
||||
'tourneyTypeId': None,
|
||||
'tourneysPlayersIds': None,
|
||||
'winnings': 0,
|
||||
'wonAtSD': 0.0,
|
||||
'wonWhenSeenStreet1': 0.0,
|
||||
'wonWhenSeenStreet2': 0.0,
|
||||
'wonWhenSeenStreet3': 0.0,
|
||||
'wonWhenSeenStreet4': 0.0},
|
||||
u'Player2': { 'card1': 0,
|
||||
'card2': 0,
|
||||
'card3': 0,
|
||||
'card4': 0,
|
||||
'card5': 0,
|
||||
'card6': 0,
|
||||
'card7': 0,
|
||||
'foldBbToStealChance': False,
|
||||
'foldSbToStealChance': False,
|
||||
'foldToOtherRaisedStreet0': False,
|
||||
'foldToOtherRaisedStreet1': False,
|
||||
'foldToOtherRaisedStreet2': False,
|
||||
'foldToOtherRaisedStreet3': False,
|
||||
'foldToOtherRaisedStreet4': False,
|
||||
'foldToStreet1CBChance': False,
|
||||
'foldToStreet1CBDone': False,
|
||||
'foldToStreet2CBChance': False,
|
||||
'foldToStreet2CBDone': False,
|
||||
'foldToStreet3CBChance': False,
|
||||
'foldToStreet3CBDone': False,
|
||||
'foldToStreet4CBChance': False,
|
||||
'foldToStreet4CBDone': False,
|
||||
'foldedBbToSteal': False,
|
||||
'foldedSbToSteal': False,
|
||||
'other3BStreet0': False,
|
||||
'other4BStreet0': False,
|
||||
'otherRaisedStreet0': False,
|
||||
'otherRaisedStreet1': False,
|
||||
'otherRaisedStreet2': False,
|
||||
'otherRaisedStreet3': False,
|
||||
'otherRaisedStreet4': False,
|
||||
'position': 0,
|
||||
'raiseFirstInChance': False,
|
||||
'raisedFirstIn': False,
|
||||
'rake': 0,
|
||||
'sawShowdown': False,
|
||||
'seatNo': 2,
|
||||
'sitout': False,
|
||||
'startCards': 0,
|
||||
'startCash': 195,
|
||||
'street0Aggr': False,
|
||||
'street0Bets': 0,
|
||||
'street0Calls': 0,
|
||||
'street0Raises': 0,
|
||||
'street0VPI': False,
|
||||
'street0_3BChance': False,
|
||||
'street0_3BDone': False,
|
||||
'street0_4BChance': False,
|
||||
'street0_4BDone': False,
|
||||
'street1Aggr': False,
|
||||
'street1Bets': 0,
|
||||
'street1CBChance': False,
|
||||
'street1CBDone': False,
|
||||
'street1Calls': 0,
|
||||
'street1CheckCallRaiseChance': False,
|
||||
'street1CheckCallRaiseDone': False,
|
||||
'street1Raises': 0,
|
||||
'street1Seen': False,
|
||||
'street2Aggr': False,
|
||||
'street2Bets': 0,
|
||||
'street2CBChance': False,
|
||||
'street2CBDone': False,
|
||||
'street2Calls': 0,
|
||||
'street2CheckCallRaiseChance': False,
|
||||
'street2CheckCallRaiseDone': False,
|
||||
'street2Raises': 0,
|
||||
'street2Seen': False,
|
||||
'street3Aggr': False,
|
||||
'street3Bets': 0,
|
||||
'street3CBChance': False,
|
||||
'street3CBDone': False,
|
||||
'street3Calls': 0,
|
||||
'street3CheckCallRaiseChance': False,
|
||||
'street3CheckCallRaiseDone': False,
|
||||
'street3Raises': 0,
|
||||
'street3Seen': False,
|
||||
'street4Aggr': False,
|
||||
'street4Bets': 0,
|
||||
'street4CBChance': False,
|
||||
'street4CBDone': False,
|
||||
'street4Calls': 0,
|
||||
'street4CheckCallRaiseChance': False,
|
||||
'street4CheckCallRaiseDone': False,
|
||||
'street4Raises': 0,
|
||||
'street4Seen': False,
|
||||
'totalProfit': 0,
|
||||
'tourneyTypeId': None,
|
||||
'tourneysPlayersIds': None,
|
||||
'winnings': 0,
|
||||
'wonAtSD': 0.0,
|
||||
'wonWhenSeenStreet1': 0.0,
|
||||
'wonWhenSeenStreet2': 0.0,
|
||||
'wonWhenSeenStreet3': 0.0,
|
||||
'wonWhenSeenStreet4': 0.0},
|
||||
u'Player3': { 'card1': 0,
|
||||
'card2': 0,
|
||||
'card3': 0,
|
||||
'card4': 0,
|
||||
'card5': 0,
|
||||
'card6': 0,
|
||||
'card7': 0,
|
||||
'foldBbToStealChance': False,
|
||||
'foldSbToStealChance': False,
|
||||
'foldToOtherRaisedStreet0': False,
|
||||
'foldToOtherRaisedStreet1': False,
|
||||
'foldToOtherRaisedStreet2': False,
|
||||
'foldToOtherRaisedStreet3': False,
|
||||
'foldToOtherRaisedStreet4': False,
|
||||
'foldToStreet1CBChance': False,
|
||||
'foldToStreet1CBDone': False,
|
||||
'foldToStreet2CBChance': False,
|
||||
'foldToStreet2CBDone': False,
|
||||
'foldToStreet3CBChance': False,
|
||||
'foldToStreet3CBDone': False,
|
||||
'foldToStreet4CBChance': False,
|
||||
'foldToStreet4CBDone': False,
|
||||
'foldedBbToSteal': False,
|
||||
'foldedSbToSteal': False,
|
||||
'other3BStreet0': False,
|
||||
'other4BStreet0': False,
|
||||
'otherRaisedStreet0': False,
|
||||
'otherRaisedStreet1': False,
|
||||
'otherRaisedStreet2': False,
|
||||
'otherRaisedStreet3': False,
|
||||
'otherRaisedStreet4': False,
|
||||
'position': 'S',
|
||||
'raiseFirstInChance': False,
|
||||
'raisedFirstIn': False,
|
||||
'rake': 0,
|
||||
'sawShowdown': False,
|
||||
'seatNo': 3,
|
||||
'sitout': False,
|
||||
'startCards': 0,
|
||||
'startCash': 94,
|
||||
'street0Aggr': False,
|
||||
'street0Bets': 0,
|
||||
'street0Calls': 1,
|
||||
'street0Raises': 0,
|
||||
'street0VPI': True,
|
||||
'street0_3BChance': False,
|
||||
'street0_3BDone': False,
|
||||
'street0_4BChance': True,
|
||||
'street0_4BDone': False,
|
||||
'street1Aggr': False,
|
||||
'street1Bets': 0,
|
||||
'street1CBChance': False,
|
||||
'street1CBDone': False,
|
||||
'street1Calls': 0,
|
||||
'street1CheckCallRaiseChance': False,
|
||||
'street1CheckCallRaiseDone': False,
|
||||
'street1Raises': 0,
|
||||
'street1Seen': False,
|
||||
'street2Aggr': False,
|
||||
'street2Bets': 0,
|
||||
'street2CBChance': False,
|
||||
'street2CBDone': False,
|
||||
'street2Calls': 0,
|
||||
'street2CheckCallRaiseChance': False,
|
||||
'street2CheckCallRaiseDone': False,
|
||||
'street2Raises': 0,
|
||||
'street2Seen': False,
|
||||
'street3Aggr': False,
|
||||
'street3Bets': 0,
|
||||
'street3CBChance': False,
|
||||
'street3CBDone': False,
|
||||
'street3Calls': 0,
|
||||
'street3CheckCallRaiseChance': False,
|
||||
'street3CheckCallRaiseDone': False,
|
||||
'street3Raises': 0,
|
||||
'street3Seen': False,
|
||||
'street4Aggr': False,
|
||||
'street4Bets': 0,
|
||||
'street4CBChance': False,
|
||||
'street4CBDone': False,
|
||||
'street4Calls': 0,
|
||||
'street4CheckCallRaiseChance': False,
|
||||
'street4CheckCallRaiseDone': False,
|
||||
'street4Raises': 0,
|
||||
'street4Seen': False,
|
||||
'totalProfit': -2,
|
||||
'tourneyTypeId': None,
|
||||
'tourneysPlayersIds': None,
|
||||
'winnings': 0,
|
||||
'wonAtSD': 0.0,
|
||||
'wonWhenSeenStreet1': 0.0,
|
||||
'wonWhenSeenStreet2': 0.0,
|
||||
'wonWhenSeenStreet3': 0.0,
|
||||
'wonWhenSeenStreet4': 0.0},
|
||||
u'Player4': { 'card1': 33,
|
||||
'card2': 7,
|
||||
'card3': 0,
|
||||
'card4': 0,
|
||||
'card5': 0,
|
||||
'card6': 0,
|
||||
'card7': 0,
|
||||
'foldBbToStealChance': False,
|
||||
'foldSbToStealChance': False,
|
||||
'foldToOtherRaisedStreet0': False,
|
||||
'foldToOtherRaisedStreet1': False,
|
||||
'foldToOtherRaisedStreet2': False,
|
||||
'foldToOtherRaisedStreet3': False,
|
||||
'foldToOtherRaisedStreet4': False,
|
||||
'foldToStreet1CBChance': False,
|
||||
'foldToStreet1CBDone': False,
|
||||
'foldToStreet2CBChance': False,
|
||||
'foldToStreet2CBDone': False,
|
||||
'foldToStreet3CBChance': False,
|
||||
'foldToStreet3CBDone': False,
|
||||
'foldToStreet4CBChance': False,
|
||||
'foldToStreet4CBDone': False,
|
||||
'foldedBbToSteal': False,
|
||||
'foldedSbToSteal': False,
|
||||
'other3BStreet0': False,
|
||||
'other4BStreet0': False,
|
||||
'otherRaisedStreet0': False,
|
||||
'otherRaisedStreet1': False,
|
||||
'otherRaisedStreet2': False,
|
||||
'otherRaisedStreet3': False,
|
||||
'otherRaisedStreet4': False,
|
||||
'position': 'B',
|
||||
'raiseFirstInChance': False,
|
||||
'raisedFirstIn': False,
|
||||
'rake': 9,
|
||||
'sawShowdown': True,
|
||||
'seatNo': 4,
|
||||
'sitout': False,
|
||||
'startCards': 85,
|
||||
'startCash': 180,
|
||||
'street0Aggr': True,
|
||||
'street0Bets': 0,
|
||||
'street0Calls': 1,
|
||||
'street0Raises': 0,
|
||||
'street0VPI': True,
|
||||
'street0_3BChance': False,
|
||||
'street0_3BDone': False,
|
||||
'street0_4BChance': True,
|
||||
'street0_4BDone': False,
|
||||
'street1Aggr': False,
|
||||
'street1Bets': 0,
|
||||
'street1CBChance': False,
|
||||
'street1CBDone': False,
|
||||
'street1Calls': 0,
|
||||
'street1CheckCallRaiseChance': False,
|
||||
'street1CheckCallRaiseDone': False,
|
||||
'street1Raises': 0,
|
||||
'street1Seen': False,
|
||||
'street2Aggr': False,
|
||||
'street2Bets': 0,
|
||||
'street2CBChance': False,
|
||||
'street2CBDone': False,
|
||||
'street2Calls': 0,
|
||||
'street2CheckCallRaiseChance': False,
|
||||
'street2CheckCallRaiseDone': False,
|
||||
'street2Raises': 0,
|
||||
'street2Seen': False,
|
||||
'street3Aggr': False,
|
||||
'street3Bets': 0,
|
||||
'street3CBChance': False,
|
||||
'street3CBDone': False,
|
||||
'street3Calls': 0,
|
||||
'street3CheckCallRaiseChance': False,
|
||||
'street3CheckCallRaiseDone': False,
|
||||
'street3Raises': 0,
|
||||
'street3Seen': False,
|
||||
'street4Aggr': False,
|
||||
'street4Bets': 0,
|
||||
'street4CBChance': False,
|
||||
'street4CBDone': False,
|
||||
'street4Calls': 0,
|
||||
'street4CheckCallRaiseChance': False,
|
||||
'street4CheckCallRaiseDone': False,
|
||||
'street4Raises': 0,
|
||||
'street4Seen': False,
|
||||
'totalProfit': 96,
|
||||
'tourneyTypeId': None,
|
||||
'tourneysPlayersIds': None,
|
||||
'winnings': 194,
|
||||
'wonAtSD': 1.0,
|
||||
'wonWhenSeenStreet1': 0.0,
|
||||
'wonWhenSeenStreet2': 0.0,
|
||||
'wonWhenSeenStreet3': 0.0,
|
||||
'wonWhenSeenStreet4': 0.0},
|
||||
u'Player5': { 'card1': 0,
|
||||
'card2': 0,
|
||||
'card3': 0,
|
||||
'card4': 0,
|
||||
'card5': 0,
|
||||
'card6': 0,
|
||||
'card7': 0,
|
||||
'foldBbToStealChance': False,
|
||||
'foldSbToStealChance': False,
|
||||
'foldToOtherRaisedStreet0': False,
|
||||
'foldToOtherRaisedStreet1': False,
|
||||
'foldToOtherRaisedStreet2': False,
|
||||
'foldToOtherRaisedStreet3': False,
|
||||
'foldToOtherRaisedStreet4': False,
|
||||
'foldToStreet1CBChance': False,
|
||||
'foldToStreet1CBDone': False,
|
||||
'foldToStreet2CBChance': False,
|
||||
'foldToStreet2CBDone': False,
|
||||
'foldToStreet3CBChance': False,
|
||||
'foldToStreet3CBDone': False,
|
||||
'foldToStreet4CBChance': False,
|
||||
'foldToStreet4CBDone': False,
|
||||
'foldedBbToSteal': False,
|
||||
'foldedSbToSteal': False,
|
||||
'other3BStreet0': False,
|
||||
'other4BStreet0': False,
|
||||
'otherRaisedStreet0': False,
|
||||
'otherRaisedStreet1': False,
|
||||
'otherRaisedStreet2': False,
|
||||
'otherRaisedStreet3': False,
|
||||
'otherRaisedStreet4': False,
|
||||
'position': 5,
|
||||
'raiseFirstInChance': True,
|
||||
'raisedFirstIn': False,
|
||||
'rake': 0,
|
||||
'sawShowdown': False,
|
||||
'seatNo': 5,
|
||||
'sitout': False,
|
||||
'startCards': 0,
|
||||
'startCash': 40,
|
||||
'street0Aggr': False,
|
||||
'street0Bets': 0,
|
||||
'street0Calls': 1,
|
||||
'street0Raises': 0,
|
||||
'street0VPI': True,
|
||||
'street0_3BChance': True,
|
||||
'street0_3BDone': False,
|
||||
'street0_4BChance': False,
|
||||
'street0_4BDone': False,
|
||||
'street1Aggr': False,
|
||||
'street1Bets': 0,
|
||||
'street1CBChance': False,
|
||||
'street1CBDone': False,
|
||||
'street1Calls': 0,
|
||||
'street1CheckCallRaiseChance': False,
|
||||
'street1CheckCallRaiseDone': False,
|
||||
'street1Raises': 0,
|
||||
'street1Seen': False,
|
||||
'street2Aggr': False,
|
||||
'street2Bets': 0,
|
||||
'street2CBChance': False,
|
||||
'street2CBDone': False,
|
||||
'street2Calls': 0,
|
||||
'street2CheckCallRaiseChance': False,
|
||||
'street2CheckCallRaiseDone': False,
|
||||
'street2Raises': 0,
|
||||
'street2Seen': False,
|
||||
'street3Aggr': False,
|
||||
'street3Bets': 0,
|
||||
'street3CBChance': False,
|
||||
'street3CBDone': False,
|
||||
'street3Calls': 0,
|
||||
'street3CheckCallRaiseChance': False,
|
||||
'street3CheckCallRaiseDone': False,
|
||||
'street3Raises': 0,
|
||||
'street3Seen': False,
|
||||
'street4Aggr': False,
|
||||
'street4Bets': 0,
|
||||
'street4CBChance': False,
|
||||
'street4CBDone': False,
|
||||
'street4Calls': 0,
|
||||
'street4CheckCallRaiseChance': False,
|
||||
'street4CheckCallRaiseDone': False,
|
||||
'street4Raises': 0,
|
||||
'street4Seen': False,
|
||||
'totalProfit': -2,
|
||||
'tourneyTypeId': None,
|
||||
'tourneysPlayersIds': None,
|
||||
'winnings': 0,
|
||||
'wonAtSD': 0.0,
|
||||
'wonWhenSeenStreet1': 0.0,
|
||||
'wonWhenSeenStreet2': 0.0,
|
||||
'wonWhenSeenStreet3': 0.0,
|
||||
'wonWhenSeenStreet4': 0.0},
|
||||
u'Player6': { 'card1': 0,
|
||||
'card2': 0,
|
||||
'card3': 0,
|
||||
'card4': 0,
|
||||
'card5': 0,
|
||||
'card6': 0,
|
||||
'card7': 0,
|
||||
'foldBbToStealChance': False,
|
||||
'foldSbToStealChance': False,
|
||||
'foldToOtherRaisedStreet0': False,
|
||||
'foldToOtherRaisedStreet1': False,
|
||||
'foldToOtherRaisedStreet2': False,
|
||||
'foldToOtherRaisedStreet3': False,
|
||||
'foldToOtherRaisedStreet4': False,
|
||||
'foldToStreet1CBChance': False,
|
||||
'foldToStreet1CBDone': False,
|
||||
'foldToStreet2CBChance': False,
|
||||
'foldToStreet2CBDone': False,
|
||||
'foldToStreet3CBChance': False,
|
||||
'foldToStreet3CBDone': False,
|
||||
'foldToStreet4CBChance': False,
|
||||
'foldToStreet4CBDone': False,
|
||||
'foldedBbToSteal': False,
|
||||
'foldedSbToSteal': False,
|
||||
'other3BStreet0': False,
|
||||
'other4BStreet0': False,
|
||||
'otherRaisedStreet0': False,
|
||||
'otherRaisedStreet1': False,
|
||||
'otherRaisedStreet2': False,
|
||||
'otherRaisedStreet3': False,
|
||||
'otherRaisedStreet4': False,
|
||||
'position': 4,
|
||||
'raiseFirstInChance': False,
|
||||
'raisedFirstIn': False,
|
||||
'rake': 0,
|
||||
'sawShowdown': False,
|
||||
'seatNo': 8,
|
||||
'sitout': False,
|
||||
'startCards': 0,
|
||||
'startCash': 151,
|
||||
'street0Aggr': False,
|
||||
'street0Bets': 0,
|
||||
'street0Calls': 0,
|
||||
'street0Raises': 0,
|
||||
'street0VPI': False,
|
||||
'street0_3BChance': False,
|
||||
'street0_3BDone': False,
|
||||
'street0_4BChance': False,
|
||||
'street0_4BDone': False,
|
||||
'street1Aggr': False,
|
||||
'street1Bets': 0,
|
||||
'street1CBChance': False,
|
||||
'street1CBDone': False,
|
||||
'street1Calls': 0,
|
||||
'street1CheckCallRaiseChance': False,
|
||||
'street1CheckCallRaiseDone': False,
|
||||
'street1Raises': 0,
|
||||
'street1Seen': False,
|
||||
'street2Aggr': False,
|
||||
'street2Bets': 0,
|
||||
'street2CBChance': False,
|
||||
'street2CBDone': False,
|
||||
'street2Calls': 0,
|
||||
'street2CheckCallRaiseChance': False,
|
||||
'street2CheckCallRaiseDone': False,
|
||||
'street2Raises': 0,
|
||||
'street2Seen': False,
|
||||
'street3Aggr': False,
|
||||
'street3Bets': 0,
|
||||
'street3CBChance': False,
|
||||
'street3CBDone': False,
|
||||
'street3Calls': 0,
|
||||
'street3CheckCallRaiseChance': False,
|
||||
'street3CheckCallRaiseDone': False,
|
||||
'street3Raises': 0,
|
||||
'street3Seen': False,
|
||||
'street4Aggr': False,
|
||||
'street4Bets': 0,
|
||||
'street4CBChance': False,
|
||||
'street4CBDone': False,
|
||||
'street4Calls': 0,
|
||||
'street4CheckCallRaiseChance': False,
|
||||
'street4CheckCallRaiseDone': False,
|
||||
'street4Raises': 0,
|
||||
'street4Seen': False,
|
||||
'totalProfit': 0,
|
||||
'tourneyTypeId': None,
|
||||
'tourneysPlayersIds': None,
|
||||
'winnings': 0,
|
||||
'wonAtSD': 0.0,
|
||||
'wonWhenSeenStreet1': 0.0,
|
||||
'wonWhenSeenStreet2': 0.0,
|
||||
'wonWhenSeenStreet3': 0.0,
|
||||
'wonWhenSeenStreet4': 0.0},
|
||||
u'Player7': { 'card1': 43,
|
||||
'card2': 22,
|
||||
'card3': 0,
|
||||
'card4': 0,
|
||||
'card5': 0,
|
||||
'card6': 0,
|
||||
'card7': 0,
|
||||
'foldBbToStealChance': False,
|
||||
'foldSbToStealChance': False,
|
||||
'foldToOtherRaisedStreet0': False,
|
||||
'foldToOtherRaisedStreet1': False,
|
||||
'foldToOtherRaisedStreet2': False,
|
||||
'foldToOtherRaisedStreet3': False,
|
||||
'foldToOtherRaisedStreet4': False,
|
||||
'foldToStreet1CBChance': False,
|
||||
'foldToStreet1CBDone': False,
|
||||
'foldToStreet2CBChance': False,
|
||||
'foldToStreet2CBDone': False,
|
||||
'foldToStreet3CBChance': False,
|
||||
'foldToStreet3CBDone': False,
|
||||
'foldToStreet4CBChance': False,
|
||||
'foldToStreet4CBDone': False,
|
||||
'foldedBbToSteal': False,
|
||||
'foldedSbToSteal': False,
|
||||
'other3BStreet0': False,
|
||||
'other4BStreet0': False,
|
||||
'otherRaisedStreet0': False,
|
||||
'otherRaisedStreet1': False,
|
||||
'otherRaisedStreet2': False,
|
||||
'otherRaisedStreet3': False,
|
||||
'otherRaisedStreet4': False,
|
||||
'position': 3,
|
||||
'raiseFirstInChance': False,
|
||||
'raisedFirstIn': False,
|
||||
'rake': 0,
|
||||
'sawShowdown': True,
|
||||
'seatNo': 9,
|
||||
'sitout': False,
|
||||
'startCards': 48,
|
||||
'startCash': 3,
|
||||
'street0Aggr': False,
|
||||
'street0Bets': 0,
|
||||
'street0Calls': 2,
|
||||
'street0Raises': 0,
|
||||
'street0VPI': True,
|
||||
'street0_3BChance': True,
|
||||
'street0_3BDone': False,
|
||||
'street0_4BChance': False,
|
||||
'street0_4BDone': False,
|
||||
'street1Aggr': False,
|
||||
'street1Bets': 0,
|
||||
'street1CBChance': False,
|
||||
'street1CBDone': False,
|
||||
'street1Calls': 0,
|
||||
'street1CheckCallRaiseChance': False,
|
||||
'street1CheckCallRaiseDone': False,
|
||||
'street1Raises': 0,
|
||||
'street1Seen': False,
|
||||
'street2Aggr': False,
|
||||
'street2Bets': 0,
|
||||
'street2CBChance': False,
|
||||
'street2CBDone': False,
|
||||
'street2Calls': 0,
|
||||
'street2CheckCallRaiseChance': False,
|
||||
'street2CheckCallRaiseDone': False,
|
||||
'street2Raises': 0,
|
||||
'street2Seen': False,
|
||||
'street3Aggr': False,
|
||||
'street3Bets': 0,
|
||||
'street3CBChance': False,
|
||||
'street3CBDone': False,
|
||||
'street3Calls': 0,
|
||||
'street3CheckCallRaiseChance': False,
|
||||
'street3CheckCallRaiseDone': False,
|
||||
'street3Raises': 0,
|
||||
'street3Seen': False,
|
||||
'street4Aggr': False,
|
||||
'street4Bets': 0,
|
||||
'street4CBChance': False,
|
||||
'street4CBDone': False,
|
||||
'street4Calls': 0,
|
||||
'street4CheckCallRaiseChance': False,
|
||||
'street4CheckCallRaiseDone': False,
|
||||
'street4Raises': 0,
|
||||
'street4Seen': False,
|
||||
'totalProfit': -3,
|
||||
'tourneyTypeId': None,
|
||||
'tourneysPlayersIds': None,
|
||||
'winnings': 0,
|
||||
'wonAtSD': 0.0,
|
||||
'wonWhenSeenStreet1': 0.0,
|
||||
'wonWhenSeenStreet2': 0.0,
|
||||
'wonWhenSeenStreet3': 0.0,
|
||||
'wonWhenSeenStreet4': 0.0},
|
||||
u'Player8': { 'card1': 0,
|
||||
'card2': 0,
|
||||
'card3': 0,
|
||||
'card4': 0,
|
||||
'card5': 0,
|
||||
'card6': 0,
|
||||
'card7': 0,
|
||||
'foldBbToStealChance': False,
|
||||
'foldSbToStealChance': False,
|
||||
'foldToOtherRaisedStreet0': False,
|
||||
'foldToOtherRaisedStreet1': False,
|
||||
'foldToOtherRaisedStreet2': False,
|
||||
'foldToOtherRaisedStreet3': False,
|
||||
'foldToOtherRaisedStreet4': False,
|
||||
'foldToStreet1CBChance': False,
|
||||
'foldToStreet1CBDone': False,
|
||||
'foldToStreet2CBChance': False,
|
||||
'foldToStreet2CBDone': False,
|
||||
'foldToStreet3CBChance': False,
|
||||
'foldToStreet3CBDone': False,
|
||||
'foldToStreet4CBChance': False,
|
||||
'foldToStreet4CBDone': False,
|
||||
'foldedBbToSteal': False,
|
||||
'foldedSbToSteal': False,
|
||||
'other3BStreet0': False,
|
||||
'other4BStreet0': False,
|
||||
'otherRaisedStreet0': False,
|
||||
'otherRaisedStreet1': False,
|
||||
'otherRaisedStreet2': False,
|
||||
'otherRaisedStreet3': False,
|
||||
'otherRaisedStreet4': False,
|
||||
'position': 2,
|
||||
'raiseFirstInChance': False,
|
||||
'raisedFirstIn': False,
|
||||
'rake': 0,
|
||||
'sawShowdown': False,
|
||||
'seatNo': 10,
|
||||
'sitout': False,
|
||||
'startCards': 0,
|
||||
'startCash': 419,
|
||||
'street0Aggr': False,
|
||||
'street0Bets': 0,
|
||||
'street0Calls': 0,
|
||||
'street0Raises': 0,
|
||||
'street0VPI': False,
|
||||
'street0_3BChance': False,
|
||||
'street0_3BDone': False,
|
||||
'street0_4BChance': False,
|
||||
'street0_4BDone': False,
|
||||
'street1Aggr': False,
|
||||
'street1Bets': 0,
|
||||
'street1CBChance': False,
|
||||
'street1CBDone': False,
|
||||
'street1Calls': 0,
|
||||
'street1CheckCallRaiseChance': False,
|
||||
'street1CheckCallRaiseDone': False,
|
||||
'street1Raises': 0,
|
||||
'street1Seen': False,
|
||||
'street2Aggr': False,
|
||||
'street2Bets': 0,
|
||||
'street2CBChance': False,
|
||||
'street2CBDone': False,
|
||||
'street2Calls': 0,
|
||||
'street2CheckCallRaiseChance': False,
|
||||
'street2CheckCallRaiseDone': False,
|
||||
'street2Raises': 0,
|
||||
'street2Seen': False,
|
||||
'street3Aggr': False,
|
||||
'street3Bets': 0,
|
||||
'street3CBChance': False,
|
||||
'street3CBDone': False,
|
||||
'street3Calls': 0,
|
||||
'street3CheckCallRaiseChance': False,
|
||||
'street3CheckCallRaiseDone': False,
|
||||
'street3Raises': 0,
|
||||
'street3Seen': False,
|
||||
'street4Aggr': False,
|
||||
'street4Bets': 0,
|
||||
'street4CBChance': False,
|
||||
'street4CBDone': False,
|
||||
'street4Calls': 0,
|
||||
'street4CheckCallRaiseChance': False,
|
||||
'street4CheckCallRaiseDone': False,
|
||||
'street4Raises': 0,
|
||||
'street4Seen': False,
|
||||
'totalProfit': 0,
|
||||
'tourneyTypeId': None,
|
||||
'tourneysPlayersIds': None,
|
||||
'winnings': 0,
|
||||
'wonAtSD': 0.0,
|
||||
'wonWhenSeenStreet1': 0.0,
|
||||
'wonWhenSeenStreet2': 0.0,
|
||||
'wonWhenSeenStreet3': 0.0,
|
||||
'wonWhenSeenStreet4': 0.0}}
|
||||
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user