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

This commit is contained in:
grindi 2009-10-02 09:20:58 +04:00
commit 0791fedd9b
23 changed files with 991 additions and 311 deletions

View File

@ -0,0 +1,5 @@
free-poker-tools (0.10.99) unstable; urgency=low
* Initial packaging release.
-- Mika Bostrom <bostik+fpdb@bostik.iki.fi> Thu, 20 Aug 2009 06:30:53 +0300

1
packaging/debian/compat Normal file
View File

@ -0,0 +1 @@
7

24
packaging/debian/control Normal file
View File

@ -0,0 +1,24 @@
Source: free-poker-tools
Maintainer: Mika Bostrom <bostik+fpdb@bostik.iki.fi>
Section: games
Priority: extra
Build-Depends: debhelper, python-support
Standards-Version: 3.8.0
Package: python-fpdb
Architecture: any
Section: games
Priority: extra
Depends: ${python:Depends}, python-gtk2, python-matplotlib,
python-support, mysql-server | postgresql | python-pysqlite2,
python-psycopg2 | python-mysqldb
Suggests: wine
Description: free poker database with HUD
FPDB is a statistics tool for online poker. It supports most sites
and several games. Most prominent feature is its heads-up display
(HUD) which shows statistical details for players in real time.
.
Due to the fact that most online poker clients are Windows-only,
you may need to install wine.
.
FPDB is under heavy development.

View File

@ -0,0 +1,7 @@
This package was debianised by Mika Bostrom <bostik+fpdb@bostik.iki.fi>
Upstream authors: ...
License: AGPL
Copyright (C) 2008- The FPDB developers

1
packaging/debian/links Normal file
View File

@ -0,0 +1 @@
/usr/share/python-support/python-fpdb/fpdb/fpdb.py /usr/bin/fpdb

View File

@ -0,0 +1,5 @@
#!/bin/sh
# When installed into .../fpdb/ the script gets mode 644
# Note: "dh_fixperms -Xfpdb.py" did not work, hence this hack
chmod 755 /usr/bin/fpdb

View File

@ -0,0 +1 @@
2.4-

45
packaging/debian/rules Executable file
View File

@ -0,0 +1,45 @@
#!/usr/bin/make -f
# -*- makefile -*-
PACKAGE := python-fpdb
build: build-stamp
build-stamp:
dh_testdir
python setup.py build
touch $@
clean:
dh_testdir
dh_testroot
python setup.py clean
rm -rf build
dh_clean build-stamp
install: build
dh_testdir
dh_testroot
dh_prep || dh_clean -k
dh_installdirs
#
python setup.py install --root=debian/$(PACKAGE) --prefix=/usr --no-compile
binary-indep: build install
dh_testdir
dh_testroot
dh_installchangelogs
dh_installdocs
dh_link
dh_compress
dh_fixperms
dh_pysupport
dh_installdeb
dh_gencontrol
dh_md5sums
dh_builddeb
binary-arch: build install
binary: binary-indep binary-arch
.PHONY: build clean binary-indep binary-arch binary install

View File

