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

This commit is contained in:
Mika Bostrom 2009-09-19 10:56:21 +03:00
commit 9af903a666
23 changed files with 1216 additions and 479 deletions

43
pyfpdb/AbsoluteToFpdb.py Normal file → Executable file
View File

@ -1,4 +1,4 @@
#!/usr/bin/env python #!/usr/bin/env python
# -*- coding: utf-8 -*- # -*- coding: utf-8 -*-
# #
# Copyright 2008, Carl Gherardi # Copyright 2008, Carl Gherardi
@ -32,6 +32,7 @@ class Absolute(HandHistoryConverter):
filetype = "text" filetype = "text"
codepage = "cp1252" codepage = "cp1252"
siteid = 8 siteid = 8
HORSEHand = False
# Static regexes # Static regexes
re_SplitHands = re.compile(r"\n\n\n+") re_SplitHands = re.compile(r"\n\n\n+")
@ -41,8 +42,11 @@ class Absolute(HandHistoryConverter):
#Seat 6 - FETS63 ($0.75 in chips) #Seat 6 - FETS63 ($0.75 in chips)
#Board [10s 5d Kh Qh 8c] #Board [10s 5d Kh Qh 8c]
re_GameInfo = re.compile(ur"^Stage #([0-9]+): (?P<GAME>Holdem|) (?P<LIMIT>No Limit|Pot Limit|Normal) (?P<CURRENCY>\$| €|)(?P<BB>[0-9]*[.0-9]+)", re.MULTILINE) re_GameInfo = re.compile(ur"^Stage #([0-9]+): (?P<GAME>Holdem|HORSE)(?: \(1 on 1\)|)? ?(?P<LIMIT>No Limit|Pot Limit|Normal|)? ?(?P<CURRENCY>\$| €|)(?P<SB>[.0-9]+)/?(?:\$| €|)(?P<BB>[.0-9]+)?", re.MULTILINE)
re_HandInfo = re.compile(ur"^Stage #(?P<HID>[0-9]+): .*(?P<DATETIME>\d\d\d\d-\d\d-\d\d \d\d:\d\d:\d\d).*\nTable: (?P<TABLE>.*) \(Real Money\)", re.MULTILINE) re_HorseGameInfo = re.compile(ur"^Game Type: (?P<LIMIT>Limit) (?P<GAME>Holdem)", re.MULTILINE)
# TODO: can set max seats via (1 on 1) to a known 2 ..
re_HandInfo = re.compile(ur"^Stage #(?P<HID>[0-9]+): .*(?P<DATETIME>\d\d\d\d-\d\d-\d\d \d\d:\d\d:\d\d).*\n(Table: (?P<TABLE>.*) \(Real Money\))?", re.MULTILINE)
re_TableFromFilename = re.compile(ur".*IHH([0-9]+) (?P<TABLE>.*) -") # on HORSE STUD games, the table name isn't in the hand info!
re_Button = re.compile(ur"Seat #(?P<BUTTON>[0-9]) is the ?[dead]* dealer$", re.MULTILINE) # TODO: that's not the right way to match for "dead" dealer is it? re_Button = re.compile(ur"Seat #(?P<BUTTON>[0-9]) is the ?[dead]* dealer$", re.MULTILINE) # TODO: that's not the right way to match for "dead" dealer is it?
re_PlayerInfo = re.compile(ur"^Seat (?P<SEAT>[0-9]) - (?P<PNAME>.*) \((?:\$| €|)(?P<CASH>[0-9]*[.0-9]+) in chips\)", re.MULTILINE) re_PlayerInfo = re.compile(ur"^Seat (?P<SEAT>[0-9]) - (?P<PNAME>.*) \((?:\$| €|)(?P<CASH>[0-9]*[.0-9]+) in chips\)", re.MULTILINE)
re_Board = re.compile(ur"\[(?P<CARDS>[^\]]*)\]? *$", re.MULTILINE) re_Board = re.compile(ur"\[(?P<CARDS>[^\]]*)\]? *$", re.MULTILINE)
@ -69,7 +73,7 @@ class Absolute(HandHistoryConverter):
self.re_Action = re.compile(ur"^%s - (?P<ATYPE>Bets |Raises |All-In |All-In\(Raise\) |Calls |Folds|Checks)?\$?(?P<BET>[0-9]*[.0-9]+)?" % player_re, re.MULTILINE) self.re_Action = re.compile(ur"^%s - (?P<ATYPE>Bets |Raises |All-In |All-In\(Raise\) |Calls |Folds|Checks)?\$?(?P<BET>[0-9]*[.0-9]+)?" % player_re, re.MULTILINE)
# print "^%s - (?P<ATYPE>Bets |Raises |All-In |All-In\(Raise\) |Calls |Folds|Checks)?\$?(?P<BET>[0-9]*[.0-9]+)?" % player_re # print "^%s - (?P<ATYPE>Bets |Raises |All-In |All-In\(Raise\) |Calls |Folds|Checks)?\$?(?P<BET>[0-9]*[.0-9]+)?" % player_re
self.re_ShowdownAction = re.compile(ur"^%s - Shows \[(?P<CARDS>.*)\]" % player_re, re.MULTILINE) self.re_ShowdownAction = re.compile(ur"^%s - Shows \[(?P<CARDS>.*)\]" % player_re, re.MULTILINE)
self.re_CollectPot = re.compile(ur"^Seat [0-9]: %s(?: \(dealer\)| \(big blind\)| \(small blind\)|) (?:won|collected) Total \((?:\$| €|)(?P<POT>[0-9]*[.0-9]+)\)" % player_re, re.MULTILINE) self.re_CollectPot = re.compile(ur"^Seat [0-9]: %s(?: \(dealer\)|)(?: \(big blind\)| \(small blind\)|) (?:won|collected) Total \((?:\$| €|)(?P<POT>[0-9]*[.0-9]+)\)" % player_re, re.MULTILINE)
#self.re_PostSB = re.compile(ur"^%s: posts small blind \[(?:\$| €|) (?P<SB>[.0-9]+)" % player_re, re.MULTILINE) #self.re_PostSB = re.compile(ur"^%s: posts small blind \[(?:\$| €|) (?P<SB>[.0-9]+)" % player_re, re.MULTILINE)
#self.re_PostBB = re.compile(ur"^%s: posts big blind \[(?:\$| €|) (?P<BB>[.0-9]+)" % player_re, re.MULTILINE) #self.re_PostBB = re.compile(ur"^%s: posts big blind \[(?:\$| €|) (?P<BB>[.0-9]+)" % player_re, re.MULTILINE)
#self.re_PostBoth = re.compile(ur"^%s: posts both blinds \[(?:\$| €|) (?P<SBBB>[.0-9]+)" % player_re, re.MULTILINE) #self.re_PostBoth = re.compile(ur"^%s: posts both blinds \[(?:\$| €|) (?P<SBBB>[.0-9]+)" % player_re, re.MULTILINE)
@ -112,7 +116,7 @@ or None if we fail to get the info """
mg = m.groupdict() mg = m.groupdict()
# translations from captured groups to our info strings # translations from captured groups to our info strings
limits = { 'No Limit':'nl', 'Pot Limit':'pl', 'Normal':'fl' } limits = { 'No Limit':'nl', 'Pot Limit':'pl', 'Normal':'fl', 'Limit':'fl'}
games = { # base, category games = { # base, category
"Holdem" : ('hold','holdem'), "Holdem" : ('hold','holdem'),
'Omaha' : ('hold','omahahi'), 'Omaha' : ('hold','omahahi'),
@ -120,10 +124,22 @@ or None if we fail to get the info """
'7 Card Stud' : ('stud','studhi') '7 Card Stud' : ('stud','studhi')
} }
currencies = { u'':'EUR', '$':'USD', '':'T$' } currencies = { u'':'EUR', '$':'USD', '':'T$' }
if 'LIMIT' in mg: if 'GAME' in mg and mg['GAME'] == "HORSE": # if we're a HORSE game, the game type is on the next line
info['limitType'] = limits[mg['LIMIT']] self.HORSEHand = True
m = self.re_HorseGameInfo.search(handText)
if not m:
return None # it's a HORSE game and we don't understand the game type
temp = m.groupdict()
#print "AP HORSE processing"
if 'GAME' not in temp or 'LIMIT' not in temp:
return None # sort of understood it but not really
#print "temp=", temp
mg['GAME'] = temp['GAME']
mg['LIMIT'] = temp['LIMIT']
if 'GAME' in mg: if 'GAME' in mg:
(info['base'], info['category']) = games[mg['GAME']] (info['base'], info['category']) = games[mg['GAME']]
if 'LIMIT' in mg:
info['limitType'] = limits[mg['LIMIT']]
if 'SB' in mg: if 'SB' in mg:
info['sb'] = mg['SB'] info['sb'] = mg['SB']
else: else:
@ -135,6 +151,11 @@ or None if we fail to get the info """
if info['currency'] == 'T$': if info['currency'] == 'T$':
info['type'] = 'tour' info['type'] = 'tour'
# NB: SB, BB must be interpreted as blinds or bets depending on limit type. # NB: SB, BB must be interpreted as blinds or bets depending on limit type.
if info['bb'] is None:
info['bb'] = mg['SB']
info['sb'] = str(float(mg['SB']) * 0.5) # TODO: AP does provide Small BET for Limit .. I think? at least 1-on-1 limit they do.. sigh
#print info;
return info return info
@ -147,9 +168,15 @@ or None if we fail to get the info """
return None return None
logging.debug("HID %s, Table %s" % (m.group('HID'), m.group('TABLE'))) logging.debug("HID %s, Table %s" % (m.group('HID'), m.group('TABLE')))
hand.handid = m.group('HID') hand.handid = m.group('HID')
if m.group('TABLE'):
hand.tablename = m.group('TABLE') hand.tablename = m.group('TABLE')
else:
t = self.re_TableFromFilename.search(self.in_path)
hand.tablename = t.group('TABLE')
hand.maxseats = 6 # assume 6-max unless we have proof it's a larger/smaller game, since absolute doesn't give seat max info hand.maxseats = 6 # assume 6-max unless we have proof it's a larger/smaller game, since absolute doesn't give seat max info
# TODO: (1-on-1) does have that info in the game type line
if self.HORSEHand:
hand.maxseats = 8
hand.starttime = datetime.datetime.strptime(m.group('DATETIME'), "%Y-%m-%d %H:%M:%S") hand.starttime = datetime.datetime.strptime(m.group('DATETIME'), "%Y-%m-%d %H:%M:%S")
return return

View File

@ -33,6 +33,11 @@ import shutil
import xml.dom.minidom import xml.dom.minidom
from xml.dom.minidom import Node from xml.dom.minidom import Node
import logging, logging.config
logging.config.fileConfig(os.path.join(sys.path[0],"logging.conf"))
log = logging.getLogger("config")
log.debug("config logger initialised")
def fix_tf(x, default = True): def fix_tf(x, default = True):
# The xml parser doesn't translate "True" to True. Therefore, we never get # The xml parser doesn't translate "True" to True. Therefore, we never get
# True or False from the parser only "True" or "False". So translate the # True or False from the parser only "True" or "False". So translate the
@ -201,6 +206,9 @@ class Database:
self.db_user = node.getAttribute("db_user") self.db_user = node.getAttribute("db_user")
self.db_type = node.getAttribute("db_type") self.db_type = node.getAttribute("db_type")
self.db_pass = node.getAttribute("db_pass") self.db_pass = node.getAttribute("db_pass")
self.db_selected = fix_tf(node.getAttribute("default"),"False")
log.debug("Database db_name:'%(name)s' db_server:'%(server)s' db_ip:'%(ip)s' db_user:'%(user)s' db_type:'%(type)s' db_pass (not logged) selected:'%(sel)s'" \
% { 'name':self.db_name, 'server':self.db_server, 'ip':self.db_ip, 'user':self.db_user, 'type':self.db_type, 'sel':self.db_selected} )
def __str__(self): def __str__(self):
temp = 'Database = ' + self.db_name + '\n' temp = 'Database = ' + self.db_name + '\n'
@ -208,7 +216,7 @@ class Database:
if key.startswith('__'): continue if key.startswith('__'): continue
value = getattr(self, key) value = getattr(self, key)
if callable(value): continue if callable(value): continue
temp = temp + ' ' + key + " = " + value + "\n" temp = temp + ' ' + key + " = " + repr(value) + "\n"
return temp return temp
class Aux_window: class Aux_window:
@ -258,6 +266,7 @@ class Popup:
class Import: class Import:
def __init__(self, node): def __init__(self, node):
self.node = node
self.interval = node.getAttribute("interval") self.interval = node.getAttribute("interval")
self.callFpdbHud = node.getAttribute("callFpdbHud") self.callFpdbHud = node.getAttribute("callFpdbHud")
self.hhArchiveBase = node.getAttribute("hhArchiveBase") self.hhArchiveBase = node.getAttribute("hhArchiveBase")
@ -279,11 +288,10 @@ class Tv:
(self.combinedStealFold, self.combined2B3B, self.combinedPostflop) ) (self.combinedStealFold, self.combined2B3B, self.combinedPostflop) )
class Config: class Config:
def __init__(self, file = None, dbname = 'fpdb'): def __init__(self, file = None, dbname = ''):
# "file" is a path to an xml file with the fpdb/HUD configuration # "file" is a path to an xml file with the fpdb/HUD configuration
# we check the existence of "file" and try to recover if it doesn't exist # we check the existence of "file" and try to recover if it doesn't exist
self.dbname = dbname
self.default_config_path = self.get_default_config_path() self.default_config_path = self.get_default_config_path()
if file != None: # configuration file path has been passed if file != None: # configuration file path has been passed
@ -309,10 +317,10 @@ class Config:
# Parse even if there was no real config file found and we are using the example # Parse even if there was no real config file found and we are using the example
# If using the example, we'll edit it later # If using the example, we'll edit it later
try: try:
print "Reading configuration file %s\n" % (file) log.info("Reading configuration file %s" % (file))
doc = xml.dom.minidom.parse(file) doc = xml.dom.minidom.parse(file)
except: except:
print "Error parsing %s. See error log file." % (file) log.error("Error parsing %s. See error log file." % (file))
traceback.print_exc(file=sys.stderr) traceback.print_exc(file=sys.stderr)
print "press enter to continue" print "press enter to continue"
sys.stdin.readline() sys.stdin.readline()
@ -338,9 +346,26 @@ class Config:
self.supported_games[game.game_name] = game self.supported_games[game.game_name] = game
# s_dbs = doc.getElementsByTagName("supported_databases") # s_dbs = doc.getElementsByTagName("supported_databases")
# select database from those defined in config by:
# 1) command line option
# or 2) selected="True" in config element
# or 3) just choose the first we come across
for db_node in doc.getElementsByTagName("database"): for db_node in doc.getElementsByTagName("database"):
try:
db = Database(node = db_node) db = Database(node = db_node)
if db.db_name in self.supported_databases:
raise FpdbError("Database names must be unique")
# If there is only one Database node, or none are marked default, the first is selected
if len(self.supported_databases) == 0:
self.db_selected = db.db_name
self.supported_databases[db.db_name] = db self.supported_databases[db.db_name] = db
if db.db_selected:
self.db_selected = db.db_name
except:
raise
if dbname and dbname in self.supported_databases:
self.db_selected = dbname
# s_dbs = doc.getElementsByTagName("mucked_windows") # s_dbs = doc.getElementsByTagName("mucked_windows")
for aw_node in doc.getElementsByTagName("aw"): for aw_node in doc.getElementsByTagName("aw"):
@ -377,6 +402,8 @@ class Config:
db_pass = df_parms['db-password']) db_pass = df_parms['db-password'])
self.save(file=os.path.join(self.default_config_path, "HUD_config.xml")) self.save(file=os.path.join(self.default_config_path, "HUD_config.xml"))
def set_hhArchiveBase(self, path):
self.imp.node.setAttribute("hhArchiveBase", path)
def find_config(self): def find_config(self):
"""Looks in cwd and in self.default_config_path for a config file.""" """Looks in cwd and in self.default_config_path for a config file."""
@ -507,7 +534,7 @@ class Config:
def get_db_parameters(self): def get_db_parameters(self):
db = {} db = {}
name = self.dbname name = self.db_selected
try: db['db-databaseName'] = name try: db['db-databaseName'] = name
except: pass except: pass

View File

