pull and merge from fpdboz
This commit is contained in:
commit
7d28f70a98
35
THANKS.txt
Normal file
35
THANKS.txt
Normal file
|
@ -0,0 +1,35 @@
|
||||||
|
=**Thanks - Contributors to FPDB**=
|
||||||
|
|
||||||
|
This page is to acknowledge the people developing and contributing to FPDB, be it with code, documentation, testing, forum support and everything else that is required to make an open source project work.
|
||||||
|
|
||||||
|
Most people have found the project though the software forum at [[http://forumserver.twoplustwo.com/45/software/|2+2]] so most references to 2+2 aliases
|
||||||
|
|
||||||
|
Sincere apologies to those not listed. FPDB started life in August 2008, but we only got around to putting together a proper contributers list in April 2009. Private messages and emails have been deleted so we dont have a full history of non-code based contributions
|
||||||
|
|
||||||
|
==**Developers**==
|
||||||
|
Active:
|
||||||
|
Steffen123 - The initial code drop and project lead.
|
||||||
|
Eratosthenes - Initial HUD code drop, release manager
|
||||||
|
Ekdikeo - Contributor - contributed Everleaf support and much HUD work
|
||||||
|
Sorrow - Contributor - Graphing, import framework
|
||||||
|
mcturnbull (2+2?) - Contributor - import framework
|
||||||
|
|
||||||
|
Inactive:
|
||||||
|
Sqlcoder - SQL query guru - Graphing filters, Player Stats, Positional Stats queries + general sql optimisation work
|
||||||
|
Bostik - Author of [[http://bostik.iki.fi/pokerstats/|PokerStats]] - Postgres linux work. PokerStats import code was the inspiration for the new framework. I'm sure well use more of his ideas in future.
|
||||||
|
FIXME - Original windows installer/packager
|
||||||
|
|
||||||
|
==Documentation==
|
||||||
|
FIXME - Original web site guy
|
||||||
|
FIXME - Guy who wrote the Mac install page
|
||||||
|
FIXME - Any other wiki editors.
|
||||||
|
|
||||||
|
==Other==
|
||||||
|
Eleatic Stranger - Super tester and contributor - Our #1 tester. Tracks the git repo and works the code harder than anyone and gives great feedback and bug reports. Thankyou.
|
||||||
|
Xaviax - Tester and honorary helpdesk - Another excellent tester tracking git, has responded to many queries in the fpdb thread on his own time.
|
||||||
|
KayosD - Hand History donation - Carbon Poker
|
||||||
|
freerollerjb - Hand History donation - Carbon Poker
|
||||||
|
puru - Hand History donation - Carbon Poker
|
||||||
|
freestailo - Hand History donation - Carbon Poker
|
||||||
|
MoDDe (Sourceforge) - Hand History Donation - Betfair
|
||||||
|
Jay10826 - Hand History donation - Ultimate Bet
|
|
@ -197,6 +197,15 @@ class Aux_window:
|
||||||
temp = temp + "%s" % self.layout[layout]
|
temp = temp + "%s" % self.layout[layout]
|
||||||
return temp
|
return temp
|
||||||
|
|
||||||
|
class HHC:
|
||||||
|
def __init__(self, node):
|
||||||
|
self.site = node.getAttribute("site")
|
||||||
|
self.converter = node.getAttribute("converter")
|
||||||
|
|
||||||
|
def __str__(self):
|
||||||
|
return "%s:\t%s" % (self.site, self.converter)
|
||||||
|
|
||||||
|
|
||||||
class Popup:
|
class Popup:
|
||||||
def __init__(self, node):
|
def __init__(self, node):
|
||||||
self.name = node.getAttribute("pu_name")
|
self.name = node.getAttribute("pu_name")
|
||||||
|
@ -277,6 +286,7 @@ class Config:
|
||||||
self.supported_games = {}
|
self.supported_games = {}
|
||||||
self.supported_databases = {}
|
self.supported_databases = {}
|
||||||
self.aux_windows = {}
|
self.aux_windows = {}
|
||||||
|
self.hhcs = {}
|
||||||
self.popup_windows = {}
|
self.popup_windows = {}
|
||||||
|
|
||||||
# s_sites = doc.getElementsByTagName("supported_sites")
|
# s_sites = doc.getElementsByTagName("supported_sites")
|
||||||
|
@ -299,6 +309,11 @@ class Config:
|
||||||
aw = Aux_window(node = aw_node)
|
aw = Aux_window(node = aw_node)
|
||||||
self.aux_windows[aw.name] = aw
|
self.aux_windows[aw.name] = aw
|
||||||
|
|
||||||
|
# s_dbs = doc.getElementsByTagName("mucked_windows")
|
||||||
|
for hhc_node in doc.getElementsByTagName("hhc"):
|
||||||
|
hhc = HHC(node = hhc_node)
|
||||||
|
self.hhcs[hhc.site] = hhc
|
||||||
|
|
||||||
# s_dbs = doc.getElementsByTagName("popup_windows")
|
# s_dbs = doc.getElementsByTagName("popup_windows")
|
||||||
for pu_node in doc.getElementsByTagName("pu"):
|
for pu_node in doc.getElementsByTagName("pu"):
|
||||||
pu = Popup(node = pu_node)
|
pu = Popup(node = pu_node)
|
||||||
|
@ -703,6 +718,11 @@ if __name__== "__main__":
|
||||||
for w in c.aux_windows.keys():
|
for w in c.aux_windows.keys():
|
||||||
print c.aux_windows[w]
|
print c.aux_windows[w]
|
||||||
print "----------- END AUX WINDOW FORMATS -----------"
|
print "----------- END AUX WINDOW FORMATS -----------"
|
||||||
|
|
||||||
|
print "\n----------- HAND HISTORY CONVERTERS -----------"
|
||||||
|
for w in c.hhcs.keys():
|
||||||
|
print c.hhcs[w]
|
||||||
|
print "----------- END HAND HISTORY CONVERTERS -----------"
|
||||||
|
|
||||||
print "\n----------- POPUP WINDOW FORMATS -----------"
|
print "\n----------- POPUP WINDOW FORMATS -----------"
|
||||||
for w in c.popup_windows.keys():
|
for w in c.popup_windows.keys():
|
||||||
|
|
|
@ -201,6 +201,9 @@ class Database:
|
||||||
t_dict = {}
|
t_dict = {}
|
||||||
for name, val in zip(colnames, row):
|
for name, val in zip(colnames, row):
|
||||||
t_dict[name.lower()] = val
|
t_dict[name.lower()] = val
|
||||||
|
# print t_dict
|
||||||
|
t_dict['screen_name'] = names[t_dict['player_id']]
|
||||||
|
t_dict['seat'] = seats[t_dict['player_id']]
|
||||||
stat_dict[t_dict['player_id']] = t_dict
|
stat_dict[t_dict['player_id']] = t_dict
|
||||||
return stat_dict
|
return stat_dict
|
||||||
|
|
||||||
|
|
|
@ -27,7 +27,8 @@ from HandHistoryConverter import *
|
||||||
class Everleaf(HandHistoryConverter):
|
class Everleaf(HandHistoryConverter):
|
||||||
|
|
||||||
# Static regexes
|
# Static regexes
|
||||||
re_SplitHands = re.compile(r"(\n\n\n+)")
|
re_SplitHands = re.compile(r"\n\n\n+")
|
||||||
|
re_TailSplitHands = re.compile(r"(\n\n\n+)")
|
||||||
re_GameInfo = re.compile(ur"^(Blinds )?(?P<CURRENCY>\$| €|)(?P<SB>[.0-9]+)/(?:\$| €)?(?P<BB>[.0-9]+) (?P<LIMIT>NL|PL|) ?(?P<GAME>(Hold\'em|Omaha|7 Card Stud))", re.MULTILINE)
|
re_GameInfo = re.compile(ur"^(Blinds )?(?P<CURRENCY>\$| €|)(?P<SB>[.0-9]+)/(?:\$| €)?(?P<BB>[.0-9]+) (?P<LIMIT>NL|PL|) ?(?P<GAME>(Hold\'em|Omaha|7 Card Stud))", re.MULTILINE)
|
||||||
#re.compile(ur"^(Blinds )?(?P<CURRENCY>\$| €|)(?P<SB>[.0-9]+)/(?:\$| €)?(?P<BB>[.0-9]+) (?P<LIMIT>NL|PL|) (?P<GAME>(Hold\'em|Omaha|7 Card Stud))", re.MULTILINE)
|
#re.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_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)
|
||||||
|
|
393
pyfpdb/Filters.py
Normal file
393
pyfpdb/Filters.py
Normal file
|
@ -0,0 +1,393 @@
|
||||||
|
#!/usr/bin/python
|
||||||
|
|
||||||
|
#Copyright 2008 Steffen Jobbagy-Felso
|
||||||
|
#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 in the docs folder of the package.
|
||||||
|
|
||||||
|
import threading
|
||||||
|
import pygtk
|
||||||
|
pygtk.require('2.0')
|
||||||
|
import gtk
|
||||||
|
import os
|
||||||
|
import sys
|
||||||
|
from optparse import OptionParser
|
||||||
|
from time import *
|
||||||
|
#import pokereval
|
||||||
|
|
||||||
|
import Configuration
|
||||||
|
import fpdb_db
|
||||||
|
import FpdbSQLQueries
|
||||||
|
|
||||||
|
class Filters(threading.Thread):
|
||||||
|
def __init__(self, db, settings, config, qdict, display = {},debug=True):
|
||||||
|
self.debug=debug
|
||||||
|
#print "start of GraphViewer constructor"
|
||||||
|
self.db=db
|
||||||
|
self.cursor=db.cursor
|
||||||
|
self.settings=settings
|
||||||
|
self.sql=qdict
|
||||||
|
self.conf = config
|
||||||
|
|
||||||
|
self.sites = {}
|
||||||
|
self.games = {}
|
||||||
|
self.limits = {}
|
||||||
|
self.siteid = {}
|
||||||
|
self.heroes = {}
|
||||||
|
|
||||||
|
# For use in date ranges.
|
||||||
|
self.start_date = gtk.Entry(max=12)
|
||||||
|
self.end_date = gtk.Entry(max=12)
|
||||||
|
self.start_date.set_property('editable', False)
|
||||||
|
self.end_date.set_property('editable', False)
|
||||||
|
|
||||||
|
# Outer Packing box
|
||||||
|
self.mainVBox = gtk.VBox(False, 0)
|
||||||
|
|
||||||
|
playerFrame = gtk.Frame("Hero:")
|
||||||
|
playerFrame.set_label_align(0.0, 0.0)
|
||||||
|
vbox = gtk.VBox(False, 0)
|
||||||
|
|
||||||
|
self.fillPlayerFrame(vbox)
|
||||||
|
playerFrame.add(vbox)
|
||||||
|
|
||||||
|
sitesFrame = gtk.Frame("Sites:")
|
||||||
|
sitesFrame.set_label_align(0.0, 0.0)
|
||||||
|
vbox = gtk.VBox(False, 0)
|
||||||
|
|
||||||
|
self.fillSitesFrame(vbox)
|
||||||
|
sitesFrame.add(vbox)
|
||||||
|
|
||||||
|
# Game types
|
||||||
|
gamesFrame = gtk.Frame("Games:")
|
||||||
|
gamesFrame.set_label_align(0.0, 0.0)
|
||||||
|
gamesFrame.show()
|
||||||
|
vbox = gtk.VBox(False, 0)
|
||||||
|
|
||||||
|
self.fillGamesFrame(vbox)
|
||||||
|
gamesFrame.add(vbox)
|
||||||
|
|
||||||
|
# Limits
|
||||||
|
limitsFrame = gtk.Frame("Limits:")
|
||||||
|
limitsFrame.set_label_align(0.0, 0.0)
|
||||||
|
limitsFrame.show()
|
||||||
|
vbox = gtk.VBox(False, 0)
|
||||||
|
|
||||||
|
self.fillLimitsFrame(vbox)
|
||||||
|
limitsFrame.add(vbox)
|
||||||
|
|
||||||
|
dateFrame = gtk.Frame("Date:")
|
||||||
|
dateFrame.set_label_align(0.0, 0.0)
|
||||||
|
dateFrame.show()
|
||||||
|
vbox = gtk.VBox(False, 0)
|
||||||
|
|
||||||
|
self.fillDateFrame(vbox)
|
||||||
|
dateFrame.add(vbox)
|
||||||
|
|
||||||
|
self.Button1=gtk.Button("Unamed 1")
|
||||||
|
|
||||||
|
self.Button2=gtk.Button("Unamed 2")
|
||||||
|
#self.exportButton.connect("clicked", self.exportGraph, "show clicked")
|
||||||
|
self.Button2.set_sensitive(False)
|
||||||
|
|
||||||
|
self.mainVBox.add(playerFrame)
|
||||||
|
self.mainVBox.add(sitesFrame)
|
||||||
|
self.mainVBox.add(gamesFrame)
|
||||||
|
self.mainVBox.add(limitsFrame)
|
||||||
|
self.mainVBox.add(dateFrame)
|
||||||
|
self.mainVBox.add(self.Button1)
|
||||||
|
self.mainVBox.add(self.Button2)
|
||||||
|
|
||||||
|
self.mainVBox.show_all()
|
||||||
|
|
||||||
|
# Should do this cleaner
|
||||||
|
if display["Heroes"] == False:
|
||||||
|
playerFrame.hide()
|
||||||
|
if display["Sites"] == False:
|
||||||
|
sitesFrame.hide()
|
||||||
|
if display["Games"] == False:
|
||||||
|
gamesFrame.hide()
|
||||||
|
if display["Limits"] == False:
|
||||||
|
limitsFrame.hide()
|
||||||
|
if display["Dates"] == False:
|
||||||
|
dateFrame.hide()
|
||||||
|
if display["Button1"] == False:
|
||||||
|
self.Button1.hide()
|
||||||
|
if display["Button2"] == False:
|
||||||
|
self.Button2.hide()
|
||||||
|
|
||||||
|
def get_vbox(self):
|
||||||
|
"""returns the vbox of this thread"""
|
||||||
|
return self.mainVBox
|
||||||
|
#end def get_vbox
|
||||||
|
|
||||||
|
def getSites(self):
|
||||||
|
return self.sites
|
||||||
|
|
||||||
|
def getSiteIds(self):
|
||||||
|
return self.siteid
|
||||||
|
|
||||||
|
def getHeroes(self):
|
||||||
|
return self.heroes
|
||||||
|
|
||||||
|
def getLimits(self):
|
||||||
|
ltuple = []
|
||||||
|
for l in self.limits:
|
||||||
|
if self.limits[l] == True:
|
||||||
|
ltuple.append(l)
|
||||||
|
return ltuple
|
||||||
|
|
||||||
|
def getDates(self):
|
||||||
|
return self.__get_dates()
|
||||||
|
|
||||||
|
def registerButton1Name(self, title):
|
||||||
|
self.Button1.set_label(title)
|
||||||
|
|
||||||
|
def registerButton1Callback(self, callback):
|
||||||
|
self.Button1.connect("clicked", callback, "clicked")
|
||||||
|
|
||||||
|
def registerButton2Name(self, title):
|
||||||
|
self.Button2.set_label(title)
|
||||||
|
|
||||||
|
def registerButton2Callback(self, callback):
|
||||||
|
self.Button2.connect("clicked", callback, "clicked")
|
||||||
|
|
||||||
|
def cardCallback(self, widget, data=None):
|
||||||
|
print "DEBUG: %s was toggled %s" % (data, ("OFF", "ON")[widget.get_active()])
|
||||||
|
|
||||||
|
def createPlayerLine(self, hbox, site, player):
|
||||||
|
label = gtk.Label(site +" id:")
|
||||||
|
hbox.pack_start(label, False, False, 0)
|
||||||
|
|
||||||
|
pname = gtk.Entry()
|
||||||
|
pname.set_text(player)
|
||||||
|
pname.set_width_chars(20)
|
||||||
|
hbox.pack_start(pname, False, True, 0)
|
||||||
|
pname.connect("changed", self.__set_hero_name, site)
|
||||||
|
#TODO: Look at GtkCompletion - to fill out usernames
|
||||||
|
|
||||||
|
self.__set_hero_name(pname, site)
|
||||||
|
|
||||||
|
def __set_hero_name(self, w, site):
|
||||||
|
self.heroes[site] = w.get_text()
|
||||||
|
# print "DEBUG: settings heroes[%s]: %s"%(site, self.heroes[site])
|
||||||
|
|
||||||
|
def createSiteLine(self, hbox, site):
|
||||||
|
cb = gtk.CheckButton(site)
|
||||||
|
cb.connect('clicked', self.__set_site_select, site)
|
||||||
|
cb.set_active(True)
|
||||||
|
hbox.pack_start(cb, False, False, 0)
|
||||||
|
|
||||||
|
def createGameLine(self, hbox, game):
|
||||||
|
cb = gtk.CheckButton(game)
|
||||||
|
cb.connect('clicked', self.__set_game_select, game)
|
||||||
|
hbox.pack_start(cb, False, False, 0)
|
||||||
|
|
||||||
|
def createLimitLine(self, hbox, limit):
|
||||||
|
cb = gtk.CheckButton(str(limit))
|
||||||
|
cb.connect('clicked', self.__set_limit_select, limit)
|
||||||
|
hbox.pack_start(cb, False, False, 0)
|
||||||
|
|
||||||
|
def __set_site_select(self, w, site):
|
||||||
|
print w.get_active()
|
||||||
|
self.sites[site] = w.get_active()
|
||||||
|
print "self.sites[%s] set to %s" %(site, self.sites[site])
|
||||||
|
|
||||||
|
def __set_game_select(self, w, game):
|
||||||
|
print w.get_active()
|
||||||
|
self.games[game] = w.get_active()
|
||||||
|
print "self.games[%s] set to %s" %(game, self.games[game])
|
||||||
|
|
||||||
|
def __set_limit_select(self, w, limit):
|
||||||
|
print w.get_active()
|
||||||
|
self.limits[limit] = w.get_active()
|
||||||
|
print "self.limit[%s] set to %s" %(limit, self.limits[limit])
|
||||||
|
|
||||||
|
def fillPlayerFrame(self, vbox):
|
||||||
|
for site in self.conf.get_supported_sites():
|
||||||
|
pathHBox = gtk.HBox(False, 0)
|
||||||
|
vbox.pack_start(pathHBox, False, True, 0)
|
||||||
|
|
||||||
|
player = self.conf.supported_sites[site].screen_name
|
||||||
|
self.createPlayerLine(pathHBox, site, player)
|
||||||
|
|
||||||
|
def fillSitesFrame(self, vbox):
|
||||||
|
for site in self.conf.get_supported_sites():
|
||||||
|
hbox = gtk.HBox(False, 0)
|
||||||
|
vbox.pack_start(hbox, False, True, 0)
|
||||||
|
self.createSiteLine(hbox, site)
|
||||||
|
#Get db site id for filtering later
|
||||||
|
self.cursor.execute(self.sql.query['getSiteId'], (site,))
|
||||||
|
result = self.db.cursor.fetchall()
|
||||||
|
if len(result) == 1:
|
||||||
|
self.siteid[site] = result[0][0]
|
||||||
|
else:
|
||||||
|
print "Either 0 or more than one site matched - EEK"
|
||||||
|
|
||||||
|
def fillGamesFrame(self, vbox):
|
||||||
|
self.cursor.execute(self.sql.query['getGames'])
|
||||||
|
result = self.db.cursor.fetchall()
|
||||||
|
if len(result) >= 1:
|
||||||
|
for line in result:
|
||||||
|
hbox = gtk.HBox(False, 0)
|
||||||
|
vbox.pack_start(hbox, False, True, 0)
|
||||||
|
self.createGameLine(hbox, line[0])
|
||||||
|
else:
|
||||||
|
print "INFO: No games returned from database"
|
||||||
|
|
||||||
|
def fillLimitsFrame(self, vbox):
|
||||||
|
self.cursor.execute(self.sql.query['getLimits'])
|
||||||
|
result = self.db.cursor.fetchall()
|
||||||
|
if len(result) >= 1:
|
||||||
|
for line in result:
|
||||||
|
hbox = gtk.HBox(False, 0)
|
||||||
|
vbox.pack_start(hbox, False, True, 0)
|
||||||
|
self.createLimitLine(hbox, line[0])
|
||||||
|
else:
|
||||||
|
print "INFO: No games returned from database"
|
||||||
|
|
||||||
|
def fillCardsFrame(self, vbox):
|
||||||
|
hbox1 = gtk.HBox(True,0)
|
||||||
|
hbox1.show()
|
||||||
|
vbox.pack_start(hbox1, True, True, 0)
|
||||||
|
|
||||||
|
cards = [ "A", "K","Q","J","T","9","8","7","6","5","4","3","2" ]
|
||||||
|
|
||||||
|
for j in range(0, len(cards)):
|
||||||
|
hbox1 = gtk.HBox(True,0)
|
||||||
|
hbox1.show()
|
||||||
|
vbox.pack_start(hbox1, True, True, 0)
|
||||||
|
for i in range(0, len(cards)):
|
||||||
|
if i < (j + 1):
|
||||||
|
suit = "o"
|
||||||
|
else:
|
||||||
|
suit = "s"
|
||||||
|
button = gtk.ToggleButton("%s%s%s" %(cards[i], cards[j], suit))
|
||||||
|
button.connect("toggled", self.cardCallback, "%s%s%s" %(cards[i], cards[j], suit))
|
||||||
|
hbox1.pack_start(button, True, True, 0)
|
||||||
|
button.show()
|
||||||
|
|
||||||
|
def fillDateFrame(self, vbox):
|
||||||
|
# Hat tip to Mika Bostrom - calendar code comes from PokerStats
|
||||||
|
hbox = gtk.HBox()
|
||||||
|
vbox.pack_start(hbox, False, True, 0)
|
||||||
|
|
||||||
|
lbl_start = gtk.Label('From:')
|
||||||
|
|
||||||
|
btn_start = gtk.Button()
|
||||||
|
btn_start.set_image(gtk.image_new_from_stock(gtk.STOCK_INDEX, gtk.ICON_SIZE_BUTTON))
|
||||||
|
btn_start.connect('clicked', self.__calendar_dialog, self.start_date)
|
||||||
|
|
||||||
|
hbox.pack_start(lbl_start, expand=False, padding=3)
|
||||||
|
hbox.pack_start(btn_start, expand=False, padding=3)
|
||||||
|
hbox.pack_start(self.start_date, expand=False, padding=2)
|
||||||
|
|
||||||
|
#New row for end date
|
||||||
|
hbox = gtk.HBox()
|
||||||
|
vbox.pack_start(hbox, False, True, 0)
|
||||||
|
|
||||||
|
lbl_end = gtk.Label(' To:')
|
||||||
|
btn_end = gtk.Button()
|
||||||
|
btn_end.set_image(gtk.image_new_from_stock(gtk.STOCK_INDEX, gtk.ICON_SIZE_BUTTON))
|
||||||
|
btn_end.connect('clicked', self.__calendar_dialog, self.end_date)
|
||||||
|
|
||||||
|
btn_clear = gtk.Button(label=' Clear Dates ')
|
||||||
|
btn_clear.connect('clicked', self.__clear_dates)
|
||||||
|
|
||||||
|
hbox.pack_start(lbl_end, expand=False, padding=3)
|
||||||
|
hbox.pack_start(btn_end, expand=False, padding=3)
|
||||||
|
hbox.pack_start(self.end_date, expand=False, padding=2)
|
||||||
|
|
||||||
|
hbox.pack_start(btn_clear, expand=False, padding=15)
|
||||||
|
|
||||||
|
def __calendar_dialog(self, widget, entry):
|
||||||
|
d = gtk.Window(gtk.WINDOW_TOPLEVEL)
|
||||||
|
d.set_title('Pick a date')
|
||||||
|
|
||||||
|
vb = gtk.VBox()
|
||||||
|
cal = gtk.Calendar()
|
||||||
|
vb.pack_start(cal, expand=False, padding=0)
|
||||||
|
|
||||||
|
btn = gtk.Button('Done')
|
||||||
|
btn.connect('clicked', self.__get_date, cal, entry, d)
|
||||||
|
|
||||||
|
vb.pack_start(btn, expand=False, padding=4)
|
||||||
|
|
||||||
|
d.add(vb)
|
||||||
|
d.set_position(gtk.WIN_POS_MOUSE)
|
||||||
|
d.show_all()
|
||||||
|
|
||||||
|
def __clear_dates(self, w):
|
||||||
|
self.start_date.set_text('')
|
||||||
|
self.end_date.set_text('')
|
||||||
|
|
||||||
|
def __get_dates(self):
|
||||||
|
t1 = self.start_date.get_text()
|
||||||
|
t2 = self.end_date.get_text()
|
||||||
|
|
||||||
|
if t1 == '':
|
||||||
|
t1 = '1970-01-01'
|
||||||
|
if t2 == '':
|
||||||
|
t2 = '2020-12-12'
|
||||||
|
|
||||||
|
return (t1, t2)
|
||||||
|
|
||||||
|
def __get_date(self, widget, calendar, entry, win):
|
||||||
|
# year and day are correct, month is 0..11
|
||||||
|
(year, month, day) = calendar.get_date()
|
||||||
|
month += 1
|
||||||
|
ds = '%04d-%02d-%02d' % (year, month, day)
|
||||||
|
entry.set_text(ds)
|
||||||
|
win.destroy()
|
||||||
|
|
||||||
|
def main(argv=None):
|
||||||
|
"""main can also be called in the python interpreter, by supplying the command line as the argument."""
|
||||||
|
if argv is None:
|
||||||
|
argv = sys.argv[1:]
|
||||||
|
|
||||||
|
def destroy(*args): # call back for terminating the main eventloop
|
||||||
|
gtk.main_quit()
|
||||||
|
|
||||||
|
parser = OptionParser()
|
||||||
|
(options, sys.argv) = parser.parse_args(args = argv)
|
||||||
|
|
||||||
|
config = Configuration.Config()
|
||||||
|
db = None
|
||||||
|
|
||||||
|
settings = {}
|
||||||
|
|
||||||
|
settings.update(config.get_db_parameters())
|
||||||
|
settings.update(config.get_tv_parameters())
|
||||||
|
settings.update(config.get_import_parameters())
|
||||||
|
settings.update(config.get_default_paths())
|
||||||
|
|
||||||
|
db = fpdb_db.fpdb_db()
|
||||||
|
db.connect(settings['db-backend'],
|
||||||
|
settings['db-host'],
|
||||||
|
settings['db-databaseName'],
|
||||||
|
settings['db-user'],
|
||||||
|
settings['db-password'])
|
||||||
|
|
||||||
|
qdict = FpdbSQLQueries.FpdbSQLQueries(db.get_backend_name())
|
||||||
|
|
||||||
|
i = Filters(db, settings, config, qdict)
|
||||||
|
main_window = gtk.Window()
|
||||||
|
main_window.connect('destroy', destroy)
|
||||||
|
main_window.add(i.get_vbox())
|
||||||
|
main_window.show()
|
||||||
|
gtk.main()
|
||||||
|
|
||||||
|
if __name__ == '__main__':
|
||||||
|
sys.exit(main())
|
||||||
|
|
||||||
|
|
|
@ -41,8 +41,8 @@ class FpdbSQLQueries:
|
||||||
self.query['list_tables'] = """ """
|
self.query['list_tables'] = """ """
|
||||||
|
|
||||||
##################################################################
|
##################################################################
|
||||||
# Drop Tables - MySQL, PostgreSQL and SQLite all share same syntax
|
# Drop Tables - MySQL, PostgreSQL and SQLite all share same syntax
|
||||||
##################################################################
|
##################################################################
|
||||||
|
|
||||||
if(self.dbname == 'MySQL InnoDB') or (self.dbname == 'PostgreSQL') or (self.dbname == 'SQLite'):
|
if(self.dbname == 'MySQL InnoDB') or (self.dbname == 'PostgreSQL') or (self.dbname == 'SQLite'):
|
||||||
self.query['drop_table'] = """DROP TABLE IF EXISTS """
|
self.query['drop_table'] = """DROP TABLE IF EXISTS """
|
||||||
|
@ -609,7 +609,7 @@ class FpdbSQLQueries:
|
||||||
elif(self.dbname == 'SQLite'):
|
elif(self.dbname == 'SQLite'):
|
||||||
self.query['getSiteId'] = """SELECT id from Sites where name = %s"""
|
self.query['getSiteId'] = """SELECT id from Sites where name = %s"""
|
||||||
|
|
||||||
if(self.dbname == 'MySQL InnoDB') or (self.dbname == 'PostgreSQL'):
|
if(self.dbname == 'MySQL InnoDB') or (self.dbname == 'PostgreSQL') or (self.dbname == 'SQLite'):
|
||||||
self.query['getRingProfitAllHandsPlayerIdSite'] = """
|
self.query['getRingProfitAllHandsPlayerIdSite'] = """
|
||||||
SELECT hp.handId, hp.winnings, coalesce(hp.ante,0) + SUM(ha.amount)
|
SELECT hp.handId, hp.winnings, coalesce(hp.ante,0) + SUM(ha.amount)
|
||||||
, hp.winnings - (coalesce(hp.ante,0) + SUM(ha.amount))
|
, hp.winnings - (coalesce(hp.ante,0) + SUM(ha.amount))
|
||||||
|
@ -617,28 +617,15 @@ class FpdbSQLQueries:
|
||||||
INNER JOIN Players pl ON hp.playerId = pl.id
|
INNER JOIN Players pl ON hp.playerId = pl.id
|
||||||
INNER JOIN Hands h ON h.id = hp.handId
|
INNER JOIN Hands h ON h.id = hp.handId
|
||||||
INNER JOIN HandsActions ha ON ha.handPlayerId = hp.id
|
INNER JOIN HandsActions ha ON ha.handPlayerId = hp.id
|
||||||
|
INNER JOIN Gametypes g ON h.gametypeId = g.id
|
||||||
where pl.id in <player_test>
|
where pl.id in <player_test>
|
||||||
AND pl.siteId in <site_test>
|
AND pl.siteId in <site_test>
|
||||||
AND h.handStart > '<startdate_test>'
|
AND h.handStart > '<startdate_test>'
|
||||||
AND h.handStart < '<enddate_test>'
|
AND h.handStart < '<enddate_test>'
|
||||||
|
AND g.bigBlind in <limit_test>
|
||||||
AND hp.tourneysPlayersId IS NULL
|
AND hp.tourneysPlayersId IS NULL
|
||||||
GROUP BY hp.handId, hp.winnings, h.handStart, hp.ante
|
GROUP BY hp.handId, hp.winnings, h.handStart, hp.ante
|
||||||
ORDER BY h.handStart"""
|
ORDER BY h.handStart"""
|
||||||
elif(self.dbname == 'SQLite'):
|
|
||||||
#Probably doesn't work.
|
|
||||||
self.query['getRingProfitAllHandsPlayerIdSite'] = """
|
|
||||||
SELECT hp.handId, hp.winnings, SUM(ha.amount), hp.winnings - SUM(ha.amount)
|
|
||||||
FROM HandsPlayers hp
|
|
||||||
INNER JOIN Players pl ON hp.playerId = pl.id
|
|
||||||
INNER JOIN Hands h ON h.id = hp.handId
|
|
||||||
INNER JOIN HandsActions ha ON ha.handPlayerId = hp.id
|
|
||||||
where pl.id in <player_test>
|
|
||||||
AND pl.siteId in <site_test>
|
|
||||||
AND h.handStart > '<startdate_test>'
|
|
||||||
AND h.handStart < '<enddate_test>'
|
|
||||||
AND hp.tourneysPlayersId IS NULL
|
|
||||||
GROUP BY hp.handId, hp.winnings, h.handStart
|
|
||||||
ORDER BY h.handStart"""
|
|
||||||
|
|
||||||
if(self.dbname == 'MySQL InnoDB'):
|
if(self.dbname == 'MySQL InnoDB'):
|
||||||
self.query['playerStats'] = """
|
self.query['playerStats'] = """
|
||||||
|
@ -1153,6 +1140,12 @@ class FpdbSQLQueries:
|
||||||
and hprof2.PlPosition = stats.PlPosition)
|
and hprof2.PlPosition = stats.PlPosition)
|
||||||
order by stats.category, stats.limittype, stats.bigBlind, cast(stats.PlPosition as signed)
|
order by stats.category, stats.limittype, stats.bigBlind, cast(stats.PlPosition as signed)
|
||||||
"""
|
"""
|
||||||
|
if(self.dbname == 'MySQL InnoDB') or (self.dbname == 'PostgreSQL') or (self.dbname == 'SQLite'):
|
||||||
|
self.query['getGames'] = """SELECT DISTINCT category from Gametypes"""
|
||||||
|
|
||||||
|
if(self.dbname == 'MySQL InnoDB') or (self.dbname == 'PostgreSQL') or (self.dbname == 'SQLite'):
|
||||||
|
self.query['getLimits'] = """SELECT DISTINCT bigBlind from Gametypes ORDER by bigBlind DESC"""
|
||||||
|
|
||||||
|
|
||||||
if __name__== "__main__":
|
if __name__== "__main__":
|
||||||
from optparse import OptionParser
|
from optparse import OptionParser
|
||||||
|
|
|
@ -28,11 +28,13 @@ class Fulltilt(HandHistoryConverter):
|
||||||
|
|
||||||
# Static regexes
|
# Static regexes
|
||||||
re_GameInfo = re.compile('- (?P<CURRENCY>\$|)?(?P<SB>[.0-9]+)/\$?(?P<BB>[.0-9]+) (Ante \$(?P<ANTE>[.0-9]+) )?- (?P<LIMIT>(No Limit|Pot Limit|Limit))? (?P<GAME>(Hold\'em|Omaha Hi|Razz))')
|
re_GameInfo = re.compile('- (?P<CURRENCY>\$|)?(?P<SB>[.0-9]+)/\$?(?P<BB>[.0-9]+) (Ante \$(?P<ANTE>[.0-9]+) )?- (?P<LIMIT>(No Limit|Pot Limit|Limit))? (?P<GAME>(Hold\'em|Omaha Hi|Razz))')
|
||||||
re_SplitHands = re.compile(r"(\n\n+)")
|
re_SplitHands = re.compile(r"\n\n+")
|
||||||
|
re_TailSplitHands = re.compile(r"(\n\n+)")
|
||||||
re_HandInfo = re.compile('.*#(?P<HID>[0-9]+): Table (?P<TABLE>[- a-zA-Z]+) (\((?P<TABLEATTRIBUTES>.+)\) )?- \$?(?P<SB>[.0-9]+)/\$?(?P<BB>[.0-9]+) (Ante \$(?P<ANTE>[.0-9]+) )?- (?P<GAMETYPE>[a-zA-Z\' ]+) - (?P<DATETIME>.*)')
|
re_HandInfo = re.compile('.*#(?P<HID>[0-9]+): Table (?P<TABLE>[- a-zA-Z]+) (\((?P<TABLEATTRIBUTES>.+)\) )?- \$?(?P<SB>[.0-9]+)/\$?(?P<BB>[.0-9]+) (Ante \$(?P<ANTE>[.0-9]+) )?- (?P<GAMETYPE>[a-zA-Z\' ]+) - (?P<DATETIME>.*)')
|
||||||
re_Button = re.compile('^The button is in seat #(?P<BUTTON>\d+)', re.MULTILINE)
|
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>.*) \(\$(?P<CASH>[.0-9]+)\)\n')
|
re_PlayerInfo = re.compile('Seat (?P<SEAT>[0-9]+): (?P<PNAME>.*) \(\$(?P<CASH>[.0-9]+)\)\n')
|
||||||
re_Board = re.compile(r"\[(?P<CARDS>.+)\]")
|
re_Board = re.compile(r"\[(?P<CARDS>.+)\]")
|
||||||
|
# NB: if we ever match "Full Tilt Poker" we should also match "FullTiltPoker", which PT Stud erroneously exports.
|
||||||
|
|
||||||
def __init__(self, in_path = '-', out_path = '-', follow = False, autostart=True):
|
def __init__(self, in_path = '-', out_path = '-', follow = False, autostart=True):
|
||||||
"""\
|
"""\
|
||||||
|
|
18
pyfpdb/GuiBulkImport.py
Normal file → Executable file
18
pyfpdb/GuiBulkImport.py
Normal file → Executable file
|
@ -66,10 +66,10 @@ class GuiBulkImport():
|
||||||
self.importer.setDropIndexes(cb_model[cb_index][0])
|
self.importer.setDropIndexes(cb_model[cb_index][0])
|
||||||
else:
|
else:
|
||||||
self.importer.setDropIndexes("auto")
|
self.importer.setDropIndexes("auto")
|
||||||
hhc=self.cbfilter.get_model()[self.cbfilter.get_active()][0]
|
sitename = self.cbfilter.get_model()[self.cbfilter.get_active()][0]
|
||||||
self.lab_info.set_text("Importing")
|
self.lab_info.set_text("Importing")
|
||||||
|
|
||||||
self.importer.addBulkImportImportFileOrDir(self.inputFile,filter=hhc)
|
self.importer.addBulkImportImportFileOrDir(self.inputFile, site = sitename)
|
||||||
self.importer.setCallHud(False)
|
self.importer.setCallHud(False)
|
||||||
starttime = time()
|
starttime = time()
|
||||||
(stored, dups, partial, errs, ttime) = self.importer.runImport()
|
(stored, dups, partial, errs, ttime) = self.importer.runImport()
|
||||||
|
@ -175,11 +175,9 @@ class GuiBulkImport():
|
||||||
|
|
||||||
# ComboBox - filter
|
# ComboBox - filter
|
||||||
self.cbfilter = gtk.combo_box_new_text()
|
self.cbfilter = gtk.combo_box_new_text()
|
||||||
self.cbfilter.append_text("passthrough")
|
for w in self.config.hhcs:
|
||||||
self.cbfilter.append_text("BetfairToFpdb")
|
print w
|
||||||
self.cbfilter.append_text("EverleafToFpdb")
|
self.cbfilter.append_text(w)
|
||||||
self.cbfilter.append_text("FulltiltToFpdb")
|
|
||||||
self.cbfilter.append_text("PokerStarsToFpdb")
|
|
||||||
self.cbfilter.set_active(0)
|
self.cbfilter.set_active(0)
|
||||||
self.table.attach(self.cbfilter, 3, 4, 2, 3, xpadding = 10, ypadding = 0, yoptions=gtk.SHRINK)
|
self.table.attach(self.cbfilter, 3, 4, 2, 3, xpadding = 10, ypadding = 0, yoptions=gtk.SHRINK)
|
||||||
self.cbfilter.show()
|
self.cbfilter.show()
|
||||||
|
@ -220,8 +218,8 @@ def main(argv=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,
|
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="passthrough", metavar="FILTER",
|
parser.add_option("-c", "--convert", dest="filtername", default="PokerStars", metavar="FILTER",
|
||||||
help="Conversion filter (*passthrough, FullTiltToFpdb, PokerStarsToFpdb, EverleafToFpdb)")
|
help="Conversion filter (*Full Tilt Poker, PokerStars, Everleaf)")
|
||||||
parser.add_option("-x", "--failOnError", action="store_true", default=False,
|
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",
|
parser.add_option("-m", "--minPrint", "--status", dest="minPrint", default="0", type="int",
|
||||||
|
@ -256,7 +254,7 @@ def main(argv=None):
|
||||||
importer = fpdb_import.Importer(False,settings, config)
|
importer = fpdb_import.Importer(False,settings, config)
|
||||||
importer.setDropIndexes("auto")
|
importer.setDropIndexes("auto")
|
||||||
importer.setFailOnError(options.failOnError)
|
importer.setFailOnError(options.failOnError)
|
||||||
importer.addBulkImportImportFileOrDir(os.path.expanduser(options.filename), filter=options.filtername)
|
importer.addBulkImportImportFileOrDir(os.path.expanduser(options.filename), site=options.filtername)
|
||||||
importer.setCallHud(False)
|
importer.setCallHud(False)
|
||||||
importer.runImport()
|
importer.runImport()
|
||||||
importer.clearFileList()
|
importer.clearFileList()
|
||||||
|
|
|
@ -39,8 +39,83 @@ except:
|
||||||
|
|
||||||
import fpdb_import
|
import fpdb_import
|
||||||
import fpdb_db
|
import fpdb_db
|
||||||
|
import Filters
|
||||||
|
|
||||||
class GuiGraphViewer (threading.Thread):
|
class GuiGraphViewer (threading.Thread):
|
||||||
|
|
||||||
|
def __init__(self, db, settings, querylist, config, debug=True):
|
||||||
|
"""Constructor for GraphViewer"""
|
||||||
|
self.debug=debug
|
||||||
|
#print "start of GraphViewer constructor"
|
||||||
|
self.db=db
|
||||||
|
self.cursor=db.cursor
|
||||||
|
self.settings=settings
|
||||||
|
self.sql=querylist
|
||||||
|
self.conf = config
|
||||||
|
|
||||||
|
filters_display = { "Heroes" : True,
|
||||||
|
"Sites" : True,
|
||||||
|
"Games" : True,
|
||||||
|
"Limits" : True,
|
||||||
|
"Dates" : True,
|
||||||
|
"Button1" : True,
|
||||||
|
"Button2" : True
|
||||||
|
}
|
||||||
|
|
||||||
|
self.filters = Filters.Filters(db, settings, config, querylist, 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.graphBox = gtk.VBox(False, 0)
|
||||||
|
|
||||||
|
self.hpane = gtk.HPaned()
|
||||||
|
self.hpane.pack1(self.leftPanelBox)
|
||||||
|
self.hpane.pack2(self.graphBox)
|
||||||
|
|
||||||
|
self.mainHBox.add(self.hpane)
|
||||||
|
|
||||||
|
self.fig = None
|
||||||
|
#self.exportButton.set_sensitive(False)
|
||||||
|
|
||||||
|
self.fig = Figure(figsize=(5,4), dpi=100)
|
||||||
|
self.canvas = None
|
||||||
|
|
||||||
|
self.mainHBox.show_all()
|
||||||
|
|
||||||
|
#################################
|
||||||
|
#
|
||||||
|
# self.db.cursor.execute("""select UNIX_TIMESTAMP(handStart) as time, id from Hands ORDER BY time""")
|
||||||
|
# THRESHOLD = 1800
|
||||||
|
# hands = self.db.cursor.fetchall()
|
||||||
|
#
|
||||||
|
# times = map(lambda x:long(x[0]), hands)
|
||||||
|
# handids = map(lambda x:int(x[1]), hands)
|
||||||
|
# print "DEBUG: len(times) %s" %(len(times))
|
||||||
|
# diffs = diff(times)
|
||||||
|
# print "DEBUG: len(diffs) %s" %(len(diffs))
|
||||||
|
# index = nonzero(diff(times) > THRESHOLD)
|
||||||
|
# print "DEBUG: len(index[0]) %s" %(len(index[0]))
|
||||||
|
# print "DEBUG: index %s" %(index)
|
||||||
|
# print "DEBUG: index[0][0] %s" %(index[0][0])
|
||||||
|
#
|
||||||
|
# total = 0
|
||||||
|
#
|
||||||
|
# last_idx = 0
|
||||||
|
# for i in range(len(index[0])):
|
||||||
|
# print "Hands in session %4s: %4s Start: %s End: %s Total: %s" %(i, index[0][i] - last_idx, strftime("%d/%m/%Y %H:%M", localtime(times[last_idx])), strftime("%d/%m/%Y %H:%M", localtime(times[index[0][i]])), times[index[0][i]] - times[last_idx])
|
||||||
|
# total = total + (index[0][i] - last_idx)
|
||||||
|
# last_idx = index[0][i] + 1
|
||||||
|
#
|
||||||
|
# print "Total: ", total
|
||||||
|
#################################
|
||||||
|
|
||||||
|
|
||||||
def get_vbox(self):
|
def get_vbox(self):
|
||||||
"""returns the vbox of this thread"""
|
"""returns the vbox of this thread"""
|
||||||
return self.mainHBox
|
return self.mainHBox
|
||||||
|
@ -59,11 +134,15 @@ class GuiGraphViewer (threading.Thread):
|
||||||
sitenos = []
|
sitenos = []
|
||||||
playerids = []
|
playerids = []
|
||||||
|
|
||||||
|
sites = self.filters.getSites()
|
||||||
|
heroes = self.filters.getHeroes()
|
||||||
|
siteids = self.filters.getSiteIds()
|
||||||
|
limits = self.filters.getLimits()
|
||||||
# Which sites are selected?
|
# Which sites are selected?
|
||||||
for site in self.sites:
|
for site in sites:
|
||||||
if self.sites[site] == True:
|
if sites[site] == True:
|
||||||
sitenos.append(self.siteid[site])
|
sitenos.append(siteids[site])
|
||||||
self.cursor.execute(self.sql.query['getPlayerId'], (self.heroes[site],))
|
self.cursor.execute(self.sql.query['getPlayerId'], (heroes[site],))
|
||||||
result = self.db.cursor.fetchall()
|
result = self.db.cursor.fetchall()
|
||||||
if len(result) == 1:
|
if len(result) == 1:
|
||||||
playerids.append(result[0][0])
|
playerids.append(result[0][0])
|
||||||
|
@ -73,18 +152,20 @@ class GuiGraphViewer (threading.Thread):
|
||||||
print "No sites selected - defaulting to PokerStars"
|
print "No sites selected - defaulting to PokerStars"
|
||||||
sitenos = [2]
|
sitenos = [2]
|
||||||
|
|
||||||
|
|
||||||
if not playerids:
|
if not playerids:
|
||||||
print "No player ids found"
|
print "No player ids found"
|
||||||
return
|
return
|
||||||
|
|
||||||
|
if not limits:
|
||||||
|
print "No limits found"
|
||||||
|
return
|
||||||
|
|
||||||
#Set graph properties
|
#Set graph properties
|
||||||
self.ax = self.fig.add_subplot(111)
|
self.ax = self.fig.add_subplot(111)
|
||||||
|
|
||||||
#Get graph data from DB
|
#Get graph data from DB
|
||||||
starttime = time()
|
starttime = time()
|
||||||
line = self.getRingProfitGraph(playerids, sitenos)
|
line = self.getRingProfitGraph(playerids, sitenos, limits)
|
||||||
print "Graph generated in: %s" %(time() - starttime)
|
print "Graph generated in: %s" %(time() - starttime)
|
||||||
|
|
||||||
self.ax.set_title("Profit graph for ring games")
|
self.ax.set_title("Profit graph for ring games")
|
||||||
|
@ -114,33 +195,32 @@ class GuiGraphViewer (threading.Thread):
|
||||||
self.exportButton.set_sensitive(True)
|
self.exportButton.set_sensitive(True)
|
||||||
#end of def showClicked
|
#end of def showClicked
|
||||||
|
|
||||||
def getRingProfitGraph(self, names, sites):
|
def getRingProfitGraph(self, names, sites, limits):
|
||||||
tmp = self.sql.query['getRingProfitAllHandsPlayerIdSite']
|
tmp = self.sql.query['getRingProfitAllHandsPlayerIdSite']
|
||||||
# print "DEBUG: getRingProfitGraph"
|
# print "DEBUG: getRingProfitGraph"
|
||||||
start_date, end_date = self.__get_dates()
|
start_date, end_date = self.filters.getDates()
|
||||||
|
|
||||||
if start_date == '':
|
|
||||||
start_date = '1970-01-01'
|
|
||||||
if end_date == '':
|
|
||||||
end_date = '2020-12-12'
|
|
||||||
|
|
||||||
#Buggered if I can find a way to do this 'nicely' take a list of intergers and longs
|
#Buggered if I can find a way to do this 'nicely' take a list of intergers and longs
|
||||||
# and turn it into a tuple readale by sql.
|
# and turn it into a tuple readale by sql.
|
||||||
# [5L] into (5) not (5,) and [5L, 2829L] into (5, 2829)
|
# [5L] into (5) not (5,) and [5L, 2829L] into (5, 2829)
|
||||||
nametest = str(tuple(names))
|
nametest = str(tuple(names))
|
||||||
sitetest = str(tuple(sites))
|
sitetest = str(tuple(sites))
|
||||||
|
limittest = str(tuple(limits))
|
||||||
nametest = nametest.replace("L", "")
|
nametest = nametest.replace("L", "")
|
||||||
nametest = nametest.replace(",)",")")
|
nametest = nametest.replace(",)",")")
|
||||||
sitetest = sitetest.replace(",)",")")
|
sitetest = sitetest.replace(",)",")")
|
||||||
|
limittest = limittest.replace("L", "")
|
||||||
|
limittest = limittest.replace(",)",")")
|
||||||
|
|
||||||
#Must be a nicer way to deal with tuples of size 1 ie. (2,) - which makes sql barf
|
#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("<player_test>", nametest)
|
||||||
tmp = tmp.replace("<site_test>", sitetest)
|
tmp = tmp.replace("<site_test>", sitetest)
|
||||||
tmp = tmp.replace("<startdate_test>", start_date)
|
tmp = tmp.replace("<startdate_test>", start_date)
|
||||||
tmp = tmp.replace("<enddate_test>", end_date)
|
tmp = tmp.replace("<enddate_test>", end_date)
|
||||||
|
tmp = tmp.replace("<limit_test>", limittest)
|
||||||
|
|
||||||
# print "DEBUG: sql query:"
|
#print "DEBUG: sql query:"
|
||||||
# print tmp
|
#print tmp
|
||||||
self.cursor.execute(tmp)
|
self.cursor.execute(tmp)
|
||||||
#returns (HandId,Winnings,Costs,Profit)
|
#returns (HandId,Winnings,Costs,Profit)
|
||||||
winnings = self.db.cursor.fetchall()
|
winnings = self.db.cursor.fetchall()
|
||||||
|
@ -153,136 +233,6 @@ class GuiGraphViewer (threading.Thread):
|
||||||
return line/100
|
return line/100
|
||||||
#end of def getRingProfitGraph
|
#end of def getRingProfitGraph
|
||||||
|
|
||||||
def createPlayerLine(self, hbox, site, player):
|
|
||||||
label = gtk.Label(site +" id:")
|
|
||||||
hbox.pack_start(label, False, False, 0)
|
|
||||||
label.show()
|
|
||||||
|
|
||||||
pname = gtk.Entry()
|
|
||||||
pname.set_text(player)
|
|
||||||
pname.set_width_chars(20)
|
|
||||||
hbox.pack_start(pname, False, True, 0)
|
|
||||||
pname.connect("changed", self.__set_hero_name, site)
|
|
||||||
#TODO: Look at GtkCompletion - to fill out usernames
|
|
||||||
pname.show()
|
|
||||||
|
|
||||||
self.__set_hero_name(pname, site)
|
|
||||||
|
|
||||||
def __set_hero_name(self, w, site):
|
|
||||||
self.heroes[site] = w.get_text()
|
|
||||||
# print "DEBUG: settings heroes[%s]: %s"%(site, self.heroes[site])
|
|
||||||
|
|
||||||
def createSiteLine(self, hbox, site):
|
|
||||||
cb = gtk.CheckButton(site)
|
|
||||||
cb.connect('clicked', self.__set_site_select, site)
|
|
||||||
hbox.pack_start(cb, False, False, 0)
|
|
||||||
cb.show()
|
|
||||||
|
|
||||||
def __set_site_select(self, w, site):
|
|
||||||
# This doesn't behave as intended - self.site only allows 1 site for the moment.
|
|
||||||
print w.get_active()
|
|
||||||
self.sites[site] = w.get_active()
|
|
||||||
print "self.sites[%s] set to %s" %(site, self.sites[site])
|
|
||||||
|
|
||||||
def fillPlayerFrame(self, vbox):
|
|
||||||
for site in self.conf.supported_sites.keys():
|
|
||||||
pathHBox = gtk.HBox(False, 0)
|
|
||||||
vbox.pack_start(pathHBox, False, True, 0)
|
|
||||||
pathHBox.show()
|
|
||||||
|
|
||||||
player = self.conf.supported_sites[site].screen_name
|
|
||||||
self.createPlayerLine(pathHBox, site, player)
|
|
||||||
|
|
||||||
def fillSitesFrame(self, vbox):
|
|
||||||
for site in self.conf.supported_sites.keys():
|
|
||||||
hbox = gtk.HBox(False, 0)
|
|
||||||
vbox.pack_start(hbox, False, True, 0)
|
|
||||||
hbox.show()
|
|
||||||
self.createSiteLine(hbox, site)
|
|
||||||
#Get db site id for filtering later
|
|
||||||
self.cursor.execute(self.sql.query['getSiteId'], (site,))
|
|
||||||
result = self.db.cursor.fetchall()
|
|
||||||
if len(result) == 1:
|
|
||||||
self.siteid[site] = result[0][0]
|
|
||||||
else:
|
|
||||||
print "Either 0 or more than one site matched - EEK"
|
|
||||||
|
|
||||||
def fillDateFrame(self, vbox):
|
|
||||||
# Hat tip to Mika Bostrom - calendar code comes from PokerStats
|
|
||||||
hbox = gtk.HBox()
|
|
||||||
vbox.pack_start(hbox, False, True, 0)
|
|
||||||
hbox.show()
|
|
||||||
|
|
||||||
lbl_start = gtk.Label('From:')
|
|
||||||
lbl_start.show()
|
|
||||||
|
|
||||||
btn_start = gtk.Button()
|
|
||||||
btn_start.set_image(gtk.image_new_from_stock(gtk.STOCK_INDEX, gtk.ICON_SIZE_BUTTON))
|
|
||||||
btn_start.connect('clicked', self.__calendar_dialog, self.start_date)
|
|
||||||
btn_start.show()
|
|
||||||
|
|
||||||
hbox.pack_start(lbl_start, expand=False, padding=3)
|
|
||||||
hbox.pack_start(btn_start, expand=False, padding=3)
|
|
||||||
hbox.pack_start(self.start_date, expand=False, padding=2)
|
|
||||||
self.start_date.show()
|
|
||||||
|
|
||||||
#New row for end date
|
|
||||||
hbox = gtk.HBox()
|
|
||||||
vbox.pack_start(hbox, False, True, 0)
|
|
||||||
hbox.show()
|
|
||||||
|
|
||||||
lbl_end = gtk.Label(' To:')
|
|
||||||
lbl_end.show()
|
|
||||||
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_end.show()
|
|
||||||
|
|
||||||
btn_clear = gtk.Button(label=' Clear Dates ')
|
|
||||||
btn_clear.connect('clicked', self.__clear_dates)
|
|
||||||
btn_clear.show()
|
|
||||||
|
|
||||||
hbox.pack_start(lbl_end, expand=False, padding=3)
|
|
||||||
hbox.pack_start(btn_end, expand=False, padding=3)
|
|
||||||
hbox.pack_start(self.end_date, expand=False, padding=2)
|
|
||||||
self.end_date.show()
|
|
||||||
|
|
||||||
hbox.pack_start(btn_clear, expand=False, padding=15)
|
|
||||||
|
|
||||||
def __calendar_dialog(self, widget, entry):
|
|
||||||
d = gtk.Window(gtk.WINDOW_TOPLEVEL)
|
|
||||||
d.set_title('Pick a date')
|
|
||||||
|
|
||||||
vb = gtk.VBox()
|
|
||||||
cal = gtk.Calendar()
|
|
||||||
vb.pack_start(cal, expand=False, padding=0)
|
|
||||||
|
|
||||||
btn = gtk.Button('Done')
|
|
||||||
btn.connect('clicked', self.__get_date, cal, entry, d)
|
|
||||||
|
|
||||||
vb.pack_start(btn, expand=False, padding=4)
|
|
||||||
|
|
||||||
d.add(vb)
|
|
||||||
d.set_position(gtk.WIN_POS_MOUSE)
|
|
||||||
d.show_all()
|
|
||||||
|
|
||||||
def __clear_dates(self, w):
|
|
||||||
self.start_date.set_text('')
|
|
||||||
self.end_date.set_text('')
|
|
||||||
|
|
||||||
def __get_dates(self):
|
|
||||||
t1 = self.start_date.get_text()
|
|
||||||
t2 = self.end_date.get_text()
|
|
||||||
return (t1, t2)
|
|
||||||
|
|
||||||
def __get_date(self, widget, calendar, entry, win):
|
|
||||||
# year and day are correct, month is 0..11
|
|
||||||
(year, month, day) = calendar.get_date()
|
|
||||||
month += 1
|
|
||||||
ds = '%04d-%02d-%02d' % (year, month, day)
|
|
||||||
entry.set_text(ds)
|
|
||||||
win.destroy()
|
|
||||||
|
|
||||||
def exportGraph (self, widget, data):
|
def exportGraph (self, widget, data):
|
||||||
if self.fig is None:
|
if self.fig is None:
|
||||||
return # Might want to disable export button until something has been generated.
|
return # Might want to disable export button until something has been generated.
|
||||||
|
@ -303,112 +253,4 @@ class GuiGraphViewer (threading.Thread):
|
||||||
#TODO: This asks for a directory but will take a filename and overwrite it.
|
#TODO: This asks for a directory but will take a filename and overwrite it.
|
||||||
self.fig.savefig(self.exportDir, format="png")
|
self.fig.savefig(self.exportDir, format="png")
|
||||||
|
|
||||||
def __init__(self, db, settings, querylist, config, debug=True):
|
|
||||||
"""Constructor for GraphViewer"""
|
|
||||||
self.debug=debug
|
|
||||||
#print "start of GraphViewer constructor"
|
|
||||||
self.db=db
|
|
||||||
self.cursor=db.cursor
|
|
||||||
self.settings=settings
|
|
||||||
self.sql=querylist
|
|
||||||
self.conf = config
|
|
||||||
|
|
||||||
self.sites = {}
|
|
||||||
self.siteid = {}
|
|
||||||
self.heroes = {}
|
|
||||||
|
|
||||||
# For use in date ranges.
|
|
||||||
self.start_date = gtk.Entry(max=12)
|
|
||||||
self.end_date = gtk.Entry(max=12)
|
|
||||||
self.start_date.set_property('editable', False)
|
|
||||||
self.end_date.set_property('editable', False)
|
|
||||||
|
|
||||||
self.mainHBox = gtk.HBox(False, 0)
|
|
||||||
self.mainHBox.show()
|
|
||||||
|
|
||||||
self.leftPanelBox = gtk.VBox(False, 0)
|
|
||||||
self.graphBox = gtk.VBox(False, 0)
|
|
||||||
|
|
||||||
self.hpane = gtk.HPaned()
|
|
||||||
self.hpane.pack1(self.leftPanelBox)
|
|
||||||
self.hpane.pack2(self.graphBox)
|
|
||||||
self.hpane.show()
|
|
||||||
|
|
||||||
self.mainHBox.add(self.hpane)
|
|
||||||
|
|
||||||
playerFrame = gtk.Frame("Hero:")
|
|
||||||
playerFrame.set_label_align(0.0, 0.0)
|
|
||||||
playerFrame.show()
|
|
||||||
vbox = gtk.VBox(False, 0)
|
|
||||||
vbox.show()
|
|
||||||
|
|
||||||
self.fillPlayerFrame(vbox)
|
|
||||||
playerFrame.add(vbox)
|
|
||||||
|
|
||||||
sitesFrame = gtk.Frame("Sites:")
|
|
||||||
sitesFrame.set_label_align(0.0, 0.0)
|
|
||||||
sitesFrame.show()
|
|
||||||
vbox = gtk.VBox(False, 0)
|
|
||||||
vbox.show()
|
|
||||||
|
|
||||||
self.fillSitesFrame(vbox)
|
|
||||||
sitesFrame.add(vbox)
|
|
||||||
|
|
||||||
dateFrame = gtk.Frame("Date:")
|
|
||||||
dateFrame.set_label_align(0.0, 0.0)
|
|
||||||
dateFrame.show()
|
|
||||||
vbox = gtk.VBox(False, 0)
|
|
||||||
vbox.show()
|
|
||||||
|
|
||||||
self.fillDateFrame(vbox)
|
|
||||||
dateFrame.add(vbox)
|
|
||||||
|
|
||||||
graphButton=gtk.Button("Generate Graph")
|
|
||||||
graphButton.connect("clicked", self.generateGraph, "cliced data")
|
|
||||||
graphButton.show()
|
|
||||||
|
|
||||||
self.fig = None
|
|
||||||
self.exportButton=gtk.Button("Export to File")
|
|
||||||
self.exportButton.connect("clicked", self.exportGraph, "show clicked")
|
|
||||||
self.exportButton.set_sensitive(False)
|
|
||||||
self.exportButton.show()
|
|
||||||
|
|
||||||
self.leftPanelBox.add(playerFrame)
|
|
||||||
self.leftPanelBox.add(sitesFrame)
|
|
||||||
self.leftPanelBox.add(dateFrame)
|
|
||||||
self.leftPanelBox.add(graphButton)
|
|
||||||
self.leftPanelBox.add(self.exportButton)
|
|
||||||
|
|
||||||
self.leftPanelBox.show()
|
|
||||||
self.graphBox.show()
|
|
||||||
|
|
||||||
self.fig = Figure(figsize=(5,4), dpi=100)
|
|
||||||
self.canvas = None
|
|
||||||
|
|
||||||
#################################
|
|
||||||
#
|
|
||||||
# self.db.cursor.execute("""select UNIX_TIMESTAMP(handStart) as time, id from Hands ORDER BY time""")
|
|
||||||
# THRESHOLD = 1800
|
|
||||||
# hands = self.db.cursor.fetchall()
|
|
||||||
#
|
|
||||||
# times = map(lambda x:long(x[0]), hands)
|
|
||||||
# handids = map(lambda x:int(x[1]), hands)
|
|
||||||
# print "DEBUG: len(times) %s" %(len(times))
|
|
||||||
# diffs = diff(times)
|
|
||||||
# print "DEBUG: len(diffs) %s" %(len(diffs))
|
|
||||||
# index = nonzero(diff(times) > THRESHOLD)
|
|
||||||
# print "DEBUG: len(index[0]) %s" %(len(index[0]))
|
|
||||||
# print "DEBUG: index %s" %(index)
|
|
||||||
# print "DEBUG: index[0][0] %s" %(index[0][0])
|
|
||||||
#
|
|
||||||
# total = 0
|
|
||||||
#
|
|
||||||
# last_idx = 0
|
|
||||||
# for i in range(len(index[0])):
|
|
||||||
# print "Hands in session %4s: %4s Start: %s End: %s Total: %s" %(i, index[0][i] - last_idx, strftime("%d/%m/%Y %H:%M", localtime(times[last_idx])), strftime("%d/%m/%Y %H:%M", localtime(times[index[0][i]])), times[index[0][i]] - times[last_idx])
|
|
||||||
# total = total + (index[0][i] - last_idx)
|
|
||||||
# last_idx = index[0][i] + 1
|
|
||||||
#
|
|
||||||
# print "Total: ", total
|
|
||||||
#################################
|
|
||||||
|
|
||||||
|
|
|
@ -23,146 +23,43 @@ import os
|
||||||
|
|
||||||
import fpdb_import
|
import fpdb_import
|
||||||
import fpdb_db
|
import fpdb_db
|
||||||
|
import Filters
|
||||||
import FpdbSQLQueries
|
import FpdbSQLQueries
|
||||||
|
|
||||||
class GuiPlayerStats (threading.Thread):
|
class GuiPlayerStats (threading.Thread):
|
||||||
def get_vbox(self):
|
|
||||||
"""returns the vbox of this thread"""
|
|
||||||
return self.main_hbox
|
|
||||||
|
|
||||||
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)
|
|
||||||
|
|
||||||
def refreshStats(self, widget, data):
|
|
||||||
try: self.stats_table.destroy()
|
|
||||||
except AttributeError: pass
|
|
||||||
self.fillStatsFrame(self.stats_frame)
|
|
||||||
|
|
||||||
def fillStatsFrame(self, vbox):
|
|
||||||
# Get currently active site and grab playerid
|
|
||||||
tmp = self.sql.query['playerStats']
|
|
||||||
|
|
||||||
result = self.cursor.execute(self.sql.query['getPlayerId'], (self.heroes[self.activesite],))
|
|
||||||
result = self.cursor.fetchall()
|
|
||||||
if not result == ():
|
|
||||||
pid = result[0][0]
|
|
||||||
pid = result[0][0]
|
|
||||||
tmp = tmp.replace("<player_test>", "(" + str(pid) + ")")
|
|
||||||
self.cursor.execute(tmp)
|
|
||||||
result = self.cursor.fetchall()
|
|
||||||
cols = 16
|
|
||||||
rows = len(result)+1 # +1 for title row
|
|
||||||
self.stats_table = gtk.Table(rows, cols, False)
|
|
||||||
self.stats_table.set_col_spacings(4)
|
|
||||||
self.stats_table.show()
|
|
||||||
vbox.add(self.stats_table)
|
|
||||||
|
|
||||||
# Create header row
|
|
||||||
titles = ("Game", "Hands", "VPIP", "PFR", "Saw_F", "SawSD", "WtSDwsF", "W$SD", "FlAFq", "TuAFq", "RvAFq", "PoFAFq", "Net($)", "BB/100", "$/hand", "Variance")
|
|
||||||
|
|
||||||
col = 0
|
|
||||||
row = 0
|
|
||||||
for t in titles:
|
|
||||||
l = gtk.Label(titles[col])
|
|
||||||
l.show()
|
|
||||||
self.stats_table.attach(l, col, col+1, row, row+1, yoptions=gtk.SHRINK)
|
|
||||||
col +=1
|
|
||||||
|
|
||||||
for row in range(rows-1):
|
|
||||||
if(row%2 == 0):
|
|
||||||
bgcolor = "white"
|
|
||||||
else:
|
|
||||||
bgcolor = "lightgrey"
|
|
||||||
for col in range(cols):
|
|
||||||
eb = gtk.EventBox()
|
|
||||||
eb.modify_bg(gtk.STATE_NORMAL, gtk.gdk.color_parse(bgcolor))
|
|
||||||
if result[row][col]:
|
|
||||||
l = gtk.Label(result[row][col])
|
|
||||||
else:
|
|
||||||
l = gtk.Label(' ')
|
|
||||||
if col == 0:
|
|
||||||
l.set_alignment(xalign=0.0, yalign=0.5)
|
|
||||||
else:
|
|
||||||
l.set_alignment(xalign=1.0, yalign=0.5)
|
|
||||||
eb.add(l)
|
|
||||||
self.stats_table.attach(eb, col, col+1, row+1, row+2, yoptions=gtk.SHRINK)
|
|
||||||
l.show()
|
|
||||||
eb.show()
|
|
||||||
self.fdb.db.commit()
|
|
||||||
#end def fillStatsFrame(self, vbox):
|
|
||||||
|
|
||||||
def fillPlayerFrame(self, vbox):
|
|
||||||
for site in self.conf.supported_sites.keys():
|
|
||||||
hbox = gtk.HBox(False, 0)
|
|
||||||
vbox.pack_start(hbox, False, True, 0)
|
|
||||||
hbox.show()
|
|
||||||
|
|
||||||
player = self.conf.supported_sites[site].screen_name
|
|
||||||
self.createPlayerLine(hbox, site, player)
|
|
||||||
hbox = gtk.HBox(False, 0)
|
|
||||||
button = gtk.Button("Refresh")
|
|
||||||
button.connect("clicked", self.refreshStats, False)
|
|
||||||
button.show()
|
|
||||||
hbox.add(button)
|
|
||||||
vbox.pack_start(hbox, False, True, 0)
|
|
||||||
hbox.show()
|
|
||||||
|
|
||||||
def createPlayerLine(self, hbox, site, player):
|
|
||||||
if(self.buttongroup == None):
|
|
||||||
button = gtk.RadioButton(None, site + " id:")
|
|
||||||
button.set_active(True)
|
|
||||||
self.buttongroup = button
|
|
||||||
self.activesite = site
|
|
||||||
else:
|
|
||||||
button = gtk.RadioButton(self.buttongroup, site + " id:")
|
|
||||||
hbox.pack_start(button, True, True, 0)
|
|
||||||
button.connect("toggled", self.toggleCallback, site)
|
|
||||||
button.show()
|
|
||||||
|
|
||||||
pname = gtk.Entry()
|
|
||||||
pname.set_text(player)
|
|
||||||
pname.set_width_chars(20)
|
|
||||||
hbox.pack_start(pname, False, True, 0)
|
|
||||||
pname.connect("changed", self.__set_hero_name, site)
|
|
||||||
#TODO: Look at GtkCompletion - to fill out usernames
|
|
||||||
pname.show()
|
|
||||||
self.__set_hero_name(pname, site)
|
|
||||||
|
|
||||||
def __set_hero_name(self, w, site):
|
|
||||||
self.heroes[site] = w.get_text()
|
|
||||||
|
|
||||||
def __init__(self, db, config, querylist, debug=True):
|
def __init__(self, db, config, querylist, debug=True):
|
||||||
self.debug=debug
|
self.debug=debug
|
||||||
self.conf=config
|
self.conf=config
|
||||||
|
|
||||||
# create new db connection to avoid conflicts with other threads
|
# create new db connection to avoid conflicts with other threads
|
||||||
self.fdb = fpdb_db.fpdb_db()
|
self.db = fpdb_db.fpdb_db()
|
||||||
self.fdb.do_connect(self.conf)
|
self.db.do_connect(self.conf)
|
||||||
self.cursor=self.fdb.cursor
|
self.cursor=self.db.cursor
|
||||||
|
|
||||||
self.sql = querylist
|
self.sql = querylist
|
||||||
|
|
||||||
self.activesite = None
|
settings = {}
|
||||||
self.buttongroup = None
|
settings.update(config.get_db_parameters())
|
||||||
|
settings.update(config.get_tv_parameters())
|
||||||
|
settings.update(config.get_import_parameters())
|
||||||
|
settings.update(config.get_default_paths())
|
||||||
|
|
||||||
|
filters_display = { "Heroes" : True,
|
||||||
|
"Sites" : True,
|
||||||
|
"Games" : False,
|
||||||
|
"Limits" : False,
|
||||||
|
"Dates" : False,
|
||||||
|
"Button1" : False,
|
||||||
|
"Button2" : False
|
||||||
|
}
|
||||||
|
|
||||||
|
self.filters = Filters.Filters(db, settings, config, querylist, display = filters_display)
|
||||||
|
|
||||||
self.heroes = {}
|
|
||||||
self.stat_table = None
|
self.stat_table = None
|
||||||
self.stats_frame = None
|
self.stats_frame = None
|
||||||
|
|
||||||
self.main_hbox = gtk.HBox(False, 0)
|
self.main_hbox = gtk.HBox(False, 0)
|
||||||
self.main_hbox.show()
|
self.main_hbox.show()
|
||||||
|
|
||||||
playerFrame = gtk.Frame("Hero:")
|
|
||||||
playerFrame.set_label_align(0.0, 0.0)
|
|
||||||
playerFrame.show()
|
|
||||||
vbox = gtk.VBox(False, 0)
|
|
||||||
vbox.show()
|
|
||||||
|
|
||||||
self.fillPlayerFrame(vbox)
|
|
||||||
playerFrame.add(vbox)
|
|
||||||
|
|
||||||
statsFrame = gtk.Frame("Stats:")
|
statsFrame = gtk.Frame("Stats:")
|
||||||
statsFrame.set_label_align(0.0, 0.0)
|
statsFrame.set_label_align(0.0, 0.0)
|
||||||
statsFrame.show()
|
statsFrame.show()
|
||||||
|
@ -172,6 +69,92 @@ class GuiPlayerStats (threading.Thread):
|
||||||
self.fillStatsFrame(self.stats_frame)
|
self.fillStatsFrame(self.stats_frame)
|
||||||
statsFrame.add(self.stats_frame)
|
statsFrame.add(self.stats_frame)
|
||||||
|
|
||||||
self.main_hbox.pack_start(playerFrame)
|
self.main_hbox.pack_start(self.filters.get_vbox())
|
||||||
self.main_hbox.pack_start(statsFrame)
|
self.main_hbox.pack_start(statsFrame)
|
||||||
|
|
||||||
|
def get_vbox(self):
|
||||||
|
"""returns the vbox of this thread"""
|
||||||
|
return self.main_hbox
|
||||||
|
|
||||||
|
def refreshStats(self, widget, data):
|
||||||
|
try: self.stats_table.destroy()
|
||||||
|
except AttributeError: pass
|
||||||
|
self.fillStatsFrame(self.stats_frame)
|
||||||
|
|
||||||
|
def fillStatsFrame(self, vbox):
|
||||||
|
sites = self.filters.getSites()
|
||||||
|
heroes = self.filters.getHeroes()
|
||||||
|
siteids = self.filters.getSiteIds()
|
||||||
|
sitenos = []
|
||||||
|
playerids = []
|
||||||
|
|
||||||
|
# Which sites are selected?
|
||||||
|
for site in sites:
|
||||||
|
if sites[site] == True:
|
||||||
|
sitenos.append(siteids[site])
|
||||||
|
self.cursor.execute(self.sql.query['getPlayerId'], (heroes[site],))
|
||||||
|
result = self.db.cursor.fetchall()
|
||||||
|
if len(result) == 1:
|
||||||
|
playerids.append(result[0][0])
|
||||||
|
|
||||||
|
if not sitenos:
|
||||||
|
#Should probably pop up here.
|
||||||
|
print "No sites selected - defaulting to PokerStars"
|
||||||
|
sitenos = [2]
|
||||||
|
if not playerids:
|
||||||
|
print "No player ids found"
|
||||||
|
return
|
||||||
|
|
||||||
|
self.createStatsTable(vbox, playerids, sitenos)
|
||||||
|
|
||||||
|
def createStatsTable(self, vbox, playerids, sitenos):
|
||||||
|
tmp = self.sql.query['playerStats']
|
||||||
|
|
||||||
|
nametest = str(tuple(playerids))
|
||||||
|
nametest = nametest.replace("L", "")
|
||||||
|
nametest = nametest.replace(",)",")")
|
||||||
|
|
||||||
|
tmp = tmp.replace("<player_test>", nametest)
|
||||||
|
|
||||||
|
self.cursor.execute(tmp)
|
||||||
|
result = self.cursor.fetchall()
|
||||||
|
cols = 16
|
||||||
|
rows = len(result)+1 # +1 for title row
|
||||||
|
self.stats_table = gtk.Table(rows, cols, False)
|
||||||
|
self.stats_table.set_col_spacings(4)
|
||||||
|
self.stats_table.show()
|
||||||
|
vbox.add(self.stats_table)
|
||||||
|
|
||||||
|
# Create header row
|
||||||
|
titles = ("Game", "Hands", "VPIP", "PFR", "Saw_F", "SawSD", "WtSDwsF", "W$SD", "FlAFq", "TuAFq", "RvAFq", "PoFAFq", "Net($)", "BB/100", "$/hand", "Variance")
|
||||||
|
|
||||||
|
col = 0
|
||||||
|
row = 0
|
||||||
|
for t in titles:
|
||||||
|
l = gtk.Label(titles[col])
|
||||||
|
l.show()
|
||||||
|
self.stats_table.attach(l, col, col+1, row, row+1, yoptions=gtk.SHRINK)
|
||||||
|
col +=1
|
||||||
|
|
||||||
|
for row in range(rows-1):
|
||||||
|
if(row%2 == 0):
|
||||||
|
bgcolor = "white"
|
||||||
|
else:
|
||||||
|
bgcolor = "lightgrey"
|
||||||
|
for col in range(cols):
|
||||||
|
eb = gtk.EventBox()
|
||||||
|
eb.modify_bg(gtk.STATE_NORMAL, gtk.gdk.color_parse(bgcolor))
|
||||||
|
if result[row][col]:
|
||||||
|
l = gtk.Label(result[row][col])
|
||||||
|
else:
|
||||||
|
l = gtk.Label(' ')
|
||||||
|
if col == 0:
|
||||||
|
l.set_alignment(xalign=0.0, yalign=0.5)
|
||||||
|
else:
|
||||||
|
l.set_alignment(xalign=1.0, yalign=0.5)
|
||||||
|
eb.add(l)
|
||||||
|
self.stats_table.attach(eb, col, col+1, row+1, row+2, yoptions=gtk.SHRINK)
|
||||||
|
l.show()
|
||||||
|
eb.show()
|
||||||
|
self.db.db.commit()
|
||||||
|
#end def fillStatsFrame(self, vbox):
|
||||||
|
|
|
@ -23,180 +23,43 @@ import os
|
||||||
|
|
||||||
import fpdb_import
|
import fpdb_import
|
||||||
import fpdb_db
|
import fpdb_db
|
||||||
|
import Filters
|
||||||
import FpdbSQLQueries
|
import FpdbSQLQueries
|
||||||
|
|
||||||
class GuiPositionalStats (threading.Thread):
|
class GuiPositionalStats (threading.Thread):
|
||||||
def get_vbox(self):
|
|
||||||
"""returns the vbox of this thread"""
|
|
||||||
return self.main_hbox
|
|
||||||
|
|
||||||
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)
|
|
||||||
|
|
||||||
def cardCallback(self, widget, data=None):
|
|
||||||
print "DEBUG: %s was toggled %s" % (data, ("OFF", "ON")[widget.get_active()])
|
|
||||||
|
|
||||||
def refreshStats(self, widget, data):
|
|
||||||
try: self.stats_table.destroy()
|
|
||||||
except AttributeError: pass
|
|
||||||
self.fillStatsFrame(self.stats_frame)
|
|
||||||
|
|
||||||
def fillStatsFrame(self, vbox):
|
|
||||||
# Get currently active site and grab playerid
|
|
||||||
print "DEBUG: attempting to fill stats frame"
|
|
||||||
tmp = self.sql.query['playerStatsByPosition']
|
|
||||||
|
|
||||||
result = self.cursor.execute(self.sql.query['getPlayerId'], (self.heroes[self.activesite],))
|
|
||||||
result = self.cursor.fetchall()
|
|
||||||
if not result == ():
|
|
||||||
pid = result[0][0]
|
|
||||||
pid = result[0][0]
|
|
||||||
tmp = tmp.replace("<player_test>", "(" + str(pid) + ")")
|
|
||||||
self.cursor.execute(tmp)
|
|
||||||
result = self.cursor.fetchall()
|
|
||||||
cols = 16
|
|
||||||
rows = len(result)+1 # +1 for title row
|
|
||||||
self.stats_table = gtk.Table(rows, cols, False)
|
|
||||||
self.stats_table.set_col_spacings(4)
|
|
||||||
self.stats_table.show()
|
|
||||||
vbox.add(self.stats_table)
|
|
||||||
|
|
||||||
# Create header row
|
|
||||||
titles = ("Game", "Position", "#", "VPIP", "PFR", "Saw_F", "SawSD", "WtSDwsF", "W$SD", "FlAFq", "TuAFq", "RvAFq", "PoFAFq", "Net($)", "BB/100", "$/hand", "Variance")
|
|
||||||
|
|
||||||
col = 0
|
|
||||||
row = 0
|
|
||||||
for t in titles:
|
|
||||||
l = gtk.Label(titles[col])
|
|
||||||
l.show()
|
|
||||||
self.stats_table.attach(l, col, col+1, row, row+1, yoptions=gtk.SHRINK)
|
|
||||||
col +=1
|
|
||||||
|
|
||||||
for row in range(rows-1):
|
|
||||||
if(row%2 == 0):
|
|
||||||
bgcolor = "white"
|
|
||||||
else:
|
|
||||||
bgcolor = "lightgrey"
|
|
||||||
for col in range(cols):
|
|
||||||
eb = gtk.EventBox()
|
|
||||||
eb.modify_bg(gtk.STATE_NORMAL, gtk.gdk.color_parse(bgcolor))
|
|
||||||
if result[row][col]:
|
|
||||||
l = gtk.Label(result[row][col])
|
|
||||||
else:
|
|
||||||
l = gtk.Label(' ')
|
|
||||||
if col == 0:
|
|
||||||
l.set_alignment(xalign=0.0, yalign=0.5)
|
|
||||||
else:
|
|
||||||
l.set_alignment(xalign=1.0, yalign=0.5)
|
|
||||||
eb.add(l)
|
|
||||||
self.stats_table.attach(eb, col, col+1, row+1, row+2, yoptions=gtk.SHRINK)
|
|
||||||
l.show()
|
|
||||||
eb.show()
|
|
||||||
self.fdb.db.commit()
|
|
||||||
#end def fillStatsFrame(self, vbox):
|
|
||||||
|
|
||||||
def fillPlayerFrame(self, vbox):
|
|
||||||
for site in self.conf.supported_sites.keys():
|
|
||||||
hbox = gtk.HBox(False, 0)
|
|
||||||
vbox.pack_start(hbox, False, True, 0)
|
|
||||||
hbox.show()
|
|
||||||
|
|
||||||
player = self.conf.supported_sites[site].screen_name
|
|
||||||
self.createPlayerLine(hbox, site, player)
|
|
||||||
hbox = gtk.HBox(False, 0)
|
|
||||||
button = gtk.Button("Refresh")
|
|
||||||
button.connect("clicked", self.refreshStats, False)
|
|
||||||
button.show()
|
|
||||||
hbox.add(button)
|
|
||||||
vbox.pack_start(hbox, False, True, 0)
|
|
||||||
hbox.show()
|
|
||||||
|
|
||||||
def fillCardsFrame(self, vbox):
|
|
||||||
hbox1 = gtk.HBox(True,0)
|
|
||||||
hbox1.show()
|
|
||||||
vbox.pack_start(hbox1, True, True, 0)
|
|
||||||
|
|
||||||
cards = [ "A", "K","Q","J","T","9","8","7","6","5","4","3","2" ]
|
|
||||||
|
|
||||||
for j in range(0, len(cards)):
|
|
||||||
hbox1 = gtk.HBox(True,0)
|
|
||||||
hbox1.show()
|
|
||||||
vbox.pack_start(hbox1, True, True, 0)
|
|
||||||
for i in range(0, len(cards)):
|
|
||||||
if i < (j + 1):
|
|
||||||
suit = "o"
|
|
||||||
else:
|
|
||||||
suit = "s"
|
|
||||||
button = gtk.ToggleButton("%s%s%s" %(cards[i], cards[j], suit))
|
|
||||||
button.connect("toggled", self.cardCallback, "%s%s%s" %(cards[i], cards[j], suit))
|
|
||||||
hbox1.pack_start(button, True, True, 0)
|
|
||||||
button.show()
|
|
||||||
|
|
||||||
def createPlayerLine(self, hbox, site, player):
|
|
||||||
if(self.buttongroup == None):
|
|
||||||
button = gtk.RadioButton(None, site + " id:")
|
|
||||||
button.set_active(True)
|
|
||||||
self.buttongroup = button
|
|
||||||
self.activesite = site
|
|
||||||
else:
|
|
||||||
button = gtk.RadioButton(self.buttongroup, site + " id:")
|
|
||||||
hbox.pack_start(button, True, True, 0)
|
|
||||||
button.connect("toggled", self.toggleCallback, site)
|
|
||||||
button.show()
|
|
||||||
|
|
||||||
pname = gtk.Entry()
|
|
||||||
pname.set_text(player)
|
|
||||||
pname.set_width_chars(20)
|
|
||||||
hbox.pack_start(pname, False, True, 0)
|
|
||||||
pname.connect("changed", self.__set_hero_name, site)
|
|
||||||
#TODO: Look at GtkCompletion - to fill out usernames
|
|
||||||
pname.show()
|
|
||||||
self.__set_hero_name(pname, site)
|
|
||||||
|
|
||||||
def __set_hero_name(self, w, site):
|
|
||||||
self.heroes[site] = w.get_text()
|
|
||||||
|
|
||||||
def __init__(self, db, config, querylist, debug=True):
|
def __init__(self, db, config, querylist, debug=True):
|
||||||
self.debug=debug
|
self.debug=debug
|
||||||
self.conf=config
|
self.conf=config
|
||||||
|
|
||||||
# create new db connection to avoid conflicts with other threads
|
# create new db connection to avoid conflicts with other threads
|
||||||
self.fdb = fpdb_db.fpdb_db()
|
self.db = fpdb_db.fpdb_db()
|
||||||
self.fdb.do_connect(self.conf)
|
self.db.do_connect(self.conf)
|
||||||
self.cursor=self.fdb.cursor
|
self.cursor=self.db.cursor
|
||||||
|
|
||||||
self.sql = querylist
|
self.sql = querylist
|
||||||
|
|
||||||
self.activesite = None
|
settings = {}
|
||||||
self.buttongroup = None
|
settings.update(config.get_db_parameters())
|
||||||
|
settings.update(config.get_tv_parameters())
|
||||||
|
settings.update(config.get_import_parameters())
|
||||||
|
settings.update(config.get_default_paths())
|
||||||
|
|
||||||
|
filters_display = { "Heroes" : True,
|
||||||
|
"Sites" : True,
|
||||||
|
"Games" : False,
|
||||||
|
"Limits" : False,
|
||||||
|
"Dates" : False,
|
||||||
|
"Button1" : False,
|
||||||
|
"Button2" : False
|
||||||
|
}
|
||||||
|
|
||||||
|
self.filters = Filters.Filters(db, settings, config, querylist, display = filters_display)
|
||||||
|
|
||||||
self.heroes = {}
|
|
||||||
self.stat_table = None
|
self.stat_table = None
|
||||||
self.stats_frame = None
|
self.stats_frame = None
|
||||||
|
|
||||||
self.main_hbox = gtk.HBox(False, 0)
|
self.main_hbox = gtk.HBox(False, 0)
|
||||||
self.main_hbox.show()
|
self.main_hbox.show()
|
||||||
|
|
||||||
playerFrame = gtk.Frame("Hero:")
|
|
||||||
playerFrame.set_label_align(0.0, 0.0)
|
|
||||||
playerFrame.show()
|
|
||||||
vbox = gtk.VBox(False, 0)
|
|
||||||
vbox.show()
|
|
||||||
|
|
||||||
self.fillPlayerFrame(vbox)
|
|
||||||
playerFrame.add(vbox)
|
|
||||||
|
|
||||||
cardsFrame = gtk.Frame("Cards:")
|
|
||||||
cardsFrame.set_label_align(0.0, 0.0)
|
|
||||||
cardsFrame.show()
|
|
||||||
vbox = gtk.VBox(False, 0)
|
|
||||||
vbox.show()
|
|
||||||
|
|
||||||
self.fillCardsFrame(vbox)
|
|
||||||
cardsFrame.add(vbox)
|
|
||||||
|
|
||||||
statsFrame = gtk.Frame("Stats:")
|
statsFrame = gtk.Frame("Stats:")
|
||||||
statsFrame.set_label_align(0.0, 0.0)
|
statsFrame.set_label_align(0.0, 0.0)
|
||||||
statsFrame.show()
|
statsFrame.show()
|
||||||
|
@ -206,6 +69,97 @@ class GuiPositionalStats (threading.Thread):
|
||||||
self.fillStatsFrame(self.stats_frame)
|
self.fillStatsFrame(self.stats_frame)
|
||||||
statsFrame.add(self.stats_frame)
|
statsFrame.add(self.stats_frame)
|
||||||
|
|
||||||
self.main_hbox.pack_start(playerFrame)
|
self.main_hbox.pack_start(self.filters.get_vbox())
|
||||||
self.main_hbox.pack_start(statsFrame)
|
self.main_hbox.pack_start(statsFrame)
|
||||||
|
|
||||||
|
def get_vbox(self):
|
||||||
|
"""returns the vbox of this thread"""
|
||||||
|
return self.main_hbox
|
||||||
|
|
||||||
|
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)
|
||||||
|
|
||||||
|
def refreshStats(self, widget, data):
|
||||||
|
try: self.stats_table.destroy()
|
||||||
|
except AttributeError: pass
|
||||||
|
self.fillStatsFrame(self.stats_frame)
|
||||||
|
|
||||||
|
def fillStatsFrame(self, vbox):
|
||||||
|
sites = self.filters.getSites()
|
||||||
|
heroes = self.filters.getHeroes()
|
||||||
|
siteids = self.filters.getSiteIds()
|
||||||
|
sitenos = []
|
||||||
|
playerids = []
|
||||||
|
|
||||||
|
# Which sites are selected?
|
||||||
|
for site in sites:
|
||||||
|
if sites[site] == True:
|
||||||
|
sitenos.append(siteids[site])
|
||||||
|
self.cursor.execute(self.sql.query['getPlayerId'], (heroes[site],))
|
||||||
|
result = self.db.cursor.fetchall()
|
||||||
|
if len(result) == 1:
|
||||||
|
playerids.append(result[0][0])
|
||||||
|
|
||||||
|
if not sitenos:
|
||||||
|
#Should probably pop up here.
|
||||||
|
print "No sites selected - defaulting to PokerStars"
|
||||||
|
sitenos = [2]
|
||||||
|
if not playerids:
|
||||||
|
print "No player ids found"
|
||||||
|
return
|
||||||
|
|
||||||
|
self.createStatsTable(vbox, playerids, sitenos)
|
||||||
|
|
||||||
|
def createStatsTable(self, vbox, playerids, sitenos):
|
||||||
|
tmp = self.sql.query['playerStatsByPosition']
|
||||||
|
|
||||||
|
nametest = str(tuple(playerids))
|
||||||
|
nametest = nametest.replace("L", "")
|
||||||
|
nametest = nametest.replace(",)",")")
|
||||||
|
|
||||||
|
tmp = tmp.replace("<player_test>", nametest)
|
||||||
|
|
||||||
|
self.cursor.execute(tmp)
|
||||||
|
result = self.cursor.fetchall()
|
||||||
|
cols = 16
|
||||||
|
rows = len(result)+1 # +1 for title row
|
||||||
|
self.stats_table = gtk.Table(rows, cols, False)
|
||||||
|
self.stats_table.set_col_spacings(4)
|
||||||
|
self.stats_table.show()
|
||||||
|
vbox.add(self.stats_table)
|
||||||
|
|
||||||
|
# Create header row
|
||||||
|
titles = ("Game", "Position", "#", "VPIP", "PFR", "Saw_F", "SawSD", "WtSDwsF", "W$SD", "FlAFq", "TuAFq", "RvAFq", "PoFAFq", "Net($)", "BB/100", "$/hand", "Variance")
|
||||||
|
|
||||||
|
col = 0
|
||||||
|
row = 0
|
||||||
|
for t in titles:
|
||||||
|
l = gtk.Label(titles[col])
|
||||||
|
l.show()
|
||||||
|
self.stats_table.attach(l, col, col+1, row, row+1, yoptions=gtk.SHRINK)
|
||||||
|
col +=1
|
||||||
|
|
||||||
|
for row in range(rows-1):
|
||||||
|
if(row%2 == 0):
|
||||||
|
bgcolor = "white"
|
||||||
|
else:
|
||||||
|
bgcolor = "lightgrey"
|
||||||
|
for col in range(cols):
|
||||||
|
eb = gtk.EventBox()
|
||||||
|
eb.modify_bg(gtk.STATE_NORMAL, gtk.gdk.color_parse(bgcolor))
|
||||||
|
if result[row][col]:
|
||||||
|
l = gtk.Label(result[row][col])
|
||||||
|
else:
|
||||||
|
l = gtk.Label(' ')
|
||||||
|
if col == 0:
|
||||||
|
l.set_alignment(xalign=0.0, yalign=0.5)
|
||||||
|
else:
|
||||||
|
l.set_alignment(xalign=1.0, yalign=0.5)
|
||||||
|
eb.add(l)
|
||||||
|
self.stats_table.attach(eb, col, col+1, row+1, row+2, yoptions=gtk.SHRINK)
|
||||||
|
l.show()
|
||||||
|
eb.show()
|
||||||
|
self.db.db.commit()
|
||||||
|
#end def fillStatsFrame(self, vbox):
|
||||||
|
|
|
@ -12,13 +12,13 @@
|
||||||
screen_name="YOUR SCREEN NAME HERE"
|
screen_name="YOUR SCREEN NAME HERE"
|
||||||
site_path="C:/Program Files/PokerStars/"
|
site_path="C:/Program Files/PokerStars/"
|
||||||
HH_path="C:/Program Files/PokerStars/HandHistory/YOUR SCREEN NAME HERE/"
|
HH_path="C:/Program Files/PokerStars/HandHistory/YOUR SCREEN NAME HERE/"
|
||||||
decoder="pokerstars_decode_table"
|
decoder="pokerstars_decode_table"
|
||||||
|
converter="PokerStarsToFpdb"
|
||||||
bgcolor="#000000"
|
bgcolor="#000000"
|
||||||
fgcolor="#FFFFFF"
|
fgcolor="#FFFFFF"
|
||||||
hudopacity="1.0"
|
hudopacity="1.0"
|
||||||
font="Sans"
|
font="Sans"
|
||||||
font_size="8"
|
font_size="8"
|
||||||
converter="passthrough"
|
|
||||||
supported_games="holdem,razz,omahahi,omahahilo,studhi,studhilo">
|
supported_games="holdem,razz,omahahi,omahahilo,studhi,studhilo">
|
||||||
<layout max="8" width="792" height="546" fav_seat="0">
|
<layout max="8" width="792" height="546" fav_seat="0">
|
||||||
<location seat="1" x="684" y="61"> </location>
|
<location seat="1" x="684" y="61"> </location>
|
||||||
|
@ -74,12 +74,12 @@
|
||||||
site_path="C:/Program Files/Full Tilt Poker/"
|
site_path="C:/Program Files/Full Tilt Poker/"
|
||||||
HH_path="C:/Program Files/Full Tilt Poker/HandHistory/YOUR SCREEN NAME HERE/"
|
HH_path="C:/Program Files/Full Tilt Poker/HandHistory/YOUR SCREEN NAME HERE/"
|
||||||
decoder="fulltilt_decode_table"
|
decoder="fulltilt_decode_table"
|
||||||
|
converter="FulltiltToFpdb"
|
||||||
bgcolor="#000000"
|
bgcolor="#000000"
|
||||||
fgcolor="#FFFFFF"
|
fgcolor="#FFFFFF"
|
||||||
hudopacity="1.0"
|
hudopacity="1.0"
|
||||||
font="Sans"
|
font="Sans"
|
||||||
font_size="8"
|
font_size="8"
|
||||||
converter="passthrough"
|
|
||||||
supported_games="holdem,razz,omahahi,omahahilo,studhi,studhilo">
|
supported_games="holdem,razz,omahahi,omahahilo,studhi,studhilo">
|
||||||
<layout fav_seat="0" height="547" max="8" width="794">
|
<layout fav_seat="0" height="547" max="8" width="794">
|
||||||
<location seat="1" x="640" y="64"> </location>
|
<location seat="1" x="640" y="64"> </location>
|
||||||
|
@ -123,7 +123,7 @@
|
||||||
site_path=""
|
site_path=""
|
||||||
HH_path=""
|
HH_path=""
|
||||||
decoder="everleaf_decode_table"
|
decoder="everleaf_decode_table"
|
||||||
converter="EverleafToFpdb"
|
converter="EverleafToFpdb"
|
||||||
supported_games="holdem">
|
supported_games="holdem">
|
||||||
<layout fav_seat="0" height="547" max="8" width="794">
|
<layout fav_seat="0" height="547" max="8" width="794">
|
||||||
<location seat="1" x="640" y="64"> </location>
|
<location seat="1" x="640" y="64"> </location>
|
||||||
|
@ -288,6 +288,12 @@
|
||||||
</aw>
|
</aw>
|
||||||
</aux_windows>
|
</aux_windows>
|
||||||
|
|
||||||
|
<hhcs>
|
||||||
|
<hhc site="PokerStars" converter="PokerStarsToFpdb"/>
|
||||||
|
<hhc site="Full Tilt Poker" converter="FulltiltToFpdb"/>
|
||||||
|
<hhc site="Everleaf" converter="EverleafToFpdb"/>
|
||||||
|
</hhcs>
|
||||||
|
|
||||||
<supported_databases>
|
<supported_databases>
|
||||||
<database db_name="fpdb" db_server="mysql" db_ip="localhost" db_user="fpdb" db_pass="YOUR MYSQL PASSWORD" db_type="fpdb"></database>
|
<database db_name="fpdb" db_server="mysql" db_ip="localhost" db_user="fpdb" db_pass="YOUR MYSQL PASSWORD" db_type="fpdb"></database>
|
||||||
</supported_databases>
|
</supported_databases>
|
||||||
|
|
|
@ -112,7 +112,9 @@ class HandHistoryConverter():
|
||||||
def start(self):
|
def start(self):
|
||||||
"""process a hand at a time from the input specified by in_path.
|
"""process a hand at a time from the input specified by in_path.
|
||||||
If in follow mode, wait for more data to turn up.
|
If in follow mode, wait for more data to turn up.
|
||||||
Otherwise, finish at eof..."""
|
Otherwise, finish at eof...
|
||||||
|
|
||||||
|
"""
|
||||||
starttime = time.time()
|
starttime = time.time()
|
||||||
if not self.sanityCheck():
|
if not self.sanityCheck():
|
||||||
print "Cowardly refusing to continue after failed sanity check"
|
print "Cowardly refusing to continue after failed sanity check"
|
||||||
|
@ -137,7 +139,11 @@ Otherwise, finish at eof..."""
|
||||||
|
|
||||||
def tailHands(self):
|
def tailHands(self):
|
||||||
"""Generator of handTexts from a tailed file:
|
"""Generator of handTexts from a tailed file:
|
||||||
Tail the in_path file and yield handTexts separated by re_SplitHands"""
|
Tail the in_path file and yield handTexts separated by re_SplitHands.
|
||||||
|
This requires a regex that greedily groups and matches the 'splitter' between hands,
|
||||||
|
which it expects to find at self.re_TailSplitHands -- see for e.g. Everleaf.py.
|
||||||
|
|
||||||
|
"""
|
||||||
if self.in_path == '-': raise StopIteration
|
if self.in_path == '-': raise StopIteration
|
||||||
interval = 1.0 # seconds to sleep between reads for new data
|
interval = 1.0 # seconds to sleep between reads for new data
|
||||||
fd = codecs.open(self.in_path,'r', self.codepage)
|
fd = codecs.open(self.in_path,'r', self.codepage)
|
||||||
|
@ -161,7 +167,7 @@ Tail the in_path file and yield handTexts separated by re_SplitHands"""
|
||||||
else:
|
else:
|
||||||
# yield hands
|
# yield hands
|
||||||
data = data + newdata
|
data = data + newdata
|
||||||
result = self.re_SplitHands.split(data)
|
result = self.re_TailSplitHands.split(data)
|
||||||
result = iter(result)
|
result = iter(result)
|
||||||
data = ''
|
data = ''
|
||||||
# --x data (- is bit of splitter, x is paragraph) yield,...,keep
|
# --x data (- is bit of splitter, x is paragraph) yield,...,keep
|
||||||
|
|
|
@ -27,7 +27,8 @@ class PokerStars(HandHistoryConverter):
|
||||||
|
|
||||||
# Static regexes
|
# Static regexes
|
||||||
re_GameInfo = re.compile("PokerStars Game #(?P<HID>[0-9]+):\s+(HORSE)? \(?(?P<GAME>Hold\'em|Razz|7 Card Stud|Omaha|Omaha Hi/Lo|Badugi) (?P<LIMIT>No Limit|Limit|Pot Limit),? \(?(?P<CURRENCY>\$|)?(?P<SB>[.0-9]+)/\$?(?P<BB>[.0-9]+)\) - (?P<DATETIME>.*$)", re.MULTILINE)
|
re_GameInfo = re.compile("PokerStars Game #(?P<HID>[0-9]+):\s+(HORSE)? \(?(?P<GAME>Hold\'em|Razz|7 Card Stud|Omaha|Omaha Hi/Lo|Badugi) (?P<LIMIT>No Limit|Limit|Pot Limit),? \(?(?P<CURRENCY>\$|)?(?P<SB>[.0-9]+)/\$?(?P<BB>[.0-9]+)\) - (?P<DATETIME>.*$)", re.MULTILINE)
|
||||||
re_SplitHands = re.compile('(\n\n+)')
|
re_SplitHands = re.compile('\n\n+')
|
||||||
|
re_TailSplitHands = re.compile('(\n\n\n+)')
|
||||||
re_HandInfo = re.compile("^Table \'(?P<TABLE>[- a-zA-Z]+)\'(?P<TABLEATTRIBUTES>.+?$)?", re.MULTILINE)
|
re_HandInfo = re.compile("^Table \'(?P<TABLE>[- a-zA-Z]+)\'(?P<TABLEATTRIBUTES>.+?$)?", re.MULTILINE)
|
||||||
re_Button = re.compile('Seat #(?P<BUTTON>\d+) is the button', re.MULTILINE)
|
re_Button = re.compile('Seat #(?P<BUTTON>\d+) is the button', re.MULTILINE)
|
||||||
re_PlayerInfo = re.compile('^Seat (?P<SEAT>[0-9]+): (?P<PNAME>.*) \(\$?(?P<CASH>[.0-9]+) in chips\)', re.MULTILINE)
|
re_PlayerInfo = re.compile('^Seat (?P<SEAT>[0-9]+): (?P<PNAME>.*) \(\$?(?P<CASH>[.0-9]+) in chips\)', re.MULTILINE)
|
||||||
|
@ -72,7 +73,7 @@ follow : whether to tail -f the input"""
|
||||||
["ring", "hold", "pl"],
|
["ring", "hold", "pl"],
|
||||||
["ring", "hold", "fl"],
|
["ring", "hold", "fl"],
|
||||||
["ring", "stud", "fl"],
|
["ring", "stud", "fl"],
|
||||||
["ring", "draw", "fl"],
|
#["ring", "draw", "fl"],
|
||||||
["ring", "omaha", "pl"]
|
["ring", "omaha", "pl"]
|
||||||
]
|
]
|
||||||
|
|
||||||
|
|
329
pyfpdb/UltimateBetToFpdb.py
Executable file
329
pyfpdb/UltimateBetToFpdb.py
Executable file
|
@ -0,0 +1,329 @@
|
||||||
|
#!/usr/bin/env python
|
||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
#
|
||||||
|
# Copyright 2008, Carl Gherardi
|
||||||
|
#
|
||||||
|
# This program is free software; you can redistribute it and/or modify
|
||||||
|
# it under the terms of the GNU General Public License as published by
|
||||||
|
# the Free Software Foundation; either version 2 of the License, or
|
||||||
|
# (at your option) any later version.
|
||||||
|
#
|
||||||
|
# This program is distributed in the hope that it will be useful,
|
||||||
|
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
# GNU General Public License for more details.
|
||||||
|
#
|
||||||
|
# You should have received a copy of the GNU General Public License
|
||||||
|
# along with this program; if not, write to the Free Software
|
||||||
|
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||||
|
########################################################################
|
||||||
|
|
||||||
|
import sys
|
||||||
|
from HandHistoryConverter import *
|
||||||
|
|
||||||
|
|
||||||
|
class UltimateBet(HandHistoryConverter):
|
||||||
|
|
||||||
|
# Static regexes
|
||||||
|
re_GameInfo = re.compile("Stage #(?P<HID>[0-9]+):\s+\(?(?P<GAME>Hold\'em|Razz|Seven Card|Omaha|Omaha Hi/Lo|Badugi) (?P<LIMIT>No Limit|Normal|Pot Limit),? \(?(?P<CURRENCY>\$|)?(?P<SB>[.0-9]+)/\$?(?P<BB>[.0-9]+)\) - (?P<DATETIME>.*$)", re.MULTILINE)
|
||||||
|
re_SplitHands = re.compile('(\n\n\n+)')
|
||||||
|
re_HandInfo = re.compile("^Table \'(?P<TABLE>[- a-zA-Z]+)\'(?P<TABLEATTRIBUTES>.+?$)?", re.MULTILINE)
|
||||||
|
re_Button = re.compile('Seat #(?P<BUTTON>\d+) is the button', re.MULTILINE)
|
||||||
|
re_PlayerInfo = re.compile('^Seat (?P<SEAT>[0-9]+) - (?P<PNAME>.*) \(\$?(?P<CASH>[.0-9]+) in chips\)', 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]+)')
|
||||||
|
|
||||||
|
def __init__(self, in_path = '-', out_path = '-', follow = False, autostart=True):
|
||||||
|
"""\
|
||||||
|
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)
|
||||||
|
logging.info("Initialising UltimateBetconverter class")
|
||||||
|
self.filetype = "text"
|
||||||
|
self.codepage = "cp1252"
|
||||||
|
if autostart:
|
||||||
|
self.start()
|
||||||
|
|
||||||
|
|
||||||
|
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)) + ")"
|
||||||
|
logging.debug("player_re: " + player_re)
|
||||||
|
self.re_PostSB = re.compile(r"^%s: posts small blind \$?(?P<SB>[.0-9]+)" % player_re, re.MULTILINE)
|
||||||
|
self.re_PostBB = re.compile(r"^%s: posts big blind \$?(?P<BB>[.0-9]+)" % player_re, re.MULTILINE)
|
||||||
|
self.re_Antes = re.compile(r"^%s - Ante \$?(?P<ANTE>[.0-9]+)" % player_re, re.MULTILINE)
|
||||||
|
self.re_BringIn = re.compile(r"^%s - Bring-In \$?(?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_HeroCards = re.compile(r"^Dealt to %s - Pocket (\[(?P<OLDCARDS>.+?)\])?( \[(?P<NEWCARDS>.+?)\])" % player_re, re.MULTILINE)
|
||||||
|
self.re_Action = re.compile(r"^%s -(?P<ATYPE> Bets| Checks| raises| Calls| Folds)( \$(?P<BET>[.\d]+))?( to \$(?P<BETTO>[.\d]+))?( (?P<NODISCARDED>\d) cards?( \[(?P<DISCARDED>.+?)\])?)?" % player_re, 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_sitsOut = re.compile("^%s sits out" % player_re, re.MULTILINE)
|
||||||
|
self.re_ShownCards = re.compile("^Seat (?P<SEAT>[0-9]+): %s \(.*\) showed \[(?P<CARDS>.*)\].*" % player_re, re.MULTILINE)
|
||||||
|
|
||||||
|
|
||||||
|
def readSupportedGames(self):
|
||||||
|
return [ ["ring", "stud", "fl"]
|
||||||
|
]
|
||||||
|
|
||||||
|
def determineGameType(self, handText):
|
||||||
|
info = {'type':'ring'}
|
||||||
|
|
||||||
|
m = self.re_GameInfo.search(handText)
|
||||||
|
if not m:
|
||||||
|
return None
|
||||||
|
|
||||||
|
mg = m.groupdict()
|
||||||
|
|
||||||
|
# translations from captured groups to our info strings
|
||||||
|
limits = { 'No Limit':'nl', 'Pot Limit':'pl', 'Limit':'fl' }
|
||||||
|
games = { # base, category
|
||||||
|
"Hold'em" : ('hold','holdem'),
|
||||||
|
'Omaha' : ('hold','omahahi'),
|
||||||
|
'Omaha Hi/Lo' : ('hold','omahahilo'),
|
||||||
|
'Razz' : ('stud','razz'),
|
||||||
|
'7 Card Stud' : ('stud','studhi'),
|
||||||
|
'Badugi' : ('draw','badugi')
|
||||||
|
}
|
||||||
|
currencies = { u'€':'EUR', '$':'USD', '':'T$' }
|
||||||
|
if 'LIMIT' in mg:
|
||||||
|
info['limitType'] = limits[mg['LIMIT']]
|
||||||
|
if 'GAME' in mg:
|
||||||
|
(info['base'], info['category']) = 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'] = currencies[mg['CURRENCY']]
|
||||||
|
# NB: SB, BB must be interpreted as blinds or bets depending on limit type.
|
||||||
|
|
||||||
|
return info
|
||||||
|
|
||||||
|
|
||||||
|
def readHandInfo(self, hand):
|
||||||
|
info = {}
|
||||||
|
m = self.re_HandInfo.search(hand.handText,re.DOTALL)
|
||||||
|
if m:
|
||||||
|
info.update(m.groupdict())
|
||||||
|
# TODO: Be less lazy and parse maxseats from the HandInfo regex
|
||||||
|
if m.group('TABLEATTRIBUTES'):
|
||||||
|
m2 = re.search("\s*(\d+)-max", m.group('TABLEATTRIBUTES'))
|
||||||
|
hand.maxseats = int(m2.group(1))
|
||||||
|
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
|
||||||
|
logging.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
|
||||||
|
m2 = re.search("(?P<Y>[0-9]{4})\/(?P<M>[0-9]{2})\/(?P<D>[0-9]{2})[\- ]+(?P<H>[0-9]+):(?P<MIN>[0-9]+):(?P<S>[0-9]+)", info[key])
|
||||||
|
datetime = "%s/%s/%s %s:%s:%s" % (m2.group('Y'), m2.group('M'),m2.group('D'),m2.group('H'),m2.group('MIN'),m2.group('S'))
|
||||||
|
hand.starttime = time.strptime(datetime, "%Y/%m/%d %H:%M:%S")
|
||||||
|
if key == 'HID':
|
||||||
|
hand.handid = info[key]
|
||||||
|
if key == 'TABLE':
|
||||||
|
hand.tablename = info[key]
|
||||||
|
if key == 'BUTTON':
|
||||||
|
hand.buttonpos = info[key]
|
||||||
|
|
||||||
|
def readButton(self, hand):
|
||||||
|
m = self.re_Button.search(hand.handText)
|
||||||
|
if m:
|
||||||
|
hand.buttonpos = int(m.group('BUTTON'))
|
||||||
|
else:
|
||||||
|
logging.info('readButton: not found')
|
||||||
|
|
||||||
|
def readPlayerStacks(self, hand):
|
||||||
|
logging.debug("readPlayerStacks")
|
||||||
|
m = self.re_PlayerInfo.finditer(hand.handText)
|
||||||
|
players = []
|
||||||
|
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.
|
||||||
|
if hand.gametype['base'] in ("hold"):
|
||||||
|
m = re.search(r"\*\*\* HOLE CARDS \*\*\*(?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)
|
||||||
|
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):
|
||||||
|
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')))
|
||||||
|
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'), 'small & big blinds', a.group('SBBB'))
|
||||||
|
|
||||||
|
def readHeroCards(self, hand):
|
||||||
|
m = self.re_HeroCards.search(hand.handText)
|
||||||
|
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('NEWCARDS')
|
||||||
|
cards = set(cards.split(' '))
|
||||||
|
hand.addHoleCards(cards, m.group('PNAME'))
|
||||||
|
|
||||||
|
def readDrawCards(self, hand, street):
|
||||||
|
logging.debug("readDrawCards")
|
||||||
|
m = self.re_HeroCards.finditer(hand.streets[street])
|
||||||
|
if m == None:
|
||||||
|
hand.involved = False
|
||||||
|
else:
|
||||||
|
for player in m:
|
||||||
|
hand.hero = player.group('PNAME') # Only really need to do this once
|
||||||
|
newcards = player.group('NEWCARDS')
|
||||||
|
oldcards = player.group('OLDCARDS')
|
||||||
|
if newcards == None:
|
||||||
|
newcards = set()
|
||||||
|
else:
|
||||||
|
newcards = set(newcards.split(' '))
|
||||||
|
if oldcards == None:
|
||||||
|
oldcards = set()
|
||||||
|
else:
|
||||||
|
oldcards = set(oldcards.split(' '))
|
||||||
|
hand.addDrawHoleCards(newcards, oldcards, player.group('PNAME'), street)
|
||||||
|
|
||||||
|
|
||||||
|
def readStudPlayerCards(self, hand, street):
|
||||||
|
# See comments of reference implementation in FullTiltToFpdb.py
|
||||||
|
logging.debug("readStudPlayerCards")
|
||||||
|
m = self.re_HeroCards.finditer(hand.streets[street])
|
||||||
|
for player in m:
|
||||||
|
#~ logging.debug(player.groupdict())
|
||||||
|
(pname, oldcards, newcards) = (player.group('PNAME'), player.group('OLDCARDS'), player.group('NEWCARDS'))
|
||||||
|
if oldcards:
|
||||||
|
oldcards = [c.strip() for c in oldcards.split(' ')]
|
||||||
|
if newcards:
|
||||||
|
newcards = [c.strip() for c in newcards.split(' ')]
|
||||||
|
if street=='ANTES':
|
||||||
|
return
|
||||||
|
elif street=='THIRD':
|
||||||
|
# we'll have observed hero holecards in CARDS and thirdstreet open cards in 'NEWCARDS'
|
||||||
|
# hero: [xx][o]
|
||||||
|
# others: [o]
|
||||||
|
hand.addPlayerCards(player = player.group('PNAME'), street = street, closed = oldcards, open = newcards)
|
||||||
|
elif street in ('FOURTH', 'FIFTH', 'SIXTH'):
|
||||||
|
# 4th:
|
||||||
|
# hero: [xxo] [o]
|
||||||
|
# others: [o] [o]
|
||||||
|
# 5th:
|
||||||
|
# hero: [xxoo] [o]
|
||||||
|
# others: [oo] [o]
|
||||||
|
# 6th:
|
||||||
|
# hero: [xxooo] [o]
|
||||||
|
# others: [ooo] [o]
|
||||||
|
hand.addPlayerCards(player = player.group('PNAME'), street = street, open = newcards)
|
||||||
|
# we may additionally want to check the earlier streets tally with what we have but lets trust it for now.
|
||||||
|
elif street=='SEVENTH' and newcards:
|
||||||
|
# hero: [xxoooo] [x]
|
||||||
|
# others: not reported.
|
||||||
|
hand.addPlayerCards(player = player.group('PNAME'), street = street, closed = newcards)
|
||||||
|
|
||||||
|
def readAction(self, hand, street):
|
||||||
|
m = self.re_Action.finditer(hand.streets[street])
|
||||||
|
for action in m:
|
||||||
|
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('NODISCARDED'), 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):
|
||||||
|
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.re_CollectPot.finditer(hand.handText):
|
||||||
|
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 = set(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="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",
|
||||||
|
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 = UltimateBet(in_path = options.ipath, out_path = options.opath, follow = options.follow)
|
|
@ -382,7 +382,7 @@ This program is licensed under the AGPL3, see docs"""+os.sep+"agpl-3.0.txt")
|
||||||
self.window.connect("destroy", self.destroy)
|
self.window.connect("destroy", self.destroy)
|
||||||
self.window.set_title("Free Poker DB - v%s or higher" % (VERSION, ))
|
self.window.set_title("Free Poker DB - v%s or higher" % (VERSION, ))
|
||||||
self.window.set_border_width(1)
|
self.window.set_border_width(1)
|
||||||
self.window.set_size_request(1020,400)
|
self.window.set_default_size(900,720)
|
||||||
self.window.set_resizable(True)
|
self.window.set_resizable(True)
|
||||||
|
|
||||||
self.menu_items = (
|
self.menu_items = (
|
||||||
|
@ -450,7 +450,7 @@ This program is licensed under the AGPL3, see docs"""+os.sep+"agpl-3.0.txt")
|
||||||
|
|
||||||
self.tab_main_help(None, None)
|
self.tab_main_help(None, None)
|
||||||
|
|
||||||
self.status_bar = gtk.Label("Status: Connected to "+self.db.get_backend_name()+" database named "+self.db.database+" on host "+self.db.host)
|
self.status_bar = gtk.Label("Status: Connected to %s database named %s on host %s"%(self.db.get_backend_name(),self.db.database, self.db.host))
|
||||||
self.main_vbox.pack_end(self.status_bar, False, True, 0)
|
self.main_vbox.pack_end(self.status_bar, False, True, 0)
|
||||||
self.status_bar.show()
|
self.status_bar.show()
|
||||||
|
|
||||||
|
|
|
@ -58,13 +58,14 @@ class Importer:
|
||||||
self.cursor = None
|
self.cursor = None
|
||||||
self.filelist = {}
|
self.filelist = {}
|
||||||
self.dirlist = {}
|
self.dirlist = {}
|
||||||
|
self.siteIds = {}
|
||||||
self.addToDirList = {}
|
self.addToDirList = {}
|
||||||
self.removeFromFileList = {} # to remove deleted files
|
self.removeFromFileList = {} # to remove deleted files
|
||||||
self.monitor = False
|
self.monitor = False
|
||||||
self.updated = {} #Time last import was run {file:mtime}
|
self.updated = {} #Time last import was run {file:mtime}
|
||||||
self.lines = None
|
self.lines = None
|
||||||
self.faobs = None #File as one big string
|
self.faobs = None # File as one big string
|
||||||
self.pos_in_file = {} # dict to remember how far we have read in the file
|
self.pos_in_file = {} # dict to remember how far we have read in the file
|
||||||
#Set defaults
|
#Set defaults
|
||||||
self.callHud = self.config.get_import_parameters().get("callFpdbHud")
|
self.callHud = self.config.get_import_parameters().get("callFpdbHud")
|
||||||
|
|
||||||
|
@ -110,20 +111,32 @@ class Importer:
|
||||||
def addImportFile(self, filename, site = "default", filter = "passthrough"):
|
def addImportFile(self, filename, site = "default", filter = "passthrough"):
|
||||||
#TODO: test it is a valid file -> put that in config!!
|
#TODO: test it is a valid file -> put that in config!!
|
||||||
self.filelist[filename] = [site] + [filter]
|
self.filelist[filename] = [site] + [filter]
|
||||||
|
if site not in self.siteIds:
|
||||||
|
# Get id from Sites table in DB
|
||||||
|
self.fdb.cursor.execute(self.fdb.sql.query['getSiteId'], (site,))
|
||||||
|
result = self.fdb.cursor.fetchall()
|
||||||
|
if len(result) == 1:
|
||||||
|
self.siteIds[site] = result[0][0]
|
||||||
|
else:
|
||||||
|
if len(result) == 0:
|
||||||
|
print "[ERROR] Database ID for %s not found" % site
|
||||||
|
else:
|
||||||
|
print "[ERROR] More than 1 Database ID found for %s - Multiple currencies not implemented yet" % site
|
||||||
|
|
||||||
|
|
||||||
# Called from GuiBulkImport to add a file or directory.
|
# Called from GuiBulkImport to add a file or directory.
|
||||||
def addBulkImportImportFileOrDir(self, inputPath,filter = "passthrough"):
|
def addBulkImportImportFileOrDir(self, inputPath, site = "PokerStars"):
|
||||||
"""Add a file or directory for bulk import"""
|
"""Add a file or directory for bulk import"""
|
||||||
|
filter = self.config.hhcs[site].converter
|
||||||
# Bulk import never monitors
|
# Bulk import never monitors
|
||||||
# if directory, add all files in it. Otherwise add single file.
|
# if directory, add all files in it. Otherwise add single file.
|
||||||
# TODO: only add sane files?
|
# TODO: only add sane files?
|
||||||
if os.path.isdir(inputPath):
|
if os.path.isdir(inputPath):
|
||||||
for subdir in os.walk(inputPath):
|
for subdir in os.walk(inputPath):
|
||||||
for file in subdir[2]:
|
for file in subdir[2]:
|
||||||
self.addImportFile(os.path.join(inputPath, subdir[0], file), site="default", filter=filter)
|
self.addImportFile(os.path.join(inputPath, subdir[0], file), site=site, filter=filter)
|
||||||
else:
|
else:
|
||||||
self.addImportFile(inputPath, site="default", filter=filter)
|
self.addImportFile(inputPath, site=site, filter=filter)
|
||||||
#Add a directory of files to filelist
|
#Add a directory of files to filelist
|
||||||
#Only one import directory per site supported.
|
#Only one import directory per site supported.
|
||||||
#dirlist is a hash of lists:
|
#dirlist is a hash of lists:
|
||||||
|
@ -194,7 +207,7 @@ class Importer:
|
||||||
self.addImportDirectory(self.dirlist[site][0], False, site, self.dirlist[site][1])
|
self.addImportDirectory(self.dirlist[site][0], False, site, self.dirlist[site][1])
|
||||||
|
|
||||||
for file in self.filelist:
|
for file in self.filelist:
|
||||||
if os.path.exists(file):
|
if os.path.exists(file):
|
||||||
stat_info = os.stat(file)
|
stat_info = os.stat(file)
|
||||||
try:
|
try:
|
||||||
lastupdate = self.updated[file]
|
lastupdate = self.updated[file]
|
||||||
|
@ -214,8 +227,8 @@ class Importer:
|
||||||
#self.import_file_dict(file, self.filelist[file][0], self.filelist[file][1])
|
#self.import_file_dict(file, self.filelist[file][0], self.filelist[file][1])
|
||||||
else:
|
else:
|
||||||
removeFromFileList[file] = True
|
removeFromFileList[file] = True
|
||||||
self.addToDirList = filter(lambda x: self.addImportDirectory(x, True, self.addToDirList[x][0], self.addToDirList[x][1]), self.addToDirList)
|
self.addToDirList = filter(lambda x: self.addImportDirectory(x, True, self.addToDirList[x][0], self.addToDirList[x][1]), self.addToDirList)
|
||||||
|
|
||||||
for file in self.removeFromFileList:
|
for file in self.removeFromFileList:
|
||||||
if file in self.filelist:
|
if file in self.filelist:
|
||||||
del self.filelist[file]
|
del self.filelist[file]
|
||||||
|
@ -295,10 +308,9 @@ class Importer:
|
||||||
print "TODO: implement importing tournament summaries"
|
print "TODO: implement importing tournament summaries"
|
||||||
#self.faobs = readfile(inputFile)
|
#self.faobs = readfile(inputFile)
|
||||||
#self.parseTourneyHistory()
|
#self.parseTourneyHistory()
|
||||||
return 0
|
return (0,0,0,1,0)
|
||||||
|
|
||||||
site = fpdb_simple.recogniseSite(firstline)
|
category=fpdb_simple.recogniseCategory(firstline)
|
||||||
category = fpdb_simple.recogniseCategory(firstline)
|
|
||||||
|
|
||||||
startpos = 0
|
startpos = 0
|
||||||
stored = 0 #counter
|
stored = 0 #counter
|
||||||
|
@ -306,61 +318,30 @@ class Importer:
|
||||||
partial = 0 #counter
|
partial = 0 #counter
|
||||||
errors = 0 #counter
|
errors = 0 #counter
|
||||||
|
|
||||||
for i in xrange (len(self.lines)): #main loop, iterates through the lines of a file and calls the appropriate parser method
|
for i in xrange (len(self.lines)):
|
||||||
if len(self.lines[i]) < 2:
|
if (len(self.lines[i])<2): #Wierd way to detect for '\r\n' or '\n'
|
||||||
endpos = i
|
endpos=i
|
||||||
hand = self.lines[startpos:endpos]
|
hand=self.lines[startpos:endpos]
|
||||||
|
|
||||||
if len(hand[0]) < 2:
|
if (len(hand[0])<2):
|
||||||
hand = hand[1:]
|
hand=hand[1:]
|
||||||
|
|
||||||
cancelled=False
|
|
||||||
damaged=False
|
|
||||||
if (site=="ftp"):
|
|
||||||
for i in range (len(hand)):
|
|
||||||
if hand[i].endswith(" has been canceled"): #this is their typo. this is a typo, right?
|
|
||||||
cancelled = True
|
|
||||||
|
|
||||||
#FTP generates lines looking like:
|
|
||||||
#Seat 1: IOS Seat 2: kashman59 (big blind) showed [8c 9d] and won ($3.25) with a pair of Eights
|
if (len(hand)<3):
|
||||||
#ie. Seat X multiple times on the same line in the summary section, when a new player sits down in the
|
|
||||||
#middle of the hand.
|
|
||||||
#TODO: Deal with this properly, either fix the file or make the parsing code work with this line.
|
|
||||||
if "Seat" in hand[i]:
|
|
||||||
mo = re.search(" Seat [0-9]+: ", hand[i])
|
|
||||||
if mo:
|
|
||||||
print "mo=", mo, "\nmo.start=", mo.start(),"\nhand[i]=",hand[i]
|
|
||||||
hand.insert(i+1, hand[i][mo.start()+1:])
|
|
||||||
hand[i] = hand[i][0:mo.start()]
|
|
||||||
|
|
||||||
if len(hand) < 3:
|
|
||||||
pass
|
pass
|
||||||
#todo: the above 2 lines are kind of a dirty hack, the mentioned circumstances should be handled elsewhere but that doesnt work with DOS/Win EOL. actually this doesnt work.
|
#TODO: This is ugly - we didn't actually find the start of the
|
||||||
elif hand[0].endswith(" (partial)"): #partial hand - do nothing
|
# hand with the outer loop so we test again...
|
||||||
partial += 1
|
else:
|
||||||
elif "Seat" not in hand[1] and "Seat" not in hand[2] and "Seat" not in hand[3]:
|
isTourney=fpdb_simple.isTourney(hand[0])
|
||||||
partial += 1
|
|
||||||
elif cancelled or damaged:
|
|
||||||
partial += 1
|
|
||||||
if damaged:
|
|
||||||
print """
|
|
||||||
DEBUG: Partial hand triggered by a line containing 'Seat X:' twice. This is a
|
|
||||||
bug in the FTP software when a player sits down in the middle of a hand.
|
|
||||||
Adding a newline after the player name will fix the issue
|
|
||||||
"""
|
|
||||||
print "File: %s" %(file)
|
|
||||||
print "Line: %s" %(startpos)
|
|
||||||
else: #normal processing
|
|
||||||
isTourney = fpdb_simple.isTourney(hand[0])
|
|
||||||
if not isTourney:
|
if not isTourney:
|
||||||
hand = fpdb_simple.filterAnteBlindFold(site,hand)
|
hand = fpdb_simple.filterAnteBlindFold(hand)
|
||||||
self.hand=hand
|
self.hand=hand
|
||||||
|
|
||||||
try:
|
try:
|
||||||
handsId = fpdb_parse_logic.mainParser(self.settings['db-backend'], self.fdb.db
|
handsId = fpdb_parse_logic.mainParser(self.settings['db-backend'], self.fdb.db
|
||||||
,self.fdb.cursor, site, category, hand, self.config)
|
,self.fdb.cursor, self.siteIds[site], category, hand, self.config)
|
||||||
self.fdb.db.commit()
|
self.fdb.db.commit()
|
||||||
|
|
||||||
stored += 1
|
stored += 1
|
||||||
if self.callHud:
|
if self.callHud:
|
||||||
#print "call to HUD here. handsId:",handsId
|
#print "call to HUD here. handsId:",handsId
|
||||||
|
@ -368,10 +349,11 @@ class Importer:
|
||||||
self.caller.pipe_to_hud.stdin.write("%s" % (handsId) + os.linesep)
|
self.caller.pipe_to_hud.stdin.write("%s" % (handsId) + os.linesep)
|
||||||
except fpdb_simple.DuplicateError:
|
except fpdb_simple.DuplicateError:
|
||||||
duplicates += 1
|
duplicates += 1
|
||||||
|
self.fdb.db.rollback()
|
||||||
except (ValueError), fe:
|
except (ValueError), fe:
|
||||||
errors += 1
|
errors += 1
|
||||||
self.printEmailErrorMessage(errors, file, hand)
|
self.printEmailErrorMessage(errors, file, hand)
|
||||||
|
|
||||||
if (self.settings['failOnError']):
|
if (self.settings['failOnError']):
|
||||||
self.fdb.db.commit() #dont remove this, in case hand processing was cancelled.
|
self.fdb.db.commit() #dont remove this, in case hand processing was cancelled.
|
||||||
raise
|
raise
|
||||||
|
@ -381,26 +363,25 @@ class Importer:
|
||||||
errors += 1
|
errors += 1
|
||||||
self.printEmailErrorMessage(errors, file, hand)
|
self.printEmailErrorMessage(errors, file, hand)
|
||||||
|
|
||||||
#fe.printStackTrace() #todo: get stacktrace
|
|
||||||
self.fdb.db.rollback()
|
self.fdb.db.rollback()
|
||||||
|
|
||||||
if self.settings['failOnError']:
|
if self.settings['failOnError']:
|
||||||
self.fdb.db.commit() #dont remove this, in case hand processing was cancelled.
|
self.fdb.db.commit() #dont remove this, in case hand processing was cancelled.
|
||||||
raise
|
raise
|
||||||
|
|
||||||
if self.settings['minPrint']:
|
if self.settings['minPrint']:
|
||||||
if not ((stored+duplicates+partial+errors) % self.settings['minPrint']):
|
if not ((stored+duplicates+errors) % self.settings['minPrint']):
|
||||||
print "stored:", stored, "duplicates:", duplicates, "partial:", partial, "errors:", errors
|
print "stored:", stored, "duplicates:", duplicates, "errors:", errors
|
||||||
|
|
||||||
if self.settings['handCount']:
|
if self.settings['handCount']:
|
||||||
if ((stored+duplicates+partial+errors) >= self.settings['handCount']):
|
if ((stored+duplicates+errors) >= self.settings['handCount']):
|
||||||
if not self.settings['quiet']:
|
if not self.settings['quiet']:
|
||||||
print "quitting due to reaching the amount of hands to be imported"
|
print "quitting due to reaching the amount of hands to be imported"
|
||||||
print "Total stored:", stored, "duplicates:", duplicates, "partial/damaged:", partial, "errors:", errors, " time:", (time() - starttime)
|
print "Total stored:", stored, "duplicates:", duplicates, "errors:", errors, " time:", (time() - starttime)
|
||||||
sys.exit(0)
|
sys.exit(0)
|
||||||
startpos = endpos
|
startpos = endpos
|
||||||
ttime = time() - starttime
|
ttime = time() - starttime
|
||||||
print "\rTotal stored:", stored, "duplicates:", duplicates, "partial:", partial, "errors:", errors, " time:", ttime
|
print "\rTotal stored:", stored, "duplicates:", duplicates, "errors:", errors, " time:", ttime
|
||||||
|
|
||||||
if not stored:
|
if not stored:
|
||||||
if duplicates:
|
if duplicates:
|
||||||
|
@ -411,16 +392,11 @@ class Importer:
|
||||||
else:
|
else:
|
||||||
print "failed to read a single hand from file:", inputFile
|
print "failed to read a single hand from file:", inputFile
|
||||||
handsId=0
|
handsId=0
|
||||||
#todo: this will cause return of an unstored hand number if the last hand was error or partial
|
#todo: this will cause return of an unstored hand number if the last hand was error
|
||||||
self.fdb.db.commit()
|
self.fdb.db.commit()
|
||||||
self.handsId=handsId
|
self.handsId=handsId
|
||||||
return (stored, duplicates, partial, errors, ttime)
|
return (stored, duplicates, partial, errors, ttime)
|
||||||
|
|
||||||
def parseTourneyHistory(self):
|
|
||||||
print "Tourney history parser stub"
|
|
||||||
#Find tournament boundaries.
|
|
||||||
#print self.foabs
|
|
||||||
|
|
||||||
def printEmailErrorMessage(self, errors, filename, line):
|
def printEmailErrorMessage(self, errors, filename, line):
|
||||||
traceback.print_exc(file=sys.stderr)
|
traceback.print_exc(file=sys.stderr)
|
||||||
print "Error No.",errors,", please send the hand causing this to steffen@sycamoretest.info so I can fix it."
|
print "Error No.",errors,", please send the hand causing this to steffen@sycamoretest.info so I can fix it."
|
||||||
|
|
|
@ -21,11 +21,11 @@ import fpdb_simple
|
||||||
import fpdb_save_to_db
|
import fpdb_save_to_db
|
||||||
|
|
||||||
#parses a holdem hand
|
#parses a holdem hand
|
||||||
def mainParser(backend, db, cursor, site, category, hand, config):
|
def mainParser(backend, db, cursor, siteID, category, hand, config):
|
||||||
category = fpdb_simple.recogniseCategory(hand[0])
|
category = fpdb_simple.recogniseCategory(hand[0])
|
||||||
|
|
||||||
base = "hold" if category == "holdem" or category == "omahahi" or category == "omahahilo" else "stud"
|
base = "hold" if category == "holdem" or category == "omahahi" or category == "omahahilo" else "stud"
|
||||||
|
|
||||||
#part 0: create the empty arrays
|
#part 0: create the empty arrays
|
||||||
lineTypes = [] #char, valid values: header, name, cards, action, win, rake, ignore
|
lineTypes = [] #char, valid values: header, name, cards, action, win, rake, ignore
|
||||||
lineStreets = [] #char, valid values: (predeal, preflop, flop, turn, river)
|
lineStreets = [] #char, valid values: (predeal, preflop, flop, turn, river)
|
||||||
|
@ -34,9 +34,7 @@ def mainParser(backend, db, cursor, site, category, hand, config):
|
||||||
|
|
||||||
#part 1: read hand no and check for duplicate
|
#part 1: read hand no and check for duplicate
|
||||||
siteHandNo = fpdb_simple.parseSiteHandNo(hand[0])
|
siteHandNo = fpdb_simple.parseSiteHandNo(hand[0])
|
||||||
handStartTime = fpdb_simple.parseHandStartTime(hand[0], site)
|
handStartTime = fpdb_simple.parseHandStartTime(hand[0])
|
||||||
siteID = fpdb_simple.recogniseSiteID(cursor, site)
|
|
||||||
#print "parse logic, siteID:",siteID,"site:",site
|
|
||||||
|
|
||||||
isTourney = fpdb_simple.isTourney(hand[0])
|
isTourney = fpdb_simple.isTourney(hand[0])
|
||||||
smallBlindLine = 0
|
smallBlindLine = 0
|
||||||
|
@ -46,11 +44,9 @@ def mainParser(backend, db, cursor, site, category, hand, config):
|
||||||
smallBlindLine = i
|
smallBlindLine = i
|
||||||
break
|
break
|
||||||
#print "small blind line:",smallBlindLine
|
#print "small blind line:",smallBlindLine
|
||||||
|
|
||||||
gametypeID = fpdb_simple.recogniseGametypeID(backend, db, cursor, hand[0], hand[smallBlindLine], siteID, category, isTourney)
|
gametypeID = fpdb_simple.recogniseGametypeID(backend, db, cursor, hand[0], hand[smallBlindLine], siteID, category, isTourney)
|
||||||
if isTourney:
|
if isTourney:
|
||||||
if site != "ps":
|
|
||||||
raise fpdb_simple.FpdbError("tourneys are only supported on PS right now")
|
|
||||||
siteTourneyNo = fpdb_simple.parseTourneyNo(hand[0])
|
siteTourneyNo = fpdb_simple.parseTourneyNo(hand[0])
|
||||||
buyin = fpdb_simple.parseBuyin(hand[0])
|
buyin = fpdb_simple.parseBuyin(hand[0])
|
||||||
fee = fpdb_simple.parseFee(hand[0])
|
fee = fpdb_simple.parseFee(hand[0])
|
||||||
|
@ -61,10 +57,10 @@ def mainParser(backend, db, cursor, site, category, hand, config):
|
||||||
rebuyOrAddon = fpdb_simple.isRebuyOrAddon(hand[0])
|
rebuyOrAddon = fpdb_simple.isRebuyOrAddon(hand[0])
|
||||||
|
|
||||||
tourneyTypeId = fpdb_simple.recogniseTourneyTypeId(cursor, siteID, buyin, fee, knockout, rebuyOrAddon)
|
tourneyTypeId = fpdb_simple.recogniseTourneyTypeId(cursor, siteID, buyin, fee, knockout, rebuyOrAddon)
|
||||||
|
|
||||||
fpdb_simple.isAlreadyInDB(cursor, gametypeID, siteHandNo)
|
fpdb_simple.isAlreadyInDB(cursor, gametypeID, siteHandNo)
|
||||||
|
|
||||||
hand = fpdb_simple.filterCrap(site, hand, isTourney)
|
hand = fpdb_simple.filterCrap(hand, isTourney)
|
||||||
|
|
||||||
#part 2: classify lines by type (e.g. cards, action, win, sectionchange) and street
|
#part 2: classify lines by type (e.g. cards, action, win, sectionchange) and street
|
||||||
fpdb_simple.classifyLines(hand, category, lineTypes, lineStreets)
|
fpdb_simple.classifyLines(hand, category, lineTypes, lineStreets)
|
||||||
|
@ -74,10 +70,10 @@ def mainParser(backend, db, cursor, site, category, hand, config):
|
||||||
for i, line in enumerate(hand):
|
for i, line in enumerate(hand):
|
||||||
if lineTypes[i] == "name":
|
if lineTypes[i] == "name":
|
||||||
seatLines.append(line)
|
seatLines.append(line)
|
||||||
|
|
||||||
names = fpdb_simple.parseNames(seatLines)
|
names = fpdb_simple.parseNames(seatLines)
|
||||||
playerIDs = fpdb_simple.recognisePlayerIDs(cursor, names, siteID)
|
playerIDs = fpdb_simple.recognisePlayerIDs(cursor, names, siteID)
|
||||||
tmp = fpdb_simple.parseCashesAndSeatNos(seatLines, site)
|
tmp = fpdb_simple.parseCashesAndSeatNos(seatLines)
|
||||||
startCashes = tmp['startCashes']
|
startCashes = tmp['startCashes']
|
||||||
seatNos = tmp['seatNos']
|
seatNos = tmp['seatNos']
|
||||||
|
|
||||||
|
@ -90,30 +86,27 @@ def mainParser(backend, db, cursor, site, category, hand, config):
|
||||||
#part 4: take appropriate action for each line based on linetype
|
#part 4: take appropriate action for each line based on linetype
|
||||||
for i, line in enumerate(hand):
|
for i, line in enumerate(hand):
|
||||||
if lineTypes[i] == "cards":
|
if lineTypes[i] == "cards":
|
||||||
fpdb_simple.parseCardLine(site, category, lineStreets[i], line, names, cardValues, cardSuits, boardValues, boardSuits)
|
fpdb_simple.parseCardLine(category, lineStreets[i], line, names, cardValues, cardSuits, boardValues, boardSuits)
|
||||||
#if category=="studhilo":
|
#if category=="studhilo":
|
||||||
# print "hand[i]:", hand[i]
|
# print "hand[i]:", hand[i]
|
||||||
# print "cardValues:", cardValues
|
# print "cardValues:", cardValues
|
||||||
# print "cardSuits:", cardSuits
|
# print "cardSuits:", cardSuits
|
||||||
elif lineTypes[i] == "action":
|
elif lineTypes[i] == "action":
|
||||||
fpdb_simple.parseActionLine(site, base, isTourney, line, lineStreets[i], playerIDs, names, actionTypes, allIns, actionAmounts, actionNos, actionTypeByNo)
|
fpdb_simple.parseActionLine(base, isTourney, line, lineStreets[i], playerIDs, names, actionTypes, allIns, actionAmounts, actionNos, actionTypeByNo)
|
||||||
elif lineTypes[i] == "win":
|
elif lineTypes[i] == "win":
|
||||||
fpdb_simple.parseWinLine(line, site, names, winnings, isTourney)
|
fpdb_simple.parseWinLine(line, names, winnings, isTourney)
|
||||||
elif lineTypes[i] == "rake":
|
elif lineTypes[i] == "rake":
|
||||||
totalRake = 0 if isTourney else fpdb_simple.parseRake(line)
|
totalRake = 0 if isTourney else fpdb_simple.parseRake(line)
|
||||||
fpdb_simple.splitRake(winnings, rakes, totalRake)
|
fpdb_simple.splitRake(winnings, rakes, totalRake)
|
||||||
elif lineTypes[i]=="header" or lineTypes[i]=="rake" or lineTypes[i]=="name" or lineTypes[i]=="ignore":
|
elif lineTypes[i]=="header" or lineTypes[i]=="rake" or lineTypes[i]=="name" or lineTypes[i]=="ignore":
|
||||||
pass
|
pass
|
||||||
elif lineTypes[i]=="ante":
|
elif lineTypes[i]=="ante":
|
||||||
fpdb_simple.parseAnteLine(line, site, isTourney, names, antes)
|
fpdb_simple.parseAnteLine(line, isTourney, names, antes)
|
||||||
elif lineTypes[i]=="table":
|
elif lineTypes[i]=="table":
|
||||||
tableResult=fpdb_simple.parseTableLine(site, base, line)
|
tableResult=fpdb_simple.parseTableLine(base, line)
|
||||||
else:
|
else:
|
||||||
raise fpdb_simple.FpdbError("unrecognised lineType:"+lineTypes[i])
|
raise fpdb_simple.FpdbError("unrecognised lineType:"+lineTypes[i])
|
||||||
|
|
||||||
if site == "ftp":
|
|
||||||
tableResult = fpdb_simple.parseTableLine(site, base, hand[0])
|
|
||||||
|
|
||||||
maxSeats = tableResult['maxSeats']
|
maxSeats = tableResult['maxSeats']
|
||||||
tableName = tableResult['tableName']
|
tableName = tableResult['tableName']
|
||||||
#print "before part5, antes:", antes
|
#print "before part5, antes:", antes
|
||||||
|
@ -128,7 +121,7 @@ def mainParser(backend, db, cursor, site, category, hand, config):
|
||||||
|
|
||||||
cursor.execute("SELECT limitType FROM Gametypes WHERE id=%s",(gametypeID, ))
|
cursor.execute("SELECT limitType FROM Gametypes WHERE id=%s",(gametypeID, ))
|
||||||
limit_type = cursor.fetchone()[0]
|
limit_type = cursor.fetchone()[0]
|
||||||
fpdb_simple.convert3B4B(site, category, limit_type, actionTypes, actionAmounts)
|
fpdb_simple.convert3B4B(category, limit_type, actionTypes, actionAmounts)
|
||||||
|
|
||||||
totalWinnings = sum(winnings)
|
totalWinnings = sum(winnings)
|
||||||
|
|
||||||
|
@ -141,7 +134,7 @@ def mainParser(backend, db, cursor, site, category, hand, config):
|
||||||
hudImportData = fpdb_simple.generateHudCacheData(playerIDs, base, category, actionTypes
|
hudImportData = fpdb_simple.generateHudCacheData(playerIDs, base, category, actionTypes
|
||||||
, allIns, actionTypeByNo, winnings, totalWinnings, None
|
, allIns, actionTypeByNo, winnings, totalWinnings, None
|
||||||
, actionTypes, actionAmounts, antes)
|
, actionTypes, actionAmounts, antes)
|
||||||
|
|
||||||
if isTourney:
|
if isTourney:
|
||||||
ranks = map(lambda x: 0, names) # create an array of 0's equal to the length of names
|
ranks = map(lambda x: 0, names) # create an array of 0's equal to the length of names
|
||||||
payin_amounts = fpdb_simple.calcPayin(len(names), buyin, fee)
|
payin_amounts = fpdb_simple.calcPayin(len(names), buyin, fee)
|
||||||
|
@ -165,7 +158,7 @@ def mainParser(backend, db, cursor, site, category, hand, config):
|
||||||
, allIns, actionAmounts, actionNos, hudImportData, maxSeats
|
, allIns, actionAmounts, actionNos, hudImportData, maxSeats
|
||||||
, tableName, seatNos)
|
, tableName, seatNos)
|
||||||
else:
|
else:
|
||||||
raise fpdb_simple.FpdbError("unrecognised category") # it's impossible to get here, but w/e
|
raise fpdb_simple.FpdbError("unrecognised category")
|
||||||
else:
|
else:
|
||||||
if base == "hold":
|
if base == "hold":
|
||||||
result = fpdb_save_to_db.ring_holdem_omaha(
|
result = fpdb_save_to_db.ring_holdem_omaha(
|
||||||
|
@ -183,7 +176,7 @@ def mainParser(backend, db, cursor, site, category, hand, config):
|
||||||
, actionAmounts, actionNos, hudImportData, maxSeats, tableName
|
, actionAmounts, actionNos, hudImportData, maxSeats, tableName
|
||||||
, seatNos)
|
, seatNos)
|
||||||
else:
|
else:
|
||||||
raise fpdb_simple.FpdbError ("unrecognised category") # also impossible to get here
|
raise fpdb_simple.FpdbError ("unrecognised category")
|
||||||
db.commit()
|
db.commit()
|
||||||
return result
|
return result
|
||||||
#end def mainParser
|
#end def mainParser
|
||||||
|
|
|
@ -32,8 +32,7 @@ saveActions = True # set this to False to avoid storing action data
|
||||||
# Pros: speeds up imports
|
# Pros: speeds up imports
|
||||||
# Cons: no action data is saved, so you need to keep the hand histories
|
# Cons: no action data is saved, so you need to keep the hand histories
|
||||||
# variance not available on stats page
|
# variance not available on stats page
|
||||||
# no graphs
|
# : No graphs
|
||||||
|
|
||||||
#stores a stud/razz hand into the database
|
#stores a stud/razz hand into the database
|
||||||
def ring_stud(config, backend, db, cursor, base, category, site_hand_no, gametype_id, hand_start_time
|
def ring_stud(config, backend, db, cursor, base, category, site_hand_no, gametype_id, hand_start_time
|
||||||
,names, player_ids, start_cashes, antes, card_values, card_suits, winnings, rakes
|
,names, player_ids, start_cashes, antes, card_values, card_suits, winnings, rakes
|
||||||
|
|
|
@ -187,10 +187,10 @@ def prepareBulkImport(fdb):
|
||||||
# mod to use tab_col for index name?
|
# mod to use tab_col for index name?
|
||||||
try:
|
try:
|
||||||
fdb.cursor.execute( "drop index %s_%s_idx" % (idx['tab'],idx['col']) )
|
fdb.cursor.execute( "drop index %s_%s_idx" % (idx['tab'],idx['col']) )
|
||||||
print "drop index %s_%s_idx" % (idx['tab'],idx['col'])
|
print "drop index %s_%s_idx" % (idx['tab'],idx['col'])
|
||||||
#print "dropped pg index ", idx['tab'], idx['col']
|
#print "dropped pg index ", idx['tab'], idx['col']
|
||||||
except:
|
except:
|
||||||
print "! failed drop index %s_%s_idx" % (idx['tab'],idx['col'])
|
print "! failed drop index %s_%s_idx" % (idx['tab'],idx['col'])
|
||||||
else:
|
else:
|
||||||
print "Only MySQL and Postgres supported so far"
|
print "Only MySQL and Postgres supported so far"
|
||||||
return -1
|
return -1
|
||||||
|
@ -392,10 +392,6 @@ def checkPositions(positions):
|
||||||
""" verify positions are valid """
|
""" verify positions are valid """
|
||||||
if any(not (p == "B" or p == "S" or (p >= 0 and p <= 9)) for p in positions):
|
if any(not (p == "B" or p == "S" or (p >= 0 and p <= 9)) for p in positions):
|
||||||
raise FpdbError("invalid position '"+p+"' found in checkPositions")
|
raise FpdbError("invalid position '"+p+"' found in checkPositions")
|
||||||
# for p in positions:
|
|
||||||
# if not (p == "B" or p == "S" or (p >= 0 and p <= 9)):
|
|
||||||
# raise FpdbError("invalid position '" + p + "' found in checkPositions")
|
|
||||||
|
|
||||||
### RHH modified to allow for "position 9" here (pos==9 is when you're a dead hand before the BB
|
### RHH modified to allow for "position 9" here (pos==9 is when you're a dead hand before the BB
|
||||||
### eric - position 8 could be valid - if only one blind is posted, but there's still 10 people, ie a sitout is present, and the small is dead...
|
### eric - position 8 could be valid - if only one blind is posted, but there's still 10 people, ie a sitout is present, and the small is dead...
|
||||||
|
|
||||||
|
@ -446,7 +442,7 @@ def classifyLines(hand, category, lineTypes, lineStreets):
|
||||||
currentStreet=3
|
currentStreet=3
|
||||||
elif line.startswith("*** 7") or line == "*** RIVER ***":
|
elif line.startswith("*** 7") or line == "*** RIVER ***":
|
||||||
lineTypes.append("ignore")
|
lineTypes.append("ignore")
|
||||||
currentStreet=4
|
currentStreet=4
|
||||||
elif isWinLine(line):
|
elif isWinLine(line):
|
||||||
lineTypes.append("win")
|
lineTypes.append("win")
|
||||||
elif line.startswith("Total pot ") and "Rake" in line:
|
elif line.startswith("Total pot ") and "Rake" in line:
|
||||||
|
@ -462,7 +458,7 @@ def classifyLines(hand, category, lineTypes, lineStreets):
|
||||||
lineStreets.append(currentStreet)
|
lineStreets.append(currentStreet)
|
||||||
#end def classifyLines
|
#end def classifyLines
|
||||||
|
|
||||||
def convert3B4B(site, category, limit_type, actionTypes, actionAmounts):
|
def convert3B4B(category, limit_type, actionTypes, actionAmounts):
|
||||||
"""calculates the actual bet amounts in the given amount array and changes it accordingly."""
|
"""calculates the actual bet amounts in the given amount array and changes it accordingly."""
|
||||||
for i in xrange(len(actionTypes)):
|
for i in xrange(len(actionTypes)):
|
||||||
for j in xrange(len(actionTypes[i])):
|
for j in xrange(len(actionTypes[i])):
|
||||||
|
@ -572,7 +568,7 @@ def fillCardArrays(player_count, base, category, card_values, card_suits):
|
||||||
|
|
||||||
#filters out a player that folded before paying ante or blinds. This should be called
|
#filters out a player that folded before paying ante or blinds. This should be called
|
||||||
#before calling the actual hand parser. manipulates hand, no return.
|
#before calling the actual hand parser. manipulates hand, no return.
|
||||||
def filterAnteBlindFold(site,hand):
|
def filterAnteBlindFold(hand):
|
||||||
#todo: this'll only get rid of one ante folder, not multiple ones
|
#todo: this'll only get rid of one ante folder, not multiple ones
|
||||||
#todo: in tourneys this should not be removed but
|
#todo: in tourneys this should not be removed but
|
||||||
#print "start of filterAnteBlindFold"
|
#print "start of filterAnteBlindFold"
|
||||||
|
@ -610,7 +606,7 @@ def stripEOLspaces(str):
|
||||||
return str.rstrip()
|
return str.rstrip()
|
||||||
|
|
||||||
#removes useless lines as well as trailing spaces
|
#removes useless lines as well as trailing spaces
|
||||||
def filterCrap(site, hand, isTourney):
|
def filterCrap(hand, isTourney):
|
||||||
#remove two trailing spaces at end of line
|
#remove two trailing spaces at end of line
|
||||||
hand = [line.rstrip() for line in hand]
|
hand = [line.rstrip() for line in hand]
|
||||||
|
|
||||||
|
@ -643,18 +639,8 @@ def filterCrap(site, hand, isTourney):
|
||||||
hand[i] = False
|
hand[i] = False
|
||||||
elif hand[i].endswith("is disconnected"):
|
elif hand[i].endswith("is disconnected"):
|
||||||
hand[i] = False
|
hand[i] = False
|
||||||
elif hand[i].endswith(" is feeling angry"):
|
elif hand[i].find(" is low with [")!=-1:
|
||||||
hand[i] = False
|
hand[i] = False
|
||||||
elif hand[i].endswith(" is feeling confused"):
|
|
||||||
hand[i] = False
|
|
||||||
elif hand[i].endswith(" is feeling happy"):
|
|
||||||
hand[i] = False
|
|
||||||
elif hand[i].endswith(" is feeling normal"):
|
|
||||||
hand[i] = False
|
|
||||||
elif " is low with [" in hand[i]:
|
|
||||||
hand[i] = False
|
|
||||||
#elif (hand[i].find("-max Seat #")!=-1 and hand[i].find(" is the button")!=-1):
|
|
||||||
# toRemove.append(hand[i])
|
|
||||||
elif hand[i].endswith(" mucks"):
|
elif hand[i].endswith(" mucks"):
|
||||||
hand[i] = False
|
hand[i] = False
|
||||||
elif hand[i].endswith(": mucks hand"):
|
elif hand[i].endswith(": mucks hand"):
|
||||||
|
@ -680,13 +666,9 @@ def filterCrap(site, hand, isTourney):
|
||||||
hand[i] = False
|
hand[i] = False
|
||||||
elif "joins the table at seat " in hand[i]:
|
elif "joins the table at seat " in hand[i]:
|
||||||
hand[i] = False
|
hand[i] = False
|
||||||
elif (hand[i].endswith(" sits down")):
|
|
||||||
hand[i] = False
|
|
||||||
elif (hand[i].endswith("leaves the table")):
|
elif (hand[i].endswith("leaves the table")):
|
||||||
hand[i] = False
|
hand[i] = False
|
||||||
elif (hand[i].endswith(" stands up")):
|
elif "is high with " in hand[i]:
|
||||||
hand[i] = False
|
|
||||||
elif "is high with" in hand[i]:
|
|
||||||
hand[i] = False
|
hand[i] = False
|
||||||
elif hand[i].endswith("doesn't show hand"):
|
elif hand[i].endswith("doesn't show hand"):
|
||||||
hand[i] = False
|
hand[i] = False
|
||||||
|
@ -696,11 +678,9 @@ def filterCrap(site, hand, isTourney):
|
||||||
hand[i] = False
|
hand[i] = False
|
||||||
elif hand[i] == "Betting is capped":
|
elif hand[i] == "Betting is capped":
|
||||||
hand[i] = False
|
hand[i] = False
|
||||||
#site specific variable position filter
|
elif (hand[i].find(" said, \"")!=-1):
|
||||||
elif 'said, "' in hand[i]:
|
|
||||||
hand[i] = False
|
|
||||||
elif site == "ftp" and ":" in hand[i] and "Seat " not in hand[i] and ": Table" not in hand[i]: # FTP chat
|
|
||||||
hand[i] = False
|
hand[i] = False
|
||||||
|
|
||||||
if isTourney and not hand[i] == False:
|
if isTourney and not hand[i] == False:
|
||||||
if (hand[i].endswith(" is sitting out") and (not hand[i].startswith("Seat "))):
|
if (hand[i].endswith(" is sitting out") and (not hand[i].startswith("Seat "))):
|
||||||
hand[i] = False
|
hand[i] = False
|
||||||
|
@ -781,7 +761,7 @@ def isWinLine(line):
|
||||||
#end def isWinLine
|
#end def isWinLine
|
||||||
|
|
||||||
#returns the amount of cash/chips put into the put in the given action line
|
#returns the amount of cash/chips put into the put in the given action line
|
||||||
def parseActionAmount(line, atype, site, isTourney):
|
def parseActionAmount(line, atype, isTourney):
|
||||||
#if (line.endswith(" and is all-in")):
|
#if (line.endswith(" and is all-in")):
|
||||||
# line=line[:-14]
|
# line=line[:-14]
|
||||||
#elif (line.endswith(", and is all in")):
|
#elif (line.endswith(", and is all in")):
|
||||||
|
@ -795,19 +775,14 @@ def parseActionAmount(line, atype, site, isTourney):
|
||||||
if atype == "fold" or atype == "check":
|
if atype == "fold" or atype == "check":
|
||||||
amount = 0
|
amount = 0
|
||||||
elif atype == "unbet":
|
elif atype == "unbet":
|
||||||
if site == "ftp":
|
pos1 = line.find("$") + 1
|
||||||
pos1 = line.find("$") + 1
|
if pos1 == 0:
|
||||||
pos2 = line.find(" returned to")
|
pos1 = line.find("(") + 1
|
||||||
amount = float2int(line[pos1:pos2])
|
pos2 = line.find(")")
|
||||||
elif site == "ps":
|
amount = float2int(line[pos1:pos2])
|
||||||
pos1 = line.find("$") + 1
|
elif atype == "bet" and line.find(": raises $")!=-1 and line.find("to $")!=-1:
|
||||||
if pos1 == 0:
|
pos=line.find("to $")+4
|
||||||
pos1 = line.find("(") + 1
|
amount=float2int(line[pos:])
|
||||||
pos2 = line.find(")")
|
|
||||||
amount = float2int(line[pos1:pos2])
|
|
||||||
elif atype == "bet" and site == "ps" and line.find(": raises $")!=-1 and line.find("to $")!=-1:
|
|
||||||
pos = line.find("to $")+4
|
|
||||||
amount = float2int(line[pos:])
|
|
||||||
else:
|
else:
|
||||||
if not isTourney:
|
if not isTourney:
|
||||||
pos = line.rfind("$")+1
|
pos = line.rfind("$")+1
|
||||||
|
@ -828,7 +803,7 @@ def parseActionAmount(line, atype, site, isTourney):
|
||||||
#doesnt return anything, simply changes the passed arrays action_types and
|
#doesnt return anything, simply changes the passed arrays action_types and
|
||||||
# action_amounts. For stud this expects numeric streets (3-7), for
|
# action_amounts. For stud this expects numeric streets (3-7), for
|
||||||
# holdem/omaha it expects predeal, preflop, flop, turn or river
|
# holdem/omaha it expects predeal, preflop, flop, turn or river
|
||||||
def parseActionLine(site, base, isTourney, line, street, playerIDs, names, action_types, allIns, action_amounts, actionNos, actionTypeByNo):
|
def parseActionLine(base, isTourney, line, street, playerIDs, names, action_types, allIns, action_amounts, actionNos, actionTypeByNo):
|
||||||
if street == "predeal" or street == "preflop":
|
if street == "predeal" or street == "preflop":
|
||||||
street = 0
|
street = 0
|
||||||
elif street == "flop":
|
elif street == "flop":
|
||||||
|
@ -847,7 +822,7 @@ def parseActionLine(site, base, isTourney, line, street, playerIDs, names, actio
|
||||||
(line, allIn) = goesAllInOnThisLine(line)
|
(line, allIn) = goesAllInOnThisLine(line)
|
||||||
atype = parseActionType(line)
|
atype = parseActionType(line)
|
||||||
playerno = recognisePlayerNo(line, names, atype)
|
playerno = recognisePlayerNo(line, names, atype)
|
||||||
amount = parseActionAmount(line, atype, site, isTourney)
|
amount = parseActionAmount(line, atype, isTourney)
|
||||||
|
|
||||||
action_types[street][playerno].append(atype)
|
action_types[street][playerno].append(atype)
|
||||||
allIns[street][playerno].append(allIn)
|
allIns[street][playerno].append(allIn)
|
||||||
|
@ -899,7 +874,7 @@ def parseActionType(line):
|
||||||
#end def parseActionType
|
#end def parseActionType
|
||||||
|
|
||||||
#parses the ante out of the given line and checks which player paid it, updates antes accordingly.
|
#parses the ante out of the given line and checks which player paid it, updates antes accordingly.
|
||||||
def parseAnteLine(line, site, isTourney, names, antes):
|
def parseAnteLine(line, isTourney, names, antes):
|
||||||
for i, name in enumerate(names):
|
for i, name in enumerate(names):
|
||||||
if line.startswith(name.encode("latin-1")):
|
if line.startswith(name.encode("latin-1")):
|
||||||
pos = line.rfind("$") + 1
|
pos = line.rfind("$") + 1
|
||||||
|
@ -925,7 +900,7 @@ def parseBuyin(topline):
|
||||||
|
|
||||||
#parses a card line and changes the passed arrays accordingly
|
#parses a card line and changes the passed arrays accordingly
|
||||||
#todo: reorganise this messy method
|
#todo: reorganise this messy method
|
||||||
def parseCardLine(site, category, street, line, names, cardValues, cardSuits, boardValues, boardSuits):
|
def parseCardLine(category, street, line, names, cardValues, cardSuits, boardValues, boardSuits):
|
||||||
if line.startswith("Dealt to") or " shows [" in line or "mucked [" in line:
|
if line.startswith("Dealt to") or " shows [" in line or "mucked [" in line:
|
||||||
playerNo = recognisePlayerNo(line, names, "card") #anything but unbet will be ok for that string
|
playerNo = recognisePlayerNo(line, names, "card") #anything but unbet will be ok for that string
|
||||||
|
|
||||||
|
@ -999,7 +974,7 @@ def parseCardLine(site, category, street, line, names, cardValues, cardSuits, bo
|
||||||
raise FpdbError ("unrecognised line:"+line)
|
raise FpdbError ("unrecognised line:"+line)
|
||||||
#end def parseCardLine
|
#end def parseCardLine
|
||||||
|
|
||||||
def parseCashesAndSeatNos(lines, site):
|
def parseCashesAndSeatNos(lines):
|
||||||
"""parses the startCashes and seatNos of each player out of the given lines and returns them as a dictionary of two arrays"""
|
"""parses the startCashes and seatNos of each player out of the given lines and returns them as a dictionary of two arrays"""
|
||||||
cashes = []
|
cashes = []
|
||||||
seatNos = []
|
seatNos = []
|
||||||
|
@ -1010,10 +985,7 @@ def parseCashesAndSeatNos(lines, site):
|
||||||
pos1=lines[i].rfind("($")+2
|
pos1=lines[i].rfind("($")+2
|
||||||
if pos1==1: #for tourneys - it's 1 instead of -1 due to adding 2 above
|
if pos1==1: #for tourneys - it's 1 instead of -1 due to adding 2 above
|
||||||
pos1=lines[i].rfind("(")+1
|
pos1=lines[i].rfind("(")+1
|
||||||
if (site=="ftp"):
|
pos2=lines[i].find(" in chips")
|
||||||
pos2=lines[i].rfind(")")
|
|
||||||
elif (site=="ps"):
|
|
||||||
pos2=lines[i].find(" in chips")
|
|
||||||
cashes.append(float2int(lines[i][pos1:pos2]))
|
cashes.append(float2int(lines[i][pos1:pos2]))
|
||||||
return {'startCashes':cashes, 'seatNos':seatNos}
|
return {'startCashes':cashes, 'seatNos':seatNos}
|
||||||
#end def parseCashesAndSeatNos
|
#end def parseCashesAndSeatNos
|
||||||
|
@ -1027,7 +999,7 @@ def parseFee(topline):
|
||||||
#end def parsefee
|
#end def parsefee
|
||||||
|
|
||||||
#returns a datetime object with the starttime indicated in the given topline
|
#returns a datetime object with the starttime indicated in the given topline
|
||||||
def parseHandStartTime(topline, site):
|
def parseHandStartTime(topline):
|
||||||
#convert x:13:35 to 0x:13:35
|
#convert x:13:35 to 0x:13:35
|
||||||
counter=0
|
counter=0
|
||||||
while counter < 10:
|
while counter < 10:
|
||||||
|
@ -1038,41 +1010,25 @@ def parseHandStartTime(topline, site):
|
||||||
counter += 1
|
counter += 1
|
||||||
|
|
||||||
isUTC=False
|
isUTC=False
|
||||||
if site=="ftp":
|
if topline.find("UTC")!=-1:
|
||||||
# Full Tilt Sit'n'Go
|
pos1 = topline.find("-")+2
|
||||||
# Full Tilt Poker Game #10311865543: $1 + $0.25 Sit & Go (78057629), Table 1 - 25/50 - No Limit Hold'em - 0:07:45 ET - 2009/01/29
|
pos2 = topline.find("UTC")
|
||||||
# Cash Game:
|
tmp=topline[pos1:pos2]
|
||||||
# Full Tilt Poker Game #9403951181: Table CR - tay - $0.05/$0.10 - No Limit Hold'em - 9:40:20 ET - 2008/12/09
|
isUTC=True
|
||||||
# Full Tilt Poker Game #9468383505: Table Bike (deep 6) - $0.05/$0.10 - No Limit Hold'em - 5:09:36 ET - 2008/12/13
|
|
||||||
pos = topline.find(" ", len(topline)-26)+1
|
|
||||||
tmp = topline[pos:]
|
|
||||||
|
|
||||||
rexx = '(?P<HR>[0-9]+):(?P<MIN>[0-9]+):(?P<SEC>[0-9]+) ET [\- ]+(?P<YEAR>[0-9]{4})\/(?P<MON>[0-9]{2})\/(?P<DAY>[0-9]{2})'
|
|
||||||
m = re.search(rexx,tmp)
|
|
||||||
result = datetime.datetime(int(m.group('YEAR')), int(m.group('MON')), int(m.group('DAY')), int(m.group('HR')), int(m.group('MIN')), int(m.group('SEC')))
|
|
||||||
elif site=="ps":
|
|
||||||
if topline.find("UTC")!=-1:
|
|
||||||
pos1 = topline.find("-")+2
|
|
||||||
pos2 = topline.find("UTC")
|
|
||||||
tmp=topline[pos1:pos2]
|
|
||||||
isUTC=True
|
|
||||||
else:
|
|
||||||
tmp=topline
|
|
||||||
#print "parsehandStartTime, tmp:", tmp
|
|
||||||
pos = tmp.find("-")+2
|
|
||||||
tmp = tmp[pos:]
|
|
||||||
#Need to match either
|
|
||||||
# 2008/09/07 06:23:14 ET or
|
|
||||||
# 2008/08/17 - 01:14:43 (ET) or
|
|
||||||
# 2008/11/12 9:33:31 CET [2008/11/12 3:33:31 ET]
|
|
||||||
rexx = '(?P<YEAR>[0-9]{4})\/(?P<MON>[0-9]{2})\/(?P<DAY>[0-9]{2})[\- ]+(?P<HR>[0-9]+):(?P<MIN>[0-9]+):(?P<SEC>[0-9]+)'
|
|
||||||
m = re.search(rexx,tmp)
|
|
||||||
#print "year:", int(m.group('YEAR')), "month", int(m.group('MON')), "day", int(m.group('DAY')), "hour", int(m.group('HR')), "minute", int(m.group('MIN')), "second", int(m.group('SEC'))
|
|
||||||
result = datetime.datetime(int(m.group('YEAR')), int(m.group('MON')), int(m.group('DAY')), int(m.group('HR')), int(m.group('MIN')), int(m.group('SEC')))
|
|
||||||
else:
|
else:
|
||||||
raise FpdbError("invalid site in parseHandStartTime")
|
tmp=topline
|
||||||
|
#print "parsehandStartTime, tmp:", tmp
|
||||||
|
pos = tmp.find("-")+2
|
||||||
|
tmp = tmp[pos:]
|
||||||
|
#Need to match either
|
||||||
|
# 2008/09/07 06:23:14 ET or
|
||||||
|
# 2008/08/17 - 01:14:43 (ET) or
|
||||||
|
# 2008/11/12 9:33:31 CET [2008/11/12 3:33:31 ET]
|
||||||
|
rexx = '(?P<YEAR>[0-9]{4})\/(?P<MON>[0-9]{2})\/(?P<DAY>[0-9]{2})[\- ]+(?P<HR>[0-9]+):(?P<MIN>[0-9]+):(?P<SEC>[0-9]+)'
|
||||||
|
m = re.search(rexx,tmp)
|
||||||
|
result = datetime.datetime(int(m.group('YEAR')), int(m.group('MON')), int(m.group('DAY')), int(m.group('HR')), int(m.group('MIN')), int(m.group('SEC')))
|
||||||
|
|
||||||
if (site=="ftp" or site=="ps") and not isUTC: #these use US ET
|
if not isUTC: #these use US ET
|
||||||
result+=datetime.timedelta(hours=5)
|
result+=datetime.timedelta(hours=5)
|
||||||
|
|
||||||
return result
|
return result
|
||||||
|
@ -1109,7 +1065,7 @@ def parsePositions(hand, names):
|
||||||
if bb != -1:
|
if bb != -1:
|
||||||
bb = recognisePlayerNo(bb, names, "bet")
|
bb = recognisePlayerNo(bb, names, "bet")
|
||||||
|
|
||||||
# print "sb = ", sb, "bb = ", bb
|
# print "sb = ", sb, "bb = ", bb
|
||||||
if bb == sb: # if big and small are same, then don't duplicate the small
|
if bb == sb: # if big and small are same, then don't duplicate the small
|
||||||
sbExists = False
|
sbExists = False
|
||||||
sb = -1
|
sb = -1
|
||||||
|
@ -1138,7 +1094,7 @@ def parsePositions(hand, names):
|
||||||
while positions[i] < 0 and i != sb:
|
while positions[i] < 0 and i != sb:
|
||||||
positions[i] = 9
|
positions[i] = 9
|
||||||
i -= 1
|
i -= 1
|
||||||
### RHH - Changed to set the null seats before BB to "9"
|
### RHH - Changed to set the null seats before BB to "9"
|
||||||
if sbExists:
|
if sbExists:
|
||||||
i = sb-1
|
i = sb-1
|
||||||
else:
|
else:
|
||||||
|
@ -1158,7 +1114,7 @@ def parsePositions(hand, names):
|
||||||
print "parsePositions names:",names
|
print "parsePositions names:",names
|
||||||
print "result:",positions
|
print "result:",positions
|
||||||
raise FpdbError ("failed to read positions")
|
raise FpdbError ("failed to read positions")
|
||||||
# print str(positions), "\n"
|
# print str(positions), "\n"
|
||||||
return positions
|
return positions
|
||||||
#end def parsePositions
|
#end def parsePositions
|
||||||
|
|
||||||
|
@ -1176,42 +1132,15 @@ def parseSiteHandNo(topline):
|
||||||
return topline[pos1:pos2]
|
return topline[pos1:pos2]
|
||||||
#end def parseSiteHandNo
|
#end def parseSiteHandNo
|
||||||
|
|
||||||
def parseTableLine(site, base, line):
|
def parseTableLine(base, line):
|
||||||
"""returns a dictionary with maxSeats and tableName"""
|
"""returns a dictionary with maxSeats and tableName"""
|
||||||
if site=="ps":
|
pos1=line.find('\'')+1
|
||||||
pos1=line.find('\'')+1
|
pos2=line.find('\'', pos1)
|
||||||
pos2=line.find('\'', pos1)
|
#print "table:",line[pos1:pos2]
|
||||||
#print "table:",line[pos1:pos2]
|
pos3=pos2+2
|
||||||
pos3=pos2+2
|
pos4=line.find("-max")
|
||||||
pos4=line.find("-max")
|
#print "seats:",line[pos3:pos4]
|
||||||
#print "seats:",line[pos3:pos4]
|
return {'maxSeats':int(line[pos3:pos4]), 'tableName':line[pos1:pos2]}
|
||||||
return {'maxSeats':int(line[pos3:pos4]), 'tableName':line[pos1:pos2]}
|
|
||||||
elif site=="ftp":
|
|
||||||
pos1=line.find("Table ")+6
|
|
||||||
pos2=line.find("-")-1
|
|
||||||
if base=="hold":
|
|
||||||
maxSeats=9
|
|
||||||
elif base=="stud":
|
|
||||||
maxSeats=8
|
|
||||||
|
|
||||||
if line.find("6 max")!=-1:
|
|
||||||
maxSeats=6
|
|
||||||
elif line.find("4 max")!=-1:
|
|
||||||
maxSeats=4
|
|
||||||
elif line.find("heads up")!=-1:
|
|
||||||
maxSeats=2
|
|
||||||
|
|
||||||
tableName = line[pos1:pos2]
|
|
||||||
for pattern in [' \(6 max\)', ' \(heads up\)', ' \(deep\)',
|
|
||||||
' \(deep hu\)', ' \(deep 6\)', ' \(2\)',
|
|
||||||
' \(edu\)', ' \(edu, 6 max\)', ' \(6\)',
|
|
||||||
' \(speed\)',
|
|
||||||
' no all-in', ' fast', ',', ' 50BB min', '\s+$']:
|
|
||||||
tableName = re.sub(pattern, '', tableName)
|
|
||||||
tableName = tableName.rstrip()
|
|
||||||
return {'maxSeats':maxSeats, 'tableName':tableName}
|
|
||||||
else:
|
|
||||||
raise FpdbError("invalid site ID")
|
|
||||||
#end def parseTableLine
|
#end def parseTableLine
|
||||||
|
|
||||||
#returns the hand no assigned by the poker site
|
#returns the hand no assigned by the poker site
|
||||||
|
@ -1223,24 +1152,18 @@ def parseTourneyNo(topline):
|
||||||
#end def parseTourneyNo
|
#end def parseTourneyNo
|
||||||
|
|
||||||
#parses a win/collect line. manipulates the passed array winnings, no explicit return
|
#parses a win/collect line. manipulates the passed array winnings, no explicit return
|
||||||
def parseWinLine(line, site, names, winnings, isTourney):
|
def parseWinLine(line, names, winnings, isTourney):
|
||||||
#print "parseWinLine: line:",line
|
#print "parseWinLine: line:",line
|
||||||
for i,n in enumerate(names):
|
for i,n in enumerate(names):
|
||||||
n = n.encode("latin-1")
|
n = n.encode("latin-1")
|
||||||
if line.startswith(n):
|
if line.startswith(n):
|
||||||
if isTourney:
|
if isTourney:
|
||||||
pos1 = line.rfind("collected ") + 10
|
pos1 = line.rfind("collected ") + 10
|
||||||
if site == "ftp":
|
pos2 = line.find(" ", pos1)
|
||||||
pos2 = line.find(")", pos1)
|
winnings[i]+=int(line[pos1:pos2])
|
||||||
elif site == "ps":
|
|
||||||
pos2 = line.find(" ", pos1)
|
|
||||||
winnings[i] += int(line[pos1:pos2])
|
|
||||||
else:
|
else:
|
||||||
pos1 = line.rfind("$") + 1
|
pos1 = line.rfind("$") + 1
|
||||||
if site == "ftp":
|
pos2 = line.find(" ", pos1)
|
||||||
pos2 = line.find(")", pos1)
|
|
||||||
elif site == "ps":
|
|
||||||
pos2 = line.find(" ", pos1)
|
|
||||||
winnings[i] += float2int(line[pos1:pos2])
|
winnings[i] += float2int(line[pos1:pos2])
|
||||||
#end def parseWinLine
|
#end def parseWinLine
|
||||||
|
|
||||||
|
@ -1286,10 +1209,7 @@ def recogniseGametypeID(backend, db, cursor, topline, smallBlindLine, site_id, c
|
||||||
pos1=pos2+2
|
pos1=pos2+2
|
||||||
if isTourney:
|
if isTourney:
|
||||||
pos1-=1
|
pos1-=1
|
||||||
if (site_id==1): #ftp
|
pos2=topline.find(")")
|
||||||
pos2=topline.find(" ", pos1)
|
|
||||||
elif (site_id==2): #ps
|
|
||||||
pos2=topline.find(")")
|
|
||||||
|
|
||||||
if pos2<=pos1:
|
if pos2<=pos1:
|
||||||
pos2=topline.find(")", pos1)
|
pos2=topline.find(")", pos1)
|
||||||
|
@ -1472,28 +1392,6 @@ def recognisePlayerNo(line, names, atype):
|
||||||
raise FpdbError ("failed to recognise player in: "+line+" atype:"+atype)
|
raise FpdbError ("failed to recognise player in: "+line+" atype:"+atype)
|
||||||
#end def recognisePlayerNo
|
#end def recognisePlayerNo
|
||||||
|
|
||||||
#returns the site abbreviation for the given site
|
|
||||||
def recogniseSite(line):
|
|
||||||
if (line.startswith("Full Tilt Poker") or line.startswith("FullTiltPoker")):
|
|
||||||
return "ftp"
|
|
||||||
elif (line.startswith("PokerStars")):
|
|
||||||
return "ps"
|
|
||||||
else:
|
|
||||||
raise FpdbError("failed to recognise site, line:"+line)
|
|
||||||
#end def recogniseSite
|
|
||||||
|
|
||||||
#returns the ID of the given site
|
|
||||||
def recogniseSiteID(cursor, site):
|
|
||||||
if (site=="ftp"):
|
|
||||||
return 1
|
|
||||||
#cursor.execute("SELECT id FROM Sites WHERE name = ('Full Tilt Poker')")
|
|
||||||
elif (site=="ps"):
|
|
||||||
return 2
|
|
||||||
#cursor.execute("SELECT id FROM Sites WHERE name = ('PokerStars')")
|
|
||||||
else:
|
|
||||||
raise FpdbError("invalid site in recogniseSiteID: "+site)
|
|
||||||
return cursor.fetchall()[0][0]
|
|
||||||
#end def recogniseSiteID
|
|
||||||
|
|
||||||
#removes trailing \n from the given array
|
#removes trailing \n from the given array
|
||||||
def removeTrailingEOL(arr):
|
def removeTrailingEOL(arr):
|
||||||
|
@ -1810,7 +1708,7 @@ sure to also change the following storage method and table_viewer.prepare_data i
|
||||||
myStreet0_3B4BDone = True
|
myStreet0_3B4BDone = True
|
||||||
|
|
||||||
#steal calculations
|
#steal calculations
|
||||||
if base == "hold":
|
if base=="hold":
|
||||||
if len(player_ids)>=3: # no point otherwise # was 5, use 3 to match pokertracker definition
|
if len(player_ids)>=3: # no point otherwise # was 5, use 3 to match pokertracker definition
|
||||||
if positions[player]==1:
|
if positions[player]==1:
|
||||||
if firstPfRaiserId==player_ids[player] \
|
if firstPfRaiserId==player_ids[player] \
|
||||||
|
@ -2285,7 +2183,7 @@ def storeHudCache(cursor, base, category, gametypeId, playerIds, hudImportData):
|
||||||
except TypeError:
|
except TypeError:
|
||||||
row=[]
|
row=[]
|
||||||
|
|
||||||
if not row:
|
if not row:
|
||||||
#print "new huddata row"
|
#print "new huddata row"
|
||||||
doInsert=True
|
doInsert=True
|
||||||
row=[]
|
row=[]
|
||||||
|
|
|
@ -46,7 +46,7 @@ def testGameInfo():
|
||||||
|
|
||||||
|
|
||||||
def testHandInfo():
|
def testHandInfo():
|
||||||
text = u""""PokerStars Game #20461877044: Hold'em No Limit ($1/$2) - 2008/09/16 18:58:01 ET"""
|
text = u"""PokerStars Game #20461877044: Hold'em No Limit ($1/$2) - 2008/09/16 18:58:01 ET"""
|
||||||
hhc = PokerStarsToFpdb.PokerStars(autostart=False)
|
hhc = PokerStarsToFpdb.PokerStars(autostart=False)
|
||||||
h = HoldemOmahaHand(None, "PokerStars", gametype, text, builtFrom = "Test")
|
h = HoldemOmahaHand(None, "PokerStars", gametype, text, builtFrom = "Test")
|
||||||
hhc.readHandInfo(h)
|
hhc.readHandInfo(h)
|
||||||
|
@ -78,4 +78,4 @@ Table 'Caia II' 6-max Seat #2 is the button"""
|
||||||
assert h.buttonpos == '2' # TODO: should this be an int?
|
assert h.buttonpos == '2' # TODO: should this be an int?
|
||||||
assert h.starttime == (2008,11 , 15, 19, 22, 21, 5, 320, -1)
|
assert h.starttime == (2008,11 , 15, 19, 22, 21, 5, 320, -1)
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -16,25 +16,24 @@ def testPokerStarsHHDate():
|
||||||
datetime.datetime(2008,9,7,11,23,14))
|
datetime.datetime(2008,9,7,11,23,14))
|
||||||
)
|
)
|
||||||
|
|
||||||
#def testFullTiltHHDate(self):
|
def testFullTiltHHDate():
|
||||||
# sitngo1 = "Full Tilt Poker Game #10311865543: $1 + $0.25 Sit & Go (78057629), Table 1 - 25/50 - No Limit Hold'em - 0:07:45 ET - 2009/01/29"
|
sitngo1 = "Full Tilt Poker Game #10311865543: $1 + $0.25 Sit & Go (78057629), Table 1 - 25/50 - No Limit Hold'em - 0:07:45 ET - 2009/01/29"
|
||||||
# cash1 = "Full Tilt Poker Game #9403951181: Table CR - tay - $0.05/$0.10 - No Limit Hold'em - 9:40:20 ET - 2008/12/09"
|
cash1 = "Full Tilt Poker Game #9403951181: Table CR - tay - $0.05/$0.10 - No Limit Hold'em - 9:40:20 ET - 2008/12/09"
|
||||||
# cash2 = "Full Tilt Poker Game #9468383505: Table Bike (deep 6) - $0.05/$0.10 - No Limit Hold'em - 5:09:36 ET - 2008/12/13"
|
cash2 = "Full Tilt Poker Game #9468383505: Table Bike (deep 6) - $0.05/$0.10 - No Limit Hold'em - 5:09:36 ET - 2008/12/13"
|
||||||
|
|
||||||
# result = fpdb_simple.parseHandStartTime(sitngo1,"ftp")
|
result = fpdb_simple.parseHandStartTime(sitngo1,"ftp")
|
||||||
# self.failUnless(result==datetime.datetime(2009,1,29,05,07,45),
|
assert result==datetime.datetime(2009,1,29,05,07,45)
|
||||||
# "Date incorrect, expected: 2009-01-29 05:07:45 got: " + str(result))
|
result = fpdb_simple.parseHandStartTime(cash1,"ftp")
|
||||||
# result = fpdb_simple.parseHandStartTime(cash1,"ftp")
|
assert result==datetime.datetime(2008,12,9,14,40,20)
|
||||||
# self.failUnless(result==datetime.datetime(2008,12,9,14,40,20),
|
result = fpdb_simple.parseHandStartTime(cash2,"ftp")
|
||||||
# "Date incorrect, expected: 2008-12-09 14:40:20 got: " + str(result))
|
assert result==datetime.datetime(2008,12,13,10,9,36)
|
||||||
# result = fpdb_simple.parseHandStartTime(cash2,"ftp")
|
|
||||||
# self.failUnless(result==datetime.datetime(2008,12,13,10,9,36),
|
|
||||||
# "Date incorrect, expected: 2008-12-13 10:09:36 got: " + str(result))
|
|
||||||
|
|
||||||
# def testTableDetection(self):
|
def testTableDetection():
|
||||||
# result = Tables.clean_title("French (deep)")
|
result = Tables.clean_title("French (deep)")
|
||||||
# self.failUnless(result == "French", "French (deep) parsed incorrectly. Expected 'French' got: " + str(result))
|
assert result == "French"
|
||||||
# result = ("French (deep) - $0.25/$0.50 - No Limit Hold'em - Logged In As xxxx")
|
result = Tables.clean_title("French (deep) - $0.25/$0.50 - No Limit Hold'em - Logged In As xxxx")
|
||||||
|
assert result == "French"
|
||||||
|
|
||||||
|
for (header, site, result) in tuples:
|
||||||
|
yield checkDateParse, header, site, result
|
||||||
|
|
||||||
for (header, site, result) in tuples:
|
|
||||||
yield checkDateParse, header, site, result
|
|
||||||
|
|
Loading…
Reference in New Issue
Block a user