@ -26,17 +26,17 @@ def twoStartCards(value1, suit1, value2, suit2):
if value1 < 2 or value2 < 2:
ret = 0
if value1 == value2: # pairs
ret = (13 * (value2-2) + (value2-1) )
ret = (13 * (value2-2) + (value2-2) )
elif suit1 == suit2:
if value1 > value2:
ret = 13 * (value1-2) + (value2-1)
ret = 13 * (value1-2) + (value2-2)
else:
ret = 13 * (value2-2) + (value1-1)
ret = 13 * (value2-2) + (value1-2)
else:
if value1 > value2:
ret = 13 * (value2-2) + (value2-1)
ret = 13 * (value2-2) + (value1-2)
else:
ret = 13 * (value1-2) + (value2-1)
ret = 13 * (value1-2) + (value2-2)
# print "twoStartCards(", value1, suit1, value2, suit2, ")=", ret
return ret
@ -46,7 +46,6 @@ def twoStartCardString(card):
into a string like AQo """
ret = 'xx'
if card > 0:
card -= 1
s = ('2', '3', '4', '5', '6', '7', '8', '9', 'T', 'J', 'Q', 'K', 'A')
x = card / 13
y = card - 13 * x

View File

@ -49,12 +49,15 @@ import logging, logging.config
logging.config.fileConfig(os.path.join(sys.path[0],"logging.conf"))
log = logging.getLogger('db')
class Database:
MYSQL_INNODB = 2
PGSQL = 3
SQLITE = 4
hero_hudstart_def = '1999-12-31' # default for length of Hero's stats in HUD
# Data Structures for index and foreign key creation
# drop_code is an int with possible values: 0 - don't drop for bulk import
# 1 - drop during bulk import
@ -70,19 +73,19 @@ class Database:
[ ] # no db with index 0
, [ ] # no db with index 1
, [ # indexes for mysql (list index 2)
{'tab':'Players', 'col':'name', 'drop':0}
, {'tab':'Hands', 'col':'siteHandNo', 'drop':0}
, {'tab':'Hands', 'col':'gametypeId', 'drop':0} # mct 22/3/09
# {'tab':'Players', 'col':'name', 'drop':0} unique indexes not dropped
# {'tab':'Hands', 'col':'siteHandNo', 'drop':0} unique indexes not dropped
{'tab':'Hands', 'col':'gametypeId', 'drop':0} # mct 22/3/09
, {'tab':'HandsPlayers', 'col':'handId', 'drop':0} # not needed, handled by fk
, {'tab':'HandsPlayers', 'col':'playerId', 'drop':0} # not needed, handled by fk
, {'tab':'HandsPlayers', 'col':'tourneyTypeId', 'drop':0}
, {'tab':'HandsPlayers', 'col':'tourneysPlayersId', 'drop':0}
, {'tab':'Tourneys', 'col':'siteTourneyNo', 'drop':0}
#, {'tab':'Tourneys', 'col':'siteTourneyNo', 'drop':0} unique indexes not dropped
]
, [ # indexes for postgres (list index 3)
{'tab':'Gametypes', 'col':'siteId', 'drop':0}
, {'tab':'Hands', 'col':'gametypeId', 'drop':0} # mct 22/3/09
, {'tab':'Hands', 'col':'siteHandNo', 'drop':0}
#, {'tab':'Hands', 'col':'siteHandNo', 'drop':0} unique indexes not dropped
, {'tab':'HandsActions', 'col':'handsPlayerId', 'drop':0}
, {'tab':'HandsPlayers', 'col':'handId', 'drop':1}
, {'tab':'HandsPlayers', 'col':'playerId', 'drop':1}
@ -91,22 +94,22 @@ class Database:
, {'tab':'HudCache', 'col':'playerId', 'drop':0}
, {'tab':'HudCache', 'col':'tourneyTypeId', 'drop':0}
, {'tab':'Players', 'col':'siteId', 'drop':1}
, {'tab':'Players', 'col':'name', 'drop':0}
#, {'tab':'Players', 'col':'name', 'drop':0} unique indexes not dropped
, {'tab':'Tourneys', 'col':'tourneyTypeId', 'drop':1}
, {'tab':'Tourneys', 'col':'siteTourneyNo', 'drop':0}
#, {'tab':'Tourneys', 'col':'siteTourneyNo', 'drop':0} unique indexes not dropped
, {'tab':'TourneysPlayers', 'col':'playerId', 'drop':0}
, {'tab':'TourneysPlayers', 'col':'tourneyId', 'drop':0}
#, {'tab':'TourneysPlayers', 'col':'tourneyId', 'drop':0} unique indexes not dropped
, {'tab':'TourneyTypes', 'col':'siteId', 'drop':0}
]
, [ # indexes for sqlite (list index 4)
{'tab':'Players', 'col':'name', 'drop':0}
, {'tab':'Hands', 'col':'siteHandNo', 'drop':0}
, {'tab':'Hands', 'col':'gametypeId', 'drop':0}
# {'tab':'Players', 'col':'name', 'drop':0} unique indexes not dropped
# {'tab':'Hands', 'col':'siteHandNo', 'drop':0} unique indexes not dropped
{'tab':'Hands', 'col':'gametypeId', 'drop':0}
, {'tab':'HandsPlayers', 'col':'handId', 'drop':0}
, {'tab':'HandsPlayers', 'col':'playerId', 'drop':0}
, {'tab':'HandsPlayers', 'col':'tourneyTypeId', 'drop':0}
, {'tab':'HandsPlayers', 'col':'tourneysPlayersId', 'drop':0}
, {'tab':'Tourneys', 'col':'siteTourneyNo', 'drop':0}
#, {'tab':'Tourneys', 'col':'siteTourneyNo', 'drop':0} unique indexes not dropped
]
]
@ -183,6 +186,7 @@ class Database:
def __init__(self, c, sql = None):
log.info("Creating Database instance, sql = %s" % sql)
self.config = c
self.fdb = fpdb_db.fpdb_db() # sets self.fdb.db self.fdb.cursor and self.fdb.sql
self.fdb.do_connect(c)
self.connection = self.fdb.db
@ -223,9 +227,10 @@ class Database:
#self.hud_hero_days = 30 # but last T days or last H hands for yourself
# vars for hand ids or dates fetched according to above config:
self.hand_1day_ago = 0 # max hand id more than 24 hrs earlier than now
self.date_ndays_ago = 'd000000' # date N days ago ('d' + YYMMDD)
self.date_nhands_ago = {} # dates N hands ago per player - not used yet
self.hand_1day_ago = 0 # max hand id more than 24 hrs earlier than now
self.date_ndays_ago = 'd000000' # date N days ago ('d' + YYMMDD)
self.h_date_ndays_ago = 'd000000' # date N days ago ('d' + YYMMDD) for hero
self.date_nhands_ago = {} # dates N hands ago per player - not used yet
self.cursor = self.fdb.cursor
@ -367,8 +372,12 @@ class Database:
winners[row[0]] = row[1]
return winners
def init_hud_stat_vars(self, hud_days):
"""Initialise variables used by Hud to fetch stats."""
def init_hud_stat_vars(self, hud_days, h_hud_days):
"""Initialise variables used by Hud to fetch stats:
self.hand_1day_ago handId of latest hand played more than a day ago
self.date_ndays_ago date n days ago
self.h_date_ndays_ago date n days ago for hero (different n)
"""
self.hand_1day_ago = 1
try:
@ -381,9 +390,14 @@ class Database:
else:
if row and row[0]:
self.hand_1_day_ago = row[0]
d = timedelta(days=hud_days)
now = datetime.utcnow() - d
self.date_ndays_ago = "d%02d%02d%02d" % (now.year - 2000, now.month, now.day)
d = timedelta(days=hud_days)
now = datetime.utcnow() - d
self.date_ndays_ago = "d%02d%02d%02d" % (now.year - 2000, now.month, now.day)
d = timedelta(days=h_hud_days)
now = datetime.utcnow() - d
self.h_date_ndays_ago = "d%02d%02d%02d" % (now.year - 2000, now.month, now.day)
def init_player_hud_stat_vars(self, playerid):
# not sure if this is workable, to be continued ...
@ -403,26 +417,48 @@ class Database:
err = traceback.extract_tb(sys.exc_info()[2])[-1]
print "***Error: "+err[2]+"("+str(err[1])+"): "+str(sys.exc_info()[1])
def get_stats_from_hand(self, hand, aggregate = False, hud_style = 'A', agg_bb_mult = 100):
if hud_style == 'S':
def get_stats_from_hand( self, hand, type # type is "ring" or "tour"
, hud_params = {'aggregate_tour':False, 'aggregate_ring':False, 'hud_style':'A', 'agg_bb_mult':100}
, hero_id = -1
):
aggregate = hud_params['aggregate_tour'] if type == "tour" else hud_params['aggregate_ring']
hud_style = hud_params['hud_style']
agg_bb_mult = hud_params['agg_bb_mult'] if aggregate else 1
h_aggregate = hud_params['h_aggregate_tour'] if type == "tour" else hud_params['h_aggregate_ring']
h_hud_style = hud_params['h_hud_style']
h_agg_bb_mult = hud_params['h_agg_bb_mult'] if h_aggregate else 1
stat_dict = {}
return( self.get_stats_from_hand_session(hand) )
if hud_style == 'S' or h_hud_style == 'S':
self.get_stats_from_hand_session(hand, stat_dict, hero_id, hud_style, h_hud_style)
if hud_style == 'S' and h_hud_style == 'S':
return stat_dict
else: # hud_style == A
if hud_style == 'T':
stylekey = self.date_ndays_ago
elif hud_style == 'A':
stylekey = '0000000' # all stylekey values should be higher than this
elif hud_style == 'S':
stylekey = 'zzzzzzz' # all stylekey values should be lower than this
#elif hud_style == 'H':
# stylekey = date_nhands_ago needs array by player here ...
if hud_style == 'T':
stylekey = self.date_ndays_ago
#elif hud_style == 'H':
# stylekey = date_nhands_ago needs array by player here ...
else: # assume A (all-time)
stylekey = '0000000' # all stylekey values should be higher than this
if h_hud_style == 'T':
h_stylekey = self.h_date_ndays_ago
elif h_hud_style == 'A':
h_stylekey = '0000000' # all stylekey values should be higher than this
elif h_hud_style == 'S':
h_stylekey = 'zzzzzzz' # all stylekey values should be lower than this
#elif h_hud_style == 'H':
# h_stylekey = date_nhands_ago needs array by player here ...
if aggregate:
query = 'get_stats_from_hand_aggregated'
subs = (hand, stylekey, agg_bb_mult, agg_bb_mult)
else:
query = 'get_stats_from_hand'
subs = (hand, stylekey)
#if aggregate: always use aggreagte query now: use agg_bb_mult of 1 for no aggregation:
query = 'get_stats_from_hand_aggregated'
subs = (hand, hero_id, stylekey, agg_bb_mult, agg_bb_mult, hero_id, h_stylekey, h_agg_bb_mult, h_agg_bb_mult)
print "agg query subs:", subs
#else:
# query = 'get_stats_from_hand'
# subs = (hand, stylekey)
#print "get stats: hud style =", hud_style, "query =", query, "subs =", subs
c = self.connection.cursor()
@ -430,7 +466,6 @@ class Database:
# now get the stats
c.execute(self.sql.query[query], subs)
colnames = [desc[0] for desc in c.description]
stat_dict = {}
for row in c.fetchall():
t_dict = {}
for name, val in zip(colnames, row):
@ -441,7 +476,13 @@ class Database:
return stat_dict
# uses query on handsplayers instead of hudcache to get stats on just this session
def get_stats_from_hand_session(self, hand):
def get_stats_from_hand_session(self, hand, stat_dict, hero_id, hud_style, h_hud_style):
"""Get stats for just this session (currently defined as any play in the last 24 hours - to
be improved at some point ...)
h_hud_style and hud_style params indicate whether to get stats for hero and/or others
- only fetch heros stats if h_hud_style == 'S',
and only fetch others stats if hud_style == 'S'
"""
query = self.sql.query['get_stats_from_hand_session']
if self.db_server == 'mysql':
@ -456,31 +497,34 @@ class Database:
#print "sess_stats: subs =", subs, "subs[0] =", subs[0]
c.execute(query, subs)
colnames = [desc[0] for desc in c.description]
n,stat_dict = 0,{}
row = c.fetchone()
while row:
if colnames[0].lower() == 'player_id':
playerid = row[0]
else:
log.error("ERROR: query %s result does not have player_id as first column" % (query,))
break
n = 0
row = c.fetchone()
if colnames[0].lower() == 'player_id':
playerid = row[0]
# Loop through stats adding them to appropriate stat_dict:
while row:
if (playerid == hero_id and h_hud_style == 'S') or (playerid != hero_id and hud_style == 'S'):
for name, val in zip(colnames, row):
if not playerid in stat_dict:
stat_dict[playerid] = {}
stat_dict[playerid][name.lower()] = val
elif not name.lower() in stat_dict[playerid]:
stat_dict[playerid][name.lower()] = val
elif name.lower() not in ('hand_id', 'player_id', 'seat', 'screen_name', 'seats'):
stat_dict[playerid][name.lower()] += val
n += 1
if n >= 10000: break # todo: don't think this is needed so set nice and high
# for now - comment out or remove?
row = c.fetchone()
else:
log.error("ERROR: query %s result does not have player_id as first column" % (query,))
for name, val in zip(colnames, row):
if not playerid in stat_dict:
stat_dict[playerid] = {}
stat_dict[playerid][name.lower()] = val
elif not name.lower() in stat_dict[playerid]:
stat_dict[playerid][name.lower()] = val
elif name.lower() not in ('hand_id', 'player_id', 'seat', 'screen_name', 'seats'):
stat_dict[playerid][name.lower()] += val
n += 1
if n >= 4000: break # todo: don't think this is needed so set nice and high
# for now - comment out or remove?
row = c.fetchone()
#print " %d rows fetched, len(stat_dict) = %d" % (n, len(stat_dict))
#print "session stat_dict =", stat_dict
return stat_dict
#return stat_dict
def get_player_id(self, config, site, player_name):
c = self.connection.cursor()
@ -491,6 +535,69 @@ class Database:
else:
return None
#returns the SQL ids of the names given in an array
# TODO: if someone gets industrious, they should make the parts that use the output of this function deal with a dict
# { playername: id } instead of depending on it's relation to the positions list
# then this can be reduced in complexity a bit
#def recognisePlayerIDs(cursor, names, site_id):
# result = []
# for i in xrange(len(names)):
# cursor.execute ("SELECT id FROM Players WHERE name=%s", (names[i],))
# tmp=cursor.fetchall()
# if (len(tmp)==0): #new player
# cursor.execute ("INSERT INTO Players (name, siteId) VALUES (%s, %s)", (names[i], site_id))
# #print "Number of players rows inserted: %d" % cursor.rowcount
# cursor.execute ("SELECT id FROM Players WHERE name=%s", (names[i],))
# tmp=cursor.fetchall()
# #print "recognisePlayerIDs, names[i]:",names[i],"tmp:",tmp
# result.append(tmp[0][0])
# return result
def recognisePlayerIDs(self, names, site_id):
c = self.get_cursor()
q = "SELECT name,id FROM Players WHERE siteid=%d and (name=%s)" %(site_id, " OR name=".join([self.sql.query['placeholder'] for n in names]))
c.execute(q, names) # get all playerids by the names passed in
ids = dict(c.fetchall()) # convert to dict
if len(ids) != len(names):
notfound = [n for n in names if n not in ids] # make list of names not in database
if notfound: # insert them into database
q_ins = "INSERT INTO Players (name, siteId) VALUES (%s, "+str(site_id)+")"
q_ins = q_ins.replace('%s', self.sql.query['placeholder'])
c.executemany(q_ins, [(n,) for n in notfound])
q2 = "SELECT name,id FROM Players WHERE siteid=%d and (name=%s)" % (site_id, " OR name=".join(["%s" for n in notfound]))
q2 = q2.replace('%s', self.sql.query['placeholder'])
c.execute(q2, notfound) # get their new ids
tmp = c.fetchall()
for n,id in tmp: # put them all into the same dict
ids[n] = id
# return them in the SAME ORDER that they came in in the names argument, rather than the order they came out of the DB
return [ids[n] for n in names]
#end def recognisePlayerIDs
# Here's a version that would work if it wasn't for the fact that it needs to have the output in the same order as input
# this version could also be improved upon using list comprehensions, etc
#def recognisePlayerIDs(cursor, names, site_id):
# result = []
# notfound = []
# cursor.execute("SELECT name,id FROM Players WHERE name='%s'" % "' OR name='".join(names))
# tmp = dict(cursor.fetchall())
# for n in names:
# if n not in tmp:
# notfound.append(n)
# else:
# result.append(tmp[n])
# if notfound:
# cursor.executemany("INSERT INTO Players (name, siteId) VALUES (%s, "+str(site_id)+")", (notfound))
# cursor.execute("SELECT id FROM Players WHERE name='%s'" % "' OR name='".join(notfound))
# tmp = cursor.fetchall()
# for n in tmp:
# result.append(n[0])
#
# return result
def get_site_id(self, site):
c = self.get_cursor()
c.execute(self.sql.query['getSiteId'], (site,))
@ -855,6 +962,7 @@ class Database:
log.debug(self.sql.query['createSettingsTable'])
c = self.get_cursor()
c.execute(self.sql.query['createSettingsTable'])
log.debug(self.sql.query['createSitesTable'])
c.execute(self.sql.query['createSitesTable'])
c.execute(self.sql.query['createGametypesTable'])
@ -867,9 +975,14 @@ class Database:
c.execute(self.sql.query['createHandsPlayersTable'])
c.execute(self.sql.query['createHandsActionsTable'])
c.execute(self.sql.query['createHudCacheTable'])
#c.execute(self.sql.query['addTourneyIndex'])
#c.execute(self.sql.query['addHandsIndex'])
#c.execute(self.sql.query['addPlayersIndex'])
# create unique indexes:
c.execute(self.sql.query['addTourneyIndex'])
c.execute(self.sql.query['addHandsIndex'])
c.execute(self.sql.query['addPlayersIndex'])
c.execute(self.sql.query['addTPlayersIndex'])
c.execute(self.sql.query['addTTypesIndex'])
self.fillDefaultData()
self.commit()
except:
@ -1011,20 +1124,48 @@ class Database:
c.execute("INSERT INTO Sites (name,currency) VALUES ('PartyPoker', 'USD')")
if self.backend == self.SQLITE:
c.execute("INSERT INTO TourneyTypes (id, siteId, buyin, fee) VALUES (NULL, 1, 0, 0);")
else:
elif self.backend == self.PGSQL:
c.execute("""insert into TourneyTypes(siteId, buyin, fee, maxSeats, knockout
,rebuyOrAddon, speed, headsUp, shootout, matrix)
values (1, 0, 0, 0, False, False, null, False, False, False);""")
elif self.backend == self.MYSQL_INNODB:
c.execute("""insert into TourneyTypes(id, siteId, buyin, fee, maxSeats, knockout
,rebuyOrAddon, speed, headsUp, shootout, matrix)
values (1, 1, 0, 0, 0, False, False, null, False, False, False);""")
#end def fillDefaultData
def rebuild_hudcache(self):
def rebuild_hudcache(self, start=None):
"""clears hudcache and rebuilds from the individual handsplayers records"""
try:
stime = time()
# derive list of program owner's player ids
self.hero = {} # name of program owner indexed by site id
self.hero_ids = {'dummy':-53, 'dummy2':-52} # playerid of owner indexed by site id
# make sure at least two values in list
# so that tuple generation creates doesn't use
# () or (1,) style
for site in self.config.get_supported_sites():
result = self.get_site_id(site)
if result:
site_id = result[0][0]
self.hero[site_id] = self.config.supported_sites[site].screen_name
p_id = self.get_player_id(self.config, site, self.hero[site_id])
if p_id:
self.hero_ids[site_id] = int(p_id)
if start == None:
start = self.hero_hudstart_def
if self.hero_ids == {}:
where = ""
else:
where = "where hp.playerId not in " + str(tuple(self.hero_ids.values())) \
+ " or h.handStart > '" + start + "'"
rebuild_sql = self.sql.query['rebuildHudCache'].replace('<where_clause>', where)
self.get_cursor().execute(self.sql.query['clearHudCache'])
self.get_cursor().execute(self.sql.query['rebuildHudCache'])
self.get_cursor().execute(rebuild_sql)
self.commit()
print "Rebuild hudcache took %.1f seconds" % (time() - stime,)
except:
@ -1033,6 +1174,39 @@ class Database:
print err
#end def rebuild_hudcache
def get_hero_hudcache_start(self):
"""fetches earliest stylekey from hudcache for one of hero's player ids"""
try:
# derive list of program owner's player ids
self.hero = {} # name of program owner indexed by site id
self.hero_ids = {'dummy':-53, 'dummy2':-52} # playerid of owner indexed by site id
# make sure at least two values in list
# so that tuple generation creates doesn't use
# () or (1,) style
for site in self.config.get_supported_sites():
result = self.get_site_id(site)
if result:
site_id = result[0][0]
self.hero[site_id] = self.config.supported_sites[site].screen_name
p_id = self.get_player_id(self.config, site, self.hero[site_id])
if p_id:
self.hero_ids[site_id] = int(p_id)
q = self.sql.query['get_hero_hudcache_start'].replace("<playerid_list>", str(tuple(self.hero_ids.values())))
c = self.get_cursor()
c.execute(q)
tmp = c.fetchone()
if tmp == (None,):
return self.hero_hudstart_def
else:
return "20"+tmp[0][1:3] + "-" + tmp[0][3:5] + "-" + tmp[0][5:7]
except:
err = traceback.extract_tb(sys.exc_info()[2])[-1]
print "Error rebuilding hudcache:", str(sys.exc_value)
print err
#end def get_hero_hudcache_start
def analyzeDB(self):
"""Do whatever the DB can offer to update index/table statistics"""
@ -1182,6 +1356,10 @@ class Database:
return result
#end def store_the_hand
###########################
# NEWIMPORT CODE
###########################
def storeHand(self, p):
#stores into table hands:
q = """INSERT INTO Hands (
@ -1257,6 +1435,109 @@ class Database:
#return getLastInsertId(backend, conn, cursor)
# def storeHand
def storeHandsPlayers(self, p):
#def store_hands_players_holdem_omaha(self, backend, category, hands_id, player_ids, start_cashes
# ,positions, card_values, card_suits, winnings, rakes, seatNos, hudCache):
# result=[]
#
# # postgres (and others?) needs the booleans converted to ints before saving:
# # (or we could just save them as boolean ... but then we can't sum them so easily in sql ???)
# # NO - storing booleans for now so don't need this
# #hudCacheInt = {}
# #for k,v in hudCache.iteritems():
# # if k in ('wonWhenSeenStreet1', 'wonAtSD', 'totalProfit'):
# # hudCacheInt[k] = v
# # else:
# # hudCacheInt[k] = map(lambda x: 1 if x else 0, v)
#
# try:
# inserts = []
# for i in xrange(len(player_ids)):
# card1 = Card.cardFromValueSuit(card_values[i][0], card_suits[i][0])
# card2 = Card.cardFromValueSuit(card_values[i][1], card_suits[i][1])
#
# if (category=="holdem"):
# startCards = Card.twoStartCards(card_values[i][0], card_suits[i][0], card_values[i][1], card_suits[i][1])
# card3 = None
# card4 = None
# elif (category=="omahahi" or category=="omahahilo"):
# startCards = Card.fourStartCards(card_values[i][0], card_suits[i][0], card_values[i][1], card_suits[i][1]
# ,card_values[i][2], card_suits[i][2], card_values[i][3], card_suits[i][3])
# card3 = Card.cardFromValueSuit(card_values[i][2], card_suits[i][2])
# card4 = Card.cardFromValueSuit(card_values[i][3], card_suits[i][3])
# else:
# raise FpdbError("invalid category")
#
# inserts.append( (
# hands_id, player_ids[i], start_cashes[i], positions[i], 1, # tourneytypeid - needed for hudcache
# card1, card2, card3, card4, startCards,
# winnings[i], rakes[i], seatNos[i], hudCache['totalProfit'][i],
# hudCache['street0VPI'][i], hudCache['street0Aggr'][i],
# hudCache['street0_3BChance'][i], hudCache['street0_3BDone'][i],
# hudCache['street1Seen'][i], hudCache['street2Seen'][i], hudCache['street3Seen'][i],
# hudCache['street4Seen'][i], hudCache['sawShowdown'][i],
# hudCache['street1Aggr'][i], hudCache['street2Aggr'][i], hudCache['street3Aggr'][i], hudCache['street4Aggr'][i],
# hudCache['otherRaisedStreet1'][i], hudCache['otherRaisedStreet2'][i],
# hudCache['otherRaisedStreet3'][i], hudCache['otherRaisedStreet4'][i],
# hudCache['foldToOtherRaisedStreet1'][i], hudCache['foldToOtherRaisedStreet2'][i],
# hudCache['foldToOtherRaisedStreet3'][i], hudCache['foldToOtherRaisedStreet4'][i],
# hudCache['wonWhenSeenStreet1'][i], hudCache['wonAtSD'][i],
# hudCache['stealAttemptChance'][i], hudCache['stealAttempted'][i], hudCache['foldBbToStealChance'][i],
# hudCache['foldedBbToSteal'][i], hudCache['foldSbToStealChance'][i], hudCache['foldedSbToSteal'][i],
# hudCache['street1CBChance'][i], hudCache['street1CBDone'][i], hudCache['street2CBChance'][i], hudCache['street2CBDone'][i],
# hudCache['street3CBChance'][i], hudCache['street3CBDone'][i], hudCache['street4CBChance'][i], hudCache['street4CBDone'][i],
# hudCache['foldToStreet1CBChance'][i], hudCache['foldToStreet1CBDone'][i],
# hudCache['foldToStreet2CBChance'][i], hudCache['foldToStreet2CBDone'][i],
# hudCache['foldToStreet3CBChance'][i], hudCache['foldToStreet3CBDone'][i],
# hudCache['foldToStreet4CBChance'][i], hudCache['foldToStreet4CBDone'][i],
# hudCache['street1CheckCallRaiseChance'][i], hudCache['street1CheckCallRaiseDone'][i],
# hudCache['street2CheckCallRaiseChance'][i], hudCache['street2CheckCallRaiseDone'][i],
# hudCache['street3CheckCallRaiseChance'][i], hudCache['street3CheckCallRaiseDone'][i],
# hudCache['street4CheckCallRaiseChance'][i], hudCache['street4CheckCallRaiseDone'][i],
# hudCache['street0Calls'][i], hudCache['street1Calls'][i], hudCache['street2Calls'][i], hudCache['street3Calls'][i], hudCache['street4Calls'][i],
# hudCache['street0Bets'][i], hudCache['street1Bets'][i], hudCache['street2Bets'][i], hudCache['street3Bets'][i], hudCache['street4Bets'][i]
# ) )
# c = self.get_cursor()
# c.executemany ("""
# INSERT INTO HandsPlayers
# (handId, playerId, startCash, position, tourneyTypeId,
# card1, card2, card3, card4, startCards, winnings, rake, seatNo, totalProfit,
# street0VPI, street0Aggr, street0_3BChance, street0_3BDone,
# street1Seen, street2Seen, street3Seen, street4Seen, sawShowdown,
# street1Aggr, street2Aggr, street3Aggr, street4Aggr,
# otherRaisedStreet1, otherRaisedStreet2, otherRaisedStreet3, otherRaisedStreet4,
# foldToOtherRaisedStreet1, foldToOtherRaisedStreet2, foldToOtherRaisedStreet3, foldToOtherRaisedStreet4,
# wonWhenSeenStreet1, wonAtSD,
# stealAttemptChance, stealAttempted, foldBbToStealChance, foldedBbToSteal, foldSbToStealChance, foldedSbToSteal,
# street1CBChance, street1CBDone, street2CBChance, street2CBDone,
# street3CBChance, street3CBDone, street4CBChance, street4CBDone,
# foldToStreet1CBChance, foldToStreet1CBDone, foldToStreet2CBChance, foldToStreet2CBDone,
# foldToStreet3CBChance, foldToStreet3CBDone, foldToStreet4CBChance, foldToStreet4CBDone,
# street1CheckCallRaiseChance, street1CheckCallRaiseDone, street2CheckCallRaiseChance, street2CheckCallRaiseDone,
# street3CheckCallRaiseChance, street3CheckCallRaiseDone, street4CheckCallRaiseChance, street4CheckCallRaiseDone,
# street0Calls, street1Calls, street2Calls, street3Calls, street4Calls,
# street0Bets, street1Bets, street2Bets, street3Bets, street4Bets
# )
# VALUES (%s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s,
# %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s,
# %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s,
# %s, %s, %s, %s, %s, %s, %s, %s, %s, %s)""".replace('%s', self.sql.query['placeholder'])
# ,inserts )
# result.append( self.get_last_insert_id(c) ) # wrong? not used currently
# except:
# raise FpdbError( "store_hands_players_holdem_omaha error: " + str(sys.exc_value) )
#
# return result
pass
#################################
# Finish of NEWIMPORT CODE
#################################
def storeHands(self, backend, site_hand_no, gametype_id
,hand_start_time, names, tableName, maxSeats, hudCache
,board_values, board_suits):
@ -1516,6 +1797,8 @@ class Database:
#cursor.execute("SELECT id FROM HandsPlayers WHERE handId=%s AND playerId+0=%s", (hands_id, player_ids[i]))
#result.append(cursor.fetchall()[0][0])
except:
err = traceback.extract_tb(sys.exc_info()[2])[-1]
print "***Error storing hand: "+err[2]+"("+str(err[1])+"): "+str(sys.exc_info()[1])
raise FpdbError( "store_hands_players_holdem_omaha_tourney error: " + str(sys.exc_value) )
return result
@ -1748,27 +2031,40 @@ class Database:
#end def storeHudCache
def store_tourneys(self, tourneyTypeId, siteTourneyNo, entries, prizepool, startTime):
ret = -1
try:
# try and create tourney record, fetch id if it already exists
# avoids race condition when doing the select first
cursor = self.get_cursor()
cursor.execute("SELECT id FROM Tourneys WHERE siteTourneyNo=%s AND tourneyTypeId+0=%s".replace('%s', self.sql.query['placeholder'])
, (siteTourneyNo, tourneyTypeId))
tmp=cursor.fetchone()
#print "tried SELECTing tourneys.id, result:",tmp
try:
len(tmp)
except TypeError:#means we have to create new one
cursor.execute("""INSERT INTO Tourneys
(tourneyTypeId, siteTourneyNo, entries, prizepool, startTime)
VALUES (%s, %s, %s, %s, %s)""".replace('%s', self.sql.query['placeholder'])
,(tourneyTypeId, siteTourneyNo, entries, prizepool, startTime))
cursor.execute("SELECT id FROM Tourneys WHERE siteTourneyNo=%s AND tourneyTypeId+0=%s", (siteTourneyNo, tourneyTypeId))
tmp=cursor.fetchone()
#print "created new tourneys.id:",tmp
cursor.execute("savepoint ins_tourney")
cursor.execute("""INSERT INTO Tourneys
(tourneyTypeId, siteTourneyNo, entries, prizepool, startTime)
VALUES (%s, %s, %s, %s, %s)""".replace('%s', self.sql.query['placeholder'])
,(tourneyTypeId, siteTourneyNo, entries, prizepool, startTime))
ret = self.get_last_insert_id(cursor)
#print "created new tourneys.id:",ret
except:
raise FpdbError( "store_tourneys error: " + str(sys.exc_value) )
#if str(sys.exc_value) contains 'sitetourneyno':
# raise FpdbError( "store_tourneys error: " + str(sys.exc_value) )
#else:
#print "error insert tourney (%s) trying select ..." % (str(sys.exc_value),)
cursor.execute("rollback to savepoint ins_tourney")
try:
cursor.execute( "SELECT id FROM Tourneys WHERE siteTourneyNo=%s AND tourneyTypeId+0=%s".replace('%s', self.sql.query['placeholder'])
, (siteTourneyNo, tourneyTypeId) )
rec = cursor.fetchone()
#print "select tourney result: ", rec
try:
len(rec)
ret = rec[0]
except:
print "Tourney id not found"
except:
print "Error selecting tourney id:", str(sys.exc_info()[1])
return tmp[0]
cursor.execute("release savepoint ins_tourney")
#print "store_tourneys returning", ret
return ret
#end def store_tourneys
def store_tourneys_players(self, tourney_id, player_ids, payin_amounts, ranks, winnings):
@ -1781,26 +2077,32 @@ class Database:
#print "ranks:",ranks
#print "winnings:",winnings
for i in xrange(len(player_ids)):
cursor.execute("SELECT id FROM TourneysPlayers WHERE tourneyId=%s AND playerId+0=%s".replace('%s', self.sql.query['placeholder'])
,(tourney_id, player_ids[i]))
tmp=cursor.fetchone()
#print "tried SELECTing tourneys_players.id:",tmp
try:
len(tmp)
except TypeError:
cursor.execute("savepoint ins_tplayer")
cursor.execute("""INSERT INTO TourneysPlayers
(tourneyId, playerId, payinAmount, rank, winnings) VALUES (%s, %s, %s, %s, %s)""".replace('%s', self.sql.query['placeholder']),
(tourneyId, playerId, payinAmount, rank, winnings) VALUES (%s, %s, %s, %s, %s)""".replace('%s', self.sql.query['placeholder']),
(tourney_id, player_ids[i], payin_amounts[i], ranks[i], winnings[i]))
cursor.execute("SELECT id FROM TourneysPlayers WHERE tourneyId=%s AND playerId+0=%s".replace('%s', self.sql.query['placeholder']),
(tourney_id, player_ids[i]))
tmp=cursor.fetchone()
#print "created new tourneys_players.id:",tmp
result.append(tmp[0])
tmp = self.get_last_insert_id(cursor)
result.append(tmp)
#print "created new tourneys_players.id:", tmp
except:
cursor.execute("rollback to savepoint ins_tplayer")
cursor.execute("SELECT id FROM TourneysPlayers WHERE tourneyId=%s AND playerId+0=%s".replace('%s', self.sql.query['placeholder'])
,(tourney_id, player_ids[i]))
tmp = cursor.fetchone()
#print "tried SELECTing tourneys_players.id:", tmp
try:
len(tmp)
result.append(tmp[0])
except:
print "tplayer id not found for tourney,player %s,%s" % (tourney_id, player_ids[i])
pass
except:
raise FpdbError( "store_tourneys_players error: " + str(sys.exc_value) )
cursor.execute("release savepoint ins_tplayer")
#print "store_tourneys_players returning", result
return result
#end def store_tourneys_players
@ -2023,10 +2325,10 @@ class Database:
def tStoreTourneyPlayers(self, tourney, dbTourneyId):
logging.debug("Database.tStoreTourneyPlayers")
# First, get playerids for the players and specifically the one for hero :
playersIds = fpdb_simple.recognisePlayerIDs(self, tourney.players, tourney.siteId)
playersIds = self.recognisePlayerIDs(tourney.players, tourney.siteId)
# hero may be None for matrix tourneys summaries
# hero = [ tourney.hero ]
# heroId = fpdb_simple.recognisePlayerIDs(self, hero , tourney.siteId)
# heroId = self.recognisePlayerIDs(hero , tourney.siteId)
# logging.debug("hero Id = %s - playersId = %s" % (heroId , playersIds))
tourneyPlayersIds=[]
@ -2240,12 +2542,12 @@ if __name__=="__main__":
if hero:
print "nutOmatic is id_player = %d" % hero
stat_dict = db_connection.get_stats_from_hand(h)
stat_dict = db_connection.get_stats_from_hand(h, "ring")
for p in stat_dict.keys():
print p, " ", stat_dict[p]
#print "nutOmatics stats:"
#stat_dict = db_connection.get_stats_from_hand(h, hero)
#stat_dict = db_connection.get_stats_from_hand(h, "ring")
#for p in stat_dict.keys():
# print p, " ", stat_dict[p]

8
pyfpdb/FulltiltToFpdb.py Normal file → Executable file
View File

@ -40,6 +40,7 @@ class Fulltilt(HandHistoryConverter):
(?P<SB>[.0-9]+)/
\$?(?P<BB>[.0-9]+)\s
(Ante\s\$?(?P<ANTE>[.0-9]+)\s)?-\s
\$?(?P<CAP>[.0-9]+\sCap\s)?
(?P<LIMIT>(No\sLimit|Pot\sLimit|Limit))?\s
(?P<GAME>(Hold\'em|Omaha\sHi|Omaha\sH/L|7\sCard\sStud|Stud\sH/L|Razz|Stud\sHi))
''', re.VERBOSE)
@ -52,6 +53,7 @@ class Fulltilt(HandHistoryConverter):
(?P<TABLE>[-\s\da-zA-Z]+)\s
(\((?P<TABLEATTRIBUTES>.+)\)\s)?-\s
\$?(?P<SB>[.0-9]+)/\$?(?P<BB>[.0-9]+)\s(Ante\s\$?(?P<ANTE>[.0-9]+)\s)?-\s
\$?(?P<CAP>[.0-9]+\sCap\s)?
(?P<GAMETYPE>[a-zA-Z\/\'\s]+)\s-\s
(?P<DATETIME>\d+:\d+:\d+\s\w+\s-\s\d+/\d+/\d+)\s?
(?P<PARTIAL>\(partial\))?\n
@ -143,6 +145,7 @@ class Fulltilt(HandHistoryConverter):
return [["ring", "hold", "nl"],
["ring", "hold", "pl"],
["ring", "hold", "fl"],
["ring", "hold", "cn"],
["ring", "stud", "fl"],
@ -175,7 +178,10 @@ class Fulltilt(HandHistoryConverter):
'Stud H/L' : ('stud','studhilo')
}
currencies = { u'':'EUR', '$':'USD', '':'T$' }
info['limitType'] = limits[mg['LIMIT']]
if mg['CAP']:
info['limitType'] = 'cn'
else:
info['limitType'] = limits[mg['LIMIT']]
info['sb'] = mg['SB']
info['bb'] = mg['BB']
if mg['GAME'] != None:

View File

@ -56,23 +56,32 @@ import Database
import Tables
import Hud
# To add to config:
aggregate_stats = {"ring": False, "tour": False} # uses agg_bb_mult
hud_style = 'A' # A=All-time
# S=Session
# T=timed (last n days - set hud_days to required value)
# Future values may also include:
# H=Hands (last n hands)
hud_days = 90 # Max number of days from each player to use for hud stats
agg_bb_mult = 100 # 1 = no aggregation. When aggregating stats across levels larger blinds
# must be < (agg_bb_mult * smaller blinds) to be aggregated
# ie. 100 will aggregate almost everything, 2 will probably agg just the
# next higher and lower levels into the current one, try 3/10/30/100
hud_session_gap = 30 # Gap (minutes) between hands that indicates a change of session
# (hands every 2 mins for 1 hour = one session, if followed
# by a 40 minute gap and then more hands on same table that is
# a new session)
#hud_hands = 0 # Max number of hands from each player to use for hud stats (not used)
# HUD params:
# - Set aggregate_ring and/or aggregate_tour to True is you want to include stats from other blind levels in the HUD display
# - If aggregation is used, the value of agg_bb_mult determines how what levels are included, e.g.
# if agg_bb_mult is 100, almost all levels are included in all HUD displays
# if agg_bb_mult is 2.1, levels from half to double the current blind level are included in the HUD
# - Set hud_style to A to see stats for all-time
# Set hud_style to S to only see stats for current session (currently this shows stats for the last 24 hours)
# Set hud_style to T to only see stats for the last N days (uses value in hud_days)
# - Set hud_days to N to see stats for the last N days in the HUD (only applies if hud_style is T)
def_hud_params = { # Settings for all players apart from program owner ('hero')
'aggregate_ring' : False
, 'aggregate_tour' : True
, 'hud_style' : 'A'
, 'hud_days' : 90
, 'agg_bb_mult' : 1 # 1 means no aggregation
# , 'hud_session_gap' : 30 not currently used
# Second set of variables for hero - these settings only apply to the program owner
, 'h_aggregate_ring' : False
, 'h_aggregate_tour' : True
, 'h_hud_style' : 'S' # A(ll) / S(ession) / T(ime in days)
, 'h_hud_days' : 30
, 'h_agg_bb_mult' : 1 # 1 means no aggregation
# , 'h_hud_session_gap' : 30 not currently used
}
class HUD_main(object):
"""A main() object to own both the read_stdin thread and the gui."""
@ -82,6 +91,7 @@ class HUD_main(object):
self.db_name = db_name
self.config = Configuration.Config(file=options.config, dbname=options.dbname)
self.hud_dict = {}
self.hud_params = def_hud_params
# a thread to read stdin
gobject.threads_init() # this is required
@ -104,12 +114,17 @@ class HUD_main(object):
# called by an event in the HUD, to kill this specific HUD
if table in self.hud_dict:
self.hud_dict[table].kill()
self.hud_dict[table].main_window.destroy()
try:
# throws exception in windows sometimes (when closing using main_window menu?)
self.hud_dict[table].main_window.destroy()
except:
pass
self.vb.remove(self.hud_dict[table].tablehudlabel)
del(self.hud_dict[table])
self.main_window.resize(1,1)
def create_HUD(self, new_hand_id, table, table_name, max, poker_game, stat_dict, cards):
def create_HUD(self, new_hand_id, table, table_name, max, poker_game, type, stat_dict, cards):
"""type is "ring" or "tour" used to set hud_params"""
def idle_func():
@ -135,6 +150,18 @@ class HUD_main(object):
self.hud_dict[table_name].table_name = table_name
self.hud_dict[table_name].stat_dict = stat_dict
self.hud_dict[table_name].cards = cards
if type == "tour" and self.hud_params['aggregate_tour'] == False:
self.hud_dict[table_name].hud_params['agg_bb_mult'] = 1
elif type == "ring" and self.hud_params['aggregate_ring'] == False:
self.hud_dict[table_name].hud_params['agg_bb_mult'] = 1
if type == "tour" and self.hud_params['h_aggregate_tour'] == False:
self.hud_dict[table_name].hud_params['h_agg_bb_mult'] = 1
elif type == "ring" and self.hud_params['h_aggregate_ring'] == False:
self.hud_dict[table_name].hud_params['h_agg_bb_mult'] = 1
self.hud_params['aggregate_ring'] == True
self.hud_params['h_aggregate_ring'] == True
[aw.update_data(new_hand_id, self.db_connection) for aw in self.hud_dict[table_name].aux_windows]
gobject.idle_add(idle_func)
@ -160,68 +187,99 @@ class HUD_main(object):
# be passed to HUDs for use in the gui thread. HUD objects should not
# need their own access to the database, but should open their own
# if it is required.
self.db_connection = Database.Database(self.config)
self.db_connection.init_hud_stat_vars(hud_days)
tourny_finder = re.compile('(\d+) (\d+)')
try:
self.db_connection = Database.Database(self.config)
tourny_finder = re.compile('(\d+) (\d+)')
while 1: # wait for a new hand number on stdin
new_hand_id = sys.stdin.readline()
new_hand_id = string.rstrip(new_hand_id)
if new_hand_id == "": # blank line means quit
self.destroy()
break # this thread is not always killed immediately with gtk.main_quit()
# get basic info about the new hand from the db
# if there is a db error, complain, skip hand, and proceed
try:
(table_name, max, poker_game, type) = self.db_connection.get_table_name(new_hand_id)
stat_dict = self.db_connection.get_stats_from_hand(new_hand_id, aggregate_stats[type]
,hud_style, agg_bb_mult)
# get hero's screen names and player ids
self.hero, self.hero_ids = {}, {}
for site in self.config.get_supported_sites():
result = self.db_connection.get_site_id(site)
if result:
site_id = result[0][0]
self.hero[site_id] = self.config.supported_sites[site].screen_name
self.hero_ids[site_id] = self.db_connection.get_player_id(self.config, site, self.hero[site_id])
cards = self.db_connection.get_cards(new_hand_id)
comm_cards = self.db_connection.get_common_cards(new_hand_id)
if comm_cards != {}: # stud!
cards['common'] = comm_cards['common']
except Exception, err:
err = traceback.extract_tb(sys.exc_info()[2])[-1]
print "db error: skipping "+str(new_hand_id)+" "+err[2]+"("+str(err[1])+"): "+str(sys.exc_info()[1])
if new_hand_id: # new_hand_id is none if we had an error prior to the store
sys.stderr.write("Database error %s in hand %d. Skipping.\n" % (err, int(new_hand_id)))
continue
while 1: # wait for a new hand number on stdin
new_hand_id = sys.stdin.readline()
new_hand_id = string.rstrip(new_hand_id)
if new_hand_id == "": # blank line means quit
self.destroy()
break # this thread is not always killed immediately with gtk.main_quit()
# get basic info about the new hand from the db
# if there is a db error, complain, skip hand, and proceed
try:
(table_name, max, poker_game, type, site_id) = self.db_connection.get_table_name(new_hand_id)
if type == "tour": # hand is from a tournament
mat_obj = tourny_finder.search(table_name)
if mat_obj:
(tour_number, tab_number) = mat_obj.group(1, 2)
temp_key = tour_number
else: # tourney, but can't get number and table
print "could not find tournament: skipping "
#sys.stderr.write("Could not find tournament %d in hand %d. Skipping.\n" % (int(tour_number), int(new_hand_id)))
cards = self.db_connection.get_cards(new_hand_id)
comm_cards = self.db_connection.get_common_cards(new_hand_id)
if comm_cards != {}: # stud!
cards['common'] = comm_cards['common']
except Exception, err:
err = traceback.extract_tb(sys.exc_info()[2])[-1]
print "db error: skipping "+str(new_hand_id)+" "+err[2]+"("+str(err[1])+"): "+str(sys.exc_info()[1])
if new_hand_id: # new_hand_id is none if we had an error prior to the store
sys.stderr.write("Database error %s in hand %d. Skipping.\n" % (err, int(new_hand_id)))
continue
else:
temp_key = table_name
if type == "tour": # hand is from a tournament
mat_obj = tourny_finder.search(table_name)
if mat_obj:
(tour_number, tab_number) = mat_obj.group(1, 2)
temp_key = tour_number
else: # tourney, but can't get number and table
print "could not find tournament: skipping "
#sys.stderr.write("Could not find tournament %d in hand %d. Skipping.\n" % (int(tour_number), int(new_hand_id)))
continue
# Update an existing HUD
if temp_key in self.hud_dict:
self.hud_dict[temp_key].stat_dict = stat_dict
self.hud_dict[temp_key].cards = cards
[aw.update_data(new_hand_id, self.db_connection) for aw in self.hud_dict[temp_key].aux_windows]
self.update_HUD(new_hand_id, temp_key, self.config)
# Or create a new HUD
else:
if type == "tour":
tablewindow = Tables.discover_tournament_table(self.config, tour_number, tab_number)
else:
tablewindow = Tables.discover_table_by_name(self.config, table_name)
if tablewindow == None:
# If no client window is found on the screen, complain and continue
temp_key = table_name
# Update an existing HUD
if temp_key in self.hud_dict:
try:
# get stats using hud's specific params
self.db_connection.init_hud_stat_vars( self.hud_dict[temp_key].hud_params['hud_days']
, self.hud_dict[temp_key].hud_params['h_hud_days'])
stat_dict = self.db_connection.get_stats_from_hand(new_hand_id, type, self.hud_dict[temp_key].hud_params, self.hero_ids[site_id])
except:
err = traceback.extract_tb(sys.exc_info()[2])[-1]
print "db get_stats error: skipping "+str(new_hand_id)+" "+err[2]+"("+str(err[1])+"): "+str(sys.exc_info()[1])
if new_hand_id: # new_hand_id is none if we had an error prior to the store
sys.stderr.write("Database get_stats error %s in hand %d. Skipping.\n" % (err, int(new_hand_id)))
continue
self.hud_dict[temp_key].stat_dict = stat_dict
self.hud_dict[temp_key].cards = cards
[aw.update_data(new_hand_id, self.db_connection) for aw in self.hud_dict[temp_key].aux_windows]
self.update_HUD(new_hand_id, temp_key, self.config)
# Or create a new HUD
else:
try:
# get stats using default params
self.db_connection.init_hud_stat_vars( self.hud_params['hud_days'], self.hud_params['h_hud_days'] )
stat_dict = self.db_connection.get_stats_from_hand(new_hand_id, type, self.hud_params, self.hero_ids[site_id])
except:
err = traceback.extract_tb(sys.exc_info()[2])[-1]
print "db get_stats error: skipping "+str(new_hand_id)+" "+err[2]+"("+str(err[1])+"): "+str(sys.exc_info()[1])
if new_hand_id: # new_hand_id is none if we had an error prior to the store
sys.stderr.write("Database get_stats error %s in hand %d. Skipping.\n" % (err, int(new_hand_id)))
continue
if type == "tour":
table_name = "%s %s" % (tour_number, tab_number)
sys.stderr.write("table name "+table_name+" not found, skipping.\n")
else:
self.create_HUD(new_hand_id, tablewindow, temp_key, max, poker_game, stat_dict, cards)
self.db_connection.connection.rollback()
tablewindow = Tables.discover_tournament_table(self.config, tour_number, tab_number)
else:
tablewindow = Tables.discover_table_by_name(self.config, table_name)
if tablewindow == None:
# If no client window is found on the screen, complain and continue
if type == "tour":
table_name = "%s %s" % (tour_number, tab_number)
sys.stderr.write("table name "+table_name+" not found, skipping.\n")
else:
self.create_HUD(new_hand_id, tablewindow, temp_key, max, poker_game, type, stat_dict, cards)
self.db_connection.connection.rollback()
except:
err = traceback.extract_tb(sys.exc_info()[2])[-1]
print "***Error: "+err[2]+"("+str(err[1])+"): "+str(sys.exc_info()[1])
if __name__== "__main__":

View File

@ -673,7 +673,14 @@ class HoldemOmahaHand(Hand):
if shown: self.shown.add(player)
if mucked: self.mucked.add(player)
else:
self.addHoleCards('PREFLOP', player, open=[], closed=cards, shown=shown, mucked=mucked, dealt=dealt)
if len(cards) in (2, 4): # avoid adding board by mistake (Everleaf problem)
self.addHoleCards('PREFLOP', player, open=[], closed=cards, shown=shown, mucked=mucked, dealt=dealt)
elif len(cards) == 5: # cards holds a winning hand, not hole cards
# filter( lambda x: x not in b, a ) # calcs a - b where a and b are lists
# so diff is set to the winning hand minus the board cards, if we're lucky that leaves the hole cards
diff = filter( lambda x: x not in self.board['FLOP']+self.board['TURN']+self.board['RIVER'], cards )
if len(diff) == 2 and self.gametype['category'] in ('holdem'):
self.addHoleCards('PREFLOP', player, open=[], closed=diff, shown=shown, mucked=mucked, dealt=dealt)
def getStreetTotals(self):
# street1Pot INT, /* pot size at flop/street4 */

View File

@ -73,6 +73,8 @@ class Hud:
self.stacked = True
self.site = table.site
self.mw_created = False
self.hud_params = parent.hud_params
self.stat_windows = {}
self.popup_windows = {}
@ -144,6 +146,78 @@ class Hud:
menu.append(repositem)
repositem.connect("activate", self.reposition_windows)
aggitem = gtk.MenuItem('Show Stats')
menu.append(aggitem)
self.aggMenu = gtk.Menu()
aggitem.set_submenu(self.aggMenu)
# set agg_bb_mult to 1 to stop aggregation
item = gtk.CheckMenuItem('For This Blind Level Only')
self.aggMenu.append(item)
item.connect("activate", self.set_aggregation, 1)
setattr(self, 'aggBBmultItem1', item)
#
item = gtk.MenuItem('For Multiple Blind Levels:')
self.aggMenu.append(item)
#
item = gtk.CheckMenuItem(' 0.5 to 2.0 x Current Blinds')
self.aggMenu.append(item)
item.connect("activate", self.set_aggregation, 2)
setattr(self, 'aggBBmultItem2', item)
#
item = gtk.CheckMenuItem(' 0.33 to 3.0 x Current Blinds')
self.aggMenu.append(item)
item.connect("activate", self.set_aggregation, 3)
setattr(self, 'aggBBmultItem3', item)
#
item = gtk.CheckMenuItem(' 0.1 to 10 x Current Blinds')
self.aggMenu.append(item)
item.connect("activate", self.set_aggregation, 10)
setattr(self, 'aggBBmultItem10', item)
#
item = gtk.CheckMenuItem(' All Levels')
self.aggMenu.append(item)
item.connect("activate", self.set_aggregation, 10000)
setattr(self, 'aggBBmultItem10000', item)
#
item = gtk.MenuItem('For Hero:')
self.aggMenu.append(item)
setattr(self, 'showStatsMenuItem7', item)
#
item = gtk.CheckMenuItem(' All Time')
self.aggMenu.append(item)
item.connect("activate", self.set_hud_style, 'HA')
setattr(self, 'HAStyleOption', item)
#
item = gtk.CheckMenuItem(' Session')
self.aggMenu.append(item)
item.connect("activate", self.set_hud_style, 'HS')
setattr(self, 'HSStyleOption', item)
#
item = gtk.CheckMenuItem(' %s Days' % (self.hud_params['h_hud_days']))
self.aggMenu.append(item)
item.connect("activate", self.set_hud_style, 'HT')
setattr(self, 'HTStyleOption', item)
# set active on current options:
if self.hud_params['agg_bb_mult'] == 1:
getattr(self, 'aggBBmultItem1').set_active(True)
elif self.hud_params['agg_bb_mult'] == 2:
getattr(self, 'aggBBmultItem2').set_active(True)
elif self.hud_params['agg_bb_mult'] == 3:
getattr(self, 'aggBBmultItem3').set_active(True)
elif self.hud_params['agg_bb_mult'] == 10:
getattr(self, 'aggBBmultItem10').set_active(True)
elif self.hud_params['agg_bb_mult'] > 9000:
getattr(self, 'aggBBmultItemAll').set_active(True)
if self.hud_params['h_hud_style'] == 'A':
getattr(self, 'HAStyleOption').set_active(True)
elif self.hud_params['h_hud_style'] == 'S':
getattr(self, 'HSStyleOption').set_active(True)
elif self.hud_params['h_hud_style'] == 'T':
getattr(self, 'HTStyleOption').set_active(True)
eventbox.connect_object("button-press-event", self.on_button_press, menu)
debugitem = gtk.MenuItem('Debug StatWindows')
menu.append(debugitem)
debugitem.connect("activate", self.debug_stat_windows)
@ -176,9 +250,46 @@ class Hud:
self.create(*self.creation_attrs)
self.update(self.hand, self.config)
except Exception, e:
print "Expcetion:",str(e)
print "Exception:",str(e)
pass
def set_aggregation(self, widget, val):
# try setting these to true all the time, and set the multiplier to 1 to turn agg off:
self.hud_params['aggregate_ring'] = True
self.hud_params['aggregate_tour'] = True
self.hud_params['h_aggregate_ring'] = True
self.hud_params['h_aggregate_tour'] = True
if self.hud_params['agg_bb_mult'] != val \
and getattr(self, 'aggBBmultItem'+str(val)).get_active():
print 'set_aggregation', val
self.hud_params['agg_bb_mult'] = val
self.hud_params['h_agg_bb_mult'] = val
for mult in ('1', '2', '3', '10', '10000'):
if mult != str(val):
getattr(self, 'aggBBmultItem'+mult).set_active(False)
def set_hud_style(self, widget, val):
# try setting these to true all the time, and set the multiplier to 1 to turn agg off:
if val[0] == 'H':
param = 'h_hud_style'
else:
param = 'hud_style'
if val[1] == 'A' and getattr(self, 'HAStyleOption').get_active():
self.hud_params[param] = 'A'
getattr(self, 'HSStyleOption').set_active(False)
getattr(self, 'HTStyleOption').set_active(False)
elif val[1] == 'S' and getattr(self, 'HSStyleOption').get_active():
self.hud_params[param] = 'S'
getattr(self, 'HAStyleOption').set_active(False)
getattr(self, 'HTStyleOption').set_active(False)
elif val[1] == 'T' and self.HTStyleOption.get_active():
self.hud_params[param] = 'T'
getattr(self, 'HAStyleOption').set_active(False)
getattr(self, 'HSStyleOption').set_active(False)
print "setting self.hud_params[%s] = %s" % (param, val[1])
def update_table_position(self):
if os.name == 'nt':
if not win32gui.IsWindow(self.table.number):
@ -218,7 +329,11 @@ class Hud:
# heap dead, burnt bodies, blood 'n guts, veins between my teeth
for s in self.stat_windows.itervalues():
s.kill_popups()
s.window.destroy()
try:
# throws "invalid window handle" in WinXP (sometimes?)
s.window.destroy()
except:
pass
self.stat_windows = {}
# also kill any aux windows
for aux in self.aux_windows:

View File

@ -331,7 +331,8 @@ class Sql:
speed varchar(10),
headsUp BOOLEAN NOT NULL DEFAULT False,
shootout BOOLEAN NOT NULL DEFAULT False,
matrix BOOLEAN NOT NULL DEFAULT False
matrix BOOLEAN NOT NULL DEFAULT False,
sng BOOLEAN NOT NULL DEFAULT False
)
ENGINE=INNODB"""
elif db_server == 'postgresql':
@ -346,7 +347,8 @@ class Sql:
speed varchar(10),
headsUp BOOLEAN NOT NULL DEFAULT False,
shootout BOOLEAN NOT NULL DEFAULT False,
matrix BOOLEAN NOT NULL DEFAULT False
matrix BOOLEAN NOT NULL DEFAULT False,
sng BOOLEAN NOT NULL DEFAULT False
)"""
elif db_server == 'sqlite':
self.query['createTourneyTypesTable'] = """CREATE TABLE TourneyTypes (
@ -360,7 +362,8 @@ class Sql:
speed TEXT,
headsUp BOOLEAN NOT NULL DEFAULT 0,
shootout BOOLEAN NOT NULL DEFAULT 0,
matrix BOOLEAN NOT NULL DEFAULT 0
matrix BOOLEAN NOT NULL DEFAULT 0,
sng BOOLEAN NOT NULL DEFAULT 0
)"""
################################
@ -820,7 +823,21 @@ class Sql:
comment TEXT,
commentTs timestamp without time zone)"""
elif db_server == 'sqlite':
self.query['createTourneysPlayersTable'] = """ """
self.query['createTourneysPlayersTable'] = """CREATE TABLE TourneysPlayers (
id INT PRIMARY KEY,
tourneyId INT,
playerId INT,
payinAmount INT,
rank INT,
winnings INT,
nbRebuys INT DEFAULT 0,
nbAddons INT DEFAULT 0,
nbKO INT DEFAULT 0,
comment TEXT,
commentTs timestamp without time zone,
FOREIGN KEY (tourneyId) REFERENCES Tourneys(id),
FOREIGN KEY (playerId) REFERENCES Players(id)
)"""
################################
@ -851,7 +868,18 @@ class Sql:
comment TEXT,
commentTs timestamp without time zone)"""
elif db_server == 'sqlite':
self.query['createHandsActionsTable'] = """ """
self.query['createHandsActionsTable'] = """CREATE TABLE HandsActions (
id INT PRIMARY KEY,
handsPlayerId BIGINT,
street SMALLINT,
actionNo SMALLINT,
action CHAR(5),
allIn INT,
amount INT,
comment TEXT,
commentTs timestamp without time zone,
FOREIGN KEY (handsPlayerId) REFERENCES HandsPlayers(id)
)"""
################################
@ -1160,26 +1188,42 @@ class Sql:
if db_server == 'mysql':
self.query['addTourneyIndex'] = """ALTER TABLE Tourneys ADD INDEX siteTourneyNo(siteTourneyNo)"""
self.query['addTourneyIndex'] = """ALTER TABLE Tourneys ADD UNIQUE INDEX siteTourneyNo(siteTourneyNo, tourneyTypeId)"""
elif db_server == 'postgresql':
self.query['addTourneyIndex'] = """CREATE INDEX siteTourneyNo ON Tourneys (siteTourneyNo)"""
self.query['addTourneyIndex'] = """CREATE UNIQUE INDEX siteTourneyNo ON Tourneys (siteTourneyNo, tourneyTypeId)"""
elif db_server == 'sqlite':
self.query['addHandsIndex'] = """ """
self.query['addTourneyIndex'] = """CREATE UNIQUE INDEX siteTourneyNo ON Tourneys (siteTourneyNo, tourneyTypeId)"""
if db_server == 'mysql':
self.query['addHandsIndex'] = """ALTER TABLE Hands ADD INDEX siteHandNo(siteHandNo)"""
self.query['addHandsIndex'] = """ALTER TABLE Hands ADD UNIQUE INDEX siteHandNo(siteHandNo, gameTypeId)"""
elif db_server == 'postgresql':
self.query['addHandsIndex'] = """CREATE INDEX siteHandNo ON Hands (siteHandNo)"""
self.query['addHandsIndex'] = """CREATE UNIQUE INDEX siteHandNo ON Hands (siteHandNo, gameTypeId)"""
elif db_server == 'sqlite':
self.query['addHandsIndex'] = """ """
self.query['addHandsIndex'] = """CREATE UNIQUE INDEX siteHandNo ON Hands (siteHandNo, gameTypeId)"""
if db_server == 'mysql':
self.query['addPlayersIndex'] = """ALTER TABLE Players ADD INDEX name(name)"""
self.query['addPlayersIndex'] = """ALTER TABLE Players ADD UNIQUE INDEX name(name, siteId)"""
elif db_server == 'postgresql':
self.query['addPlayersIndex'] = """CREATE INDEX name ON Players (name)"""
self.query['addPlayersIndex'] = """CREATE UNIQUE INDEX name ON Players (name, siteId)"""
elif db_server == 'sqlite':
self.query['addPlayersIndex'] = """ """
self.query['addPlayersIndex'] = """CREATE UNIQUE INDEX name ON Players (name, siteId)"""
if db_server == 'mysql':
self.query['addTPlayersIndex'] = """ALTER TABLE TourneysPlayers ADD UNIQUE INDEX tourneyId(tourneyId, playerId)"""
elif db_server == 'postgresql':
self.query['addTPlayersIndex'] = """CREATE UNIQUE INDEX tourneyId ON TourneysPlayers (tourneyId, playerId)"""
elif db_server == 'sqlite':
self.query['addTPlayersIndex'] = """CREATE UNIQUE INDEX tourneyId ON TourneysPlayers (tourneyId, playerId)"""
if db_server == 'mysql':
self.query['addTTypesIndex'] = """ALTER TABLE TourneyTypes ADD UNIQUE INDEX tourneytypes_all(buyin, fee
, maxSeats, knockout, rebuyOrAddon, speed, headsUp, shootout, matrix, sng)"""
elif db_server == 'postgresql':
self.query['addTTypesIndex'] = """CREATE UNIQUE INDEX tourneyTypes_all ON TourneyTypes (buyin, fee
, maxSeats, knockout, rebuyOrAddon, speed, headsUp, shootout, matrix, sng)"""
elif db_server == 'sqlite':
self.query['addTTypesIndex'] = """CREATE UNIQUE INDEX tourneyTypes_all ON TourneyTypes (buyin, fee
, maxSeats, knockout, rebuyOrAddon, speed, headsUp, shootout, matrix, sng)"""
self.query['get_last_hand'] = "select max(id) from Hands"
@ -1188,7 +1232,7 @@ class Sql:
from Players, Sites
where Players.name = %s
and Sites.name = %s
and Players.SiteId = Sites.id
and Players.siteId = Sites.id
"""
self.query['getSiteId'] = """SELECT id from Sites where name = %s"""
@ -1340,28 +1384,45 @@ class Sql:
INNER JOIN HudCache hc ON (hc.playerId = hp.playerId)
INNER JOIN Players p ON (p.id = hc.playerId)
WHERE h.id = %s
AND hc.styleKey > %s
/* styleKey is currently 'd' (for date) followed by a yyyymmdd
date key. Set it to 0000000 or similar to get all records */
/* Note: s means the placeholder 'percent's but we can't include that
in comments. (db api thinks they are actual arguments)
Could also check activeseats here even if only 3 groups eg 2-3/4-6/7+
e.g. could use a multiplier:
AND h.seats > s / 1.25 and hp.seats < s * 1.25
where s is the number of active players at the current table (and
1.25 would be a config value so user could change it)
*/
AND hc.gametypeId+0 in
(SELECT gt1.id from Gametypes gt1, Gametypes gt2
WHERE gt1.siteid = gt2.siteid /* find gametypes where these match: */
AND gt1.type = gt2.type /* ring/tourney */
AND gt1.category = gt2.category /* holdem/stud*/
AND gt1.limittype = gt2.limittype /* fl/nl */
AND gt1.bigblind < gt2.bigblind * %s /* bigblind similar size */
AND gt1.bigblind > gt2.bigblind / %s
AND gt2.id = h.gametypeId)
AND ( /* 2 separate parts for hero and opponents */
( hp.playerId != %s
AND hc.styleKey > %s
AND hc.gametypeId+0 in
(SELECT gt1.id from Gametypes gt1, Gametypes gt2
WHERE gt1.siteid = gt2.siteid /* find gametypes where these match: */
AND gt1.type = gt2.type /* ring/tourney */
AND gt1.category = gt2.category /* holdem/stud*/
AND gt1.limittype = gt2.limittype /* fl/nl */
AND gt1.bigblind <= gt2.bigblind * %s /* bigblind similar size */
AND gt1.bigblind >= gt2.bigblind / %s
AND gt2.id = h.gametypeId)
)
OR
( hp.playerId = %s
AND hc.styleKey > %s
AND hc.gametypeId+0 in
(SELECT gt1.id from Gametypes gt1, Gametypes gt2
WHERE gt1.siteid = gt2.siteid /* find gametypes where these match: */
AND gt1.type = gt2.type /* ring/tourney */
AND gt1.category = gt2.category /* holdem/stud*/
AND gt1.limittype = gt2.limittype /* fl/nl */
AND gt1.bigblind <= gt2.bigblind * %s /* bigblind similar size */
AND gt1.bigblind >= gt2.bigblind / %s
AND gt2.id = h.gametypeId)
)
)
GROUP BY hc.PlayerId, p.name
"""
# NOTES on above cursor:
# - Do NOT include %s inside query in a comment - the db api thinks
# they are actual arguments.
# - styleKey is currently 'd' (for date) followed by a yyyymmdd
# date key. Set it to 0000000 or similar to get all records
# Could also check activeseats here even if only 3 groups eg 2-3/4-6/7+
# e.g. could use a multiplier:
# AND h.seats > %s / 1.25 and hp.seats < %s * 1.25
# where %s is the number of active players at the current table (and
# 1.25 would be a config value so user could change it)
if db_server == 'mysql':
self.query['get_stats_from_hand_session'] = """
@ -1537,10 +1598,11 @@ class Sql:
"""
self.query['get_table_name'] = """
select tableName, maxSeats, category, type
from Hands,Gametypes
where Hands.id = %s
and Gametypes.id = Hands.gametypeId
select h.tableName, h.maxSeats, gt.category, gt.type, gt.siteId
from Hands h
,Gametypes gt
where h.id = %s
and gt.id = h.gametypeId
"""
self.query['get_actual_seat'] = """
@ -2466,6 +2528,7 @@ class Sql:
,sum(street4CheckCallRaiseDone)
FROM HandsPlayers hp
INNER JOIN Hands h ON (h.id = hp.handId)
<where_clause>
GROUP BY h.gametypeId
,hp.playerId
,h.seats
@ -2614,6 +2677,7 @@ class Sql:
,sum(CAST(street4CheckCallRaiseDone as integer))
FROM HandsPlayers hp
INNER JOIN Hands h ON (h.id = hp.handId)
<where_clause>
GROUP BY h.gametypeId
,hp.playerId
,h.seats
@ -2762,6 +2826,7 @@ class Sql:
,sum(CAST(street4CheckCallRaiseDone as integer))
FROM HandsPlayers hp
INNER JOIN Hands h ON (h.id = hp.handId)
<where_clause>
GROUP BY h.gametypeId
,hp.playerId
,h.seats
@ -2770,9 +2835,14 @@ class Sql:
,'d' || substr(strftime('%Y%m%d', h.handStart),3,7)
"""
self.query['get_hero_hudcache_start'] = """select min(hc.styleKey)
from HudCache hc
where hc.playerId in <playerid_list>
and hc.styleKey like 'd%'"""
if db_server == 'mysql':
self.query['analyze'] = """
analyze table Autorates, GameTypes, Hands, HandsPlayers, Hudcache, Players
analyze table Autorates, GameTypes, Hands, HandsPlayers, HudCache, Players
, Settings, Sites, Tourneys, TourneysPlayers, TourneyTypes
"""
else: # assume postgres

View File

@ -376,7 +376,7 @@ def clean_title(name):
"""Clean the little info strings from the table name."""
# these strings could go in a config file
for pattern in [' \(6 max\)', ' \(heads up\)', ' \(deep\)',
' \(deep hu\)', ' \(deep 6\)', ' \(2\)',
' \(deep hu\)', ' \(deep 6\)', '\(6 max, deep\)', ' \(2\)',
' \(edu\)', ' \(edu, 6 max\)', ' \(6\)',
' \(speed\)', 'special', 'newVPP',
' no all-in', ' fast', ',', ' 50BB min', '50bb min', '\s+$']:

View File

@ -248,7 +248,7 @@ class ttracker_main(object):
# get basic info about the new hand from the db
# if there is a db error, complain, skip hand, and proceed
try:
(table_name, max, poker_game, type) = self.db_connection.get_table_name(new_hand_id)
(table_name, max, poker_game, type, site_id) = self.db_connection.get_table_name(new_hand_id)
stat_dict = self.db_connection.get_stats_from_hand(new_hand_id, aggregate_stats[type]
,hud_style, agg_bb_mult)

View File

@ -257,18 +257,66 @@ class fpdb:
def dia_recreate_hudcache(self, widget, data=None):
if self.obtain_global_lock():
dia_confirm = gtk.MessageDialog(parent=None, flags=0, type=gtk.MESSAGE_WARNING, buttons=(gtk.BUTTONS_YES_NO), message_format="Confirm recreating HUD cache")
self.dia_confirm = gtk.MessageDialog(parent=None, flags=0, type=gtk.MESSAGE_WARNING, buttons=(gtk.BUTTONS_YES_NO), message_format="Confirm recreating HUD cache")
diastring = "Please confirm that you want to re-create the HUD cache."
dia_confirm.format_secondary_text(diastring)
self.dia_confirm.format_secondary_text(diastring)
response = dia_confirm.run()
dia_confirm.destroy()
hb = gtk.HBox(True, 1)
self.start_date = gtk.Entry(max=12)
self.start_date.set_text( self.db.get_hero_hudcache_start() )
lbl = gtk.Label(" Hero's cache starts: ")
btn = gtk.Button()
btn.set_image(gtk.image_new_from_stock(gtk.STOCK_INDEX, gtk.ICON_SIZE_BUTTON))
btn.connect('clicked', self.__calendar_dialog, self.start_date)
hb.pack_start(lbl, expand=True, padding=3)
hb.pack_start(self.start_date, expand=True, padding=2)
hb.pack_start(btn, expand=False, padding=3)
self.dia_confirm.vbox.add(hb)
hb.show_all()
response = self.dia_confirm.run()
self.dia_confirm.destroy()
if response == gtk.RESPONSE_YES:
self.db.rebuild_hudcache()
elif response == gtk.REPSONSE_NO:
self.db.rebuild_hudcache( self.start_date.get_text() )
elif response == gtk.RESPONSE_NO:
print 'User cancelled rebuilding hud cache'
self.release_global_lock()
def __calendar_dialog(self, widget, entry):
self.dia_confirm.set_modal(False)
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 __get_dates(self):
t1 = self.start_date.get_text()
if t1 == '':
t1 = '1970-01-01'
return (t1)
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()
self.dia_confirm.set_modal(True)
def dia_regression_test(self, widget, data=None):
self.warning_box("Unimplemented: Regression Test")
self.obtain_global_lock()

View File

@ -38,6 +38,8 @@ class fpdb_db:
MYSQL_INNODB = 2
PGSQL = 3
SQLITE = 4
sqlite_db_dir = ".." + os.sep + "database"
def __init__(self):
"""Simple constructor, doesnt really do anything"""
self.db = None
@ -119,7 +121,12 @@ class fpdb_db:
sqlite3 = pool.manage(sqlite3, pool_size=1)
else:
logging.warning("SQLite won't work well without 'sqlalchemy' installed.")
self.db = sqlite3.connect(database,detect_types=sqlite3.PARSE_DECLTYPES)
if not os.path.isdir(self.sqlite_db_dir):
print "Creating directory: '%s'" % (self.sqlite_db_dir)
os.mkdir(self.sqlite_db_dir)
self.db = sqlite3.connect( self.sqlite_db_dir + os.sep + database
, detect_types=sqlite3.PARSE_DECLTYPES )
sqlite3.register_converter("bool", lambda x: bool(int(x)))
sqlite3.register_adapter(bool, lambda x: "1" if x else "0")
else:

View File

@ -547,7 +547,7 @@ class Importer:
if self.callHud:
#print "call to HUD here. handsId:",handsId
#pipe the Hands.id out to the HUD
#print "sending hand to hud", handsId, "pipe =", self.caller.pipe_to_hud
print "sending hand to hud", handsId, "pipe =", self.caller.pipe_to_hud
self.caller.pipe_to_hud.stdin.write("%s" % (handsId) + os.linesep)
except Exceptions.DuplicateError:
duplicates += 1

View File

@ -81,7 +81,7 @@ def mainParser(settings, siteID, category, hand, config, db = None, writeq = Non
fee = fpdb_simple.parseFee(hand[0])
entries = -1 #todo: parse this
prizepool = -1 #todo: parse this
knockout = 0
knockout = False
tourneyStartTime= handStartTime #todo: read tourney start time
rebuyOrAddon = fpdb_simple.isRebuyOrAddon(hand[0])
@ -118,7 +118,7 @@ def mainParser(settings, siteID, category, hand, config, db = None, writeq = Non
seatLines.append(line)
names = fpdb_simple.parseNames(seatLines)
playerIDs = fpdb_simple.recognisePlayerIDs(db, names, siteID) # inserts players as needed
playerIDs = db.recognisePlayerIDs(names, siteID) # inserts players as needed
tmp = fpdb_simple.parseCashesAndSeatNos(seatLines)
startCashes = tmp['startCashes']
seatNos = tmp['seatNos']

View File

@ -913,92 +913,54 @@ def recogniseGametypeID(backend, db, cursor, topline, smallBlindLine, site_id, c
#end def recogniseGametypeID
def recogniseTourneyTypeId(db, siteId, tourneySiteId, buyin, fee, knockout, rebuyOrAddon):
ret = -1
cursor = db.get_cursor()
# First we try to find the tourney itself (by its tourneySiteId) in case it has already been inserted before (by a summary file for instance)
# The reason is that some tourneys may not be identified correctly in the HH toplines (especially Buy-In and Fee which are used to search/create the TourneyTypeId)
#TODO: When the summary file will be dumped to BD, if the tourney is already in, Buy-In/Fee may need an update (e.g. creation of a new type and link to the Tourney)
cursor.execute (db.sql.query['getTourneyTypeIdByTourneyNo'].replace('%s', db.sql.query['placeholder']), (tourneySiteId, siteId))
result=cursor.fetchone()
result = cursor.fetchone()
try:
len(result)
ret = result[0]
except:
cursor.execute ("SELECT id FROM TourneyTypes WHERE siteId=%s AND buyin=%s AND fee=%s AND knockout=%s AND rebuyOrAddon=%s", (siteId, buyin, fee, knockout, rebuyOrAddon))
result=cursor.fetchone()
#print "tried SELECTing gametypes.id, result:",result
cursor.execute( """SELECT id FROM TourneyTypes
WHERE siteId=%s AND buyin=%s AND fee=%s
AND knockout=%s AND rebuyOrAddon=%s"""
, (siteId, buyin, fee, knockout, rebuyOrAddon) )
result = cursor.fetchone()
#print "tried selecting tourneytypes.id, result:", result
try:
len(result)
ret = result[0]
except TypeError:#this means we need to create a new entry
cursor.execute("""INSERT INTO TourneyTypes (siteId, buyin, fee, knockout, rebuyOrAddon) VALUES (%s, %s, %s, %s, %s)""", (siteId, buyin, fee, knockout, rebuyOrAddon))
cursor.execute("SELECT id FROM TourneyTypes WHERE siteId=%s AND buyin=%s AND fee=%s AND knockout=%s AND rebuyOrAddon=%s", (siteId, buyin, fee, knockout, rebuyOrAddon))
result=cursor.fetchone()
#print "insert new tourneytype record ..."
try:
cursor.execute( """INSERT INTO TourneyTypes (siteId, buyin, fee, knockout, rebuyOrAddon)
VALUES (%s, %s, %s, %s, %s)"""
, (siteId, buyin, fee, knockout, rebuyOrAddon) )
ret = db.get_last_insert_id(cursor)
except:
#print "maybe tourneytype was created since select, try selecting again ..."
cursor.execute( """SELECT id FROM TourneyTypes
WHERE siteId=%s AND buyin=%s AND fee=%s
AND knockout=%s AND rebuyOrAddon=%s"""
, (siteId, buyin, fee, knockout, rebuyOrAddon) )
result = cursor.fetchone()
try:
len(result)
ret = result[0]
except:
print "Failed to find or insert TourneyTypes record"
ret = -1 # failed to find or insert record
#print "tried selecting tourneytypes.id again, result:", result
return result[0]
#print "recogniseTourneyTypeId: returning", ret
return ret
#end def recogniseTourneyTypeId
#returns the SQL ids of the names given in an array
# TODO: if someone gets industrious, they should make the parts that use the output of this function deal with a dict
# { playername: id } instead of depending on it's relation to the positions list
# then this can be reduced in complexity a bit
#def recognisePlayerIDs(cursor, names, site_id):
# result = []
# for i in xrange(len(names)):
# cursor.execute ("SELECT id FROM Players WHERE name=%s", (names[i],))
# tmp=cursor.fetchall()
# if (len(tmp)==0): #new player
# cursor.execute ("INSERT INTO Players (name, siteId) VALUES (%s, %s)", (names[i], site_id))
# #print "Number of players rows inserted: %d" % cursor.rowcount
# cursor.execute ("SELECT id FROM Players WHERE name=%s", (names[i],))
# tmp=cursor.fetchall()
# #print "recognisePlayerIDs, names[i]:",names[i],"tmp:",tmp
# result.append(tmp[0][0])
# return result
def recognisePlayerIDs(db, names, site_id):
c = db.get_cursor()
q = "SELECT name,id FROM Players WHERE siteid=%d and (name=%s)" %(site_id, " OR name=".join([db.sql.query['placeholder'] for n in names]))
c.execute(q, names) # get all playerids by the names passed in
ids = dict(c.fetchall()) # convert to dict
if len(ids) != len(names):
notfound = [n for n in names if n not in ids] # make list of names not in database
if notfound: # insert them into database
q_ins = "INSERT INTO Players (name, siteId) VALUES (%s, "+str(site_id)+")"
q_ins = q_ins.replace('%s', db.sql.query['placeholder'])
c.executemany(q_ins, [(n,) for n in notfound])
q2 = "SELECT name,id FROM Players WHERE siteid=%d and (name=%s)" % (site_id, " OR name=".join(["%s" for n in notfound]))
q2 = q2.replace('%s', db.sql.query['placeholder'])
c.execute(q2, notfound) # get their new ids
tmp = c.fetchall()
for n,id in tmp: # put them all into the same dict
ids[n] = id
# return them in the SAME ORDER that they came in in the names argument, rather than the order they came out of the DB
return [ids[n] for n in names]
#end def recognisePlayerIDs
# Here's a version that would work if it wasn't for the fact that it needs to have the output in the same order as input
# this version could also be improved upon using list comprehensions, etc
#def recognisePlayerIDs(cursor, names, site_id):
# result = []
# notfound = []
# cursor.execute("SELECT name,id FROM Players WHERE name='%s'" % "' OR name='".join(names))
# tmp = dict(cursor.fetchall())
# for n in names:
# if n not in tmp:
# notfound.append(n)
# else:
# result.append(tmp[n])
# if notfound:
# cursor.executemany("INSERT INTO Players (name, siteId) VALUES (%s, "+str(site_id)+")", (notfound))
# cursor.execute("SELECT id FROM Players WHERE name='%s'" % "' OR name='".join(notfound))
# tmp = cursor.fetchall()
# for n in tmp:
# result.append(n[0])
#
# return result
#recognises the name in the given line and returns its array position in the given array
def recognisePlayerNo(line, names, atype):

17
setup.py Normal file
View File

@ -0,0 +1,17 @@
# setup.py
# Python packaging for fpdb
from distutils.core import setup
setup(name = 'fpdb',
description = 'Free Poker Database',
version = '0.10.999',
author = 'FPDB team',
author_email = 'fpdb-main@lists.sourceforge.net',
packages = ['fpdb'],
package_dir = { 'fpdb' : 'pyfpdb' },
data_files = [
('/usr/share/doc/python-fpdb',
['docs/readme.txt', 'docs/release-notes.txt',
'docs/tabledesign.html', 'THANKS.txt'])]
)