@ -24,6 +24,7 @@ Create and manage the database objects.
# postmaster -D /var/lib/pgsql/data # postmaster -D /var/lib/pgsql/data
# Standard Library modules # Standard Library modules
import os
import sys import sys
import traceback import traceback
from datetime import datetime, date, time, timedelta from datetime import datetime, date, time, timedelta
@ -31,7 +32,6 @@ from time import time, strftime, sleep
from decimal import Decimal from decimal import Decimal
import string import string
import re import re
import logging
import Queue import Queue
# pyGTK modules # pyGTK modules
@ -42,6 +42,12 @@ import fpdb_simple
import Configuration import Configuration
import SQL import SQL
import Card import Card
import Tourney
from Exceptions import *
import logging, logging.config
logging.config.fileConfig(os.path.join(sys.path[0],"logging.conf"))
log = logging.getLogger('db')
class Database: class Database:
@ -93,6 +99,14 @@ class Database:
, {'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':'Hands', 'col':'siteHandNo', 'drop':0}
, {'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}
] ]
] ]
@ -161,8 +175,14 @@ class Database:
# CREATE INDEX idx ON tab(col) # CREATE INDEX idx ON tab(col)
# DROP INDEX idx # DROP INDEX idx
# SQLite notes:
# To add an index:
# create index indexname on tablename (col);
def __init__(self, c, db_name = None, game = None, sql = None): # db_name and game not used any more def __init__(self, c, db_name = None, game = None, sql = None): # db_name and game not used any more
print "\ncreating Database instance, sql =", sql log.info("Creating Database instance, sql = %s" % sql)
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
@ -179,12 +199,18 @@ class Database:
#ISOLATION_LEVEL_READ_COMMITTED = 1 #ISOLATION_LEVEL_READ_COMMITTED = 1
#ISOLATION_LEVEL_SERIALIZABLE = 2 #ISOLATION_LEVEL_SERIALIZABLE = 2
# where possible avoid creating new SQL instance by using the global one passed in # where possible avoid creating new SQL instance by using the global one passed in
if sql == None: if sql == None:
self.sql = SQL.Sql(type = self.type, db_server = db_params['db-server']) self.sql = SQL.Sql(type = self.type, db_server = db_params['db-server'])
else: else:
self.sql = sql self.sql = sql
if self.backend == self.SQLITE and db_params['db-databaseName'] == ':memory:' and self.fdb.wrongDbVersion:
log.info("sqlite/:memory: - creating")
self.recreate_tables()
self.fdb.wrongDbVersion = False
self.pcache = None # PlayerId cache self.pcache = None # PlayerId cache
self.cachemiss = 0 # Delete me later - using to count player cache misses self.cachemiss = 0 # Delete me later - using to count player cache misses
self.cachehit = 0 # Delete me later - using to count player cache hits self.cachehit = 0 # Delete me later - using to count player cache hits
@ -244,7 +270,7 @@ class Database:
elif self.backend==4: elif self.backend==4:
return "SQLite" return "SQLite"
else: else:
raise fpdb_simple.FpdbError("invalid backend") raise FpdbError("invalid backend")
def get_table_name(self, hand_id): def get_table_name(self, hand_id):
c = self.connection.cursor() c = self.connection.cursor()
@ -439,7 +465,7 @@ class Database:
if colnames[0].lower() == 'player_id': if colnames[0].lower() == 'player_id':
playerid = row[0] playerid = row[0]
else: else:
print "ERROR: query %s result does not have player_id as first column" % (query,) log.error("ERROR: query %s result does not have player_id as first column" % (query,))
break break
for name, val in zip(colnames, row): for name, val in zip(colnames, row):
@ -480,7 +506,7 @@ class Database:
if self.backend == self.MYSQL_INNODB: if self.backend == self.MYSQL_INNODB:
ret = self.connection.insert_id() ret = self.connection.insert_id()
if ret < 1 or ret > 999999999: if ret < 1 or ret > 999999999:
print "getLastInsertId(): problem fetching insert_id? ret=", ret log.warning("getLastInsertId(): problem fetching insert_id? ret=%d" % ret)
ret = -1 ret = -1
elif self.backend == self.PGSQL: elif self.backend == self.PGSQL:
# some options: # some options:
@ -492,14 +518,14 @@ class Database:
ret = c.execute ("SELECT lastval()") ret = c.execute ("SELECT lastval()")
row = c.fetchone() row = c.fetchone()
if not row: if not row:
print "getLastInsertId(%s): problem fetching lastval? row=" % seq, row log.warning("getLastInsertId(%s): problem fetching lastval? row=%d" % (seq, row))
ret = -1 ret = -1
else: else:
ret = row[0] ret = row[0]
elif self.backend == self.SQLITE: elif self.backend == self.SQLITE:
ret = cursor.lastrowid ret = cursor.lastrowid
else: else:
print "getLastInsertId(): unknown backend ", self.backend log.error("getLastInsertId(): unknown backend: %d" % self.backend)
ret = -1 ret = -1
except: except:
ret = -1 ret = -1
@ -584,7 +610,7 @@ class Database:
hands_players_ids = self.store_hands_players_holdem_omaha_tourney( hands_players_ids = self.store_hands_players_holdem_omaha_tourney(
self.backend, category, hands_id, player_ids, start_cashes, positions self.backend, category, hands_id, player_ids, start_cashes, positions
, card_values, card_suits, winnings, rakes, seatNos, tourneys_players_ids , card_values, card_suits, winnings, rakes, seatNos, tourneys_players_ids
, hudImportData) , hudImportData, tourneyTypeId)
#print "tourney holdem, backend=%d" % backend #print "tourney holdem, backend=%d" % backend
if 'dropHudCache' not in settings or settings['dropHudCache'] != 'drop': if 'dropHudCache' not in settings or settings['dropHudCache'] != 'drop':
@ -612,7 +638,7 @@ class Database:
hands_players_ids = self.store_hands_players_stud_tourney(self.backend, hands_id hands_players_ids = self.store_hands_players_stud_tourney(self.backend, hands_id
, playerIds, startCashes, antes, cardValues, cardSuits , playerIds, startCashes, antes, cardValues, cardSuits
, winnings, rakes, seatNos, tourneys_players_ids) , winnings, rakes, seatNos, tourneys_players_ids, tourneyTypeId)
if 'dropHudCache' not in settings or settings['dropHudCache'] != 'drop': if 'dropHudCache' not in settings or settings['dropHudCache'] != 'drop':
self.storeHudCache(self.backend, base, category, gametypeId, hand_start_time, playerIds, hudImportData) self.storeHudCache(self.backend, base, category, gametypeId, hand_start_time, playerIds, hudImportData)
@ -823,16 +849,16 @@ class Database:
self.create_tables() self.create_tables()
self.createAllIndexes() self.createAllIndexes()
self.commit() self.commit()
print "Finished recreating tables" log.info("Finished recreating tables")
#end def recreate_tables #end def recreate_tables
def create_tables(self): def create_tables(self):
#todo: should detect and fail gracefully if tables already exist. #todo: should detect and fail gracefully if tables already exist.
try: try:
logging.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'])
logging.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'])
c.execute(self.sql.query['createPlayersTable']) c.execute(self.sql.query['createPlayersTable'])
@ -859,35 +885,51 @@ class Database:
def drop_tables(self): def drop_tables(self):
"""Drops the fpdb tables from the current db""" """Drops the fpdb tables from the current db"""
try: try:
c = self.get_cursor() c = self.get_cursor()
if(self.get_backend_name() == 'MySQL InnoDB'): except:
#Databases with FOREIGN KEY support need this switched of before you can drop tables print "*** Error unable to get cursor"
self.drop_referential_integrity() else:
backend = self.get_backend_name()
# Query the DB to see what tables exist if backend == 'MySQL InnoDB': # what happens if someone is using MyISAM?
c.execute(self.sql.query['list_tables']) try:
for table in c: self.drop_referential_integrity() # needed to drop tables with foreign keys
c.execute(self.sql.query['drop_table'] + table[0])
elif(self.get_backend_name() == 'PostgreSQL'):
self.commit()# I have no idea why this makes the query work--REB 07OCT2008
c.execute(self.sql.query['list_tables']) c.execute(self.sql.query['list_tables'])
tables = c.fetchall() tables = c.fetchall()
for table in tables: for table in tables:
c.execute(self.sql.query['drop_table'] + table[0] + ' cascade')
elif(self.get_backend_name() == 'SQLite'):
c.execute(self.sql.query['list_tables'])
for table in c.fetchall():
logging.debug(self.sql.query['drop_table'] + table[0])
c.execute(self.sql.query['drop_table'] + table[0]) c.execute(self.sql.query['drop_table'] + table[0])
self.commit()
except: except:
err = traceback.extract_tb(sys.exc_info()[2])[-1] err = traceback.extract_tb(sys.exc_info()[2])[-1]
print "***Error dropping tables: "+err[2]+"("+str(err[1])+"): "+str(sys.exc_info()[1]) print "***Error dropping tables: "+err[2]+"("+str(err[1])+"): "+str(sys.exc_info()[1])
self.rollback() self.rollback()
raise elif backend == 'PostgreSQL':
try:
self.commit()
c.execute(self.sql.query['list_tables'])
tables = c.fetchall()
for table in tables:
c.execute(self.sql.query['drop_table'] + table[0] + ' cascade')
except:
err = traceback.extract_tb(sys.exc_info()[2])[-1]
print "***Error dropping tables: "+err[2]+"("+str(err[1])+"): "+str(sys.exc_info()[1])
self.rollback()
elif backend == 'SQLite':
try:
c.execute(self.sql.query['list_tables'])
for table in c.fetchall():
log.debug(self.sql.query['drop_table'] + table[0])
c.execute(self.sql.query['drop_table'] + table[0])
except:
err = traceback.extract_tb(sys.exc_info()[2])[-1]
print "***Error dropping tables: "+err[2]+"("+str(err[1])+"): "+str(sys.exc_info()[1])
self.rollback()
try:
self.commit()
except:
print "*** Error in committing table drop"
err = traceback.extract_tb(sys.exc_info()[2])[-1]
print "***Error dropping tables: "+err[2]+"("+str(err[1])+"): "+str(sys.exc_info()[1])
self.rollback()
#end def drop_tables #end def drop_tables
def createAllIndexes(self): def createAllIndexes(self):
@ -912,14 +954,21 @@ class Database:
self.get_cursor().execute(s) self.get_cursor().execute(s)
except: except:
print " create idx failed: " + str(sys.exc_info()) print " create idx failed: " + str(sys.exc_info())
elif self.backend == self.SQLITE:
log.debug("Creating sqlite index %s %s" % (idx['tab'], idx['col']))
try:
s = "create index %s_%s_idx on %s(%s)" % (idx['tab'], idx['col'], idx['tab'], idx['col'])
self.get_cursor().execute(s)
except:
log.debug("Create idx failed: " + str(sys.exc_info()))
else: else:
print "Only MySQL and Postgres supported so far" print "Only MySQL, Postgres and SQLite supported so far"
return -1 return -1
if self.backend == self.PGSQL: if self.backend == self.PGSQL:
self.connection.set_isolation_level(1) # go back to normal isolation level self.connection.set_isolation_level(1) # go back to normal isolation level
except: except:
print "Error creating indexes: " + str(sys.exc_value) print "Error creating indexes: " + str(sys.exc_value)
raise fpdb_simple.FpdbError( "Error creating indexes " + str(sys.exc_value) ) raise FpdbError( "Error creating indexes " + str(sys.exc_value) )
#end def createAllIndexes #end def createAllIndexes
def dropAllIndexes(self): def dropAllIndexes(self):
@ -964,12 +1013,10 @@ class Database:
c.execute("INSERT INTO Sites (name,currency) VALUES ('Absolute', 'USD')") c.execute("INSERT INTO Sites (name,currency) VALUES ('Absolute', 'USD')")
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 VALUES (NULL, 1, 0, 0, 0, 0);") c.execute("INSERT INTO TourneyTypes (id, siteId, buyin, fee) VALUES (NULL, 1, 0, 0);")
else: else:
c.execute("INSERT INTO TourneyTypes VALUES (DEFAULT, 1, 0, 0, 0, False);") c.execute("insert into TourneyTypes values (0,1,0,0,0,0,0,null,0,0,0);")
#c.execute("""INSERT INTO TourneyTypes
# (siteId,buyin,fee,knockout,rebuyOrAddon) VALUES
# (1,0,0,0,?)""",(False,) )
#end def fillDefaultData #end def fillDefaultData
def rebuild_hudcache(self): def rebuild_hudcache(self):
@ -1107,7 +1154,7 @@ class Database:
, h.allIns, h.actionAmounts, h.actionNos, h.hudImportData, h.maxSeats , h.allIns, h.actionAmounts, h.actionNos, h.hudImportData, h.maxSeats
, h.tableName, h.seatNos) , h.tableName, h.seatNos)
else: else:
raise fpdb_simple.FpdbError("unrecognised category") raise FpdbError("unrecognised category")
else: else:
if h.base == "hold": if h.base == "hold":
result = self.ring_holdem_omaha( result = self.ring_holdem_omaha(
@ -1125,7 +1172,7 @@ class Database:
, h.actionAmounts, h.actionNos, h.hudImportData, h.maxSeats, h.tableName , h.actionAmounts, h.actionNos, h.hudImportData, h.maxSeats, h.tableName
, h.seatNos) , h.seatNos)
else: else:
raise fpdb_simple.FpdbError("unrecognised category") raise FpdbError("unrecognised category")
except: except:
print "Error storing hand: " + str(sys.exc_value) print "Error storing hand: " + str(sys.exc_value)
self.rollback() self.rollback()
@ -1245,7 +1292,7 @@ class Database:
ret = self.get_last_insert_id(c) ret = self.get_last_insert_id(c)
except: except:
ret = -1 ret = -1
raise fpdb_simple.FpdbError( "storeHands error: " + str(sys.exc_value) ) raise FpdbError( "storeHands error: " + str(sys.exc_value) )
return ret return ret
#end def storeHands #end def storeHands
@ -1280,10 +1327,10 @@ class Database:
card3 = Card.cardFromValueSuit(card_values[i][2], card_suits[i][2]) card3 = Card.cardFromValueSuit(card_values[i][2], card_suits[i][2])
card4 = Card.cardFromValueSuit(card_values[i][3], card_suits[i][3]) card4 = Card.cardFromValueSuit(card_values[i][3], card_suits[i][3])
else: else:
raise fpdb_simple.FpdbError("invalid category") raise FpdbError("invalid category")
inserts.append( ( inserts.append( (
hands_id, player_ids[i], start_cashes[i], positions[i], 1, # tourneytypeid hands_id, player_ids[i], start_cashes[i], positions[i], 1, # tourneytypeid - needed for hudcache
card1, card2, card3, card4, startCards, card1, card2, card3, card4, startCards,
winnings[i], rakes[i], seatNos[i], hudCache['totalProfit'][i], winnings[i], rakes[i], seatNos[i], hudCache['totalProfit'][i],
hudCache['street0VPI'][i], hudCache['street0Aggr'][i], hudCache['street0VPI'][i], hudCache['street0Aggr'][i],
@ -1339,7 +1386,7 @@ class Database:
,inserts ) ,inserts )
result.append( self.get_last_insert_id(c) ) # wrong? not used currently result.append( self.get_last_insert_id(c) ) # wrong? not used currently
except: except:
raise fpdb_simple.FpdbError( "store_hands_players_holdem_omaha error: " + str(sys.exc_value) ) raise FpdbError( "store_hands_players_holdem_omaha error: " + str(sys.exc_value) )
return result return result
#end def store_hands_players_holdem_omaha #end def store_hands_players_holdem_omaha
@ -1377,7 +1424,7 @@ class Database:
#result.append(cursor.fetchall()[0][0]) #result.append(cursor.fetchall()[0][0])
result.append( self.get_last_insert_id(c) ) result.append( self.get_last_insert_id(c) )
except: except:
raise fpdb_simple.FpdbError( "store_hands_players_stud error: " + str(sys.exc_value) ) raise FpdbError( "store_hands_players_stud error: " + str(sys.exc_value) )
return result return result
#end def store_hands_players_stud #end def store_hands_players_stud
@ -1385,7 +1432,7 @@ class Database:
def store_hands_players_holdem_omaha_tourney(self, backend, category, hands_id, player_ids def store_hands_players_holdem_omaha_tourney(self, backend, category, hands_id, player_ids
,start_cashes, positions, card_values, card_suits ,start_cashes, positions, card_values, card_suits
,winnings, rakes, seatNos, tourneys_players_ids ,winnings, rakes, seatNos, tourneys_players_ids
,hudCache): ,hudCache, tourneyTypeId):
#stores hands_players for tourney holdem/omaha hands #stores hands_players for tourney holdem/omaha hands
try: try:
@ -1407,7 +1454,7 @@ class Database:
else: else:
raise FpdbError ("invalid card_values length:"+str(len(card_values[0]))) raise FpdbError ("invalid card_values length:"+str(len(card_values[0])))
inserts.append( (hands_id, player_ids[i], start_cashes[i], positions[i], 1, # tourneytypeid inserts.append( (hands_id, player_ids[i], start_cashes[i], positions[i], tourneyTypeId,
card1, card2, card3, card4, startCards, card1, card2, card3, card4, startCards,
winnings[i], rakes[i], tourneys_players_ids[i], seatNos[i], hudCache['totalProfit'][i], winnings[i], rakes[i], tourneys_players_ids[i], seatNos[i], hudCache['totalProfit'][i],
hudCache['street0VPI'][i], hudCache['street0Aggr'][i], hudCache['street0VPI'][i], hudCache['street0Aggr'][i],
@ -1470,13 +1517,13 @@ 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:
raise fpdb_simple.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
#end def store_hands_players_holdem_omaha_tourney #end def store_hands_players_holdem_omaha_tourney
def store_hands_players_stud_tourney(self, backend, hands_id, player_ids, start_cashes, def store_hands_players_stud_tourney(self, backend, hands_id, player_ids, start_cashes,
antes, card_values, card_suits, winnings, rakes, seatNos, tourneys_players_ids): antes, card_values, card_suits, winnings, rakes, seatNos, tourneys_players_ids, tourneyTypeId):
#stores hands_players for tourney stud/razz hands #stores hands_players for tourney stud/razz hands
try: try:
@ -1488,19 +1535,19 @@ class Database:
card1Value, card1Suit, card2Value, card2Suit, card1Value, card1Suit, card2Value, card2Suit,
card3Value, card3Suit, card4Value, card4Suit, card3Value, card3Suit, card4Value, card4Suit,
card5Value, card5Suit, card6Value, card6Suit, card5Value, card5Suit, card6Value, card6Suit,
card7Value, card7Suit, winnings, rake, tourneysPlayersId, seatNo) card7Value, card7Suit, winnings, rake, tourneysPlayersId, seatNo, tourneyTypeId)
VALUES (%s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, VALUES (%s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s,
%s, %s, %s, %s, %s, %s)""".replace('%s', self.sql.query['placeholder']), %s, %s, %s, %s, %s, %s, %s)""".replace('%s', self.sql.query['placeholder']),
(hands_id, player_ids[i], start_cashes[i], antes[i], (hands_id, player_ids[i], start_cashes[i], antes[i],
card_values[i][0], card_suits[i][0], card_values[i][1], card_suits[i][1], 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], card_values[i][2], card_suits[i][2], card_values[i][3], card_suits[i][3],
card_values[i][4], card_suits[i][4], card_values[i][5], card_suits[i][5], card_values[i][4], card_suits[i][4], card_values[i][5], card_suits[i][5],
card_values[i][6], card_suits[i][6], winnings[i], rakes[i], tourneys_players_ids[i], seatNos[i])) card_values[i][6], card_suits[i][6], winnings[i], rakes[i], tourneys_players_ids[i], seatNos[i], tourneyTypeId))
#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])
result.append( self.get_last_insert_id(c) ) result.append( self.get_last_insert_id(c) )
except: except:
raise fpdb_simple.FpdbError( "store_hands_players_stud_tourney error: " + str(sys.exc_value) ) raise FpdbError( "store_hands_players_stud_tourney error: " + str(sys.exc_value) )
return result return result
#end def store_hands_players_stud_tourney #end def store_hands_players_stud_tourney
@ -1697,7 +1744,7 @@ class Database:
# print "todo: implement storeHudCache for stud base" # print "todo: implement storeHudCache for stud base"
except: except:
raise fpdb_simple.FpdbError( "storeHudCache error: " + str(sys.exc_value) ) raise FpdbError( "storeHudCache error: " + str(sys.exc_value) )
#end def storeHudCache #end def storeHudCache
@ -1720,7 +1767,7 @@ class Database:
tmp=cursor.fetchone() tmp=cursor.fetchone()
#print "created new tourneys.id:",tmp #print "created new tourneys.id:",tmp
except: except:
raise fpdb_simple.FpdbError( "store_tourneys error: " + str(sys.exc_value) ) raise FpdbError( "store_tourneys error: " + str(sys.exc_value) )
return tmp[0] return tmp[0]
#end def store_tourneys #end def store_tourneys
@ -1753,7 +1800,7 @@ class Database:
#print "created new tourneys_players.id:",tmp #print "created new tourneys_players.id:",tmp
result.append(tmp[0]) result.append(tmp[0])
except: except:
raise fpdb_simple.FpdbError( "store_tourneys_players error: " + str(sys.exc_value) ) raise FpdbError( "store_tourneys_players error: " + str(sys.exc_value) )
return result return result
#end def store_tourneys_players #end def store_tourneys_players
@ -1834,6 +1881,236 @@ class Database:
print "***Error sending finish: "+err[2]+"("+str(err[1])+"): "+str(sys.exc_info()[1]) print "***Error sending finish: "+err[2]+"("+str(err[1])+"): "+str(sys.exc_info()[1])
# end def send_finish_msg(): # end def send_finish_msg():
def tRecogniseTourneyType(self, tourney):
logging.debug("Database.tRecogniseTourneyType")
typeId = 1
# Check if Tourney exists, and if so retrieve TTypeId : in that case, check values of the ttype
cursor = self.get_cursor()
cursor.execute (self.sql.query['getTourneyTypeIdByTourneyNo'].replace('%s', self.sql.query['placeholder']),
(tourney.tourNo, tourney.siteId)
)
result=cursor.fetchone()
expectedValues = { 1 : "buyin", 2 : "fee", 4 : "isKO", 5 : "isRebuy", 6 : "speed",
7 : "isHU", 8 : "isShootout", 9 : "isMatrix" }
typeIdMatch = True
try:
len(result)
typeId = result[0]
logging.debug("Tourney found in db with Tourney_Type_ID = %d" % typeId)
for ev in expectedValues :
if ( getattr( tourney, expectedValues.get(ev) ) <> result[ev] ):
logging.debug("TypeId mismatch : wrong %s : Tourney=%s / db=%s" % (expectedValues.get(ev), getattr( tourney, expectedValues.get(ev)), result[ev]) )
typeIdMatch = False
#break
except:
# Tourney not found : a TourneyTypeId has to be found or created for that specific tourney
typeIdMatch = False
if typeIdMatch == False :
# Check for an existing TTypeId that matches tourney info (buyin/fee, knockout, rebuy, speed, matrix, shootout)
# if not found create it
logging.debug("Searching for a TourneyTypeId matching TourneyType data")
cursor.execute (self.sql.query['getTourneyTypeId'].replace('%s', self.sql.query['placeholder']),
(tourney.siteId, tourney.buyin, tourney.fee, tourney.isKO,
tourney.isRebuy, tourney.speed, tourney.isHU, tourney.isShootout, tourney.isMatrix)
)
result=cursor.fetchone()
try:
len(result)
typeId = result[0]
logging.debug("Existing Tourney Type Id found : %d" % typeId)
except TypeError: #this means we need to create a new entry
logging.debug("Tourney Type Id not found : create one")
cursor.execute (self.sql.query['insertTourneyTypes'].replace('%s', self.sql.query['placeholder']),
(tourney.siteId, tourney.buyin, tourney.fee, tourney.isKO, tourney.isRebuy,
tourney.speed, tourney.isHU, tourney.isShootout, tourney.isMatrix)
)
typeId = self.get_last_insert_id(cursor)
return typeId
#end def tRecogniseTourneyType
def tRecognizeTourney(self, tourney, dbTourneyTypeId):
logging.debug("Database.tRecognizeTourney")
tourneyID = 1
# Check if tourney exists in db (based on tourney.siteId and tourney.tourNo)
# If so retrieve all data to check for consistency
cursor = self.get_cursor()
cursor.execute (self.sql.query['getTourney'].replace('%s', self.sql.query['placeholder']),
(tourney.tourNo, tourney.siteId)
)
result=cursor.fetchone()
expectedValuesDecimal = { 2 : "entries", 3 : "prizepool", 6 : "buyInChips", 9 : "rebuyChips",
10 : "addOnChips", 11 : "rebuyAmount", 12 : "addOnAmount", 13 : "totalRebuys",
14 : "totalAddOns", 15 : "koBounty" }
expectedValues = { 7 : "tourneyName", 16 : "tourneyComment" }
tourneyDataMatch = True
tCommentTs = None
starttime = None
endtime = None
try:
len(result)
tourneyID = result[0]
logging.debug("Tourney found in db with TourneyID = %d" % tourneyID)
if result[1] <> dbTourneyTypeId:
tourneyDataMatch = False
logging.debug("Tourney has wrong type ID (expected : %s - found : %s)" % (dbTourneyTypeId, result[1]))
if (tourney.starttime is None and result[4] is not None) or ( tourney.starttime is not None and fpdb_simple.parseHandStartTime("- %s" % tourney.starttime) <> result[4]) :
tourneyDataMatch = False
logging.debug("Tourney data mismatch : wrong starttime : Tourney=%s / db=%s" % (tourney.starttime, result[4]))
if (tourney.endtime is None and result[5] is not None) or ( tourney.endtime is not None and fpdb_simple.parseHandStartTime("- %s" % tourney.endtime) <> result[5]) :
tourneyDataMatch = False
logging.debug("Tourney data mismatch : wrong endtime : Tourney=%s / db=%s" % (tourney.endtime, result[5]))
for ev in expectedValues :
if ( getattr( tourney, expectedValues.get(ev) ) <> result[ev] ):
logging.debug("Tourney data mismatch : wrong %s : Tourney=%s / db=%s" % (expectedValues.get(ev), getattr( tourney, expectedValues.get(ev)), result[ev]) )
tourneyDataMatch = False
#break
for evD in expectedValuesDecimal :
if ( Decimal(getattr( tourney, expectedValuesDecimal.get(evD)) ) <> result[evD] ):
logging.debug("Tourney data mismatch : wrong %s : Tourney=%s / db=%s" % (expectedValuesDecimal.get(evD), getattr( tourney, expectedValuesDecimal.get(evD)), result[evD]) )
tourneyDataMatch = False
#break
# TO DO : Deal with matrix summary mutliple parsings
except:
# Tourney not found : create
logging.debug("Tourney is not found : create")
if tourney.tourneyComment is not None :
tCommentTs = datetime.today()
if tourney.starttime is not None :
starttime = fpdb_simple.parseHandStartTime("- %s" % tourney.starttime)
if tourney.endtime is not None :
endtime = fpdb_simple.parseHandStartTime("- %s" % tourney.endtime)
# TODO : deal with matrix Id processed
cursor.execute (self.sql.query['insertTourney'].replace('%s', self.sql.query['placeholder']),
(dbTourneyTypeId, tourney.tourNo, tourney.entries, tourney.prizepool, starttime,
endtime, tourney.buyInChips, tourney.tourneyName, 0, tourney.rebuyChips, tourney.addOnChips,
tourney.rebuyAmount, tourney.addOnAmount, tourney.totalRebuys, tourney.totalAddOns, tourney.koBounty,
tourney.tourneyComment, tCommentTs)
)
tourneyID = self.get_last_insert_id(cursor)
# Deal with inconsistent tourney in db
if tourneyDataMatch == False :
# Update Tourney
if result[16] <> tourney.tourneyComment :
tCommentTs = datetime.today()
if tourney.starttime is not None :
starttime = fpdb_simple.parseHandStartTime("- %s" % tourney.starttime)
if tourney.endtime is not None :
endtime = fpdb_simple.parseHandStartTime("- %s" % tourney.endtime)
cursor.execute (self.sql.query['updateTourney'].replace('%s', self.sql.query['placeholder']),
(dbTourneyTypeId, tourney.entries, tourney.prizepool, starttime,
endtime, tourney.buyInChips, tourney.tourneyName, 0, tourney.rebuyChips, tourney.addOnChips,
tourney.rebuyAmount, tourney.addOnAmount, tourney.totalRebuys, tourney.totalAddOns, tourney.koBounty,
tourney.tourneyComment, tCommentTs, tourneyID)
)
return tourneyID
#end def tRecognizeTourney
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)
# hero may be None for matrix tourneys summaries
# hero = [ tourney.hero ]
# heroId = fpdb_simple.recognisePlayerIDs(self, hero , tourney.siteId)
# logging.debug("hero Id = %s - playersId = %s" % (heroId , playersIds))
tourneyPlayersIds=[]
try:
cursor = self.get_cursor()
for i in xrange(len(playersIds)):
cursor.execute(self.sql.query['getTourneysPlayers'].replace('%s', self.sql.query['placeholder'])
,(dbTourneyId, playersIds[i]))
result=cursor.fetchone()
#print "tried SELECTing tourneys_players.id:",tmp
try:
len(result)
# checking data
logging.debug("TourneysPlayers found : checking data")
expectedValuesDecimal = { 1 : "payinAmounts", 2 : "finishPositions", 3 : "winnings", 4 : "countRebuys",
5 : "countAddOns", 6 : "countKO" }
tourneyPlayersIds.append(result[0]);
tourneysPlayersDataMatch = True
for evD in expectedValuesDecimal :
if ( Decimal(getattr( tourney, expectedValuesDecimal.get(evD))[tourney.players[i]] ) <> result[evD] ):
logging.debug("TourneysPlayers data mismatch for TourneysPlayer id=%d, name=%s : wrong %s : Tourney=%s / db=%s" % (result[0], tourney.players[i], expectedValuesDecimal.get(evD), getattr( tourney, expectedValuesDecimal.get(evD))[tourney.players[i]], result[evD]) )
tourneysPlayersDataMatch = False
#break
if tourneysPlayersDataMatch == False:
logging.debug("TourneysPlayers data update needed")
cursor.execute (self.sql.query['updateTourneysPlayers'].replace('%s', self.sql.query['placeholder']),
(tourney.payinAmounts[tourney.players[i]], tourney.finishPositions[tourney.players[i]],
tourney.winnings[tourney.players[i]] , tourney.countRebuys[tourney.players[i]],
tourney.countAddOns[tourney.players[i]] , tourney.countKO[tourney.players[i]],
result[7], result[8], result[0])
)
except TypeError:
logging.debug("TourneysPlayers not found : need insert")
cursor.execute (self.sql.query['insertTourneysPlayers'].replace('%s', self.sql.query['placeholder']),
(dbTourneyId, playersIds[i],
tourney.payinAmounts[tourney.players[i]], tourney.finishPositions[tourney.players[i]],
tourney.winnings[tourney.players[i]] , tourney.countRebuys[tourney.players[i]],
tourney.countAddOns[tourney.players[i]] , tourney.countKO[tourney.players[i]],
None, None)
)
tourneyPlayersIds.append(self.get_last_insert_id(cursor))
except:
raise fpdb_simple.FpdbError( "tStoreTourneyPlayers error: " + str(sys.exc_value) )
return tourneyPlayersIds
#end def tStoreTourneyPlayers
def tUpdateTourneysHandsPlayers(self, tourney, dbTourneysPlayersIds, dbTourneyTypeId):
logging.debug("Database.tCheckTourneysHandsPlayers")
try:
# Massive update seems to take quite some time ...
# query = self.sql.query['updateHandsPlayersForTTypeId2'] % (dbTourneyTypeId, self.sql.query['handsPlayersTTypeId_joiner'].join([self.sql.query['placeholder'] for id in dbTourneysPlayersIds]) )
# cursor = self.get_cursor()
# cursor.execute (query, dbTourneysPlayersIds)
query = self.sql.query['selectHandsPlayersWithWrongTTypeId'] % (dbTourneyTypeId, self.sql.query['handsPlayersTTypeId_joiner'].join([self.sql.query['placeholder'] for id in dbTourneysPlayersIds]) )
#print "query : %s" % query
cursor = self.get_cursor()
cursor.execute (query, dbTourneysPlayersIds)
result=cursor.fetchall()
if (len(result) > 0):
logging.debug("%d lines need update : %s" % (len(result), result) )
listIds = []
for i in result:
listIds.append(i[0])
query2 = self.sql.query['updateHandsPlayersForTTypeId'] % (dbTourneyTypeId, self.sql.query['handsPlayersTTypeId_joiner_id'].join([self.sql.query['placeholder'] for id in listIds]) )
cursor.execute (query2, listIds)
else:
logging.debug("No need to update, HandsPlayers are correct")
except:
raise fpdb_simple.FpdbError( "tStoreTourneyPlayers error: " + str(sys.exc_value) )
#end def tUpdateTourneysHandsPlayers
# Class used to hold all the data needed to write a hand to the db # Class used to hold all the data needed to write a hand to the db
# mainParser() in fpdb_parse_logic.py creates one of these and then passes it to # mainParser() in fpdb_parse_logic.py creates one of these and then passes it to

