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: if value1 < 2 or value2 < 2:
ret = 0 ret = 0
if value1 == value2: # pairs if value1 == value2: # pairs
ret = (13 * (value2-2) + (value2-1) ) ret = (13 * (value2-2) + (value2-2) )
elif suit1 == suit2: elif suit1 == suit2:
if value1 > value2: if value1 > value2:
ret = 13 * (value1-2) + (value2-1) ret = 13 * (value1-2) + (value2-2)
else: else:
ret = 13 * (value2-2) + (value1-1) ret = 13 * (value2-2) + (value1-2)
else: else:
if value1 > value2: if value1 > value2:
ret = 13 * (value2-2) + (value2-1) ret = 13 * (value2-2) + (value1-2)
else: else:
ret = 13 * (value1-2) + (value2-1) ret = 13 * (value1-2) + (value2-2)
# print "twoStartCards(", value1, suit1, value2, suit2, ")=", ret # print "twoStartCards(", value1, suit1, value2, suit2, ")=", ret
return ret return ret
@ -46,7 +46,6 @@ def twoStartCardString(card):
into a string like AQo """ into a string like AQo """
ret = 'xx' ret = 'xx'
if card > 0: if card > 0:
card -= 1
s = ('2', '3', '4', '5', '6', '7', '8', '9', 'T', 'J', 'Q', 'K', 'A') s = ('2', '3', '4', '5', '6', '7', '8', '9', 'T', 'J', 'Q', 'K', 'A')
x = card / 13 x = card / 13
y = card - 13 * x 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")) logging.config.fileConfig(os.path.join(sys.path[0],"logging.conf"))
log = logging.getLogger('db') log = logging.getLogger('db')
class Database: class Database:
MYSQL_INNODB = 2 MYSQL_INNODB = 2
PGSQL = 3 PGSQL = 3
SQLITE = 4 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 # Data Structures for index and foreign key creation
# drop_code is an int with possible values: 0 - don't drop for bulk import # drop_code is an int with possible values: 0 - don't drop for bulk import
# 1 - drop during bulk import # 1 - drop during bulk import
@ -70,19 +73,19 @@ class Database:
[ ] # no db with index 0 [ ] # no db with index 0
, [ ] # no db with index 1 , [ ] # no db with index 1
, [ # indexes for mysql (list index 2) , [ # indexes for mysql (list index 2)
{'tab':'Players', 'col':'name', 'drop':0} # {'tab':'Players', 'col':'name', 'drop':0} unique indexes not dropped
, {'tab':'Hands', 'col':'siteHandNo', 'drop':0} # {'tab':'Hands', 'col':'siteHandNo', 'drop':0} unique indexes not dropped
, {'tab':'Hands', 'col':'gametypeId', 'drop':0} # mct 22/3/09 {'tab':'Hands', 'col':'gametypeId', 'drop':0} # mct 22/3/09
, {'tab':'HandsPlayers', 'col':'handId', 'drop':0} # not needed, handled by fk , {'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':'playerId', 'drop':0} # not needed, handled by fk
, {'tab':'HandsPlayers', 'col':'tourneyTypeId', 'drop':0} , {'tab':'HandsPlayers', 'col':'tourneyTypeId', 'drop':0}
, {'tab':'HandsPlayers', 'col':'tourneysPlayersId', '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) , [ # indexes for postgres (list index 3)
{'tab':'Gametypes', 'col':'siteId', 'drop':0} {'tab':'Gametypes', 'col':'siteId', 'drop':0}
, {'tab':'Hands', 'col':'gametypeId', 'drop':0} # mct 22/3/09 , {'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':'HandsActions', 'col':'handsPlayerId', 'drop':0}
, {'tab':'HandsPlayers', 'col':'handId', 'drop':1} , {'tab':'HandsPlayers', 'col':'handId', 'drop':1}
, {'tab':'HandsPlayers', 'col':'playerId', 'drop':1} , {'tab':'HandsPlayers', 'col':'playerId', 'drop':1}
@ -91,22 +94,22 @@ class Database:
, {'tab':'HudCache', 'col':'playerId', 'drop':0} , {'tab':'HudCache', 'col':'playerId', 'drop':0}
, {'tab':'HudCache', 'col':'tourneyTypeId', 'drop':0} , {'tab':'HudCache', 'col':'tourneyTypeId', 'drop':0}
, {'tab':'Players', 'col':'siteId', 'drop':1} , {'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':'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':'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} , {'tab':'TourneyTypes', 'col':'siteId', 'drop':0}
] ]
, [ # indexes for sqlite (list index 4) , [ # indexes for sqlite (list index 4)
{'tab':'Players', 'col':'name', 'drop':0} # {'tab':'Players', 'col':'name', 'drop':0} unique indexes not dropped
, {'tab':'Hands', 'col':'siteHandNo', 'drop':0} # {'tab':'Hands', 'col':'siteHandNo', 'drop':0} unique indexes not dropped
, {'tab':'Hands', 'col':'gametypeId', 'drop':0} {'tab':'Hands', 'col':'gametypeId', 'drop':0}
, {'tab':'HandsPlayers', 'col':'handId', 'drop':0} , {'tab':'HandsPlayers', 'col':'handId', 'drop':0}
, {'tab':'HandsPlayers', 'col':'playerId', 'drop':0} , {'tab':'HandsPlayers', 'col':'playerId', 'drop':0}
, {'tab':'HandsPlayers', 'col':'tourneyTypeId', 'drop':0} , {'tab':'HandsPlayers', 'col':'tourneyTypeId', 'drop':0}
, {'tab':'HandsPlayers', 'col':'tourneysPlayersId', '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): def __init__(self, c, sql = None):
log.info("Creating Database instance, sql = %s" % sql) 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 = fpdb_db.fpdb_db() # sets self.fdb.db self.fdb.cursor and self.fdb.sql
self.fdb.do_connect(c) self.fdb.do_connect(c)
self.connection = self.fdb.db 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 #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: # 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.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_ndays_ago = 'd000000' # date N days ago ('d' + YYMMDD)
self.date_nhands_ago = {} # dates N hands ago per player - not used yet 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 self.cursor = self.fdb.cursor
@ -367,8 +372,12 @@ class Database:
winners[row[0]] = row[1] winners[row[0]] = row[1]
return winners return winners
def init_hud_stat_vars(self, hud_days): def init_hud_stat_vars(self, hud_days, h_hud_days):
"""Initialise variables used by Hud to fetch stats.""" """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 self.hand_1day_ago = 1
try: try:
@ -381,9 +390,14 @@ class Database:
else: else:
if row and row[0]: if row and row[0]:
self.hand_1_day_ago = row[0] self.hand_1_day_ago = row[0]
d = timedelta(days=hud_days)
now = datetime.utcnow() - d d = timedelta(days=hud_days)
self.date_ndays_ago = "d%02d%02d%02d" % (now.year - 2000, now.month, now.day) 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): def init_player_hud_stat_vars(self, playerid):
# not sure if this is workable, to be continued ... # not sure if this is workable, to be continued ...
@ -403,26 +417,48 @@ class Database:
err = traceback.extract_tb(sys.exc_info()[2])[-1] err = traceback.extract_tb(sys.exc_info()[2])[-1]
print "***Error: "+err[2]+"("+str(err[1])+"): "+str(sys.exc_info()[1]) print "***Error: "+err[2]+"("+str(err[1])+"): "+str(sys.exc_info()[1])
def get_stats_from_hand(self, hand, aggregate = False, hud_style = 'A', agg_bb_mult = 100): def get_stats_from_hand( self, hand, type # type is "ring" or "tour"
if hud_style == 'S': , 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': if h_hud_style == 'T':
stylekey = self.date_ndays_ago h_stylekey = self.h_date_ndays_ago
#elif hud_style == 'H': elif h_hud_style == 'A':
# stylekey = date_nhands_ago needs array by player here ... h_stylekey = '0000000' # all stylekey values should be higher than this
else: # assume A (all-time) elif h_hud_style == 'S':
stylekey = '0000000' # all stylekey values should be higher than this 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: #if aggregate: always use aggreagte query now: use agg_bb_mult of 1 for no aggregation:
query = 'get_stats_from_hand_aggregated' query = 'get_stats_from_hand_aggregated'
subs = (hand, stylekey, agg_bb_mult, agg_bb_mult) subs = (hand, hero_id, stylekey, agg_bb_mult, agg_bb_mult, hero_id, h_stylekey, h_agg_bb_mult, h_agg_bb_mult)
else: print "agg query subs:", subs
query = 'get_stats_from_hand' #else:
subs = (hand, stylekey) # query = 'get_stats_from_hand'
# subs = (hand, stylekey)
#print "get stats: hud style =", hud_style, "query =", query, "subs =", subs #print "get stats: hud style =", hud_style, "query =", query, "subs =", subs
c = self.connection.cursor() c = self.connection.cursor()
@ -430,7 +466,6 @@ class Database:
# now get the stats # now get the stats
c.execute(self.sql.query[query], subs) c.execute(self.sql.query[query], subs)
colnames = [desc[0] for desc in c.description] colnames = [desc[0] for desc in c.description]
stat_dict = {}
for row in c.fetchall(): for row in c.fetchall():
t_dict = {} t_dict = {}
for name, val in zip(colnames, row): for name, val in zip(colnames, row):
@ -441,7 +476,13 @@ class Database:
return stat_dict return stat_dict
# uses query on handsplayers instead of hudcache to get stats on just this session # 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'] query = self.sql.query['get_stats_from_hand_session']
if self.db_server == 'mysql': if self.db_server == 'mysql':
@ -456,31 +497,34 @@ class Database:
#print "sess_stats: subs =", subs, "subs[0] =", subs[0] #print "sess_stats: subs =", subs, "subs[0] =", subs[0]
c.execute(query, subs) c.execute(query, subs)
colnames = [desc[0] for desc in c.description] colnames = [desc[0] for desc in c.description]
n,stat_dict = 0,{} n = 0
row = c.fetchone()
while row: row = c.fetchone()
if colnames[0].lower() == 'player_id': if colnames[0].lower() == 'player_id':
playerid = row[0] playerid = row[0]
else:
log.error("ERROR: query %s result does not have player_id as first column" % (query,)) # Loop through stats adding them to appropriate stat_dict:
break 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 " %d rows fetched, len(stat_dict) = %d" % (n, len(stat_dict))
#print "session stat_dict =", stat_dict #print "session stat_dict =", stat_dict
return stat_dict #return stat_dict
def get_player_id(self, config, site, player_name): def get_player_id(self, config, site, player_name):
c = self.connection.cursor() c = self.connection.cursor()
@ -491,6 +535,69 @@ class Database:
else: else:
return None 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): def get_site_id(self, site):
c = self.get_cursor() c = self.get_cursor()
c.execute(self.sql.query['getSiteId'], (site,)) c.execute(self.sql.query['getSiteId'], (site,))
@ -855,6 +962,7 @@ class Database:
log.debug(self.sql.query['createSettingsTable']) log.debug(self.sql.query['createSettingsTable'])
c = self.get_cursor() c = self.get_cursor()
c.execute(self.sql.query['createSettingsTable']) c.execute(self.sql.query['createSettingsTable'])
log.debug(self.sql.query['createSitesTable']) log.debug(self.sql.query['createSitesTable'])
c.execute(self.sql.query['createSitesTable']) c.execute(self.sql.query['createSitesTable'])
c.execute(self.sql.query['createGametypesTable']) c.execute(self.sql.query['createGametypesTable'])
@ -867,9 +975,14 @@ class Database:
c.execute(self.sql.query['createHandsPlayersTable']) c.execute(self.sql.query['createHandsPlayersTable'])
c.execute(self.sql.query['createHandsActionsTable']) c.execute(self.sql.query['createHandsActionsTable'])
c.execute(self.sql.query['createHudCacheTable']) c.execute(self.sql.query['createHudCacheTable'])
#c.execute(self.sql.query['addTourneyIndex'])
#c.execute(self.sql.query['addHandsIndex']) # create unique indexes:
#c.execute(self.sql.query['addPlayersIndex']) 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.fillDefaultData()
self.commit() self.commit()
except: except:
@ -1011,20 +1124,48 @@ class Database:
c.execute("INSERT INTO Sites (name,currency) VALUES ('PartyPoker', 'USD')") c.execute("INSERT INTO Sites (name,currency) VALUES ('PartyPoker', 'USD')")
if self.backend == self.SQLITE: if self.backend == self.SQLITE:
c.execute("INSERT INTO TourneyTypes (id, siteId, buyin, fee) VALUES (NULL, 1, 0, 0);") 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 c.execute("""insert into TourneyTypes(id, siteId, buyin, fee, maxSeats, knockout
,rebuyOrAddon, speed, headsUp, shootout, matrix) ,rebuyOrAddon, speed, headsUp, shootout, matrix)
values (1, 1, 0, 0, 0, False, False, null, False, False, False);""") values (1, 1, 0, 0, 0, False, False, null, False, False, False);""")
#end def fillDefaultData #end def fillDefaultData
def rebuild_hudcache(self): def rebuild_hudcache(self, start=None):
"""clears hudcache and rebuilds from the individual handsplayers records""" """clears hudcache and rebuilds from the individual handsplayers records"""
try: try:
stime = time() 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['clearHudCache'])
self.get_cursor().execute(self.sql.query['rebuildHudCache']) self.get_cursor().execute(rebuild_sql)
self.commit() self.commit()
print "Rebuild hudcache took %.1f seconds" % (time() - stime,) print "Rebuild hudcache took %.1f seconds" % (time() - stime,)
except: except:
@ -1033,6 +1174,39 @@ class Database:
print err print err
#end def rebuild_hudcache #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): def analyzeDB(self):
"""Do whatever the DB can offer to update index/table statistics""" """Do whatever the DB can offer to update index/table statistics"""
@ -1182,6 +1356,10 @@ class Database:
return result return result
#end def store_the_hand #end def store_the_hand
###########################
# NEWIMPORT CODE
###########################
def storeHand(self, p): def storeHand(self, p):
#stores into table hands: #stores into table hands:
q = """INSERT INTO Hands ( q = """INSERT INTO Hands (
@ -1257,6 +1435,109 @@ class Database:
#return getLastInsertId(backend, conn, cursor) #return getLastInsertId(backend, conn, cursor)
# def storeHand # 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 def storeHands(self, backend, site_hand_no, gametype_id
,hand_start_time, names, tableName, maxSeats, hudCache ,hand_start_time, names, tableName, maxSeats, hudCache
,board_values, board_suits): ,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])) #cursor.execute("SELECT id FROM HandsPlayers WHERE handId=%s AND playerId+0=%s", (hands_id, player_ids[i]))
#result.append(cursor.fetchall()[0][0]) #result.append(cursor.fetchall()[0][0])
except: 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) ) raise FpdbError( "store_hands_players_holdem_omaha_tourney error: " + str(sys.exc_value) )
return result return result
@ -1748,27 +2031,40 @@ class Database:
#end def storeHudCache #end def storeHudCache
def store_tourneys(self, tourneyTypeId, siteTourneyNo, entries, prizepool, startTime): def store_tourneys(self, tourneyTypeId, siteTourneyNo, entries, prizepool, startTime):
ret = -1
try: 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 = self.get_cursor()
cursor.execute("SELECT id FROM Tourneys WHERE siteTourneyNo=%s AND tourneyTypeId+0=%s".replace('%s', self.sql.query['placeholder']) cursor.execute("savepoint ins_tourney")
, (siteTourneyNo, tourneyTypeId)) cursor.execute("""INSERT INTO Tourneys
tmp=cursor.fetchone() (tourneyTypeId, siteTourneyNo, entries, prizepool, startTime)
#print "tried SELECTing tourneys.id, result:",tmp VALUES (%s, %s, %s, %s, %s)""".replace('%s', self.sql.query['placeholder'])
,(tourneyTypeId, siteTourneyNo, entries, prizepool, startTime))
try: ret = self.get_last_insert_id(cursor)
len(tmp) #print "created new tourneys.id:",ret
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
except: 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) )
return tmp[0] #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])
cursor.execute("release savepoint ins_tourney")
#print "store_tourneys returning", ret
return ret
#end def store_tourneys #end def store_tourneys
def store_tourneys_players(self, tourney_id, player_ids, payin_amounts, ranks, winnings): def store_tourneys_players(self, tourney_id, player_ids, payin_amounts, ranks, winnings):
@ -1781,26 +2077,32 @@ class Database:
#print "ranks:",ranks #print "ranks:",ranks
#print "winnings:",winnings #print "winnings:",winnings
for i in xrange(len(player_ids)): 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: try:
len(tmp) cursor.execute("savepoint ins_tplayer")
except TypeError:
cursor.execute("""INSERT INTO TourneysPlayers 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])) (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']), tmp = self.get_last_insert_id(cursor)
(tourney_id, player_ids[i])) result.append(tmp)
tmp=cursor.fetchone() #print "created new tourneys_players.id:", tmp
#print "created new tourneys_players.id:",tmp except:
result.append(tmp[0]) 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: except:
raise FpdbError( "store_tourneys_players error: " + str(sys.exc_value) ) raise FpdbError( "store_tourneys_players error: " + str(sys.exc_value) )
cursor.execute("release savepoint ins_tplayer")
#print "store_tourneys_players returning", result
return result return result
#end def store_tourneys_players #end def store_tourneys_players
@ -2023,10 +2325,10 @@ class Database:
def tStoreTourneyPlayers(self, tourney, dbTourneyId): def tStoreTourneyPlayers(self, tourney, dbTourneyId):
logging.debug("Database.tStoreTourneyPlayers") logging.debug("Database.tStoreTourneyPlayers")
# First, get playerids for the players and specifically the one for hero : # 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 may be None for matrix tourneys summaries
# hero = [ tourney.hero ] # 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)) # logging.debug("hero Id = %s - playersId = %s" % (heroId , playersIds))
tourneyPlayersIds=[] tourneyPlayersIds=[]
@ -2240,12 +2542,12 @@ if __name__=="__main__":
if hero: if hero:
print "nutOmatic is id_player = %d" % 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(): for p in stat_dict.keys():
print p, " ", stat_dict[p] print p, " ", stat_dict[p]
#print "nutOmatics stats:" #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(): #for p in stat_dict.keys():
# print p, " ", stat_dict[p] # 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<SB>[.0-9]+)/
\$?(?P<BB>[.0-9]+)\s \$?(?P<BB>[.0-9]+)\s
(Ante\s\$?(?P<ANTE>[.0-9]+)\s)?-\s (Ante\s\$?(?P<ANTE>[.0-9]+)\s)?-\s
\$?(?P<CAP>[.0-9]+\sCap\s)?
(?P<LIMIT>(No\sLimit|Pot\sLimit|Limit))?\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)) (?P<GAME>(Hold\'em|Omaha\sHi|Omaha\sH/L|7\sCard\sStud|Stud\sH/L|Razz|Stud\sHi))
''', re.VERBOSE) ''', re.VERBOSE)
@ -52,6 +53,7 @@ class Fulltilt(HandHistoryConverter):
(?P<TABLE>[-\s\da-zA-Z]+)\s (?P<TABLE>[-\s\da-zA-Z]+)\s
(\((?P<TABLEATTRIBUTES>.+)\)\s)?-\s (\((?P<TABLEATTRIBUTES>.+)\)\s)?-\s
\$?(?P<SB>[.0-9]+)/\$?(?P<BB>[.0-9]+)\s(Ante\s\$?(?P<ANTE>[.0-9]+)\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<GAMETYPE>[a-zA-Z\/\'\s]+)\s-\s
(?P<DATETIME>\d+:\d+:\d+\s\w+\s-\s\d+/\d+/\d+)\s? (?P<DATETIME>\d+:\d+:\d+\s\w+\s-\s\d+/\d+/\d+)\s?
(?P<PARTIAL>\(partial\))?\n (?P<PARTIAL>\(partial\))?\n
@ -143,6 +145,7 @@ class Fulltilt(HandHistoryConverter):
return [["ring", "hold", "nl"], return [["ring", "hold", "nl"],
["ring", "hold", "pl"], ["ring", "hold", "pl"],
["ring", "hold", "fl"], ["ring", "hold", "fl"],
["ring", "hold", "cn"],
["ring", "stud", "fl"], ["ring", "stud", "fl"],
@ -175,7 +178,10 @@ class Fulltilt(HandHistoryConverter):
'Stud H/L' : ('stud','studhilo') 'Stud H/L' : ('stud','studhilo')
} }
currencies = { u'':'EUR', '$':'USD', '':'T$' } 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['sb'] = mg['SB']
info['bb'] = mg['BB'] info['bb'] = mg['BB']
if mg['GAME'] != None: if mg['GAME'] != None:

View File

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

View File

@ -673,7 +673,14 @@ class HoldemOmahaHand(Hand):
if shown: self.shown.add(player) if shown: self.shown.add(player)
if mucked: self.mucked.add(player) if mucked: self.mucked.add(player)
else: 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): def getStreetTotals(self):
# street1Pot INT, /* pot size at flop/street4 */ # street1Pot INT, /* pot size at flop/street4 */

View File

@ -73,6 +73,8 @@ class Hud:
self.stacked = True self.stacked = True
self.site = table.site self.site = table.site
self.mw_created = False self.mw_created = False
self.hud_params = parent.hud_params
self.stat_windows = {} self.stat_windows = {}
self.popup_windows = {} self.popup_windows = {}
@ -143,6 +145,78 @@ class Hud:
repositem = gtk.MenuItem('Reposition StatWindows') repositem = gtk.MenuItem('Reposition StatWindows')
menu.append(repositem) menu.append(repositem)
repositem.connect("activate", self.reposition_windows) 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') debugitem = gtk.MenuItem('Debug StatWindows')
menu.append(debugitem) menu.append(debugitem)
@ -176,9 +250,46 @@ class Hud:
self.create(*self.creation_attrs) self.create(*self.creation_attrs)
self.update(self.hand, self.config) self.update(self.hand, self.config)
except Exception, e: except Exception, e:
print "Expcetion:",str(e) print "Exception:",str(e)
pass 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): def update_table_position(self):
if os.name == 'nt': if os.name == 'nt':
if not win32gui.IsWindow(self.table.number): if not win32gui.IsWindow(self.table.number):
@ -218,7 +329,11 @@ class Hud:
# heap dead, burnt bodies, blood 'n guts, veins between my teeth # heap dead, burnt bodies, blood 'n guts, veins between my teeth
for s in self.stat_windows.itervalues(): for s in self.stat_windows.itervalues():
s.kill_popups() s.kill_popups()
s.window.destroy() try:
# throws "invalid window handle" in WinXP (sometimes?)
s.window.destroy()
except:
pass
self.stat_windows = {} self.stat_windows = {}
# also kill any aux windows # also kill any aux windows
for aux in self.aux_windows: for aux in self.aux_windows:
@ -626,7 +741,7 @@ class Popup_window:
# window.window.reparent(self.table.gdkhandle, 0, 0) # window.window.reparent(self.table.gdkhandle, 0, 0)
window.window.set_transient_for(self.table.gdkhandle) window.window.set_transient_for(self.table.gdkhandle)
# window.present() # window.present()
if __name__== "__main__": if __name__== "__main__":
main_window = gtk.Window() main_window = gtk.Window()

View File

@ -331,7 +331,8 @@ class Sql:
speed varchar(10), speed varchar(10),
headsUp BOOLEAN NOT NULL DEFAULT False, headsUp BOOLEAN NOT NULL DEFAULT False,
shootout 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""" ENGINE=INNODB"""
elif db_server == 'postgresql': elif db_server == 'postgresql':
@ -346,7 +347,8 @@ class Sql:
speed varchar(10), speed varchar(10),
headsUp BOOLEAN NOT NULL DEFAULT False, headsUp BOOLEAN NOT NULL DEFAULT False,
shootout 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': elif db_server == 'sqlite':
self.query['createTourneyTypesTable'] = """CREATE TABLE TourneyTypes ( self.query['createTourneyTypesTable'] = """CREATE TABLE TourneyTypes (
@ -360,7 +362,8 @@ class Sql:
speed TEXT, speed TEXT,
headsUp BOOLEAN NOT NULL DEFAULT 0, headsUp BOOLEAN NOT NULL DEFAULT 0,
shootout 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, comment TEXT,
commentTs timestamp without time zone)""" commentTs timestamp without time zone)"""
elif db_server == 'sqlite': 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, comment TEXT,
commentTs timestamp without time zone)""" commentTs timestamp without time zone)"""
elif db_server == 'sqlite': 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': 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': 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': elif db_server == 'sqlite':
self.query['addHandsIndex'] = """ """ self.query['addTourneyIndex'] = """CREATE UNIQUE INDEX siteTourneyNo ON Tourneys (siteTourneyNo, tourneyTypeId)"""
if db_server == 'mysql': 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': 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': elif db_server == 'sqlite':
self.query['addHandsIndex'] = """ """ self.query['addHandsIndex'] = """CREATE UNIQUE INDEX siteHandNo ON Hands (siteHandNo, gameTypeId)"""
if db_server == 'mysql': 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': 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': 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" self.query['get_last_hand'] = "select max(id) from Hands"
@ -1188,7 +1232,7 @@ class Sql:
from Players, Sites from Players, Sites
where Players.name = %s where Players.name = %s
and Sites.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""" 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 HudCache hc ON (hc.playerId = hp.playerId)
INNER JOIN Players p ON (p.id = hc.playerId) INNER JOIN Players p ON (p.id = hc.playerId)
WHERE h.id = %s WHERE h.id = %s
AND hc.styleKey > %s AND ( /* 2 separate parts for hero and opponents */
/* styleKey is currently 'd' (for date) followed by a yyyymmdd ( hp.playerId != %s
date key. Set it to 0000000 or similar to get all records */ AND hc.styleKey > %s
/* Note: s means the placeholder 'percent's but we can't include that AND hc.gametypeId+0 in
in comments. (db api thinks they are actual arguments) (SELECT gt1.id from Gametypes gt1, Gametypes gt2
Could also check activeseats here even if only 3 groups eg 2-3/4-6/7+ WHERE gt1.siteid = gt2.siteid /* find gametypes where these match: */
e.g. could use a multiplier: AND gt1.type = gt2.type /* ring/tourney */
AND h.seats > s / 1.25 and hp.seats < s * 1.25 AND gt1.category = gt2.category /* holdem/stud*/
where s is the number of active players at the current table (and AND gt1.limittype = gt2.limittype /* fl/nl */
1.25 would be a config value so user could change it) AND gt1.bigblind <= gt2.bigblind * %s /* bigblind similar size */
*/ AND gt1.bigblind >= gt2.bigblind / %s
AND hc.gametypeId+0 in AND gt2.id = h.gametypeId)
(SELECT gt1.id from Gametypes gt1, Gametypes gt2 )
WHERE gt1.siteid = gt2.siteid /* find gametypes where these match: */ OR
AND gt1.type = gt2.type /* ring/tourney */ ( hp.playerId = %s
AND gt1.category = gt2.category /* holdem/stud*/ AND hc.styleKey > %s
AND gt1.limittype = gt2.limittype /* fl/nl */ AND hc.gametypeId+0 in
AND gt1.bigblind < gt2.bigblind * %s /* bigblind similar size */ (SELECT gt1.id from Gametypes gt1, Gametypes gt2
AND gt1.bigblind > gt2.bigblind / %s WHERE gt1.siteid = gt2.siteid /* find gametypes where these match: */
AND gt2.id = h.gametypeId) 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 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': if db_server == 'mysql':
self.query['get_stats_from_hand_session'] = """ self.query['get_stats_from_hand_session'] = """
@ -1537,10 +1598,11 @@ class Sql:
""" """
self.query['get_table_name'] = """ self.query['get_table_name'] = """
select tableName, maxSeats, category, type select h.tableName, h.maxSeats, gt.category, gt.type, gt.siteId
from Hands,Gametypes from Hands h
where Hands.id = %s ,Gametypes gt
and Gametypes.id = Hands.gametypeId where h.id = %s
and gt.id = h.gametypeId
""" """
self.query['get_actual_seat'] = """ self.query['get_actual_seat'] = """
@ -2466,6 +2528,7 @@ class Sql:
,sum(street4CheckCallRaiseDone) ,sum(street4CheckCallRaiseDone)
FROM HandsPlayers hp FROM HandsPlayers hp
INNER JOIN Hands h ON (h.id = hp.handId) INNER JOIN Hands h ON (h.id = hp.handId)
<where_clause>
GROUP BY h.gametypeId GROUP BY h.gametypeId
,hp.playerId ,hp.playerId
,h.seats ,h.seats
@ -2614,6 +2677,7 @@ class Sql:
,sum(CAST(street4CheckCallRaiseDone as integer)) ,sum(CAST(street4CheckCallRaiseDone as integer))
FROM HandsPlayers hp FROM HandsPlayers hp
INNER JOIN Hands h ON (h.id = hp.handId) INNER JOIN Hands h ON (h.id = hp.handId)
<where_clause>
GROUP BY h.gametypeId GROUP BY h.gametypeId
,hp.playerId ,hp.playerId
,h.seats ,h.seats
@ -2762,6 +2826,7 @@ class Sql:
,sum(CAST(street4CheckCallRaiseDone as integer)) ,sum(CAST(street4CheckCallRaiseDone as integer))
FROM HandsPlayers hp FROM HandsPlayers hp
INNER JOIN Hands h ON (h.id = hp.handId) INNER JOIN Hands h ON (h.id = hp.handId)
<where_clause>
GROUP BY h.gametypeId GROUP BY h.gametypeId
,hp.playerId ,hp.playerId
,h.seats ,h.seats
@ -2770,9 +2835,14 @@ class Sql:
,'d' || substr(strftime('%Y%m%d', h.handStart),3,7) ,'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': if db_server == 'mysql':
self.query['analyze'] = """ self.query['analyze'] = """
analyze table Autorates, GameTypes, Hands, HandsPlayers, Hudcache, Players analyze table Autorates, GameTypes, Hands, HandsPlayers, HudCache, Players
, Settings, Sites, Tourneys, TourneysPlayers, TourneyTypes , Settings, Sites, Tourneys, TourneysPlayers, TourneyTypes
""" """
else: # assume postgres else: # assume postgres

View File

@ -376,7 +376,7 @@ def clean_title(name):
"""Clean the little info strings from the table name.""" """Clean the little info strings from the table name."""
# these strings could go in a config file # these strings could go in a config file
for pattern in [' \(6 max\)', ' \(heads up\)', ' \(deep\)', 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\)', ' \(edu\)', ' \(edu, 6 max\)', ' \(6\)',
' \(speed\)', 'special', 'newVPP', ' \(speed\)', 'special', 'newVPP',
' no all-in', ' fast', ',', ' 50BB min', '50bb min', '\s+$']: ' 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 # get basic info about the new hand from the db
# if there is a db error, complain, skip hand, and proceed # if there is a db error, complain, skip hand, and proceed
try: 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] stat_dict = self.db_connection.get_stats_from_hand(new_hand_id, aggregate_stats[type]
,hud_style, agg_bb_mult) ,hud_style, agg_bb_mult)