View File

@ -1,7 +1,21 @@
class FPDBError(Exception): class FpdbError(Exception):
def __init__(self, value):
self.value = value
def __str__(self):
return repr(self.value)
class FpdbParseError(FpdbError):
def __init__(self,value='',hid=''):
self.value = value
self.hid = hid
def __str__(self):
if hid:
return repr("HID:"+hid+", "+self.value)
else:
return repr(self.value)
class FpdbDatabaseError(FpdbError):
pass pass
class FpdbParseError(FPDBError): class DuplicateError(FpdbError):
def __init__(self,hid=None): pass
self.hid = hid

View File

@ -57,6 +57,13 @@ class Fulltilt(HandHistoryConverter):
(?P<PARTIAL>\(partial\))?\n (?P<PARTIAL>\(partial\))?\n
(?:.*?\n(?P<CANCELLED>Hand\s\#(?P=HID)\shas\sbeen\scanceled))? (?:.*?\n(?P<CANCELLED>Hand\s\#(?P=HID)\shas\sbeen\scanceled))?
''', re.VERBOSE|re.DOTALL) ''', re.VERBOSE|re.DOTALL)
re_TourneyExtraInfo = re.compile('''(((?P<TOURNEY_NAME>[^$]+)?
(?P<CURRENCY>\$)?(?P<BUYIN>[.0-9]+)?\s*\+\s*\$?(?P<FEE>[.0-9]+)?
(\s(?P<SPECIAL>(KO|Heads\sUp|Matrix\s\dx|Rebuy|Madness)))?
(\s(?P<SHOOTOUT>Shootout))?
(\s(?P<SNG>Sit\s&\sGo))?
(\s\((?P<TURBO>Turbo)\))?)|(?P<UNREADABLE_INFO>.+))
''', re.VERBOSE)
re_Button = re.compile('^The button is in seat #(?P<BUTTON>\d+)', re.MULTILINE) re_Button = re.compile('^The button is in seat #(?P<BUTTON>\d+)', re.MULTILINE)
re_PlayerInfo = re.compile('Seat (?P<SEAT>[0-9]+): (?P<PNAME>.*) \(\$(?P<CASH>[,.0-9]+)\)$', re.MULTILINE) re_PlayerInfo = re.compile('Seat (?P<SEAT>[0-9]+): (?P<PNAME>.*) \(\$(?P<CASH>[,.0-9]+)\)$', re.MULTILINE)
re_TourneyPlayerInfo = re.compile('Seat (?P<SEAT>[0-9]+): (?P<PNAME>.*) \(\$?(?P<CASH>[,.0-9]+)\)', re.MULTILINE) re_TourneyPlayerInfo = re.compile('Seat (?P<SEAT>[0-9]+): (?P<PNAME>.*) \(\$?(?P<CASH>[,.0-9]+)\)', re.MULTILINE)
@ -66,7 +73,7 @@ class Fulltilt(HandHistoryConverter):
re_TourneyInfo = re.compile('''Tournament\sSummary\s re_TourneyInfo = re.compile('''Tournament\sSummary\s
(?P<TOURNAMENT_NAME>[^$(]+)?\s* (?P<TOURNAMENT_NAME>[^$(]+)?\s*
((?P<CURRENCY>\$|)?(?P<BUYIN>[.0-9]+)\s*\+\s*\$?(?P<FEE>[.0-9]+)\s)? ((?P<CURRENCY>\$|)?(?P<BUYIN>[.0-9]+)\s*\+\s*\$?(?P<FEE>[.0-9]+)\s)?
((?P<SPECIAL>(KO|Heads\sUp|Matrix\s\dx|Rebuy))\s)? ((?P<SPECIAL>(KO|Heads\sUp|Matrix\s\dx|Rebuy|Madness))\s)?
((?P<SHOOTOUT>Shootout)\s)? ((?P<SHOOTOUT>Shootout)\s)?
((?P<SNG>Sit\s&\sGo)\s)? ((?P<SNG>Sit\s&\sGo)\s)?
(\((?P<TURBO1>Turbo)\)\s)? (\((?P<TURBO1>Turbo)\)\s)?
@ -202,16 +209,30 @@ class Fulltilt(HandHistoryConverter):
if m.group('PLAY') != None: if m.group('PLAY') != None:
hand.gametype['currency'] = 'play' hand.gametype['currency'] = 'play'
# TODO: if there's a way to figure these out, we should.. otherwise we have to stuff it with unknowns # Done: if there's a way to figure these out, we should.. otherwise we have to stuff it with unknowns
re_SNGBuyInFee = re.compile('''(?P<CURRENCY>\$)?(?P<BUYIN>[.0-9]+) \+ \$?(?P<FEE>[.0-9]+) (?P<EXTRA_INFO>[\sA-Za-z&()]+)?''') if m.group('TOURNAMENT') is not None:
# TO DO : See if important info can be retrieved from EXTRA_INFO (sould be things like Turbo, Matrix, KO, ...) n = self.re_TourneyExtraInfo.search(m.group('TOURNAMENT'))
try: if n.group('UNREADABLE_INFO') is not None:
n = re_SNGBuyInFee.search(m.group('TOURNAMENT')) hand.tourneyComment = n.group('UNREADABLE_INFO')
#print "cur %s BUYIN %s FEE %s EXTRA %s" %(n.group('CURRENCY'), n.group('BUYIN'), n.group('FEE'), n.group('EXTRA_INFO')) else:
hand.tourneyComment = n.group('TOURNEY_NAME') # can be None
if (n.group('CURRENCY') is not None and n.group('BUYIN') is not None and n.group('FEE') is not None):
hand.buyin = "%s%s+%s%s" %(n.group('CURRENCY'), n.group('BUYIN'), n.group('CURRENCY'), n.group('FEE')) hand.buyin = "%s%s+%s%s" %(n.group('CURRENCY'), n.group('BUYIN'), n.group('CURRENCY'), n.group('FEE'))
except: if n.group('TURBO') is not None :
#print "Unable to collect BuyIn/Fee Info" hand.speed = "Turbo"
logging.info("Unable to collect BuyIn/Fee Info from HandInfo") if n.group('SPECIAL') is not None :
special = n.group('SPECIAL')
if special == "Rebuy":
hand.isRebuy = True
if special == "KO":
hand.isKO = True
if special == "Head's Up":
hand.isHU = True
if re.search("Matrix", special):
hand.isMatrix = True
if special == "Shootout":
hand.isShootout = True
if hand.buyin == None: if hand.buyin == None:
hand.buyin = "$0.00+$0.00" hand.buyin = "$0.00+$0.00"
@ -405,9 +426,9 @@ class Fulltilt(HandHistoryConverter):
self.status = False self.status = False
else: else:
self.tourney = Tourney.Tourney(sitename = self.sitename, gametype = None, summaryText = summaryInfoList, builtFrom = "HHC") self.tourney = Tourney.Tourney(sitename = self.sitename, gametype = None, summaryText = summaryInfoList, builtFrom = "HHC")
self.status = self.determineTourneyType(self.tourney) self.status = self.getPlayersPositionsAndWinnings(self.tourney)
if self.status == True : if self.status == True :
self.status = status = self.getPlayersPositionsAndWinnings(self.tourney) self.status = self.determineTourneyType(self.tourney)
#print self.tourney #print self.tourney
else: else:
log.info("Parsing NOK : rejected") log.info("Parsing NOK : rejected")
@ -454,10 +475,10 @@ class Fulltilt(HandHistoryConverter):
# Additional info can be stored in the tourney object # Additional info can be stored in the tourney object
if mg['BUYIN'] is not None: if mg['BUYIN'] is not None:
tourney.buyin = mg['BUYIN'] tourney.buyin = 100*Decimal(re.sub(u',', u'', "%s" % mg['BUYIN']))
tourney.fee = 0 tourney.fee = 0
if mg['FEE'] is not None: if mg['FEE'] is not None:
tourney.fee = mg['FEE'] tourney.fee = 100*Decimal(re.sub(u',', u'', "%s" % mg['FEE']))
if mg['TOURNAMENT_NAME'] is not None: if mg['TOURNAMENT_NAME'] is not None:
# Tournament Name can have a trailing space at the end (depending on the tournament description) # Tournament Name can have a trailing space at the end (depending on the tournament description)
tourney.tourneyName = mg['TOURNAMENT_NAME'].rstrip() tourney.tourneyName = mg['TOURNAMENT_NAME'].rstrip()
@ -472,6 +493,8 @@ class Fulltilt(HandHistoryConverter):
tourney.isMatrix = True tourney.isMatrix = True
if special == "Rebuy": if special == "Rebuy":
tourney.isRebuy = True tourney.isRebuy = True
if special == "Madness":
tourney.tourneyComment = "Madness"
if mg['SHOOTOUT'] is not None: if mg['SHOOTOUT'] is not None:
tourney.isShootout = True tourney.isShootout = True
if mg['TURBO1'] is not None or mg['TURBO2'] is not None : if mg['TURBO1'] is not None or mg['TURBO2'] is not None :
@ -500,25 +523,25 @@ class Fulltilt(HandHistoryConverter):
mg = m.groupdict() mg = m.groupdict()
if tourney.isMatrix : if tourney.isMatrix :
if mg['BUYIN'] is not None: if mg['BUYIN'] is not None:
tourney.subTourneyBuyin = mg['BUYIN'] tourney.subTourneyBuyin = 100*Decimal(re.sub(u',', u'', "%s" % mg['BUYIN']))
tourney.subTourneyFee = 0 tourney.subTourneyFee = 0
if mg['FEE'] is not None: if mg['FEE'] is not None:
tourney.subTourneyFee = mg['FEE'] tourney.subTourneyFee = 100*Decimal(re.sub(u',', u'', "%s" % mg['FEE']))
else : else :
if mg['BUYIN'] is not None: if mg['BUYIN'] is not None:
if tourney.buyin is None: if tourney.buyin is None:
tourney.buyin = mg['BUYIN'] tourney.buyin = 100*Decimal(re.sub(u',', u'', "%s" % mg['BUYIN']))
else : else :
if mg['BUYIN'] != tourney.buyin: if 100*Decimal(re.sub(u',', u'', "%s" % mg['BUYIN'])) != tourney.buyin:
log.error( "Conflict between buyins read in topline (%s) and in BuyIn field (%s)" % (touney.buyin, mg['BUYIN']) ) log.error( "Conflict between buyins read in topline (%s) and in BuyIn field (%s)" % (touney.buyin, 100*Decimal(re.sub(u',', u'', "%s" % mg['BUYIN']))) )
tourney.subTourneyBuyin = mg['BUYIN'] tourney.subTourneyBuyin = 100*Decimal(re.sub(u',', u'', "%s" % mg['BUYIN']))
if mg['FEE'] is not None: if mg['FEE'] is not None:
if tourney.fee is None: if tourney.fee is None:
tourney.fee = mg['FEE'] tourney.fee = 100*Decimal(re.sub(u',', u'', "%s" % mg['FEE']))
else : else :
if mg['FEE'] != tourney.fee: if 100*Decimal(re.sub(u',', u'', "%s" % mg['FEE'])) != tourney.fee:
log.error( "Conflict between fees read in topline (%s) and in BuyIn field (%s)" % (touney.fee, mg['FEE']) ) log.error( "Conflict between fees read in topline (%s) and in BuyIn field (%s)" % (touney.fee, 100*Decimal(re.sub(u',', u'', "%s" % mg['FEE']))) )
tourney.subTourneyFee = mg['FEE'] tourney.subTourneyFee = 100*Decimal(re.sub(u',', u'', "%s" % mg['FEE']))
if tourney.buyin is None: if tourney.buyin is None:
log.info( "Unable to affect a buyin to this tournament : assume it's a freeroll" ) log.info( "Unable to affect a buyin to this tournament : assume it's a freeroll" )
@ -535,15 +558,12 @@ class Fulltilt(HandHistoryConverter):
"PRIZEPOOL" : self.re_TourneyPrizePool, "PRIZEPOOL" : self.re_TourneyPrizePool,
"REBUY_AMOUNT" : self.re_TourneyRebuyAmount, "REBUY_AMOUNT" : self.re_TourneyRebuyAmount,
"ADDON_AMOUNT" : self.re_TourneyAddOnAmount, "ADDON_AMOUNT" : self.re_TourneyAddOnAmount,
"REBUY_COUNT" : self.re_TourneyRebuyCount,
"ADDON_COUNT" : self.re_TourneyAddOnCount,
"REBUY_TOTAL" : self.re_TourneyRebuysTotal, "REBUY_TOTAL" : self.re_TourneyRebuysTotal,
"ADDONS_TOTAL" : self.re_TourneyAddOnsTotal, "ADDONS_TOTAL" : self.re_TourneyAddOnsTotal,
"REBUY_CHIPS" : self.re_TourneyRebuyChips, "REBUY_CHIPS" : self.re_TourneyRebuyChips,
"ADDON_CHIPS" : self.re_TourneyAddOnChips, "ADDON_CHIPS" : self.re_TourneyAddOnChips,
"STARTTIME" : self.re_TourneyTimeInfo, "STARTTIME" : self.re_TourneyTimeInfo,
"KO_BOUNTY_AMOUNT" : self.re_TourneyKOBounty, "KO_BOUNTY_AMOUNT" : self.re_TourneyKOBounty,
"COUNT_KO" : self.re_TourneyCountKO
} }
@ -552,15 +572,12 @@ class Fulltilt(HandHistoryConverter):
"PRIZEPOOL" : "prizepool", "PRIZEPOOL" : "prizepool",
"REBUY_AMOUNT" : "rebuyAmount", "REBUY_AMOUNT" : "rebuyAmount",
"ADDON_AMOUNT" : "addOnAmount", "ADDON_AMOUNT" : "addOnAmount",
"REBUY_COUNT" : "countRebuys",
"ADDON_COUNT" : "countAddOns",
"REBUY_TOTAL" : "totalRebuys", "REBUY_TOTAL" : "totalRebuys",
"ADDONS_TOTAL" : "totalAddOns", "ADDONS_TOTAL" : "totalAddOns",
"REBUY_CHIPS" : "rebuyChips", "REBUY_CHIPS" : "rebuyChips",
"ADDON_CHIPS" : "addOnChips", "ADDON_CHIPS" : "addOnChips",
"STARTTIME" : "starttime", "STARTTIME" : "starttime",
"KO_BOUNTY_AMOUNT" : "koBounty", "KO_BOUNTY_AMOUNT" : "koBounty"
"COUNT_KO" : "countKO"
} }
mg = {} # After the loop, mg will contain all the matching groups, including the ones that have not been used, like ENDTIME and IN-PROGRESS mg = {} # After the loop, mg will contain all the matching groups, including the ones that have not been used, like ENDTIME and IN-PROGRESS
@ -573,8 +590,43 @@ class Fulltilt(HandHistoryConverter):
if mg['IN_PROGRESS'] is not None or mg['ENDTIME'] is not None: if mg['IN_PROGRESS'] is not None or mg['ENDTIME'] is not None:
# Assign endtime to tourney (if None, that's ok, it's because the tourney wans't over over when the summary file was produced) # Assign endtime to tourney (if None, that's ok, it's because the tourney wans't over over when the summary file was produced)
tourney.endtime = mg['ENDTIME'] tourney.endtime = mg['ENDTIME']
#print mg
# Deal with hero specific information
if tourney.hero is not None :
m = self.re_TourneyRebuyCount.search(tourneyText)
if m is not None:
mg = m.groupdict()
if mg['REBUY_COUNT'] is not None :
tourney.countRebuys.update( { tourney.hero : Decimal(mg['REBUY_COUNT']) } )
m = self.re_TourneyAddOnCount.search(tourneyText)
if m is not None:
mg = m.groupdict()
if mg['ADDON_COUNT'] is not None :
tourney.countAddOns.update( { tourney.hero : Decimal(mg['ADDON_COUNT']) } )
m = self.re_TourneyCountKO.search(tourneyText)
if m is not None:
mg = m.groupdict()
if mg['COUNT_KO'] is not None :
tourney.countKO.update( { tourney.hero : Decimal(mg['COUNT_KO']) } )
# Deal with money amounts
tourney.koBounty = 100*Decimal(re.sub(u',', u'', "%s" % tourney.koBounty))
tourney.prizepool = 100*Decimal(re.sub(u',', u'', "%s" % tourney.prizepool))
tourney.rebuyAmount = 100*Decimal(re.sub(u',', u'', "%s" % tourney.rebuyAmount))
tourney.addOnAmount = 100*Decimal(re.sub(u',', u'', "%s" % tourney.addOnAmount))
# Calculate payin amounts and update winnings -- not possible to take into account nb of rebuys, addons or Knockouts for other players than hero on FTP
for p in tourney.players :
tourney.payinAmounts[p] = tourney.buyin + tourney.fee + (tourney.rebuyAmount * tourney.countRebuys[p]) + (tourney.addOnAmount * tourney.countAddOns[p])
#print " player %s : payinAmount = %d" %( p, tourney.payinAmounts[p])
if tourney.isKO :
#tourney.incrementPlayerWinnings(tourney.players[p], Decimal(tourney.koBounty)*Decimal(tourney.countKO[p]))
tourney.winnings[p] += Decimal(tourney.koBounty)*Decimal(tourney.countKO[p])
#print "player %s : winnings %d" % (p, tourney.winnings[p])
#print mg
return True return True
def getPlayersPositionsAndWinnings(self, tourney): def getPlayersPositionsAndWinnings(self, tourney):
@ -590,15 +642,15 @@ class Fulltilt(HandHistoryConverter):
rank = Decimal(a.group('RANK')) rank = Decimal(a.group('RANK'))
if a.group('WINNING') is not None: if a.group('WINNING') is not None:
winnings = a.group('WINNING') winnings = 100*Decimal(re.sub(u',', u'', "%s" % a.group('WINNING')))
else: else:
winnings = "0" winnings = "0"
tourney.addPlayer(rank, a.group('PNAME'), winnings) tourney.addPlayer(rank, a.group('PNAME'), winnings, 0, 0, 0, 0)
else: else:
print "Player finishing stats unreadable : %s" % a print "Player finishing stats unreadable : %s" % a
# Deal with KO tournaments for hero winnings calculation # Find Hero
n = self.re_TourneyHeroFinishingP.search(playersText) n = self.re_TourneyHeroFinishingP.search(playersText)
if n is not None: if n is not None:
heroName = n.group('HERO_NAME') heroName = n.group('HERO_NAME')
@ -606,9 +658,6 @@ class Fulltilt(HandHistoryConverter):
# Is this really useful ? # Is this really useful ?
if (tourney.finishPositions[heroName] != Decimal(n.group('HERO_FINISHING_POS'))): if (tourney.finishPositions[heroName] != Decimal(n.group('HERO_FINISHING_POS'))):
print "Bad parsing : finish position incoherent : %s / %s" % (tourney.finishPositions[heroName], n.group('HERO_FINISHING_POS')) print "Bad parsing : finish position incoherent : %s / %s" % (tourney.finishPositions[heroName], n.group('HERO_FINISHING_POS'))
if tourney.isKO:
#Update the winnings with the (KO amount) * (# of KO)
tourney.incrementPlayerWinnings(n.group('HERO_NAME'), Decimal(tourney.koBounty)*Decimal(tourney.countKO))
return True return True

View File

@ -34,6 +34,7 @@ import string
class GuiAutoImport (threading.Thread): class GuiAutoImport (threading.Thread):
def __init__(self, settings, config, sql): def __init__(self, settings, config, sql):
"""Constructor for GuiAutoImport""" """Constructor for GuiAutoImport"""
self.importtimer = 0
self.settings=settings self.settings=settings
self.config=config self.config=config
self.sql = sql self.sql = sql
@ -196,11 +197,14 @@ class GuiAutoImport (threading.Thread):
self.do_import() self.do_import()
interval = int(self.intervalEntry.get_text()) interval = int(self.intervalEntry.get_text())
gobject.timeout_add(interval*1000, self.do_import) if self.importtimer != 0:
gobject.source_remove(self.importtimer)
self.importtimer = gobject.timeout_add(interval*1000, self.do_import)
else: else:
print "auto-import aborted - global lock not available" print "auto-import aborted - global lock not available"
else: # toggled off else: # toggled off
gobject.source_remove(self.importtimer)
self.settings['global_lock'].release() self.settings['global_lock'].release()
self.doAutoImportBool = False # do_import will return this and stop the gobject callback timer self.doAutoImportBool = False # do_import will return this and stop the gobject callback timer
print "Stopping autoimport - global lock released." print "Stopping autoimport - global lock released."

View File

@ -27,11 +27,13 @@ import traceback
import pygtk import pygtk
pygtk.require('2.0') pygtk.require('2.0')
import gtk import gtk
import gobject
# fpdb/FreePokerTools modules # fpdb/FreePokerTools modules
import fpdb_simple import fpdb_simple
import fpdb_import import fpdb_import
import Configuration import Configuration
import Exceptions
class GuiBulkImport(): class GuiBulkImport():
@ -53,12 +55,22 @@ class GuiBulkImport():
else: else:
self.importer.RunImportThreaded() self.importer.RunImportThreaded()
def dopulse(self):
self.progressbar.pulse()
return True
def load_clicked(self, widget, data=None): def load_clicked(self, widget, data=None):
# Does the lock acquisition need to be more sophisticated for multiple dirs? # Does the lock acquisition need to be more sophisticated for multiple dirs?
# (see comment above about what to do if pipe already open) # (see comment above about what to do if pipe already open)
if self.settings['global_lock'].acquire(False): # returns false immediately if lock not acquired if self.settings['global_lock'].acquire(False): # returns false immediately if lock not acquired
try: try:
print "\nGlobal lock taken ..." print "\nGlobal lock taken ..."
self.progressbar.set_text("Importing...")
self.progressbar.pulse()
while gtk.events_pending(): # see http://faq.pygtk.org/index.py?req=index for more hints (3.7)
gtk.main_iteration(False)
self.timer = gobject.timeout_add(100, self.dopulse)
# get the dir to import from the chooser # get the dir to import from the chooser
self.inputFile = self.chooser.get_filename() self.inputFile = self.chooser.get_filename()
@ -74,9 +86,7 @@ class GuiBulkImport():
cb_hmodel = self.cb_drophudcache.get_model() cb_hmodel = self.cb_drophudcache.get_model()
cb_hindex = self.cb_drophudcache.get_active() cb_hindex = self.cb_drophudcache.get_active()
self.lab_info.set_markup('<span foreground="blue">Importing ...</span>') # uses pango markup! #self.lab_info.set_markup('<span foreground="blue">Importing ...</span>') # uses pango markup!
while gtk.events_pending(): # see http://faq.pygtk.org/index.py?req=index for more hints (3.7)
gtk.main_iteration(False)
if cb_index: if cb_index:
self.importer.setDropIndexes(cb_model[cb_index][0]) self.importer.setDropIndexes(cb_model[cb_index][0])
@ -91,7 +101,14 @@ class GuiBulkImport():
self.importer.addBulkImportImportFileOrDir(self.inputFile, site = sitename) self.importer.addBulkImportImportFileOrDir(self.inputFile, site = sitename)
self.importer.setCallHud(False) self.importer.setCallHud(False)
starttime = time() starttime = time()
try:
(stored, dups, partial, errs, ttime) = self.importer.runImport() (stored, dups, partial, errs, ttime) = self.importer.runImport()
except:
print "*** EXCEPTION DURING BULKIMPORT!!!"
raise Exceptions.FpdbError
finally:
gobject.source_remove(self.timer)
ttime = time() - starttime ttime = time() - starttime
if ttime == 0: if ttime == 0:
ttime = 1 ttime = 1
@ -106,7 +123,8 @@ class GuiBulkImport():
self.cb_drophudcache.set_active(0) self.cb_drophudcache.set_active(0)
self.lab_hdrop.set_sensitive(True) self.lab_hdrop.set_sensitive(True)
self.lab_info.set_text("Import finished") self.progressbar.set_text("Import Complete")
self.progressbar.set_fraction(0)
except: except:
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])
@ -251,9 +269,14 @@ class GuiBulkImport():
self.lab_spacer.show() self.lab_spacer.show()
# label - info # label - info
self.lab_info = gtk.Label() # self.lab_info = gtk.Label()
self.table.attach(self.lab_info, 3, 5, 4, 5, xpadding = 0, ypadding = 0, yoptions=gtk.SHRINK) # self.table.attach(self.lab_info, 3, 5, 4, 5, xpadding = 0, ypadding = 0, yoptions=gtk.SHRINK)
self.lab_info.show() # self.lab_info.show()
self.progressbar = gtk.ProgressBar()
self.table.attach(self.progressbar, 3, 5, 4, 5, xpadding = 0, ypadding = 0, yoptions = gtk.SHRINK)
self.progressbar.set_text("Waiting...")
self.progressbar.set_fraction(0)
self.progressbar.show()
# see how many hands are in the db and adjust accordingly # see how many hands are in the db and adjust accordingly
tcursor = self.importer.database.cursor tcursor = self.importer.database.cursor
@ -284,7 +307,7 @@ def main(argv=None):
parser.add_option("-q", "--quiet", action="store_false", dest="gui", default=True, parser.add_option("-q", "--quiet", action="store_false", dest="gui", default=True,
help="don't start gui; deprecated (just give a filename with -f).") help="don't start gui; deprecated (just give a filename with -f).")
parser.add_option("-c", "--convert", dest="filtername", default="PokerStars", metavar="FILTER", parser.add_option("-c", "--convert", dest="filtername", default="PokerStars", metavar="FILTER",
help="Conversion filter (*Full Tilt Poker, PokerStars, Everleaf)") help="Conversion filter (*Full Tilt Poker, PokerStars, Everleaf, Absolute)")
parser.add_option("-x", "--failOnError", action="store_true", default=False, parser.add_option("-x", "--failOnError", action="store_true", default=False,
help="If this option is passed it quits when it encounters any error") help="If this option is passed it quits when it encounters any error")
parser.add_option("-m", "--minPrint", "--status", dest="minPrint", default="0", type="int", parser.add_option("-m", "--minPrint", "--status", dest="minPrint", default="0", type="int",
@ -319,6 +342,7 @@ def main(argv=None):
# importer.setDropIndexes("auto") # importer.setDropIndexes("auto")
importer.setDropIndexes("don't drop") importer.setDropIndexes("don't drop")
importer.setFailOnError(options.failOnError) importer.setFailOnError(options.failOnError)
importer.setThreads(-1)
importer.addBulkImportImportFileOrDir(os.path.expanduser(options.filename), site=options.filtername) importer.addBulkImportImportFileOrDir(os.path.expanduser(options.filename), site=options.filtername)
importer.setCallHud(False) importer.setCallHud(False)
importer.runImport() importer.runImport()

View File

@ -21,7 +21,11 @@ pygtk.require('2.0')
import gtk import gtk
import os import os
from time import time, strftime, localtime from time import time, strftime, localtime
from numpy import diff, nonzero try:
from numpy import diff, nonzero
except:
print """Failed to load numpy in Session Viewer"""
print """This is of no consequence as the module currently doesn't do anything."""
import Card import Card
import fpdb_import import fpdb_import

View File

@ -24,6 +24,7 @@ import fpdb_simple
import fpdb_import import fpdb_import
import fpdb_db import fpdb_db
from Exceptions import *
class GuiTableViewer (threading.Thread): class GuiTableViewer (threading.Thread):
@ -73,7 +74,7 @@ class GuiTableViewer (threading.Thread):
tmp+=("WtSD", "W$wsF", "W$SD") tmp+=("WtSD", "W$wsF", "W$SD")
else: else:
raise fpdb_simple.FpdbError("reimplement stud") raise FpdbError("reimplement stud")
arr.append(tmp) arr.append(tmp)
#then the data rows #then the data rows
@ -93,7 +94,7 @@ class GuiTableViewer (threading.Thread):
elif seatCount==2 or seatCount==3: elif seatCount==2 or seatCount==3:
minSeats,maxSeats=seatCount,seatCount minSeats,maxSeats=seatCount,seatCount
else: else:
fpdb_simple.FpdbError("invalid seatCount") FpdbError("invalid seatCount")
self.cursor.execute("SELECT * FROM HudCache WHERE gametypeId=%s AND playerId=%s AND activeSeats>=%s AND activeSeats<=%s", (self.gametype_id, self.player_ids[player][0], minSeats, maxSeats)) self.cursor.execute("SELECT * FROM HudCache WHERE gametypeId=%s AND playerId=%s AND activeSeats>=%s AND activeSeats<=%s", (self.gametype_id, self.player_ids[player][0], minSeats, maxSeats))
rows=self.cursor.fetchall() rows=self.cursor.fetchall()

View File

@ -195,7 +195,7 @@ class HUD_main(object):
temp_key = tour_number temp_key = tour_number
else: # tourney, but can't get number and table else: # tourney, but can't get number and table
print "could not find tournament: skipping " 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))) #sys.stderr.write("Could not find tournament %d in hand %d. Skipping.\n" % (int(tour_number), int(new_hand_id)))
continue continue
else: else:

View File

@ -1,4 +1,5 @@
#!/usr/bin/python #!/usr/bin/python
# -*- coding: utf-8 -*-
#Copyright 2008 Carl Gherardi #Copyright 2008 Carl Gherardi
#This program is free software: you can redistribute it and/or modify #This program is free software: you can redistribute it and/or modify
@ -63,6 +64,15 @@ class Hand(object):
self.fee = None # the Database code is looking for this one .. ? self.fee = None # the Database code is looking for this one .. ?
self.level = None self.level = None
self.mixed = None self.mixed = None
# Some attributes for hand from a tourney
self.speed = "Normal"
self.isRebuy = False
self.isKO = False
self.isHU = False
self.isMatrix = False
self.isShootout = False
self.tourneyComment = None
self.seating = [] self.seating = []
self.players = [] self.players = []
self.posted = [] self.posted = []
@ -471,7 +481,6 @@ Add a raise on [street] by [player] to [amountTo]
For when a player shows cards for any reason (for showdown or out of choice). For when a player shows cards for any reason (for showdown or out of choice).
Card ranks will be uppercased Card ranks will be uppercased
""" """
import sys; sys.exit(1)
log.debug("addShownCards %s hole=%s all=%s" % (player, cards, holeandboard)) log.debug("addShownCards %s hole=%s all=%s" % (player, cards, holeandboard))
if cards is not None: if cards is not None:
self.addHoleCards(cards,player,shown, mucked) self.addHoleCards(cards,player,shown, mucked)
@ -583,8 +592,15 @@ Map the tuple self.gametype onto the pokerstars string describing it
else: # non-mixed cash games else: # non-mixed cash games
gs = gs + " %s (%s) - " % (self.getGameTypeAsString(), self.getStakesAsString()) gs = gs + " %s (%s) - " % (self.getGameTypeAsString(), self.getStakesAsString())
return gs + datetime.datetime.strftime(self.starttime,'%Y/%m/%d %H:%M:%S ET') try:
timestr = datetime.datetime.strftime(self.starttime, '%Y/%m/%d %H:%M:%S ET')
except TypeError:
print "*** ERROR - HAND: calling writeGameLine with unexpected STARTTIME value, expecting datetime.date object, received:", self.starttime
print "*** Make sure your HandHistoryConverter is setting hand.starttime properly!"
print "*** Game String:", gs
return gs
else:
return gs + timestr
def writeTableLine(self): def writeTableLine(self):
table_string = "Table \'%s\' %s-max" % (self.tablename, self.maxseats) table_string = "Table \'%s\' %s-max" % (self.tablename, self.maxseats)
@ -672,7 +688,7 @@ class HoldemOmahaHand(Hand):
tmp5 = 0 tmp5 = 0
return (tmp1,tmp2,tmp3,tmp4,tmp5) return (tmp1,tmp2,tmp3,tmp4,tmp5)
def writeHTMLHand(self, fh=sys.__stdout__): def writeHTMLHand(self):
from nevow import tags as T from nevow import tags as T
from nevow import flat from nevow import flat
players_who_act_preflop = (([x[0] for x in self.actions['PREFLOP']]+[x[0] for x in self.actions['BLINDSANTES']])) players_who_act_preflop = (([x[0] for x in self.actions['PREFLOP']]+[x[0] for x in self.actions['BLINDSANTES']]))

View File