View File

@ -257,17 +257,65 @@ class fpdb:
def dia_recreate_hudcache(self, widget, data=None): def dia_recreate_hudcache(self, widget, data=None):
if self.obtain_global_lock(): 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." 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() hb = gtk.HBox(True, 1)
dia_confirm.destroy() 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: if response == gtk.RESPONSE_YES:
self.db.rebuild_hudcache() self.db.rebuild_hudcache( self.start_date.get_text() )
elif response == gtk.REPSONSE_NO: elif response == gtk.RESPONSE_NO:
print 'User cancelled rebuilding hud cache' print 'User cancelled rebuilding hud cache'
self.release_global_lock() 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): def dia_regression_test(self, widget, data=None):
self.warning_box("Unimplemented: Regression Test") self.warning_box("Unimplemented: Regression Test")

View File

@ -38,6 +38,8 @@ class fpdb_db:
MYSQL_INNODB = 2 MYSQL_INNODB = 2
PGSQL = 3 PGSQL = 3
SQLITE = 4 SQLITE = 4
sqlite_db_dir = ".." + os.sep + "database"
def __init__(self): def __init__(self):
"""Simple constructor, doesnt really do anything""" """Simple constructor, doesnt really do anything"""
self.db = None self.db = None
@ -119,7 +121,12 @@ class fpdb_db:
sqlite3 = pool.manage(sqlite3, pool_size=1) sqlite3 = pool.manage(sqlite3, pool_size=1)
else: else:
logging.warning("SQLite won't work well without 'sqlalchemy' installed.") 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_converter("bool", lambda x: bool(int(x)))
sqlite3.register_adapter(bool, lambda x: "1" if x else "0") sqlite3.register_adapter(bool, lambda x: "1" if x else "0")
else: else:

View File

@ -547,7 +547,7 @@ class Importer:
if self.callHud: if self.callHud:
#print "call to HUD here. handsId:",handsId #print "call to HUD here. handsId:",handsId
#pipe the Hands.id out to the HUD #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) self.caller.pipe_to_hud.stdin.write("%s" % (handsId) + os.linesep)
except Exceptions.DuplicateError: except Exceptions.DuplicateError:
duplicates += 1 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]) fee = fpdb_simple.parseFee(hand[0])
entries = -1 #todo: parse this entries = -1 #todo: parse this
prizepool = -1 #todo: parse this prizepool = -1 #todo: parse this
knockout = 0 knockout = False
tourneyStartTime= handStartTime #todo: read tourney start time tourneyStartTime= handStartTime #todo: read tourney start time
rebuyOrAddon = fpdb_simple.isRebuyOrAddon(hand[0]) rebuyOrAddon = fpdb_simple.isRebuyOrAddon(hand[0])
@ -118,7 +118,7 @@ def mainParser(settings, siteID, category, hand, config, db = None, writeq = Non
seatLines.append(line) seatLines.append(line)
names = fpdb_simple.parseNames(seatLines) 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) tmp = fpdb_simple.parseCashesAndSeatNos(seatLines)
startCashes = tmp['startCashes'] startCashes = tmp['startCashes']
seatNos = tmp['seatNos'] seatNos = tmp['seatNos']