@ -37,9 +37,12 @@ import gettext
gettext.install('fpdb') gettext.install('fpdb')
import logging, logging.config import logging, logging.config
logging.config.fileConfig("logging.conf") logging.config.fileConfig(os.path.join(sys.path[0],"logging.conf"))
log = logging.getLogger("parser") log = logging.getLogger("parser")
import pygtk
import gtk
class HandHistoryConverter(): class HandHistoryConverter():
READ_CHUNK_SIZE = 10000 # bytes to read at a time from file in tail mode READ_CHUNK_SIZE = 10000 # bytes to read at a time from file in tail mode
@ -82,13 +85,21 @@ follow : whether to tail -f the input"""
# TODO: out_path should be sanity checked. # TODO: out_path should be sanity checked.
out_dir = os.path.dirname(self.out_path) out_dir = os.path.dirname(self.out_path)
if not os.path.isdir(out_dir) and out_dir != '': if not os.path.isdir(out_dir) and out_dir != '':
log.info("Creating directory '%s'" % out_dir) try:
os.makedirs(out_dir) os.makedirs(out_dir)
except: # we get a WindowsError here in Windows.. pretty sure something else for Linux :D
log.error("Unable to create output directory %s for HHC!" % out_dir)
print "*** ERROR: UNABLE TO CREATE OUTPUT DIRECTORY", out_dir
# TODO: pop up a box to allow person to choose output directory?
# TODO: shouldn't that be done when we startup, actually?
else:
log.info("Created directory '%s'" % out_dir)
try: try:
self.out_fh = codecs.open(self.out_path, 'w', 'cp1252') self.out_fh = codecs.open(self.out_path, 'w', 'cp1252')
log.debug("out_path %s opened as %s" % (self.out_path, self.out_fh))
except: except:
log.error("out_path %s couldn't be opened" % (self.out_path)) log.error("out_path %s couldn't be opened" % (self.out_path))
else:
log.debug("out_path %s opened as %s" % (self.out_path, self.out_fh))
self.follow = follow self.follow = follow
self.compiledPlayers = set() self.compiledPlayers = set()
@ -116,6 +127,9 @@ If in follow mode, wait for more data to turn up.
Otherwise, finish at EOF. Otherwise, finish at EOF.
""" """
while gtk.events_pending():
gtk.main_iteration(False)
starttime = time.time() starttime = time.time()
if not self.sanityCheck(): if not self.sanityCheck():
log.warning("Failed sanity check") log.warning("Failed sanity check")
@ -139,7 +153,8 @@ Otherwise, finish at EOF.
handsList = self.allHandsAsList() handsList = self.allHandsAsList()
log.info("Parsing %d hands" % len(handsList)) log.info("Parsing %d hands" % len(handsList))
# Determine if we're dealing with a HH file or a Summary file # Determine if we're dealing with a HH file or a Summary file
if self.isSummary(handsList[0]) == False: # quick fix : empty files make the handsList[0] fail ==> If empty file, go on with HH parsing
if len(handsList) == 0 or self.isSummary(handsList[0]) == False:
self.parsedObjectType = "HH" self.parsedObjectType = "HH"
for handText in handsList: for handText in handsList:
try: try:
@ -411,10 +426,8 @@ or None if we fail to get the info """
log.debug("Reading stdin with %s" % self.codepage) # is this necessary? or possible? or what? log.debug("Reading stdin with %s" % self.codepage) # is this necessary? or possible? or what?
in_fh = codecs.getreader('cp1252')(sys.stdin) in_fh = codecs.getreader('cp1252')(sys.stdin)
else: else:
success = False
for kodec in self.__listof(self.codepage): for kodec in self.__listof(self.codepage):
if success: break #print "trying", kodec
print "trying", kodec
try: try:
in_fh = codecs.open(self.in_path, 'r', kodec) in_fh = codecs.open(self.in_path, 'r', kodec)
in_fh.seek(self.index) in_fh.seek(self.index)
@ -422,9 +435,11 @@ or None if we fail to get the info """
self.obs = in_fh.read() self.obs = in_fh.read()
self.index = in_fh.tell() self.index = in_fh.tell()
in_fh.close() in_fh.close()
success = True break
except: except:
pass pass
else:
print "unable to read file with any codec in list!", self.in_path
elif(self.filetype == "xml"): elif(self.filetype == "xml"):
doc = xml.dom.minidom.parse(filename) doc = xml.dom.minidom.parse(filename)
self.doc = doc self.doc = doc

View File

@ -81,6 +81,10 @@ class Hud:
(font, font_size) = config.get_default_font(self.table.site) (font, font_size) = config.get_default_font(self.table.site)
self.colors = config.get_default_colors(self.table.site) self.colors = config.get_default_colors(self.table.site)
self.backgroundcolor = gtk.gdk.color_parse(self.colors['hudbgcolor'])
self.foregroundcolor = gtk.gdk.color_parse(self.colors['hudfgcolor'])
if font == None: if font == None:
font = "Sans" font = "Sans"
if font_size == None: if font_size == None:
@ -102,84 +106,66 @@ class Hud:
def create_mw(self): def create_mw(self):
# Set up a main window for this this instance of the HUD # Set up a main window for this this instance of the HUD
self.main_window = gtk.Window() win = gtk.Window()
self.main_window.set_gravity(gtk.gdk.GRAVITY_STATIC) win.set_gravity(gtk.gdk.GRAVITY_STATIC)
self.main_window.set_title("%s FPDBHUD" % (self.table.name)) win.set_title("%s FPDBHUD" % (self.table.name))
self.main_window.set_decorated(False) win.set_skip_taskbar_hint(True)
self.main_window.set_opacity(self.colors["hudopacity"]) win.set_decorated(False)
self.main_window.set_focus_on_map(False) win.set_opacity(self.colors["hudopacity"])
self.ebox = gtk.EventBox() eventbox = gtk.EventBox()
self.label = gtk.Label("FPDB Menu (Right Click)\nLeft-drag to move") label = gtk.Label("FPDB Menu - Right click\nLeft-Drag to Move")
self.backgroundcolor = gtk.gdk.color_parse(self.colors['hudbgcolor']) win.add(eventbox)
self.foregroundcolor = gtk.gdk.color_parse(self.colors['hudfgcolor']) eventbox.add(label)
self.label.modify_bg(gtk.STATE_NORMAL, self.backgroundcolor) label.modify_bg(gtk.STATE_NORMAL, self.backgroundcolor)
self.label.modify_fg(gtk.STATE_NORMAL, self.foregroundcolor) label.modify_fg(gtk.STATE_NORMAL, self.foregroundcolor)
self.main_window.add(self.ebox) eventbox.modify_bg(gtk.STATE_NORMAL, self.backgroundcolor)
self.ebox.add(self.label) eventbox.modify_fg(gtk.STATE_NORMAL, self.foregroundcolor)
self.ebox.modify_bg(gtk.STATE_NORMAL, self.backgroundcolor)
self.ebox.modify_fg(gtk.STATE_NORMAL, self.foregroundcolor)
self.main_window = win
self.main_window.move(self.table.x, self.table.y) self.main_window.move(self.table.x, self.table.y)
# A popup menu for the main window # A popup menu for the main window
self.menu = gtk.Menu() menu = gtk.Menu()
self.item1 = gtk.MenuItem('Kill this HUD')
self.menu.append(self.item1) killitem = gtk.MenuItem('Kill This HUD')
menu.append(killitem)
if self.parent != None: if self.parent != None:
self.item1.connect("activate", self.parent.kill_hud, self.table_name) killitem.connect("activate", self.parent.kill_hud, self.table_name)
self.item1.show()
self.item2 = gtk.MenuItem('Save Layout') saveitem = gtk.MenuItem('Save HUD Layout')
self.menu.append(self.item2) menu.append(saveitem)
self.item2.connect("activate", self.save_layout) saveitem.connect("activate", self.save_layout)
self.item2.show()
self.item3 = gtk.MenuItem('Reposition Stats') repositem = gtk.MenuItem('Reposition StatWindows')
self.menu.append(self.item3) menu.append(repositem)
self.item3.connect("activate", self.reposition_windows) repositem.connect("activate", self.reposition_windows)
self.item3.show()
self.item4 = gtk.MenuItem('Debug Stat Windows') debugitem = gtk.MenuItem('Debug StatWindows')
self.menu.append(self.item4) menu.append(debugitem)
self.item4.connect("activate", self.debug_stat_windows) debugitem.connect("activate", self.debug_stat_windows)
self.item4.show()
self.item5 = gtk.MenuItem('Set max seats') item5 = gtk.MenuItem('Set max seats')
self.menu.append(self.item5) menu.append(item5)
self.item5.show() maxSeatsMenu = gtk.Menu()
self.maxSeatsMenu = gtk.Menu() item5.set_submenu(maxSeatsMenu)
self.item5.set_submenu(self.maxSeatsMenu)
for i in range(2, 11, 1): for i in range(2, 11, 1):
item = gtk.MenuItem('%d-max' % i) item = gtk.MenuItem('%d-max' % i)
item.ms = i item.ms = i
self.maxSeatsMenu.append(item) maxSeatsMenu.append(item)
item.connect("activate", self.change_max_seats) item.connect("activate", self.change_max_seats)
item.show()
setattr(self, 'maxSeatsMenuItem%d' % (i-1), item) setattr(self, 'maxSeatsMenuItem%d' % (i-1), item)
eventbox.connect_object("button-press-event", self.on_button_press, menu)
self.ebox.connect_object("button-press-event", self.on_button_press, self.menu)
self.main_window.show_all()
self.mw_created = True self.mw_created = True
self.label = label
# TODO: fold all uses of this type of 'topify' code into a single function, if the differences between the versions don't menu.show_all()
# create adverse effects? self.main_window.show_all()
if os.name == 'nt':
self.topify_window(self.main_window) self.topify_window(self.main_window)
else:
self.main_window.parentgdkhandle = gtk.gdk.window_foreign_new(int(self.table.number)) # gets a gdk handle for poker client
self.main_window.gdkhandle = gtk.gdk.window_foreign_new(self.main_window.window.xid) # gets a gdk handle for the hud table window
self.main_window.gdkhandle.set_transient_for(self.main_window.parentgdkhandle) #
self.update_table_position()
def change_max_seats(self, widget): def change_max_seats(self, widget):
if self.max != widget.ms: if self.max != widget.ms:
@ -199,8 +185,8 @@ class Hud:
self.parent.kill_hud(self, self.table.name) self.parent.kill_hud(self, self.table.name)
return False return False
# anyone know how to do this in unix, or better yet, trap the X11 error that is triggered when executing the get_origin() for a closed window? # anyone know how to do this in unix, or better yet, trap the X11 error that is triggered when executing the get_origin() for a closed window?
if self.table.gdkhandle is not None:
(x, y) = self.main_window.parentgdkhandle.get_origin() (x, y) = self.table.gdkhandle.get_origin()
if self.table.x != x or self.table.y != y: if self.table.x != x or self.table.y != y:
self.table.x = x self.table.x = x
self.table.y = y self.table.y = y
@ -350,7 +336,8 @@ class Hud:
for s in self.stat_dict: for s in self.stat_dict:
statd = self.stat_dict[s] statd = self.stat_dict[s]
try: try:
self.stat_windows[self.stat_dict[s]['seat']].player_id = self.stat_dict[s]['player_id'] self.stat_windows[statd['seat']].player_id = statd['player_id']
#self.stat_windows[self.stat_dict[s]['seat']].player_id = self.stat_dict[s]['player_id']
except: # omg, we have more seats than stat windows .. damn poker sites with incorrect max seating info .. let's force 10 here except: # omg, we have more seats than stat windows .. damn poker sites with incorrect max seating info .. let's force 10 here
self.max = 10 self.max = 10
self.create(hand, config, self.stat_dict, self.cards) self.create(hand, config, self.stat_dict, self.cards)
@ -374,30 +361,12 @@ class Hud:
Stats.do_tip(window.e_box[r][c], tip) Stats.do_tip(window.e_box[r][c], tip)
def topify_window(self, window): def topify_window(self, window):
# """Set the specified gtk window to stayontop in MS Windows.""" window.set_focus_on_map(False)
# window.set_accept_focus(False)
# def windowEnumerationHandler(hwnd, resultList):
# '''Callback for win32gui.EnumWindows() to generate list of window handles.'''
# resultList.append((hwnd, win32gui.GetWindowText(hwnd)))
# unique_name = 'unique name for finding this window'
# real_name = window.get_title()
# window.set_title(unique_name)
# tl_windows = []
# win32gui.EnumWindows(windowEnumerationHandler, tl_windows)
#
# for w in tl_windows:
# if w[1] == unique_name:
self.main_window.parentgdkhandle = gtk.gdk.window_foreign_new(long(self.table.number))
# self.main_window.gdkhandle = gtk.gdk.window_foreign_new(w[0])
self.main_window.gdkhandle = self.main_window.window
self.main_window.gdkhandle.set_transient_for(self.main_window.parentgdkhandle)
style = win32gui.GetWindowLong(self.table.number, win32con.GWL_EXSTYLE) if not self.table.gdkhandle:
style |= win32con.WS_CLIPCHILDREN self.table.gdkhandle = gtk.gdk.window_foreign_new(int(self.table.number)) # gtk handle to poker window
win32gui.SetWindowLong(self.table.number, win32con.GWL_EXSTYLE, style) window.window.set_transient_for(self.table.gdkhandle)
# break
# window.set_title(real_name)
class Stat_Window: class Stat_Window:
@ -407,7 +376,10 @@ class Stat_Window:
# and double-clicks. # and double-clicks.
if event.button == 3: # right button event if event.button == 3: # right button event
self.popups.append(Popup_window(widget, self)) newpopup = Popup_window(self.window, self)
#print "added popup", newpopup
# TODO: how should we go about making sure it doesn't open a dozen popups if you click?
self.popups.append(newpopup)
return True return True
if event.button == 2: # middle button event if event.button == 2: # middle button event
@ -416,6 +388,7 @@ class Stat_Window:
if event.button == 1: # left button event if event.button == 1: # left button event
# TODO: make position saving save sizes as well? # TODO: make position saving save sizes as well?
self.window.show_all()
if event.state & gtk.gdk.SHIFT_MASK: if event.state & gtk.gdk.SHIFT_MASK:
self.window.begin_resize_drag(gtk.gdk.WINDOW_EDGE_SOUTH_EAST, event.button, int(event.x_root), int(event.y_root), event.time) self.window.begin_resize_drag(gtk.gdk.WINDOW_EDGE_SOUTH_EAST, event.button, int(event.x_root), int(event.y_root), event.time)
else: else:
@ -423,12 +396,13 @@ class Stat_Window:
return True return True
return False return False
def noop(self, *args): # i'm going to try to connect the focus-in and focus-out events here, to see if that fixes any of the focus problems. def noop(self, arga=None, argb=None): # i'm going to try to connect the focus-in and focus-out events here, to see if that fixes any of the focus problems.
return True return True
def kill_popup(self, popup): def kill_popup(self, popup):
popup.window.destroy() print "remove popup", popup
self.popups.remove(popup) self.popups.remove(popup)
popup.window.destroy()
def kill_popups(self): def kill_popups(self):
map(lambda x: x.window.destroy(), self.popups) map(lambda x: x.window.destroy(), self.popups)
@ -458,7 +432,6 @@ class Stat_Window:
self.window.set_title("%s" % seat) self.window.set_title("%s" % seat)
self.window.set_property("skip-taskbar-hint", True) self.window.set_property("skip-taskbar-hint", True)
self.window.set_transient_for(parent.main_window)
self.window.set_focus_on_map(False) self.window.set_focus_on_map(False)
grid = gtk.Table(rows = game.rows, columns = game.cols, homogeneous = False) grid = gtk.Table(rows = game.rows, columns = game.cols, homogeneous = False)
@ -510,11 +483,26 @@ class Stat_Window:
self.window.connect("focus-in-event", self.noop) self.window.connect("focus-in-event", self.noop)
self.window.connect("focus-out-event", self.noop) self.window.connect("focus-out-event", self.noop)
self.window.connect("button_press_event", self.button_press_cb) self.window.connect("button_press_event", self.button_press_cb)
self.window.set_focus_on_map(False)
self.window.set_accept_focus(False)
self.window.move(self.x, self.y) self.window.move(self.x, self.y)
self.window.realize() # window must be realized before it has a gdkwindow so we can attach it to the table window..
self.topify_window(self.window)
self.window.hide() self.window.hide()
def topify_window(self, window):
window.set_focus_on_map(False)
window.set_accept_focus(False)
if not self.table.gdkhandle:
self.table.gdkhandle = gtk.gdk.window_foreign_new(int(self.table.number)) # gtk handle to poker window
# window.window.reparent(self.table.gdkhandle, 0, 0)
window.window.set_transient_for(self.table.gdkhandle)
# window.present()
def destroy(*args): # call back for terminating the main eventloop def destroy(*args): # call back for terminating the main eventloop
gtk.main_quit() gtk.main_quit()
@ -530,6 +518,8 @@ class Popup_window:
self.window.set_gravity(gtk.gdk.GRAVITY_STATIC) self.window.set_gravity(gtk.gdk.GRAVITY_STATIC)
self.window.set_title("popup") self.window.set_title("popup")
self.window.set_property("skip-taskbar-hint", True) self.window.set_property("skip-taskbar-hint", True)
self.window.set_focus_on_map(False)
self.window.set_accept_focus(False)
self.window.set_transient_for(parent.get_toplevel()) self.window.set_transient_for(parent.get_toplevel())
self.window.set_position(gtk.WIN_POS_CENTER_ON_PARENT) self.window.set_position(gtk.WIN_POS_CENTER_ON_PARENT)
@ -595,9 +585,6 @@ class Popup_window:
self.window.set_transient_for(stat_window.window) self.window.set_transient_for(stat_window.window)
if os.name == 'nt':
self.topify_window(self.window)
def button_press_cb(self, widget, event, *args): def button_press_cb(self, widget, event, *args):
# This handles all callbacks from button presses on the event boxes in # This handles all callbacks from button presses on the event boxes in
# the popup windows. There is a bit of an ugly kludge to separate single- # the popup windows. There is a bit of an ugly kludge to separate single-
@ -626,27 +613,15 @@ class Popup_window:
top.move(x, y) top.move(x, y)
def topify_window(self, window): def topify_window(self, window):
"""Set the specified gtk window to stayontop in MS Windows.""" window.set_focus_on_map(False)
window.set_accept_focus(False)
# def windowEnumerationHandler(hwnd, resultList): if not self.table.gdkhandle:
# '''Callback for win32gui.EnumWindows() to generate list of window handles.''' self.table.gdkhandle = gtk.gdk.window_foreign_new(int(self.table.number)) # gtk handle to poker window
# resultList.append((hwnd, win32gui.GetWindowText(hwnd))) # window.window.reparent(self.table.gdkhandle, 0, 0)
window.window.set_transient_for(self.table.gdkhandle)
# window.present()
# unique_name = 'unique name for finding this window'
# real_name = window.get_title()
# window.set_title(unique_name)
# tl_windows = []
# win32gui.EnumWindows(windowEnumerationHandler, tl_windows)
# for w in tl_windows:
# if w[1] == unique_name:
window.set_transient_for(self.parent.main_window)
style = win32gui.GetWindowLong(self.table.number, win32con.GWL_EXSTYLE)
style |= win32con.WS_CLIPCHILDREN
win32gui.SetWindowLong(self.table.number, win32con.GWL_EXSTYLE, style)
# break
# window.set_title(real_name)
if __name__== "__main__": if __name__== "__main__":
main_window = gtk.Window() main_window = gtk.Window()
@ -657,7 +632,7 @@ if __name__== "__main__":
c = Configuration.Config() c = Configuration.Config()
#tables = Tables.discover(c) #tables = Tables.discover(c)
t = Tables.discover_table_by_name(c, "Patriot Dr") t = Tables.discover_table_by_name(c, "Corona")
if t is None: if t is None:
print "Table not found." print "Table not found."
db = Database.Database(c, 'fpdb', 'holdem') db = Database.Database(c, 'fpdb', 'holdem')

View File

@ -325,8 +325,14 @@ class Sql:
siteId SMALLINT UNSIGNED NOT NULL, FOREIGN KEY (siteId) REFERENCES Sites(id), siteId SMALLINT UNSIGNED NOT NULL, FOREIGN KEY (siteId) REFERENCES Sites(id),
buyin INT NOT NULL, buyin INT NOT NULL,
fee INT NOT NULL, fee INT NOT NULL,
knockout INT NOT NULL, maxSeats INT NOT NULL DEFAULT -1,
rebuyOrAddon BOOLEAN NOT NULL) knockout BOOLEAN NOT NULL DEFAULT False,
rebuyOrAddon BOOLEAN NOT NULL DEFAULT False,
speed varchar(10),
headsUp BOOLEAN NOT NULL DEFAULT False,
shootout BOOLEAN NOT NULL DEFAULT False,
matrix BOOLEAN NOT NULL DEFAULT False
)
ENGINE=INNODB""" ENGINE=INNODB"""
elif db_server == 'postgresql': elif db_server == 'postgresql':
self.query['createTourneyTypesTable'] = """CREATE TABLE TourneyTypes ( self.query['createTourneyTypesTable'] = """CREATE TABLE TourneyTypes (
@ -334,16 +340,28 @@ class Sql:
siteId INT NOT NULL, FOREIGN KEY (siteId) REFERENCES Sites(id), siteId INT NOT NULL, FOREIGN KEY (siteId) REFERENCES Sites(id),
buyin INT NOT NULL, buyin INT NOT NULL,
fee INT NOT NULL, fee INT NOT NULL,
knockout INT NOT NULL, maxSeats INT NOT NULL DEFAULT -1,
rebuyOrAddon BOOLEAN NOT NULL)""" knockout BOOLEAN NOT NULL DEFAULT False,
rebuyOrAddon BOOLEAN NOT NULL DEFAULT False,
speed varchar(10),
headsUp BOOLEAN NOT NULL DEFAULT False,
shootout BOOLEAN NOT NULL DEFAULT False,
matrix 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 (
id INTEGER PRIMARY KEY, id INTEGER PRIMARY KEY,
siteId INT NOT NULL, siteId INT NOT NULL,
buyin INT NOT NULL, buyin INT NOT NULL,
fee INT NOT NULL, fee INT NOT NULL,
knockout INT NOT NULL, maxSeats INT NOT NULL DEFAULT -1,
rebuyOrAddon BOOLEAN NOT NULL)""" knockout BOOLEAN NOT NULL DEFAULT 0,
rebuyOrAddon BOOLEAN NOT NULL DEFAULT 0,
speed TEXT,
headsUp BOOLEAN NOT NULL DEFAULT 0,
shootout BOOLEAN NOT NULL DEFAULT 0,
matrix BOOLEAN NOT NULL DEFAULT 0
)"""
################################ ################################
# Create Tourneys # Create Tourneys
@ -352,32 +370,65 @@ class Sql:
if db_server == 'mysql': if db_server == 'mysql':
self.query['createTourneysTable'] = """CREATE TABLE Tourneys ( self.query['createTourneysTable'] = """CREATE TABLE Tourneys (
id INT UNSIGNED AUTO_INCREMENT NOT NULL, PRIMARY KEY (id), id INT UNSIGNED AUTO_INCREMENT NOT NULL, PRIMARY KEY (id),
tourneyTypeId SMALLINT UNSIGNED NOT NULL, FOREIGN KEY (tourneyTypeId) REFERENCES TourneyTypes(id), tourneyTypeId SMALLINT UNSIGNED NOT NULL DEFAULT 1, FOREIGN KEY (tourneyTypeId) REFERENCES TourneyTypes(id),
siteTourneyNo BIGINT NOT NULL, siteTourneyNo BIGINT NOT NULL,
entries INT NOT NULL, entries INT NOT NULL,
prizepool INT NOT NULL, prizepool INT NOT NULL,
startTime DATETIME NOT NULL, startTime DATETIME NOT NULL,
endTime DATETIME,
buyinChips INT,
tourneyName varchar(40),
matrixIdProcessed TINYINT UNSIGNED DEFAULT 0, /* Mask use : 1=Positionnal Winnings|2=Match1|4=Match2|...|pow(2,n)=Matchn */
rebuyChips INT DEFAULT 0,
addonChips INT DEFAULT 0,
rebuyAmount INT DEFAULT 0,
addonAmount INT DEFAULT 0,
totalRebuys INT DEFAULT 0,
totalAddons INT DEFAULT 0,
koBounty INT DEFAULT 0,
comment TEXT, comment TEXT,
commentTs DATETIME) commentTs DATETIME)
ENGINE=INNODB""" ENGINE=INNODB"""
elif db_server == 'postgresql': elif db_server == 'postgresql':
self.query['createTourneysTable'] = """CREATE TABLE Tourneys ( self.query['createTourneysTable'] = """CREATE TABLE Tourneys (
id SERIAL, PRIMARY KEY (id), id SERIAL, PRIMARY KEY (id),
tourneyTypeId INT, FOREIGN KEY (tourneyTypeId) REFERENCES TourneyTypes(id), tourneyTypeId INT DEFAULT 1, FOREIGN KEY (tourneyTypeId) REFERENCES TourneyTypes(id),
siteTourneyNo BIGINT, siteTourneyNo BIGINT,
entries INT, entries INT,
prizepool INT, prizepool INT,
startTime timestamp without time zone, startTime timestamp without time zone,
endTime timestamp without time zone,
buyinChips INT,
tourneyName varchar(40),
matrixIdProcessed SMALLINT UNSIGNED DEFAULT 0, /* Mask use : 1=Positionnal Winnings|2=Match1|4=Match2|...|pow(2,n)=Matchn */
rebuyChips INT DEFAULT 0,
addonChips INT DEFAULT 0,
rebuyAmount INT DEFAULT 0,
addonAmount INT DEFAULT 0,
totalRebuys INT DEFAULT 0,
totalAddons INT DEFAULT 0,
koBounty INT DEFAULT 0,
comment TEXT, comment TEXT,
commentTs timestamp without time zone)""" commentTs timestamp without time zone)"""
elif db_server == 'sqlite': elif db_server == 'sqlite':
self.query['createTourneysTable'] = """CREATE TABLE Tourneys ( self.query['createTourneysTable'] = """CREATE TABLE Tourneys (
id INTEGER PRIMARY KEY, id INTEGER PRIMARY KEY,
tourneyTypeId INT, tourneyTypeId INT DEFAULT 1,
siteTourneyNo INT, siteTourneyNo INT,
entries INT, entries INT,
prizepool INT, prizepool INT,
startTime REAL, startTime REAL,
endTime REAL,
buyinChips INT,
tourneyName TEXT,
matrixIdProcessed INT UNSIGNED DEFAULT 0, /* Mask use : 1=Positionnal Winnings|2=Match1|4=Match2|...|pow(2,n)=Matchn */
rebuyChips INT DEFAULT 0,
addonChips INT DEFAULT 0,
rebuyAmount INT DEFAULT 0,
addonAmount INT DEFAULT 0,
totalRebuys INT DEFAULT 0,
totalAddons INT DEFAULT 0,
koBounty INT DEFAULT 0,
comment TEXT, comment TEXT,
commentTs REAL)""" commentTs REAL)"""
################################ ################################
@ -409,7 +460,7 @@ class Sql:
comment text, comment text,
commentTs DATETIME, commentTs DATETIME,
tourneysPlayersId BIGINT UNSIGNED, tourneysPlayersId BIGINT UNSIGNED,
tourneyTypeId SMALLINT UNSIGNED NOT NULL, FOREIGN KEY (tourneyTypeId) REFERENCES TourneyTypes(id), tourneyTypeId SMALLINT UNSIGNED NOT NULL DEFAULT 1, FOREIGN KEY (tourneyTypeId) REFERENCES TourneyTypes(id),
wonWhenSeenStreet1 FLOAT, wonWhenSeenStreet1 FLOAT,
wonWhenSeenStreet2 FLOAT, wonWhenSeenStreet2 FLOAT,
@ -527,7 +578,7 @@ class Sql:
comment text, comment text,
commentTs timestamp without time zone, commentTs timestamp without time zone,
tourneysPlayersId BIGINT, tourneysPlayersId BIGINT,
tourneyTypeId INT NOT NULL, FOREIGN KEY (tourneyTypeId) REFERENCES TourneyTypes(id), tourneyTypeId INT NOT NULL DEFAULT 1, FOREIGN KEY (tourneyTypeId) REFERENCES TourneyTypes(id),
wonWhenSeenStreet1 FLOAT, wonWhenSeenStreet1 FLOAT,
wonWhenSeenStreet2 FLOAT, wonWhenSeenStreet2 FLOAT,
@ -644,7 +695,7 @@ class Sql:
comment TEXT, comment TEXT,
commentTs REAL, commentTs REAL,
tourneysPlayersId INT, tourneysPlayersId INT,
tourneyTypeId INT NOT NULL, tourneyTypeId INT NOT NULL DEFAULT 1,
wonWhenSeenStreet1 REAL, wonWhenSeenStreet1 REAL,
wonWhenSeenStreet2 REAL, wonWhenSeenStreet2 REAL,
@ -749,6 +800,9 @@ class Sql:
payinAmount INT NOT NULL, payinAmount INT NOT NULL,
rank INT NOT NULL, rank INT NOT NULL,
winnings INT NOT NULL, winnings INT NOT NULL,
nbRebuys INT DEFAULT 0,
nbAddons INT DEFAULT 0,
nbKO INT DEFAULT 0,
comment TEXT, comment TEXT,
commentTs DATETIME) commentTs DATETIME)
ENGINE=INNODB""" ENGINE=INNODB"""
@ -760,6 +814,9 @@ class Sql:
payinAmount INT, payinAmount INT,
rank INT, rank INT,
winnings INT, winnings INT,
nbRebuys INT DEFAULT 0,
nbAddons INT DEFAULT 0,
nbKO INT DEFAULT 0,
comment TEXT, comment TEXT,
commentTs timestamp without time zone)""" commentTs timestamp without time zone)"""
elif db_server == 'sqlite': elif db_server == 'sqlite':
@ -808,7 +865,7 @@ class Sql:
playerId INT UNSIGNED NOT NULL, FOREIGN KEY (playerId) REFERENCES Players(id), playerId INT UNSIGNED NOT NULL, FOREIGN KEY (playerId) REFERENCES Players(id),
activeSeats SMALLINT NOT NULL, activeSeats SMALLINT NOT NULL,
position CHAR(1), position CHAR(1),
tourneyTypeId SMALLINT UNSIGNED NOT NULL, FOREIGN KEY (tourneyTypeId) REFERENCES TourneyTypes(id), tourneyTypeId SMALLINT UNSIGNED NOT NULL DEFAULT 1, FOREIGN KEY (tourneyTypeId) REFERENCES TourneyTypes(id),
styleKey CHAR(7) NOT NULL, /* 1st char is style (A/T/H/S), other 6 are the key */ styleKey CHAR(7) NOT NULL, /* 1st char is style (A/T/H/S), other 6 are the key */
HDs INT NOT NULL, HDs INT NOT NULL,
@ -909,7 +966,7 @@ class Sql:
playerId INT, FOREIGN KEY (playerId) REFERENCES Players(id), playerId INT, FOREIGN KEY (playerId) REFERENCES Players(id),
activeSeats SMALLINT, activeSeats SMALLINT,
position CHAR(1), position CHAR(1),
tourneyTypeId INT, FOREIGN KEY (tourneyTypeId) REFERENCES TourneyTypes(id), tourneyTypeId INT DEFAULT 1, FOREIGN KEY (tourneyTypeId) REFERENCES TourneyTypes(id),
styleKey CHAR(7) NOT NULL, /* 1st char is style (A/T/H/S), other 6 are the key */ styleKey CHAR(7) NOT NULL, /* 1st char is style (A/T/H/S), other 6 are the key */
HDs INT, HDs INT,
@ -1008,7 +1065,7 @@ class Sql:
playerId INT, playerId INT,
activeSeats INT, activeSeats INT,
position TEXT, position TEXT,
tourneyTypeId INT, tourneyTypeId INT DEFAULT 1,
styleKey TEXT NOT NULL, /* 1st char is style (A/T/H/S), other 6 are the key */ styleKey TEXT NOT NULL, /* 1st char is style (A/T/H/S), other 6 are the key */
HDs INT, HDs INT,
@ -2759,6 +2816,143 @@ class Sql:
WHERE gametypeId=%s AND siteHandNo=%s WHERE gametypeId=%s AND siteHandNo=%s
""" """
self.query['getTourneyTypeIdByTourneyNo'] = """SELECT tt.id,
tt.buyin,
tt.fee,
tt.maxSeats,
tt.knockout,
tt.rebuyOrAddon,
tt.speed,
tt.headsUp,
tt.shootout,
tt.matrix
FROM TourneyTypes tt
INNER JOIN Tourneys t ON (t.tourneyTypeId = tt.id)
WHERE t.siteTourneyNo=%s AND tt.siteId=%s
"""
self.query['getTourneyTypeId'] = """SELECT id
FROM TourneyTypes
WHERE siteId=%s
AND buyin=%s
AND fee=%s
AND knockout=%s
AND rebuyOrAddon=%s
AND speed=%s
AND headsUp=%s
AND shootout=%s
AND matrix=%s
"""
self.query['insertTourneyTypes'] = """INSERT INTO TourneyTypes
(siteId, buyin, fee, knockout, rebuyOrAddon
,speed, headsUp, shootout, matrix)
VALUES (%s, %s, %s, %s, %s, %s, %s, %s, %s)
"""
self.query['getTourney'] = """SELECT t.id,
t.tourneyTypeId,
t.entries,
t.prizepool,
t.startTime,
t.endTime,
t.buyinChips,
t.tourneyName,
t.matrixIdProcessed,
t.rebuyChips,
t.addonChips,
t.rebuyAmount,
t.addonAmount,
t.totalRebuys,
t.totalAddons,
t.koBounty,
t.comment
FROM Tourneys t
INNER JOIN TourneyTypes tt ON (t.tourneyTypeId = tt.id)
WHERE t.siteTourneyNo=%s AND tt.siteId=%s
"""
self.query['insertTourney'] = """INSERT INTO Tourneys
(tourneyTypeId, siteTourneyNo, entries, prizepool,
startTime, endTime, buyinChips, tourneyName, matrixIdProcessed,
rebuyChips, addonChips, rebuyAmount, addonAmount, totalRebuys,
totalAddons, koBounty, comment, commentTs)
VALUES (%s, %s, %s, %s, %s, %s, %s, %s, %s, %s,
%s, %s, %s, %s, %s, %s, %s, %s)
"""
self.query['updateTourney'] = """UPDATE Tourneys
SET tourneyTypeId = %s,
entries = %s,
prizepool = %s,
startTime = %s,
endTime = %s,
buyinChips = %s,
tourneyName = %s,
matrixIdProcessed = %s,
rebuyChips = %s,
addonChips = %s,
rebuyAmount = %s,
addonAmount = %s,
totalRebuys = %s,
totalAddons = %s,
koBounty = %s,
comment = %s,
commentTs = %s
WHERE id=%s
"""
self.query['getTourneysPlayers'] = """SELECT id,
payinAmount,
rank,
winnings,
nbRebuys,
nbAddons,
nbKO,
comment,
commentTs
FROM TourneysPlayers
WHERE tourneyId=%s AND playerId+0=%s
"""
self.query['updateTourneysPlayers'] = """UPDATE TourneysPlayers
SET payinAmount = %s,
rank = %s,
winnings = %s,
nbRebuys = %s,
nbAddons = %s,
nbKO = %s,
comment = %s,
commentTs = %s
WHERE id=%s
"""
self.query['insertTourneysPlayers'] = """INSERT INTO TourneysPlayers
(tourneyId, playerId, payinAmount, rank, winnings, nbRebuys, nbAddons, nbKO, comment, commentTs)
VALUES (%s, %s, %s, %s, %s, %s, %s, %s, %s, %s)
"""
self.query['selectHandsPlayersWithWrongTTypeId'] = """SELECT id
FROM HandsPlayers
WHERE tourneyTypeId <> %s AND (TourneysPlayersId+0=%s)
"""
# self.query['updateHandsPlayersForTTypeId2'] = """UPDATE HandsPlayers
# SET tourneyTypeId= %s
# WHERE (TourneysPlayersId+0=%s)
# """
self.query['updateHandsPlayersForTTypeId'] = """UPDATE HandsPlayers
SET tourneyTypeId= %s
WHERE (id=%s)
"""
self.query['handsPlayersTTypeId_joiner'] = " OR TourneysPlayersId+0="
self.query['handsPlayersTTypeId_joiner_id'] = " OR id="
if db_server == 'mysql': if db_server == 'mysql':
self.query['placeholder'] = u'%s' self.query['placeholder'] = u'%s'
elif db_server == 'postgresql': elif db_server == 'postgresql':