View File

@ -913,92 +913,54 @@ def recogniseGametypeID(backend, db, cursor, topline, smallBlindLine, site_id, c
#end def recogniseGametypeID #end def recogniseGametypeID
def recogniseTourneyTypeId(db, siteId, tourneySiteId, buyin, fee, knockout, rebuyOrAddon): def recogniseTourneyTypeId(db, siteId, tourneySiteId, buyin, fee, knockout, rebuyOrAddon):
ret = -1
cursor = db.get_cursor() 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) # 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) # 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) #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)) cursor.execute (db.sql.query['getTourneyTypeIdByTourneyNo'].replace('%s', db.sql.query['placeholder']), (tourneySiteId, siteId))
result=cursor.fetchone() result = cursor.fetchone()
try: try:
len(result) len(result)
ret = result[0]
except: 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)) cursor.execute( """SELECT id FROM TourneyTypes
result=cursor.fetchone() WHERE siteId=%s AND buyin=%s AND fee=%s
#print "tried SELECTing gametypes.id, result:",result AND knockout=%s AND rebuyOrAddon=%s"""
, (siteId, buyin, fee, knockout, rebuyOrAddon) )
result = cursor.fetchone()
#print "tried selecting tourneytypes.id, result:", result
try: try:
len(result) len(result)
ret = result[0]
except TypeError:#this means we need to create a new entry 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)) #print "insert new tourneytype record ..."
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)) try:
result=cursor.fetchone() 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 #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 #recognises the name in the given line and returns its array position in the given array
def recognisePlayerNo(line, names, atype): 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'])]
)