View File

@ -69,6 +69,7 @@ class Table_Window:
if 'site' in info: self.site = info['site'] if 'site' in info: self.site = info['site']
if 'title' in info: self.title = info['title'] if 'title' in info: self.title = info['title']
if 'name' in info: self.name = info['name'] if 'name' in info: self.name = info['name']
self.gdkhandle = None
def __str__(self): def __str__(self):
# __str__ method for testing # __str__ method for testing
@ -243,6 +244,9 @@ def discover_nt_by_name(c, tablename):
if 'History for table:' in titles[hwnd]: continue # Everleaf Network HH viewer window if 'History for table:' in titles[hwnd]: continue # Everleaf Network HH viewer window
if 'HUD:' in titles[hwnd]: continue # FPDB HUD window if 'HUD:' in titles[hwnd]: continue # FPDB HUD window
if 'Chat:' in titles[hwnd]: continue # Some sites (FTP? PS? Others?) have seperable or seperately constructed chat windows if 'Chat:' in titles[hwnd]: continue # Some sites (FTP? PS? Others?) have seperable or seperately constructed chat windows
if ' - Table ' in titles[hwnd]: continue # Absolute table Chat window.. sigh. TODO: Can we tell what site we're trying to discover for somehow in here, so i can limit this check just to AP searches?
temp = decode_windows(c, titles[hwnd], hwnd)
#print "attach to window", temp
return decode_windows(c, titles[hwnd], hwnd) return decode_windows(c, titles[hwnd], hwnd)
return None return None

View File

@ -46,7 +46,6 @@ class Tourney(object):
def __init__(self, sitename, gametype, summaryText, builtFrom = "HHC"): def __init__(self, sitename, gametype, summaryText, builtFrom = "HHC"):
print "Tourney.__init__"
self.sitename = sitename self.sitename = sitename
self.siteId = self.SITEIDS[sitename] self.siteId = self.SITEIDS[sitename]
self.gametype = gametype self.gametype = gametype
@ -74,21 +73,21 @@ class Tourney(object):
self.subTourneyFee = None self.subTourneyFee = None
self.rebuyChips = 0 self.rebuyChips = 0
self.addOnChips = 0 self.addOnChips = 0
self.countRebuys = 0
self.countAddOns = 0
self.rebuyAmount = 0 self.rebuyAmount = 0
self.addOnAmount = 0 self.addOnAmount = 0
self.totalRebuys = 0 self.totalRebuys = 0
self.totalAddOns = 0 self.totalAddOns = 0
self.koBounty = 0 self.koBounty = 0
self.countKO = 0 #To use for winnings calculation which is not counted in the rest of the summary file self.tourneyComment = None
self.players = [] self.players = []
# Collections indexed by player names # Collections indexed by player names
self.finishPositions = {} self.finishPositions = {}
self.winnings = {} self.winnings = {}
self.payinAmounts = {}
self.countRebuys = {}
self.countAddOns = {}
self.countKO = {}
# currency symbol for this summary # currency symbol for this summary
self.sym = None self.sym = None
@ -122,20 +121,20 @@ class Tourney(object):
("ADDON CHIPS", self.addOnChips), ("ADDON CHIPS", self.addOnChips),
("REBUY AMOUNT", self.rebuyAmount), ("REBUY AMOUNT", self.rebuyAmount),
("ADDON AMOUNT", self.addOnAmount), ("ADDON AMOUNT", self.addOnAmount),
("COUNT REBUYS", self.countRebuys),
("COUNT ADDONS", self.countAddOns),
("NB REBUYS", self.countRebuys),
("NB ADDONS", self.countAddOns),
("TOTAL REBUYS", self.totalRebuys), ("TOTAL REBUYS", self.totalRebuys),
("TOTAL ADDONS", self.totalAddOns), ("TOTAL ADDONS", self.totalAddOns),
("KO BOUNTY", self.koBounty), ("KO BOUNTY", self.koBounty),
("NB OF KO", self.countKO) ("TOURNEY COMMENT", self.tourneyComment)
) )
structs = ( ("GAMETYPE", self.gametype), structs = ( ("GAMETYPE", self.gametype),
("PLAYERS", self.players), ("PLAYERS", self.players),
("PAYIN AMOUNTS", self.payinAmounts),
("POSITIONS", self.finishPositions), ("POSITIONS", self.finishPositions),
("WINNINGS", self.winnings), ("WINNINGS", self.winnings),
("COUNT REBUYS", self.countRebuys),
("COUNT ADDONS", self.countAddOns),
("NB OF KO", self.countKO)
) )
str = '' str = ''
for (name, var) in vars: for (name, var) in vars:
@ -152,7 +151,6 @@ class Tourney(object):
pass pass
def insert(self, db): def insert(self, db):
print "TODO: Insert Tourney in DB"
# First : check all needed info is filled in the object, especially for the initial select # First : check all needed info is filled in the object, especially for the initial select
# Notes on DB Insert # Notes on DB Insert
@ -163,6 +161,19 @@ class Tourney(object):
# Starttime may not match the one in the Summary file : HH = time of the first Hand / could be slighltly different from the one in the summary file # Starttime may not match the one in the Summary file : HH = time of the first Hand / could be slighltly different from the one in the summary file
# Note: If the TourneyNo could be a unique id .... this would really be a relief to deal with matrix matches ==> Ask on the IRC / Ask Fulltilt ?? # Note: If the TourneyNo could be a unique id .... this would really be a relief to deal with matrix matches ==> Ask on the IRC / Ask Fulltilt ??
dbTourneyTypeId = db.tRecogniseTourneyType(self)
logging.debug("Tourney Type ID = %d" % dbTourneyTypeId)
dbTourneyId = db.tRecognizeTourney(self, dbTourneyTypeId)
logging.debug("Tourney ID = %d" % dbTourneyId)
dbTourneysPlayersIds = db.tStoreTourneyPlayers(self, dbTourneyId)
logging.debug("TourneysPlayersId = %s" % dbTourneysPlayersIds)
db.tUpdateTourneysHandsPlayers(self, dbTourneysPlayersIds, dbTourneyTypeId)
logging.debug("tUpdateTourneysHandsPlayers done")
logging.debug("Tourney Insert done")
# TO DO : Return what has been done (tourney created, updated, nothing)
# ?? stored = 1 if tourney is fully created / duplicates = 1, if everything was already here and correct / partial=1 if some things were already here (between tourney, tourneyPlayers and handsplayers)
# if so, prototypes may need changes to know what has been done or make some kind of dict in Tourney object that could be updated during the insert process to store that information
stored = 0 stored = 0
duplicates = 0 duplicates = 0
partial = 0 partial = 0
@ -246,18 +257,21 @@ db: a connected fpdb_db object"""
def addPlayer(self, rank, name, winnings): def addPlayer(self, rank, name, winnings, payinAmount, nbRebuys, nbAddons, nbKO):
"""\ """\
Adds a player to the tourney, and initialises data structures indexed by player. Adds a player to the tourney, and initialises data structures indexed by player.
rank (int) indicating the finishing rank (can be -1 if unknown) rank (int) indicating the finishing rank (can be -1 if unknown)
name (string) player name name (string) player name
winnings (string) the money the player ended the tourney with (can be 0, or -1 if unknown) winnings (decimal) the money the player ended the tourney with (can be 0, or -1 if unknown)
""" """
log.debug("addPlayer: rank:%s - name : '%s' - Winnings (%s)" % (rank, name, winnings)) log.debug("addPlayer: rank:%s - name : '%s' - Winnings (%s)" % (rank, name, winnings))
winnings = re.sub(u',', u'', winnings) #some sites have commas
self.players.append(name) self.players.append(name)
self.finishPositions.update( { name : Decimal(rank) } ) self.finishPositions.update( { name : Decimal(rank) } )
self.winnings.update( { name : Decimal(winnings) } ) self.winnings.update( { name : Decimal(winnings) } )
self.payinAmounts.update( {name : Decimal(payinAmount) } )
self.countRebuys.update( {name: Decimal(nbRebuys) } )
self.countAddOns.update( {name: Decimal(nbAddons) } )
self.countKO.update( {name : Decimal(nbKO) } )
def incrementPlayerWinnings(self, name, additionnalWinnings): def incrementPlayerWinnings(self, name, additionnalWinnings):
@ -270,11 +284,6 @@ winnings (string) the money the player ended the tourney with (can be 0, or -
self.winnings[name] = oldWins + Decimal(additionnalWinnings) self.winnings[name] = oldWins + Decimal(additionnalWinnings)
def calculatePayinAmount(self):
return self.buyin + self.fee + (self.rebuyAmount * self.countRebuys) + (self.addOnAmount * self.countAddOns )
def checkPlayerExists(self,player): def checkPlayerExists(self,player):
if player not in [p[1] for p in self.players]: if player not in [p[1] for p in self.players]:
print "checkPlayerExists", player, "fail" print "checkPlayerExists", player, "fail"

View File

@ -76,43 +76,37 @@ import SQL
import Database import Database
import FpdbSQLQueries import FpdbSQLQueries
import Configuration import Configuration
from Exceptions import *
VERSION = "0.11" VERSION = "0.11"
class fpdb: class fpdb:
def tab_clicked(self, widget, tab_name): def tab_clicked(self, widget, tab_name):
"""called when a tab button is clicked to activate that tab""" """called when a tab button is clicked to activate that tab"""
#print "start of tab_clicked"
self.display_tab(tab_name) self.display_tab(tab_name)
#end def tab_clicked
def add_and_display_tab(self, new_tab, new_tab_name): def add_and_display_tab(self, new_tab, new_tab_name):
"""just calls the component methods""" """just calls the component methods"""
self.add_tab(new_tab, new_tab_name) self.add_tab(new_tab, new_tab_name)
self.display_tab(new_tab_name) self.display_tab(new_tab_name)
#end def add_and_display_tab
def add_tab(self, new_tab, new_tab_name): def add_tab(self, new_tab, new_tab_name):
"""adds a tab, namely creates the button and displays it and appends all the relevant arrays""" """adds a tab, namely creates the button and displays it and appends all the relevant arrays"""
#print "start of add_tab"
for i in self.tab_names: #todo: check this is valid for i in self.tab_names: #todo: check this is valid
if i==new_tab_name: if i == new_tab_name:
return # we depend on this to not create duplicate tabs, there's no reason to raise an error here? return # if tab already exists, just go to it
# raise fpdb_simple.FpdbError("duplicate tab_name not permitted")
self.tabs.append(new_tab) self.tabs.append(new_tab)
self.tab_names.append(new_tab_name) self.tab_names.append(new_tab_name)
new_tab_sel_button=gtk.ToggleButton(new_tab_name) new_tab_sel_button = gtk.ToggleButton(new_tab_name)
new_tab_sel_button.connect("clicked", self.tab_clicked, new_tab_name) new_tab_sel_button.connect("clicked", self.tab_clicked, new_tab_name)
self.tab_box.add(new_tab_sel_button) self.tab_box.add(new_tab_sel_button)
new_tab_sel_button.show() new_tab_sel_button.show()
self.tab_buttons.append(new_tab_sel_button) self.tab_buttons.append(new_tab_sel_button)
#end def add_tab
def display_tab(self, new_tab_name): def display_tab(self, new_tab_name):
"""displays the indicated tab""" """displays the indicated tab"""
#print "start of display_tab, len(self.tab_names):",len(self.tab_names)
tab_no = -1 tab_no = -1
for i, name in enumerate(self.tab_names): for i, name in enumerate(self.tab_names):
if name == new_tab_name: if name == new_tab_name:
@ -120,73 +114,71 @@ class fpdb:
break break
if tab_no == -1: if tab_no == -1:
raise fpdb_simple.FpdbError("invalid tab_no") raise FpdbError("invalid tab_no")
else: else:
self.main_vbox.remove(self.current_tab) self.main_vbox.remove(self.current_tab)
#self.current_tab.destroy()
self.current_tab=self.tabs[tab_no] self.current_tab=self.tabs[tab_no]
self.main_vbox.add(self.current_tab) self.main_vbox.add(self.current_tab)
self.tab_buttons[tab_no].set_active(True) self.tab_buttons[tab_no].set_active(True)
self.current_tab.show() self.current_tab.show()
#end def display_tab
def delete_event(self, widget, event, data=None): def delete_event(self, widget, event, data=None):
return False return False
#end def delete_event
def destroy(self, widget, data=None): def destroy(self, widget, data=None):
self.quit(widget) self.quit(widget)
#end def destroy
def dia_about(self, widget, data=None): def dia_about(self, widget, data=None):
print "todo: implement dia_about", #self.warning_box("About FPDB:\n\nFPDB was originally created by a guy named Steffen, sometime in 2008, \nand is mostly worked on these days by people named Eratosthenes, s0rrow, _mt, EricBlade, sqlcoder, and other strange people.\n\n", "ABOUT FPDB")
print " version = %s, requires database version %s" % (VERSION, "118") dia = gtk.AboutDialog()
#end def dia_about dia.set_name("FPDB")
dia.set_version(VERSION)
dia.set_copyright("2008-2009, Steffen, Eratosthenes, s0rrow, EricBlade, _mt, sqlcoder, and others")
dia.set_comments("GTK AboutDialog comments here")
dia.set_license("GPL v3")
dia.set_website("http://fpdb.sourceforge.net/")
dia.set_authors("Steffen, Eratosthenes, s0rrow, EricBlade, _mt, and others")
dia.set_program_name("FPDB")
dia.run()
dia.destroy()
def dia_create_del_database(self, widget, data=None): def dia_create_del_database(self, widget, data=None):
print "todo: implement dia_create_del_database" self.warning_box("Unimplemented: Create/Delete Database")
self.obtain_global_lock() self.obtain_global_lock()
self.release_global_lock() self.release_global_lock()
#end def dia_create_del_database
def dia_create_del_user(self, widget, data=None): def dia_create_del_user(self, widget, data=None):
print "todo: implement dia_create_del_user" self.warning_box("Unimplemented: Create/Delete user")
self.obtain_global_lock() self.obtain_global_lock()
self.release_global_lock() self.release_global_lock()
#end def dia_create_del_user
def dia_database_stats(self, widget, data=None): def dia_database_stats(self, widget, data=None):
print "todo: implement dia_database_stats" self.warning_box("Unimplemented: Database Stats")
#string=fpdb_db.getDbStats(db, cursor)
#end def dia_database_stats
def dia_database_sessions(self, widget, data=None): def dia_database_sessions(self, widget, data=None):
new_sessions_thread=GuiSessionViewer.GuiSessionViewer(self.config, self.sql) new_sessions_thread = GuiSessionViewer.GuiSessionViewer(self.config, self.sql)
self.threads.append(new_sessions_thread) self.threads.append(new_sessions_thread)
sessions_tab=new_sessions_thread.get_vbox() sessions_tab=new_sessions_thread.get_vbox()
self.add_and_display_tab(sessions_tab, "Sessions") self.add_and_display_tab(sessions_tab, "Sessions")
def dia_delete_db_parts(self, widget, data=None): def dia_delete_db_parts(self, widget, data=None):
print "todo: implement dia_delete_db_parts" self.warning_box("Unimplemented: Delete Database Parts")
self.obtain_global_lock() self.obtain_global_lock()
self.release_global_lock() self.release_global_lock()
#end def dia_delete_db_parts
def dia_edit_profile(self, widget=None, data=None, create_default=False, path=None): def dia_edit_profile(self, widget=None, data=None, create_default=False, path=None):
print "todo: implement dia_edit_profile" self.warning_box("Unimplemented: Edit Profile")
self.obtain_global_lock() self.obtain_global_lock()
self.release_global_lock() self.release_global_lock()
#end def dia_edit_profile
def dia_export_db(self, widget, data=None): def dia_export_db(self, widget, data=None):
print "todo: implement dia_export_db" self.warning_box("Unimplemented: Export Database")
self.obtain_global_lock() self.obtain_global_lock()
self.release_global_lock() self.release_global_lock()
#end def dia_export_db
def dia_get_db_root_credentials(self): def dia_get_db_root_credentials(self):
"""obtains db root credentials from user""" """obtains db root credentials from user"""
print "todo: implement dia_get_db_root_credentials" self.warning_box("Unimplemented: Get Root Database Credentials")
# user, pw=None, None # user, pw=None, None
# #
# dialog=gtk.Dialog(title="DB Credentials needed", parent=None, flags=0, # dialog=gtk.Dialog(title="DB Credentials needed", parent=None, flags=0,
@ -202,17 +194,14 @@ class fpdb:
# response=dialog.run() # response=dialog.run()
# dialog.destroy() # dialog.destroy()
# return (user, pw, response) # return (user, pw, response)
#end def dia_get_db_root_credentials
def dia_import_db(self, widget, data=None): def dia_import_db(self, widget, data=None):
print "todo: implement dia_import_db" self.warning_box("Unimplemented: Import Database")
self.obtain_global_lock() self.obtain_global_lock()
self.release_global_lock() self.release_global_lock()
#end def dia_import_db
def dia_licensing(self, widget, data=None): def dia_licensing(self, widget, data=None):
print "todo: implement dia_licensing" self.warning_box("Unimplemented: Licensing")
#end def dia_licensing
def dia_load_profile(self, widget, data=None): def dia_load_profile(self, widget, data=None):
"""Dialogue to select a file to load a profile from""" """Dialogue to select a file to load a profile from"""
@ -236,7 +225,6 @@ class fpdb:
#except: #except:
# pass # pass
self.release_global_lock() self.release_global_lock()
#end def dia_load_profile
def dia_recreate_tables(self, widget, data=None): def dia_recreate_tables(self, widget, data=None):
"""Dialogue that asks user to confirm that he wants to delete and recreate the tables""" """Dialogue that asks user to confirm that he wants to delete and recreate the tables"""
@ -266,7 +254,6 @@ class fpdb:
print 'User cancelled recreating tables' print 'User cancelled recreating tables'
#if not lock_released: #if not lock_released:
self.release_global_lock() self.release_global_lock()
#end def dia_recreate_tables
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():
@ -282,20 +269,15 @@ class fpdb:
print 'User cancelled rebuilding hud cache' print 'User cancelled rebuilding hud cache'
self.release_global_lock() self.release_global_lock()
def dia_regression_test(self, widget, data=None): def dia_regression_test(self, widget, data=None):
print "todo: implement dia_regression_test" self.warning_box("Unimplemented: Regression Test")
self.obtain_global_lock() self.obtain_global_lock()
self.release_global_lock() self.release_global_lock()
#end def dia_regression_test
def dia_save_profile(self, widget, data=None): def dia_save_profile(self, widget, data=None):
print "todo: implement dia_save_profile" self.warning_box("Unimplemented: Save Profile (try saving a HUD layout, that should do it)")
#end def dia_save_profile
def diaSetupWizard(self, path): def diaSetupWizard(self, path):
print "todo: implement setup wizard"
print "setup wizard not implemented - please create the default configuration file:", path
diaSetupWizard = gtk.Dialog(title="Fatal Error - Config File Missing", parent=None, flags=0, buttons=(gtk.STOCK_QUIT,gtk.RESPONSE_OK)) diaSetupWizard = gtk.Dialog(title="Fatal Error - Config File Missing", parent=None, flags=0, buttons=(gtk.STOCK_QUIT,gtk.RESPONSE_OK))
label = gtk.Label("Please copy the config file from the docs folder to:") label = gtk.Label("Please copy the config file from the docs folder to:")
@ -312,7 +294,6 @@ class fpdb:
response = diaSetupWizard.run() response = diaSetupWizard.run()
sys.exit(1) sys.exit(1)
#end def diaSetupWizard
def get_menu(self, window): def get_menu(self, window):
"""returns the menu for this program""" """returns the menu for this program"""
@ -327,6 +308,7 @@ class fpdb:
<menuitem action="Quit"/> <menuitem action="Quit"/>
</menu> </menu>
<menu action="import"> <menu action="import">
<menuitem action="sethharchive"/>
<menuitem action="bulkimp"/> <menuitem action="bulkimp"/>
<menuitem action="autoimp"/> <menuitem action="autoimp"/>
<menuitem action="autorate"/> <menuitem action="autorate"/>
@ -369,6 +351,7 @@ class fpdb:
('EditProf', None, '_Edit Profile (todo)', '<control>E', 'Edit your profile', self.dia_edit_profile), ('EditProf', None, '_Edit Profile (todo)', '<control>E', 'Edit your profile', self.dia_edit_profile),
('SaveProf', None, '_Save Profile (todo)', '<control>S', 'Save your profile', self.dia_save_profile), ('SaveProf', None, '_Save Profile (todo)', '<control>S', 'Save your profile', self.dia_save_profile),
('import', None, '_Import'), ('import', None, '_Import'),
('sethharchive', None, '_Set HandHistory Archive Directory', None, 'Set HandHistory Archive Directory', self.select_hhArchiveBase),
('bulkimp', None, '_Bulk Import', '<control>B', 'Bulk Import', self.tab_bulk_import), ('bulkimp', None, '_Bulk Import', '<control>B', 'Bulk Import', self.tab_bulk_import),
('autorate', None, 'Auto _Rating (todo)', '<control>R', 'Auto Rating (todo)', self.not_implemented), ('autorate', None, 'Auto _Rating (todo)', '<control>R', 'Auto Rating (todo)', self.not_implemented),
('viewers', None, '_Viewers'), ('viewers', None, '_Viewers'),
@ -401,7 +384,6 @@ class fpdb:
menubar = uimanager.get_widget('/MenuBar') menubar = uimanager.get_widget('/MenuBar')
window.add_accel_group(accel_group) window.add_accel_group(accel_group)
return menubar return menubar
#end def get_menu
def load_profile(self): def load_profile(self):
"""Loads profile from the provided path name.""" """Loads profile from the provided path name."""
@ -452,11 +434,11 @@ class fpdb:
# Database connected to successfully, load queries to pass on to other classes # Database connected to successfully, load queries to pass on to other classes
self.db.connection.rollback() self.db.connection.rollback()
#end def load_profile
self.validate_config()
def not_implemented(self, widget, data=None): def not_implemented(self, widget, data=None):
print "todo: called unimplemented menu entry (users: pls ignore this)"#remove this once more entries are implemented self.warning_box("Unimplemented menu entry")
#end def not_implemented
def obtain_global_lock(self): def obtain_global_lock(self):
ret = self.lock.acquire(False) # will return false if lock is already held ret = self.lock.acquire(False) # will return false if lock is already held
@ -468,31 +450,25 @@ class fpdb:
# need to release it later: # need to release it later:
# self.lock.release() # self.lock.release()
#end def obtain_global_lock
def quit(self, widget, data=None): def quit(self, widget, data=None):
print "Quitting normally" print "Quitting normally"
#check if current settings differ from profile, if so offer to save or abort #check if current settings differ from profile, if so offer to save or abort
self.db.disconnect() self.db.disconnect()
gtk.main_quit() gtk.main_quit()
#end def quit_cliecked
def release_global_lock(self): def release_global_lock(self):
self.lock.release() self.lock.release()
print "Global lock released.\n" print "Global lock released.\n"
#end def release_global_lock
def tab_abbreviations(self, widget, data=None): def tab_abbreviations(self, widget, data=None):
print "todo: implement tab_abbreviations" print "todo: implement tab_abbreviations"
#end def tab_abbreviations
def tab_auto_import(self, widget, data=None): def tab_auto_import(self, widget, data=None):
"""opens the auto import tab""" """opens the auto import tab"""
new_aimp_thread=GuiAutoImport.GuiAutoImport(self.settings, self.config, self.sql) new_aimp_thread = GuiAutoImport.GuiAutoImport(self.settings, self.config, self.sql)
self.threads.append(new_aimp_thread) self.threads.append(new_aimp_thread)
aimp_tab=new_aimp_thread.get_vbox() aimp_tab=new_aimp_thread.get_vbox()
self.add_and_display_tab(aimp_tab, "Auto Import") self.add_and_display_tab(aimp_tab, "Auto Import")
#end def tab_auto_import
def tab_bulk_import(self, widget, data=None): def tab_bulk_import(self, widget, data=None):
"""opens a tab for bulk importing""" """opens a tab for bulk importing"""
@ -501,10 +477,9 @@ class fpdb:
self.threads.append(new_import_thread) self.threads.append(new_import_thread)
bulk_tab=new_import_thread.get_vbox() bulk_tab=new_import_thread.get_vbox()
self.add_and_display_tab(bulk_tab, "Bulk Import") self.add_and_display_tab(bulk_tab, "Bulk Import")
#end def tab_bulk_import
def tab_player_stats(self, widget, data=None): def tab_player_stats(self, widget, data=None):
new_ps_thread=GuiPlayerStats.GuiPlayerStats(self.config, self.sql, self.window) new_ps_thread = GuiPlayerStats.GuiPlayerStats(self.config, self.sql, self.window)
self.threads.append(new_ps_thread) self.threads.append(new_ps_thread)
ps_tab=new_ps_thread.get_vbox() ps_tab=new_ps_thread.get_vbox()
self.add_and_display_tab(ps_tab, "Player Stats") self.add_and_display_tab(ps_tab, "Player Stats")
@ -517,31 +492,25 @@ class fpdb:
def tab_main_help(self, widget, data=None): def tab_main_help(self, widget, data=None):
"""Displays a tab with the main fpdb help screen""" """Displays a tab with the main fpdb help screen"""
#print "start of tab_main_help"
mh_tab=gtk.Label("""Welcome to Fpdb! mh_tab=gtk.Label("""Welcome to Fpdb!
For documentation please visit our website at http://fpdb.sourceforge.net/ or check the docs directory in the fpdb folder. For documentation please visit our website at http://fpdb.sourceforge.net/ or check the docs directory in the fpdb folder.
Please note that default.conf is no longer needed nor used, all configuration now happens in HUD_config.xml Please note that default.conf is no longer needed nor used, all configuration now happens in HUD_config.xml
This program is licensed under the AGPL3, see docs"""+os.sep+"agpl-3.0.txt") This program is licensed under the AGPL3, see docs"""+os.sep+"agpl-3.0.txt")
self.add_and_display_tab(mh_tab, "Help") self.add_and_display_tab(mh_tab, "Help")
#end def tab_main_help
def tab_table_viewer(self, widget, data=None): def tab_table_viewer(self, widget, data=None):
"""opens a table viewer tab""" """opens a table viewer tab"""
#print "start of tab_table_viewer"
new_tv_thread = GuiTableViewer.GuiTableViewer(self.db, self.settings, self.config) new_tv_thread = GuiTableViewer.GuiTableViewer(self.db, self.settings, self.config)
self.threads.append(new_tv_thread) self.threads.append(new_tv_thread)
tv_tab=new_tv_thread.get_vbox() tv_tab = new_tv_thread.get_vbox()
self.add_and_display_tab(tv_tab, "Table Viewer") self.add_and_display_tab(tv_tab, "Table Viewer")
#end def tab_table_viewer
def tabGraphViewer(self, widget, data=None): def tabGraphViewer(self, widget, data=None):
"""opens a graph viewer tab""" """opens a graph viewer tab"""
#print "start of tabGraphViewer"
new_gv_thread = GuiGraphViewer.GuiGraphViewer(self.sql, self.config) new_gv_thread = GuiGraphViewer.GuiGraphViewer(self.sql, self.config)
self.threads.append(new_gv_thread) self.threads.append(new_gv_thread)
gv_tab=new_gv_thread.get_vbox() gv_tab = new_gv_thread.get_vbox()
self.add_and_display_tab(gv_tab, "Graphs") self.add_and_display_tab(gv_tab, "Graphs")
#end def tabGraphViewer
def __init__(self): def __init__(self):
self.threads = [] self.threads = []
@ -586,12 +555,50 @@ This program is licensed under the AGPL3, see docs"""+os.sep+"agpl-3.0.txt")
self.window.show() self.window.show()
self.load_profile() self.load_profile()
sys.stderr.write("fpdb starting ...") sys.stderr.write("fpdb starting ...")
#end def __init__
def warning_box(self, str, diatitle="FPDB WARNING"):
diaWarning = gtk.Dialog(title=diatitle, parent=None, flags=0, buttons=(gtk.STOCK_OK,gtk.RESPONSE_OK))
label = gtk.Label(str)
diaWarning.vbox.add(label)
label.show()
response = diaWarning.run()
diaWarning.destroy()
return response
def validate_config(self):
hhbase = self.config.get_import_parameters().get("hhArchiveBase")
hhbase = os.path.expanduser(hhbase)
#hhdir = os.path.join(hhbase,site)
hhdir = hhbase
if not os.path.isdir(hhdir):
diapath = gtk.MessageDialog(parent=None, flags=0, type=gtk.MESSAGE_WARNING, buttons=(gtk.BUTTONS_YES_NO), message_format="Setup hh dir")
diastring = "WARNING: Unable to find output hh directory %s\n\n Press YES to create this directory, or NO to select a new one." % hhdir
diapath.format_secondary_text(diastring)
response = diapath.run()
diapath.destroy()
if response == gtk.RESPONSE_YES:
try:
os.makedirs(hhdir)
except:
self.warning_box("WARNING: Unable to create hand output directory. Importing is not likely to work until this is fixed.")
elif response == gtk.RESPONSE_NO:
self.select_hhArchiveBase()
def select_hhArchiveBase(self, widget=None):
fc = gtk.FileChooserDialog(title="Select HH Output Directory", parent=None, action=gtk.FILE_CHOOSER_ACTION_SELECT_FOLDER, buttons=(gtk.STOCK_OPEN,gtk.RESPONSE_OK), backend=None)
fc.run()
# TODO: We need to put in a Cancel button, and handle if the user presses that or the "Close" box without selecting anything as a cancel, and return to the prior setting
#self.warning_box("You selected %s" % fc.get_filename())
self.config.set_hhArchiveBase(fc.get_filename())
self.config.save()
self.load_profile() # we can't do this at the end of this func because load_profile calls this func
fc.destroy() # TODO: loop this to make sure we get valid data back from it, because the open directory thing in GTK lets you select files and not select things and other stupid bullshit
def main(self): def main(self):
gtk.main() gtk.main()
return 0 return 0
#end def main
if __name__ == "__main__": if __name__ == "__main__":
me = fpdb() me = fpdb()

View File

@ -1,4 +1,5 @@
#!/usr/bin/python #!/usr/bin/python
# -*- coding: utf-8 -*-
#Copyright 2008 Steffen Jobbagy-Felso #Copyright 2008 Steffen Jobbagy-Felso
#This program is free software: you can redistribute it and/or modify #This program is free software: you can redistribute it and/or modify
@ -21,8 +22,18 @@ import sys
import logging import logging
from time import time, strftime from time import time, strftime
use_pool = False
try:
import sqlalchemy.pool as pool
use_pool = True
except:
logging.info("Not using sqlalchemy connection pool.")
import fpdb_simple import fpdb_simple
import FpdbSQLQueries import FpdbSQLQueries
from Exceptions import *
class fpdb_db: class fpdb_db:
MYSQL_INNODB = 2 MYSQL_INNODB = 2
@ -63,13 +74,17 @@ class fpdb_db:
self.database=database self.database=database
if backend==fpdb_db.MYSQL_INNODB: if backend==fpdb_db.MYSQL_INNODB:
import MySQLdb import MySQLdb
if use_pool:
MySQLdb = pool.manage(MySQLdb, pool_size=5)
try: try:
self.db = MySQLdb.connect(host = host, user = user, passwd = password, db = database, use_unicode=True) self.db = MySQLdb.connect(host = host, user = user, passwd = password, db = database, use_unicode=True)
except: except:
raise fpdb_simple.FpdbError("MySQL connection failed") raise FpdbError("MySQL connection failed")
elif backend==fpdb_db.PGSQL: elif backend==fpdb_db.PGSQL:
import psycopg2 import psycopg2
import psycopg2.extensions import psycopg2.extensions
if use_pool:
psycopg2 = pool.manage(psycopg2, pool_size=5)
psycopg2.extensions.register_type(psycopg2.extensions.UNICODE) psycopg2.extensions.register_type(psycopg2.extensions.UNICODE)
# If DB connection is made over TCP, then the variables # If DB connection is made over TCP, then the variables
# host, user and password are required # host, user and password are required
@ -87,7 +102,7 @@ class fpdb_db:
pass pass
#msg = "PostgreSQL direct connection to database (%s) failed, trying with user ..." % (database,) #msg = "PostgreSQL direct connection to database (%s) failed, trying with user ..." % (database,)
#print msg #print msg
#raise fpdb_simple.FpdbError(msg) #raise FpdbError(msg)
if not connected: if not connected:
try: try:
self.db = psycopg2.connect(host = host, self.db = psycopg2.connect(host = host,
@ -97,16 +112,19 @@ class fpdb_db:
except: except:
msg = "PostgreSQL connection to database (%s) user (%s) failed." % (database, user) msg = "PostgreSQL connection to database (%s) user (%s) failed." % (database, user)
print msg print msg
raise fpdb_simple.FpdbError(msg) raise FpdbError(msg)
elif backend==fpdb_db.SQLITE: elif backend==fpdb_db.SQLITE:
logging.info("Connecting to SQLite:%(database)s" % {'database':database}) logging.info("Connecting to SQLite:%(database)s" % {'database':database})
import sqlite3 import sqlite3
if use_pool:
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) self.db = sqlite3.connect(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:
raise fpdb_simple.FpdbError("unrecognised database backend:"+backend) raise FpdbError("unrecognised database backend:"+backend)
self.cursor=self.db.cursor() self.cursor=self.db.cursor()
# Set up query dictionary as early in the connection process as we can. # Set up query dictionary as early in the connection process as we can.
self.sql = FpdbSQLQueries.FpdbSQLQueries(self.get_backend_name()) self.sql = FpdbSQLQueries.FpdbSQLQueries(self.get_backend_name())
@ -119,7 +137,7 @@ class fpdb_db:
print "outdated or too new database version - please recreate tables" print "outdated or too new database version - please recreate tables"
self.wrongDbVersion=True self.wrongDbVersion=True
except:# _mysql_exceptions.ProgrammingError: except:# _mysql_exceptions.ProgrammingError:
print "failed to read settings table - please recreate tables" if database != ":memory:": print "failed to read settings table - please recreate tables"
self.wrongDbVersion=True self.wrongDbVersion=True
#end def connect #end def connect
@ -148,7 +166,7 @@ class fpdb_db:
elif self.backend==4: elif self.backend==4:
return "SQLite" return "SQLite"
else: else:
raise fpdb_simple.FpdbError("invalid backend") raise FpdbError("invalid backend")
#end def get_backend_name #end def get_backend_name
def get_db_info(self): def get_db_info(self):

View File

@ -22,7 +22,6 @@
import os # todo: remove this once import_dir is in fpdb_import import os # todo: remove this once import_dir is in fpdb_import
import sys import sys
from time import time, strftime, sleep from time import time, strftime, sleep
import logging
import traceback import traceback
import math import math
import datetime import datetime
@ -31,6 +30,9 @@ import Queue
from collections import deque # using Queue for now from collections import deque # using Queue for now
import threading import threading
import pygtk
import gtk
# fpdb/FreePokerTools modules # fpdb/FreePokerTools modules
import fpdb_simple import fpdb_simple
@ -38,22 +40,28 @@ import fpdb_db
import Database import Database
import fpdb_parse_logic import fpdb_parse_logic
import Configuration import Configuration
import Exceptions
import logging, logging.config
logging.config.fileConfig(os.path.join(sys.path[0],"logging.conf"))
log = logging.getLogger('importer')
# database interface modules # database interface modules
try: try:
import MySQLdb import MySQLdb
mysqlLibFound=True mysqlLibFound=True
log.debug("Import module: MySQLdb")
except: except:
pass log.debug("Import module: MySQLdb not found")
try: try:
import psycopg2 import psycopg2
pgsqlLibFound=True pgsqlLibFound=True
import psycopg2.extensions import psycopg2.extensions
psycopg2.extensions.register_type(psycopg2.extensions.UNICODE) psycopg2.extensions.register_type(psycopg2.extensions.UNICODE)
log.debug("Import module: psycopg2")
except: except:
pass log.debug("Import module: psycopg2 not found")
class Importer: class Importer:
@ -145,6 +153,8 @@ class Importer:
#Add an individual file to filelist #Add an individual file to filelist
def addImportFile(self, filename, site = "default", filter = "passthrough"): def addImportFile(self, filename, site = "default", filter = "passthrough"):
#TODO: test it is a valid file -> put that in config!! #TODO: test it is a valid file -> put that in config!!
if filename in self.filelist or not os.path.exists(filename):
return
self.filelist[filename] = [site] + [filter] self.filelist[filename] = [site] + [filter]
if site not in self.siteIds: if site not in self.siteIds:
# Get id from Sites table in DB # Get id from Sites table in DB
@ -153,9 +163,9 @@ class Importer:
self.siteIds[site] = result[0][0] self.siteIds[site] = result[0][0]
else: else:
if len(result) == 0: if len(result) == 0:
print "[ERROR] Database ID for %s not found" % site log.error("Database ID for %s not found" % site)
else: else:
print "[ERROR] More than 1 Database ID found for %s - Multiple currencies not implemented yet" % site log.error("[ERROR] More than 1 Database ID found for %s - Multiple currencies not implemented yet" % site)
# Called from GuiBulkImport to add a file or directory. # Called from GuiBulkImport to add a file or directory.
@ -168,7 +178,7 @@ class Importer:
if os.path.isdir(inputPath): if os.path.isdir(inputPath):
for subdir in os.walk(inputPath): for subdir in os.walk(inputPath):
for file in subdir[2]: for file in subdir[2]:
self.addImportFile(os.path.join(inputPath, subdir[0], file), site=site, filter=filter) self.addImportFile(os.path.join(subdir[0], file), site=site, filter=filter)
else: else:
self.addImportFile(inputPath, site=site, filter=filter) self.addImportFile(inputPath, site=site, filter=filter)
#Add a directory of files to filelist #Add a directory of files to filelist
@ -189,7 +199,7 @@ class Importer:
#print " adding file ", file #print " adding file ", file
self.addImportFile(os.path.join(dir, file), site, filter) self.addImportFile(os.path.join(dir, file), site, filter)
else: else:
print "Warning: Attempted to add non-directory: '" + str(dir) + "' as an import directory" log.warning("Attempted to add non-directory: '" + str(dir) + "' as an import directory")
def runImport(self): def runImport(self):
""""Run full import on self.filelist. This is called from GuiBulkImport.py""" """"Run full import on self.filelist. This is called from GuiBulkImport.py"""
@ -199,7 +209,7 @@ class Importer:
# Initial setup # Initial setup
start = datetime.datetime.now() start = datetime.datetime.now()
starttime = time() starttime = time()
print "Started at", start, "--", len(self.filelist), "files to import.", self.settings['dropIndexes'] log.info("Started at %s -- %d files to import. indexes: %s" % (start, len(self.filelist), self.settings['dropIndexes']))
if self.settings['dropIndexes'] == 'auto': if self.settings['dropIndexes'] == 'auto':
self.settings['dropIndexes'] = self.calculate_auto2(self.database, 12.0, 500.0) self.settings['dropIndexes'] = self.calculate_auto2(self.database, 12.0, 500.0)
if 'dropHudCache' in self.settings and self.settings['dropHudCache'] == 'auto': if 'dropHudCache' in self.settings and self.settings['dropHudCache'] == 'auto':
@ -208,7 +218,7 @@ class Importer:
if self.settings['dropIndexes'] == 'drop': if self.settings['dropIndexes'] == 'drop':
self.database.prepareBulkImport() self.database.prepareBulkImport()
else: else:
print "No need to drop indexes." log.debug("No need to drop indexes.")
#print "dropInd =", self.settings['dropIndexes'], " dropHudCache =", self.settings['dropHudCache'] #print "dropInd =", self.settings['dropIndexes'], " dropHudCache =", self.settings['dropHudCache']
if self.settings['threads'] <= 0: if self.settings['threads'] <= 0:
@ -346,6 +356,7 @@ class Importer:
#rulog.writelines("path exists ") #rulog.writelines("path exists ")
if file in self.updatedsize: # we should be able to assume that if we're in size, we're in time as well if file in self.updatedsize: # we should be able to assume that if we're in size, we're in time as well
if stat_info.st_size > self.updatedsize[file] or stat_info.st_mtime > self.updatedtime[file]: if stat_info.st_size > self.updatedsize[file] or stat_info.st_mtime > self.updatedtime[file]:
# print "file",counter," updated", os.path.basename(file), stat_info.st_size, self.updatedsize[file], stat_info.st_mtime, self.updatedtime[file]
self.import_file_dict(self.database, file, self.filelist[file][0], self.filelist[file][1], None) self.import_file_dict(self.database, file, self.filelist[file][0], self.filelist[file][1], None)
self.updatedsize[file] = stat_info.st_size self.updatedsize[file] = stat_info.st_size
self.updatedtime[file] = time() self.updatedtime[file] = time()
@ -358,6 +369,7 @@ class Importer:
self.updatedtime[file] = time() self.updatedtime[file] = time()
else: else:
self.removeFromFileList[file] = True self.removeFromFileList[file] = True
self.addToDirList = filter(lambda x: self.addImportDirectory(x, True, self.addToDirList[x][0], self.addToDirList[x][1]), self.addToDirList) self.addToDirList = filter(lambda x: self.addImportDirectory(x, True, self.addToDirList[x][0], self.addToDirList[x][1]), self.addToDirList)
for file in self.removeFromFileList: for file in self.removeFromFileList:
@ -373,6 +385,7 @@ class Importer:
# This is now an internal function that should not be called directly. # This is now an internal function that should not be called directly.
def import_file_dict(self, db, file, site, filter, q=None): def import_file_dict(self, db, file, site, filter, q=None):
#print "import_file_dict" #print "import_file_dict"
if os.path.isdir(file): if os.path.isdir(file):
self.addToDirList[file] = [site] + [filter] self.addToDirList[file] = [site] + [filter]
return return
@ -384,9 +397,9 @@ class Importer:
# Load filter, process file, pass returned filename to import_fpdb_file # Load filter, process file, pass returned filename to import_fpdb_file
if self.settings['threads'] > 0 and self.writeq != None: if self.settings['threads'] > 0 and self.writeq != None:
print "\nConverting " + file + " (" + str(q.qsize()) + ")" log.info("Converting " + file + " (" + str(q.qsize()) + ")")
else: else:
print "\nConverting " + file log.info("Converting " + file)
hhbase = self.config.get_import_parameters().get("hhArchiveBase") hhbase = self.config.get_import_parameters().get("hhArchiveBase")
hhbase = os.path.expanduser(hhbase) hhbase = os.path.expanduser(hhbase)
hhdir = os.path.join(hhbase,site) hhdir = os.path.join(hhbase,site)
@ -396,11 +409,11 @@ class Importer:
out_path = os.path.join(hhdir, "x"+strftime("%d-%m-%y")+os.path.basename(file)) out_path = os.path.join(hhdir, "x"+strftime("%d-%m-%y")+os.path.basename(file))
filter_name = filter.replace("ToFpdb", "") filter_name = filter.replace("ToFpdb", "")
mod = __import__(filter) mod = __import__(filter)
obj = getattr(mod, filter_name, None) obj = getattr(mod, filter_name, None)
if callable(obj): if callable(obj):
hhc = obj(in_path = file, out_path = out_path, index = 0) # Index into file 0 until changeover hhc = obj(in_path = file, out_path = out_path, index = 0) # Index into file 0 until changeover
if hhc.getParsedObjectType() == "HH":
if(hhc.getStatus() and self.NEWIMPORT == False): if(hhc.getStatus() and self.NEWIMPORT == False):
(stored, duplicates, partial, errors, ttime) = self.import_fpdb_file(db, out_path, site, q) (stored, duplicates, partial, errors, ttime) = self.import_fpdb_file(db, out_path, site, q)
elif (hhc.getStatus() and self.NEWIMPORT == True): elif (hhc.getStatus() and self.NEWIMPORT == True):
@ -414,26 +427,10 @@ class Importer:
else: else:
# conversion didn't work # conversion didn't work
# TODO: appropriate response? # TODO: appropriate response?
return (0, 0, 0, 1, 0, -1) return (0, 0, 0, 1, 0)
elif hhc.getParsedObjectType() == "Summary":
if(hhc.getStatus()):
tourney = hhc.getTourney()
#print tourney
#tourney.prepInsert()
(stored, duplicates, partial, errors, ttime) = tourney.insert(self.database)
return (stored, duplicates, partial, errors, ttime)
else: else:
# conversion didn't work log.warning("Unknown filter filter_name:'%s' in filter:'%s'" %(filter_name, filter))
# Could just be the parsing of a non summary file (classic HH file) return (0, 0, 0, 1, 0)
return (0, 0, 0, 0, 0)
else:
print "Unknown objects parsed by HHC :'%s'" %(hhc.getObjectTypeRead())
return (0, 0, 0, 1, 0, -1)
else:
print "Unknown filter filter_name:'%s' in filter:'%s'" %(filter_name, filter)
return (0, 0, 0, 1, 0, -1)
#This will barf if conv.getStatus != True #This will barf if conv.getStatus != True
return (stored, duplicates, partial, errors, ttime) return (stored, duplicates, partial, errors, ttime)
@ -475,7 +472,7 @@ class Importer:
db.commit() db.commit()
ttime = time() - starttime ttime = time() - starttime
if q == None: if q == None:
print "\rTotal stored:", stored, " duplicates:", duplicates, "errors:", errors, " time:", ttime log.info("Total stored: %(stored)d\tduplicates:%(duplicates)d\terrors:%(errors)d\ttime:%(ttime)s" % locals())
if not stored: if not stored:
if duplicates: if duplicates:
@ -497,6 +494,8 @@ class Importer:
"""Import an fpdb hand history held in the list lines, could be one hand or many""" """Import an fpdb hand history held in the list lines, could be one hand or many"""
#db.lock_for_insert() # should be ok when using one thread, but doesn't help?? #db.lock_for_insert() # should be ok when using one thread, but doesn't help??
while gtk.events_pending():
gtk.main_iteration(False)
try: # sometimes we seem to be getting an empty self.lines, in which case, we just want to return. try: # sometimes we seem to be getting an empty self.lines, in which case, we just want to return.
firstline = lines[0] firstline = lines[0]
@ -550,9 +549,9 @@ 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 fpdb_simple.DuplicateError: except Exceptions.DuplicateError:
duplicates += 1 duplicates += 1
db.rollback() db.rollback()
except (ValueError), fe: except (ValueError), fe:

View File

@ -22,6 +22,7 @@ import sys
import fpdb_simple import fpdb_simple
import Database import Database
from time import time, strftime from time import time, strftime
from Exceptions import *
#parses a holdem hand #parses a holdem hand
@ -67,7 +68,8 @@ def mainParser(settings, siteID, category, hand, config, db = None, writeq = Non
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])
tourneyTypeId = fpdb_simple.recogniseTourneyTypeId(db.get_cursor(), siteID, buyin, fee, knockout, rebuyOrAddon) ## The tourney site id has to be searched because it may already be in db with a TourneyTypeId which is different from the one automatically calculated (Summary import first)
tourneyTypeId = fpdb_simple.recogniseTourneyTypeId(db, siteID, siteTourneyNo, buyin, fee, knockout, rebuyOrAddon)
else: else:
siteTourneyNo = -1 siteTourneyNo = -1
buyin = -1 buyin = -1
@ -126,7 +128,7 @@ def mainParser(settings, siteID, category, hand, config, db = None, writeq = Non
elif lineTypes[i]=="table": elif lineTypes[i]=="table":
tableResult=fpdb_simple.parseTableLine(base, line) tableResult=fpdb_simple.parseTableLine(base, line)
else: else:
raise fpdb_simple.FpdbError("unrecognised lineType:"+lineTypes[i]) raise FpdbError("unrecognised lineType:"+lineTypes[i])
maxSeats = tableResult['maxSeats'] maxSeats = tableResult['maxSeats']
tableName = tableResult['tableName'] tableName = tableResult['tableName']

View File

@ -25,6 +25,7 @@ import datetime
import time import time
import re import re
import sys import sys
from Exceptions import *
import locale import locale
import Card import Card
@ -40,18 +41,6 @@ SQLITE = 4
LOCALE_ENCODING = locale.getdefaultlocale()[1] LOCALE_ENCODING = locale.getdefaultlocale()[1]
class DuplicateError(Exception):
def __init__(self, value):
self.value = value
def __str__(self):
return repr(self.value)
class FpdbError(Exception):
def __init__(self, value):
self.value = value
def __str__(self):
return repr(self.value)
#returns an array of the total money paid. intending to add rebuys/addons here #returns an array of the total money paid. intending to add rebuys/addons here
def calcPayin(count, buyin, fee): def calcPayin(count, buyin, fee):
return [buyin + fee for i in xrange(count)] return [buyin + fee for i in xrange(count)]
@ -227,7 +216,7 @@ def fillCardArrays(player_count, base, category, card_values, card_suits):
elif base=="stud": elif base=="stud":
cardCount = 7 cardCount = 7
else: else:
raise fpdb_simple.FpdbError("invalid category:", category) raise FpdbError("invalid category:", category)
for i in xrange(player_count): for i in xrange(player_count):
while (len(card_values[i]) < cardCount): while (len(card_values[i]) < cardCount):
@ -954,7 +943,17 @@ def recogniseGametypeID(backend, db, cursor, topline, smallBlindLine, site_id, c
return result[0] return result[0]
#end def recogniseGametypeID #end def recogniseGametypeID
def recogniseTourneyTypeId(cursor, siteId, buyin, fee, knockout, rebuyOrAddon): def recogniseTourneyTypeId(db, siteId, tourneySiteId, buyin, fee, knockout, rebuyOrAddon):
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()
try:
len(result)
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 WHERE siteId=%s AND buyin=%s AND fee=%s AND knockout=%s AND rebuyOrAddon=%s", (siteId, buyin, fee, knockout, rebuyOrAddon))
result=cursor.fetchone() result=cursor.fetchone()
#print "tried SELECTing gametypes.id, result:",result #print "tried SELECTing gametypes.id, result:",result
@ -965,6 +964,7 @@ def recogniseTourneyTypeId(cursor, siteId, buyin, fee, knockout, rebuyOrAddon):
cursor.execute("""INSERT INTO TourneyTypes (siteId, buyin, fee, knockout, rebuyOrAddon) VALUES (%s, %s, %s, %s, %s)""", (siteId, buyin, fee, knockout, rebuyOrAddon)) 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)) 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() result=cursor.fetchone()
return result[0] return result[0]
#end def recogniseTourneyTypeId #end def recogniseTourneyTypeId

View File

@ -1,5 +1,5 @@
[loggers] [loggers]
keys=root,parser keys=root,parser,importer,config,db
[handlers] [handlers]
keys=consoleHandler,fileHandler keys=consoleHandler,fileHandler
@ -13,20 +13,37 @@ handlers=consoleHandler,fileHandler
[logger_parser] [logger_parser]
level=INFO level=INFO
# set to NOTSET or DEBUG to see everything the parser does
handlers=consoleHandler,fileHandler handlers=consoleHandler,fileHandler
qualname=parser qualname=parser
propagate=0 propagate=0
[logger_importer]
level=DEBUG
handlers=consoleHandler,fileHandler
qualname=importer
propagate=0
[logger_config]
level=DEBUG
handlers=consoleHandler,fileHandler
qualname=config
propagate=0
[logger_db]
level=DEBUG
handlers=consoleHandler,fileHandler
qualname=db
propagate=0
[handler_consoleHandler] [handler_consoleHandler]
class=StreamHandler class=StreamHandler
level=INFO level=ERROR
formatter=stderrFormatter formatter=stderrFormatter
args=(sys.stderr,) args=(sys.stderr,)
[handler_fileHandler] [handler_fileHandler]
class=FileHandler class=FileHandler
level=INFO level=DEBUG
formatter=fileFormatter formatter=fileFormatter
args=('logging.out', 'a') args=('logging.out', 'a')

54
pyfpdb/py2exe_setup.py Normal file
View File

@ -0,0 +1,54 @@
#!/usr/bin/env python
"""setup.py
Py2exe script for fpdb.
"""
# Copyright 2009, Ray E. Barker
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
########################################################################
#TODO: change GuiAutoImport so that it knows to start HUD_main.exe, when appropriate
# include the lib needed to handle png files in mucked
# get rid of all the uneeded libraries (e.g., pyQT)
# think about an installer
from distutils.core import setup
import py2exe
setup(
name = 'fpdb',
description = 'Free Poker DataBase',
version = '0.12',
console = [ {'script': 'fpdb.py', },
{'script': 'HUD_main.py', }
],
options = {'py2exe': {
'packages' :'encodings',
'includes' : 'cairo, pango, pangocairo, atk, gobject, PokerStarsToFpdb',
'excludes' : '_tkagg, _agg2, cocoaagg, fltkagg',
'dll_excludes': 'libglade-2.0-0.dll',
}
},
data_files = ['HUD_config.xml',
'Cards01.png'
]
)