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

Conflicts:
	run_fpdb.py
This commit is contained in:
Gerko de Roo 2010-01-29 20:15:04 +01:00
commit 71fc7279ec
11 changed files with 244 additions and 135 deletions

85
pyfpdb/Configuration.py Executable file → Normal file
View File

@ -59,28 +59,44 @@ def get_exec_path():
return sys.path[0] return sys.path[0]
def get_config(file_name, fallback = True): def get_config(file_name, fallback = True):
"""Looks in exec dir and in self.default_config_path for a config file.""" """Looks in cwd and in self.default_config_path for a config file."""
config_path = os.path.join(DIR_SELF, file_name) # look in exec dir exec_dir = get_exec_path()
if os.path.exists(config_path) and os.path.isfile(config_path): config_path = os.path.join(exec_dir, file_name)
return config_path # there is a file in the exec dir so we use it # print "config_path=", config_path
else: if os.path.exists(config_path): # there is a file in the cwd
config_path = os.path.join(DIR_CONFIG, file_name) # look in config dir return config_path # so we use it
if os.path.exists(config_path) and os.path.isfile(config_path): else: # no file in the cwd, look where it should be in the first place
default_dir = get_default_config_path()
config_path = os.path.join(default_dir, file_name)
# print "config path 2=", config_path
if os.path.exists(config_path):
return config_path return config_path
# No file found # No file found
if not fallback: if not fallback:
return False return False
# OK, fall back to the .example file, should be in the exec dir # OK, fall back to the .example file, should be in the start dir
if os.path.exists(os.path.join(DIR_SELF, file_name + ".example")): if os.path.exists(file_name + ".example"):
try: try:
shutil.copyfile(os.path.join(DIR_SELF, file_name + ".example"), os.path.join(DIR_CONFIG, file_name)) print ""
print "No %s found, using %s.example.\n" % (file_name, file_name) if not os.path.isdir(default_dir):
print "A %s file has been created. You will probably have to edit it." % os.path.join(DIR_CONFIG, file_name) msg = "Creating directory: '%s'" % (default_dir)
log.error("No %s found, using %s.example.\n" % (file_name, file_name) ) print msg
logging.info(msg)
os.mkdir(default_dir)
shutil.copyfile(file_name + ".example", config_path)
msg = "No %s found in %s or %s\n" % (file_name, exec_dir, default_dir) \
+ "Config file has been created at %s.\n" % config_path \
+ "Edit your screen_name and hand history path in the supported_sites "\
+ "section of the \nPreferences window (Main menu) before trying to import hands."
print msg
logging.info(msg)
file_name = config_path
except: except:
print "No %s found, cannot fall back. Exiting.\n" % file_name print "Error copying .example file, cannot fall back. Exiting.\n"
sys.stderr.write("Error copying .example file, cannot fall back. Exiting.\n")
sys.stderr.write( str(sys.exc_info()) )
sys.exit() sys.exit()
else: else:
print "No %s found, cannot fall back. Exiting.\n" % file_name print "No %s found, cannot fall back. Exiting.\n" % file_name
@ -94,26 +110,18 @@ def get_logger(file_name, config = "config", fallback = False):
try: try:
logging.config.fileConfig(conf) logging.config.fileConfig(conf)
log = logging.getLogger(config) log = logging.getLogger(config)
log.debug("%s logger initialised" % config)
return log return log
except: except:
pass pass
log = logging.basicConfig() log = logging.basicConfig()
log = logging.getLogger() log = logging.getLogger()
log.error("basicConfig logger initialised") log.debug("config logger initialised")
return log return log
def check_dir(path, create = True): # find a logging.conf file and set up logging
"""Check if a dir exists, optionally creates if not.""" log = get_logger("logging.conf")
if os.path.exists(path):
if os.path.isdir(path):
return path
else:
return False
if create:
print "creating directory %s" % path
else:
return False
######################################################################## ########################################################################
# application wide consts # application wide consts
@ -121,32 +129,20 @@ def check_dir(path, create = True):
APPLICATION_NAME_SHORT = 'fpdb' APPLICATION_NAME_SHORT = 'fpdb'
APPLICATION_VERSION = 'xx.xx.xx' APPLICATION_VERSION = 'xx.xx.xx'
DIR_SELF = get_exec_path()
DIR_CONFIG = check_dir(get_default_config_path())
DIR_DATABASE = check_dir(os.path.join(DIR_CONFIG, 'database'))
DIR_LOG = check_dir(os.path.join(DIR_CONFIG, 'log'))
DATABASE_TYPE_POSTGRESQL = 'postgresql' DATABASE_TYPE_POSTGRESQL = 'postgresql'
DATABASE_TYPE_SQLITE = 'sqlite' DATABASE_TYPE_SQLITE = 'sqlite'
DATABASE_TYPE_MYSQL = 'mysql' DATABASE_TYPE_MYSQL = 'mysql'
#TODO: should this be a tuple or a dict
DATABASE_TYPES = ( DATABASE_TYPES = (
DATABASE_TYPE_POSTGRESQL, DATABASE_TYPE_POSTGRESQL,
DATABASE_TYPE_SQLITE, DATABASE_TYPE_SQLITE,
DATABASE_TYPE_MYSQL, DATABASE_TYPE_MYSQL,
) )
# find a logging.conf file and set up logging #LOCALE_ENCODING = locale.getdefaultlocale()[1]
log = get_logger("logging.conf", config = "config") LOCALE_ENCODING = locale.getpreferredencoding()
log.debug("config logger initialised") if LOCALE_ENCODING == "US-ASCII":
print "Default encoding set to US-ASCII, defaulting to CP1252 instead -- If you're not on a Mac, please report this problem."
# and then log our consts LOCALE_ENCODING = "cp1252"
log.info("DIR SELF = %s" % DIR_SELF)
log.info("DIR CONFIG = %s" % DIR_CONFIG)
log.info("DIR DATABASE = %s" % DIR_DATABASE)
log.info("DIR LOG = %s" % DIR_LOG)
NEWIMPORT = True
LOCALE_ENCODING = locale.getdefaultlocale()[1]
######################################################################## ########################################################################
def string_to_bool(string, default=True): def string_to_bool(string, default=True):
@ -428,7 +424,8 @@ class Config:
if file is not None: # config file path passed in if file is not None: # config file path passed in
file = os.path.expanduser(file) file = os.path.expanduser(file)
if not os.path.exists(file): if not os.path.exists(file):
log.error("Specified configuration file %s not found. Using defaults." % (file)) print "Configuration file %s not found. Using defaults." % (file)
sys.stderr.write("Configuration file %s not found. Using defaults." % (file))
file = None file = None
if file is None: file = get_config("HUD_config.xml", True) if file is None: file = get_config("HUD_config.xml", True)

View File

@ -39,41 +39,38 @@ import string
import re import re
import Queue import Queue
import codecs import codecs
import logging
import math import math
# pyGTK modules # pyGTK modules
# FreePokerTools modules
import SQL
import Card
import Tourney
import Charset
from Exceptions import *
import Configuration
log = Configuration.get_logger("logging.conf","db")
# Other library modules # Other library modules
try: try:
import sqlalchemy.pool as pool import sqlalchemy.pool as pool
use_pool = True use_pool = True
except ImportError: except ImportError:
logging.info("Not using sqlalchemy connection pool.") log.info("Not using sqlalchemy connection pool.")
use_pool = False use_pool = False
try: try:
from numpy import var from numpy import var
use_numpy = True use_numpy = True
except ImportError: except ImportError:
logging.info("Not using numpy to define variance in sqlite.") log.info("Not using numpy to define variance in sqlite.")
use_numpy = False use_numpy = False
# FreePokerTools modules
import Configuration
import SQL
import Card
import Tourney
import Charset
from Exceptions import *
log = Configuration.get_logger("logging.conf", config = "db")
log.debug("db logger initialized.")
encoder = codecs.lookup('utf-8')
DB_VERSION = 119 DB_VERSION = 119
@ -247,13 +244,14 @@ class Database:
# connect to db # connect to db
self.do_connect(c) self.do_connect(c)
print "connection =", self.connection
if self.backend == self.PGSQL: if self.backend == self.PGSQL:
from psycopg2.extensions import ISOLATION_LEVEL_AUTOCOMMIT, ISOLATION_LEVEL_READ_COMMITTED, ISOLATION_LEVEL_SERIALIZABLE from psycopg2.extensions import ISOLATION_LEVEL_AUTOCOMMIT, ISOLATION_LEVEL_READ_COMMITTED, ISOLATION_LEVEL_SERIALIZABLE
#ISOLATION_LEVEL_AUTOCOMMIT = 0 #ISOLATION_LEVEL_AUTOCOMMIT = 0
#ISOLATION_LEVEL_READ_COMMITTED = 1 #ISOLATION_LEVEL_READ_COMMITTED = 1
#ISOLATION_LEVEL_SERIALIZABLE = 2 #ISOLATION_LEVEL_SERIALIZABLE = 2
if self.backend == self.SQLITE and self.database == ':memory:' and self.wrongDbVersion: if self.backend == self.SQLITE and self.database == ':memory:' and self.wrongDbVersion:
log.info("sqlite/:memory: - creating") log.info("sqlite/:memory: - creating")
self.recreate_tables() self.recreate_tables()
@ -374,20 +372,20 @@ class Database:
print msg print msg
raise FpdbError(msg) raise FpdbError(msg)
elif backend == Database.SQLITE: elif backend == Database.SQLITE:
logging.info("Connecting to SQLite: %(database)s" % {'database':database}) log.info("Connecting to SQLite: %(database)s" % {'database':database})
import sqlite3 import sqlite3
if use_pool: if use_pool:
sqlite3 = pool.manage(sqlite3, pool_size=1) sqlite3 = pool.manage(sqlite3, pool_size=1)
else: else:
logging.warning("SQLite won't work well without 'sqlalchemy' installed.") log.warning("SQLite won't work well without 'sqlalchemy' installed.")
if database != ":memory:": if database != ":memory:":
if not os.path.isdir(self.config.dir_databases): if not os.path.isdir(self.config.dir_databases):
print "Creating directory: '%s'" % (self.config.dir_databases) print "Creating directory: '%s'" % (self.config.dir_databases)
logging.info("Creating directory: '%s'" % (self.config.dir_databases)) log.info("Creating directory: '%s'" % (self.config.dir_databases))
os.mkdir(self.config.dir_databases) os.mkdir(self.config.dir_databases)
database = os.path.join(self.config.dir_databases, database) database = os.path.join(self.config.dir_databases, database)
logging.info(" sqlite db: " + database) log.info(" sqlite db: " + database)
self.connection = sqlite3.connect(database, detect_types=sqlite3.PARSE_DECLTYPES ) self.connection = 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")
@ -397,7 +395,10 @@ class Database:
if use_numpy: if use_numpy:
self.connection.create_aggregate("variance", 1, VARIANCE) self.connection.create_aggregate("variance", 1, VARIANCE)
else: else:
logging.warning("Some database functions will not work without NumPy support") log.warning("Some database functions will not work without NumPy support")
self.cursor = self.connection.cursor()
self.cursor.execute('PRAGMA temp_store=2') # use memory for temp tables/indexes
self.cursor.execute('PRAGMA synchronous=0') # don't wait for file writes to finish
else: else:
raise FpdbError("unrecognised database backend:"+backend) raise FpdbError("unrecognised database backend:"+backend)
@ -412,7 +413,7 @@ class Database:
self.cursor.execute("SELECT * FROM Settings") self.cursor.execute("SELECT * FROM Settings")
settings = self.cursor.fetchone() settings = self.cursor.fetchone()
if settings[0] != DB_VERSION: if settings[0] != DB_VERSION:
logging.error("outdated or too new database version (%s) - please recreate tables" log.error("outdated or too new database version (%s) - please recreate tables"
% (settings[0])) % (settings[0]))
self.wrongDbVersion = True self.wrongDbVersion = True
except:# _mysql_exceptions.ProgrammingError: except:# _mysql_exceptions.ProgrammingError:
@ -422,11 +423,6 @@ class Database:
log.info("failed to read settings table - recreating tables") log.info("failed to read settings table - recreating tables")
self.recreate_tables() self.recreate_tables()
self.check_version(database=database, create=False) self.check_version(database=database, create=False)
if not self.wrongDbVersion:
msg = "Edit your screen_name and hand history path in the supported_sites "\
+"section of the \nPreferences window (Main menu) before trying to import hands"
print "\n%s" % msg
log.warning(msg)
else: else:
print "Failed to read settings table - please recreate tables" print "Failed to read settings table - please recreate tables"
log.info("failed to read settings table - please recreate tables") log.info("failed to read settings table - please recreate tables")
@ -436,7 +432,27 @@ class Database:
#end def connect #end def connect
def commit(self): def commit(self):
self.connection.commit() if self.backend != self.SQLITE:
self.connection.commit()
else:
# sqlite commits can fail because of shared locks on the database (SQLITE_BUSY)
# re-try commit if it fails in case this happened
maxtimes = 5
pause = 1
ok = False
for i in xrange(maxtimes):
try:
ret = self.connection.commit()
log.debug("commit finished ok, i = "+str(i))
ok = True
except:
log.debug("commit "+str(i)+" failed: info=" + str(sys.exc_info())
+ " value=" + str(sys.exc_value))
sleep(pause)
if ok: break
if not ok:
log.debug("commit failed")
raise FpdbError('sqlite commit failed')
def rollback(self): def rollback(self):
self.connection.rollback() self.connection.rollback()
@ -1313,6 +1329,7 @@ class Database:
c.execute("INSERT INTO Sites (name,currency) VALUES ('PartyPoker', 'USD')") c.execute("INSERT INTO Sites (name,currency) VALUES ('PartyPoker', 'USD')")
c.execute("INSERT INTO Sites (name,currency) VALUES ('Partouche', 'EUR')") c.execute("INSERT INTO Sites (name,currency) VALUES ('Partouche', 'EUR')")
c.execute("INSERT INTO Sites (name,currency) VALUES ('Carbon', 'USD')") c.execute("INSERT INTO Sites (name,currency) VALUES ('Carbon', 'USD')")
c.execute("INSERT INTO Sites (name,currency) VALUES ('PKR', 'USD')")
if self.backend == self.SQLITE: if self.backend == self.SQLITE:
c.execute("INSERT INTO TourneyTypes (id, siteId, buyin, fee) VALUES (NULL, 1, 0, 0);") c.execute("INSERT INTO TourneyTypes (id, siteId, buyin, fee) VALUES (NULL, 1, 0, 0);")
elif self.backend == self.PGSQL: elif self.backend == self.PGSQL:
@ -1752,7 +1769,10 @@ class Database:
def insertPlayer(self, name, site_id): def insertPlayer(self, name, site_id):
result = None result = None
_name = Charset.to_db_utf8(name) if self.backend == self.SQLITE:
_name = name
else:
_name = Charset.to_db_utf8(name)
c = self.get_cursor() c = self.get_cursor()
q = "SELECT name, id FROM Players WHERE siteid=%s and name=%s" q = "SELECT name, id FROM Players WHERE siteid=%s and name=%s"
q = q.replace('%s', self.sql.query['placeholder']) q = q.replace('%s', self.sql.query['placeholder'])
@ -1908,7 +1928,7 @@ class Database:
# end def send_finish_msg(): # end def send_finish_msg():
def tRecogniseTourneyType(self, tourney): def tRecogniseTourneyType(self, tourney):
logging.debug("Database.tRecogniseTourneyType") log.debug("Database.tRecogniseTourneyType")
typeId = 1 typeId = 1
# Check if Tourney exists, and if so retrieve TTypeId : in that case, check values of the ttype # Check if Tourney exists, and if so retrieve TTypeId : in that case, check values of the ttype
cursor = self.get_cursor() cursor = self.get_cursor()
@ -1924,10 +1944,10 @@ class Database:
try: try:
len(result) len(result)
typeId = result[0] typeId = result[0]
logging.debug("Tourney found in db with Tourney_Type_ID = %d" % typeId) log.debug("Tourney found in db with Tourney_Type_ID = %d" % typeId)
for ev in expectedValues : for ev in expectedValues :
if ( getattr( tourney, expectedValues.get(ev) ) <> result[ev] ): 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]) ) log.debug("TypeId mismatch : wrong %s : Tourney=%s / db=%s" % (expectedValues.get(ev), getattr( tourney, expectedValues.get(ev)), result[ev]) )
typeIdMatch = False typeIdMatch = False
#break #break
except: except:
@ -1937,7 +1957,7 @@ class Database:
if typeIdMatch == False : if typeIdMatch == False :
# Check for an existing TTypeId that matches tourney info (buyin/fee, knockout, rebuy, speed, matrix, shootout) # Check for an existing TTypeId that matches tourney info (buyin/fee, knockout, rebuy, speed, matrix, shootout)
# if not found create it # if not found create it
logging.debug("Searching for a TourneyTypeId matching TourneyType data") log.debug("Searching for a TourneyTypeId matching TourneyType data")
cursor.execute (self.sql.query['getTourneyTypeId'].replace('%s', self.sql.query['placeholder']), cursor.execute (self.sql.query['getTourneyTypeId'].replace('%s', self.sql.query['placeholder']),
(tourney.siteId, tourney.buyin, tourney.fee, tourney.isKO, (tourney.siteId, tourney.buyin, tourney.fee, tourney.isKO,
tourney.isRebuy, tourney.speed, tourney.isHU, tourney.isShootout, tourney.isMatrix) tourney.isRebuy, tourney.speed, tourney.isHU, tourney.isShootout, tourney.isMatrix)
@ -1947,9 +1967,9 @@ class Database:
try: try:
len(result) len(result)
typeId = result[0] typeId = result[0]
logging.debug("Existing Tourney Type Id found : %d" % typeId) log.debug("Existing Tourney Type Id found : %d" % typeId)
except TypeError: #this means we need to create a new entry except TypeError: #this means we need to create a new entry
logging.debug("Tourney Type Id not found : create one") log.debug("Tourney Type Id not found : create one")
cursor.execute (self.sql.query['insertTourneyTypes'].replace('%s', self.sql.query['placeholder']), cursor.execute (self.sql.query['insertTourneyTypes'].replace('%s', self.sql.query['placeholder']),
(tourney.siteId, tourney.buyin, tourney.fee, tourney.isKO, tourney.isRebuy, (tourney.siteId, tourney.buyin, tourney.fee, tourney.isKO, tourney.isRebuy,
tourney.speed, tourney.isHU, tourney.isShootout, tourney.isMatrix) tourney.speed, tourney.isHU, tourney.isShootout, tourney.isMatrix)

View File

@ -48,5 +48,11 @@ class FpdbPostgresqlNoDatabase(FpdbDatabaseError):
def __str__(self): def __str__(self):
return repr(self.value +" " + self.errmsg) return repr(self.value +" " + self.errmsg)
class DuplicateError(FpdbError): class FpdbHandError(FpdbError):
pass
class FpdbHandDuplicate(FpdbHandError):
pass
class FpdbHandPartial(FpdbHandError):
pass pass

View File

@ -42,6 +42,26 @@ class Filters(threading.Thread):
self.conf = db.config self.conf = db.config
self.display = display self.display = display
# text used on screen stored here so that it can be configured
self.filterText = {'limitsall':'All', 'limitsnone':'None', 'limitsshow':'Show _Limits'
,'seatsbetween':'Between:', 'seatsand':'And:', 'seatsshow':'Show Number of _Players'
,'playerstitle':'Hero:', 'sitestitle':'Sites:', 'gamestitle':'Games:'
,'limitstitle':'Limits:', 'seatstitle':'Number of Players:'
,'groupstitle':'Grouping:', 'posnshow':'Show Position Stats:'
,'datestitle':'Date:'
,'groupsall':'All Players'
,'limitsFL':'FL', 'limitsNL':'NL', 'limitsPL':'PL', 'ring':'Ring', 'tour':'Tourney'
}
# Outer Packing box
self.mainVBox = gtk.VBox(False, 0)
self.label = {}
self.callback = {}
self.make_filter()
def make_filter(self):
self.sites = {} self.sites = {}
self.games = {} self.games = {}
self.limits = {} self.limits = {}
@ -60,16 +80,6 @@ class Filters(threading.Thread):
else: else:
print "Either 0 or more than one site matched - EEK" print "Either 0 or more than one site matched - EEK"
# text used on screen stored here so that it can be configured
self.filterText = {'limitsall':'All', 'limitsnone':'None', 'limitsshow':'Show _Limits'
,'seatsbetween':'Between:', 'seatsand':'And:', 'seatsshow':'Show Number of _Players'
,'limitstitle':'Limits:', 'seatstitle':'Number of Players:'
,'groupstitle':'Grouping:', 'posnshow':'Show Position Stats:'
,'groupsall':'All Players'
,'limitsFL':'FL', 'limitsNL':'NL', 'limitsPL':'PL', 'ring':'Ring', 'tour':'Tourney'
}
# For use in date ranges. # For use in date ranges.
self.start_date = gtk.Entry(max=12) self.start_date = gtk.Entry(max=12)
self.end_date = gtk.Entry(max=12) self.end_date = gtk.Entry(max=12)
@ -80,34 +90,28 @@ class Filters(threading.Thread):
self.sbGroups = {} self.sbGroups = {}
self.numHands = 0 self.numHands = 0
# Outer Packing box playerFrame = gtk.Frame()
self.mainVBox = gtk.VBox(False, 0)
playerFrame = gtk.Frame("Hero:")
playerFrame.set_label_align(0.0, 0.0) playerFrame.set_label_align(0.0, 0.0)
vbox = gtk.VBox(False, 0) vbox = gtk.VBox(False, 0)
self.fillPlayerFrame(vbox, self.display) self.fillPlayerFrame(vbox, self.display)
playerFrame.add(vbox) playerFrame.add(vbox)
self.boxes['player'] = vbox
sitesFrame = gtk.Frame("Sites:") sitesFrame = gtk.Frame()
sitesFrame.set_label_align(0.0, 0.0) sitesFrame.set_label_align(0.0, 0.0)
vbox = gtk.VBox(False, 0) vbox = gtk.VBox(False, 0)
self.fillSitesFrame(vbox) self.fillSitesFrame(vbox)
sitesFrame.add(vbox) sitesFrame.add(vbox)
self.boxes['sites'] = vbox
# Game types # Game types
gamesFrame = gtk.Frame("Games:") gamesFrame = gtk.Frame()
gamesFrame.set_label_align(0.0, 0.0) gamesFrame.set_label_align(0.0, 0.0)
gamesFrame.show() gamesFrame.show()
vbox = gtk.VBox(False, 0) vbox = gtk.VBox(False, 0)
self.fillGamesFrame(vbox) self.fillGamesFrame(vbox)
gamesFrame.add(vbox) gamesFrame.add(vbox)
self.boxes['games'] = vbox
# Limits # Limits
limitsFrame = gtk.Frame() limitsFrame = gtk.Frame()
@ -144,14 +148,13 @@ class Filters(threading.Thread):
groupsFrame.add(vbox) groupsFrame.add(vbox)
# Date # Date
dateFrame = gtk.Frame("Date:") dateFrame = gtk.Frame()
dateFrame.set_label_align(0.0, 0.0) dateFrame.set_label_align(0.0, 0.0)
dateFrame.show() dateFrame.show()
vbox = gtk.VBox(False, 0) vbox = gtk.VBox(False, 0)
self.fillDateFrame(vbox) self.fillDateFrame(vbox)
dateFrame.add(vbox) dateFrame.add(vbox)
self.boxes['date'] = vbox
# Buttons # Buttons
self.Button1=gtk.Button("Unnamed 1") self.Button1=gtk.Button("Unnamed 1")
@ -192,6 +195,17 @@ class Filters(threading.Thread):
if "Button2" not in self.display or self.display["Button2"] == False: if "Button2" not in self.display or self.display["Button2"] == False:
self.Button2.hide() self.Button2.hide()
if 'button1' in self.label and self.label['button1']:
self.Button1.set_label( self.label['button1'] )
if 'button2' in self.label and self.label['button2']:
self.Button2.set_label( self.label['button2'] )
if 'button1' in self.callback and self.callback['button1']:
self.Button1.connect("clicked", self.callback['button1'], "clicked")
self.Button1.set_sensitive(True)
if 'button2' in self.callback and self.callback['button2']:
self.Button2.connect("clicked", self.callback['button2'], "clicked")
self.Button2.set_sensitive(True)
def get_vbox(self): def get_vbox(self):
"""returns the vbox of this thread""" """returns the vbox of this thread"""
return self.mainVBox return self.mainVBox
@ -237,17 +251,21 @@ class Filters(threading.Thread):
def registerButton1Name(self, title): def registerButton1Name(self, title):
self.Button1.set_label(title) self.Button1.set_label(title)
self.label['button1'] = title
def registerButton1Callback(self, callback): def registerButton1Callback(self, callback):
self.Button1.connect("clicked", callback, "clicked") self.Button1.connect("clicked", callback, "clicked")
self.Button1.set_sensitive(True) self.Button1.set_sensitive(True)
self.callback['button1'] = callback
def registerButton2Name(self, title): def registerButton2Name(self, title):
self.Button2.set_label(title) self.Button2.set_label(title)
self.label['button2'] = title
def registerButton2Callback(self, callback): def registerButton2Callback(self, callback):
self.Button2.connect("clicked", callback, "clicked") self.Button2.connect("clicked", callback, "clicked")
self.Button2.set_sensitive(True) self.Button2.set_sensitive(True)
self.callback['button2'] = callback
def cardCallback(self, widget, data=None): def cardCallback(self, widget, data=None):
print "DEBUG: %s was toggled %s" % (data, ("OFF", "ON")[widget.get_active()]) print "DEBUG: %s was toggled %s" % (data, ("OFF", "ON")[widget.get_active()])
@ -255,7 +273,7 @@ class Filters(threading.Thread):
def createPlayerLine(self, hbox, site, player): def createPlayerLine(self, hbox, site, player):
print 'DEBUG :: add:"%s"' % player print 'DEBUG :: add:"%s"' % player
label = gtk.Label(site +" id:") label = gtk.Label(site +" id:")
hbox.pack_start(label, False, False, 0) hbox.pack_start(label, False, False, 3)
pname = gtk.Entry() pname = gtk.Entry()
pname.set_text(player) pname.set_text(player)
@ -464,9 +482,22 @@ class Filters(threading.Thread):
print "self.groups[%s] set to %s" %(group, self.groups[group]) print "self.groups[%s] set to %s" %(group, self.groups[group])
def fillPlayerFrame(self, vbox, display): def fillPlayerFrame(self, vbox, display):
top_hbox = gtk.HBox(False, 0)
vbox.pack_start(top_hbox, False, False, 0)
lbl_title = gtk.Label(self.filterText['playerstitle'])
lbl_title.set_alignment(xalign=0.0, yalign=0.5)
top_hbox.pack_start(lbl_title, expand=True, padding=3)
showb = gtk.Button(label="refresh", stock=None, use_underline=True)
showb.set_alignment(xalign=1.0, yalign=0.5)
showb.connect('clicked', self.__refresh, 'players')
vbox1 = gtk.VBox(False, 0)
vbox.pack_start(vbox1, False, False, 0)
self.boxes['players'] = vbox1
for site in self.conf.get_supported_sites(): for site in self.conf.get_supported_sites():
hBox = gtk.HBox(False, 0) hBox = gtk.HBox(False, 0)
vbox.pack_start(hBox, False, True, 0) vbox1.pack_start(hBox, False, True, 0)
player = self.conf.supported_sites[site].screen_name player = self.conf.supported_sites[site].screen_name
_pname = Charset.to_gui(player) _pname = Charset.to_gui(player)
@ -474,7 +505,7 @@ class Filters(threading.Thread):
if "GroupsAll" in display and display["GroupsAll"] == True: if "GroupsAll" in display and display["GroupsAll"] == True:
hbox = gtk.HBox(False, 0) hbox = gtk.HBox(False, 0)
vbox.pack_start(hbox, False, False, 0) vbox1.pack_start(hbox, False, False, 0)
cb = gtk.CheckButton(self.filterText['groupsall']) cb = gtk.CheckButton(self.filterText['groupsall'])
cb.connect('clicked', self.__set_group_select, 'allplayers') cb.connect('clicked', self.__set_group_select, 'allplayers')
hbox.pack_start(cb, False, False, 0) hbox.pack_start(cb, False, False, 0)
@ -490,11 +521,30 @@ class Filters(threading.Thread):
phands.set_width_chars(8) phands.set_width_chars(8)
hbox.pack_start(phands, False, False, 0) hbox.pack_start(phands, False, False, 0)
phands.connect("changed", self.__set_num_hands, site) phands.connect("changed", self.__set_num_hands, site)
top_hbox.pack_start(showb, expand=False, padding=1)
def fillSitesFrame(self, vbox): def fillSitesFrame(self, vbox):
top_hbox = gtk.HBox(False, 0)
top_hbox.show()
vbox.pack_start(top_hbox, False, False, 0)
lbl_title = gtk.Label(self.filterText['sitestitle'])
lbl_title.set_alignment(xalign=0.0, yalign=0.5)
top_hbox.pack_start(lbl_title, expand=True, padding=3)
showb = gtk.Button(label="hide", stock=None, use_underline=True)
showb.set_alignment(xalign=1.0, yalign=0.5)
showb.connect('clicked', self.__toggle_box, 'sites')
showb.show()
top_hbox.pack_start(showb, expand=False, padding=1)
vbox1 = gtk.VBox(False, 0)
self.boxes['sites'] = vbox1
vbox.pack_start(vbox1, False, False, 0)
for site in self.conf.get_supported_sites(): for site in self.conf.get_supported_sites():
hbox = gtk.HBox(False, 0) hbox = gtk.HBox(False, 0)
vbox.pack_start(hbox, False, True, 0) vbox1.pack_start(hbox, False, True, 0)
self.createSiteLine(hbox, site) self.createSiteLine(hbox, site)
#Get db site id for filtering later #Get db site id for filtering later
#self.cursor.execute(self.sql.query['getSiteId'], (site,)) #self.cursor.execute(self.sql.query['getSiteId'], (site,))
@ -505,12 +555,26 @@ class Filters(threading.Thread):
# print "Either 0 or more than one site matched - EEK" # print "Either 0 or more than one site matched - EEK"
def fillGamesFrame(self, vbox): def fillGamesFrame(self, vbox):
top_hbox = gtk.HBox(False, 0)
vbox.pack_start(top_hbox, False, False, 0)
lbl_title = gtk.Label(self.filterText['gamestitle'])
lbl_title.set_alignment(xalign=0.0, yalign=0.5)
top_hbox.pack_start(lbl_title, expand=True, padding=3)
showb = gtk.Button(label="hide", stock=None, use_underline=True)
showb.set_alignment(xalign=1.0, yalign=0.5)
showb.connect('clicked', self.__toggle_box, 'games')
top_hbox.pack_start(showb, expand=False, padding=1)
vbox1 = gtk.VBox(False, 0)
vbox.pack_start(vbox1, False, False, 0)
self.boxes['games'] = vbox1
self.cursor.execute(self.sql.query['getGames']) self.cursor.execute(self.sql.query['getGames'])
result = self.db.cursor.fetchall() result = self.db.cursor.fetchall()
if len(result) >= 1: if len(result) >= 1:
for line in result: for line in result:
hbox = gtk.HBox(False, 0) hbox = gtk.HBox(False, 0)
vbox.pack_start(hbox, False, True, 0) vbox1.pack_start(hbox, False, True, 0)
self.createGameLine(hbox, line[0]) self.createGameLine(hbox, line[0])
else: else:
print "INFO: No games returned from database" print "INFO: No games returned from database"
@ -705,8 +769,22 @@ class Filters(threading.Thread):
def fillDateFrame(self, vbox): def fillDateFrame(self, vbox):
# Hat tip to Mika Bostrom - calendar code comes from PokerStats # Hat tip to Mika Bostrom - calendar code comes from PokerStats
top_hbox = gtk.HBox(False, 0)
vbox.pack_start(top_hbox, False, False, 0)
lbl_title = gtk.Label(self.filterText['datestitle'])
lbl_title.set_alignment(xalign=0.0, yalign=0.5)
top_hbox.pack_start(lbl_title, expand=True, padding=3)
showb = gtk.Button(label="hide", stock=None, use_underline=True)
showb.set_alignment(xalign=1.0, yalign=0.5)
showb.connect('clicked', self.__toggle_box, 'dates')
top_hbox.pack_start(showb, expand=False, padding=1)
vbox1 = gtk.VBox(False, 0)
vbox.pack_start(vbox1, False, False, 0)
self.boxes['dates'] = vbox1
hbox = gtk.HBox() hbox = gtk.HBox()
vbox.pack_start(hbox, False, True, 0) vbox1.pack_start(hbox, False, True, 0)
lbl_start = gtk.Label('From:') lbl_start = gtk.Label('From:')
@ -720,7 +798,7 @@ class Filters(threading.Thread):
#New row for end date #New row for end date
hbox = gtk.HBox() hbox = gtk.HBox()
vbox.pack_start(hbox, False, True, 0) vbox1.pack_start(hbox, False, True, 0)
lbl_end = gtk.Label(' To:') lbl_end = gtk.Label(' To:')
btn_end = gtk.Button() btn_end = gtk.Button()
@ -736,10 +814,13 @@ class Filters(threading.Thread):
hbox.pack_start(btn_clear, expand=False, padding=15) hbox.pack_start(btn_clear, expand=False, padding=15)
def __refresh(self, widget, entry):
for w in self.mainVBox.get_children():
w.destroy()
self.make_filter()
def __toggle_box(self, widget, entry): def __toggle_box(self, widget, entry):
if "Limits" not in self.display or self.display["Limits"] == False: if self.boxes[entry].props.visible:
self.boxes[entry].hide()
elif self.boxes[entry].props.visible:
self.boxes[entry].hide() self.boxes[entry].hide()
widget.set_label("show") widget.set_label("show")
else: else:

View File

@ -194,7 +194,7 @@ class GuiAutoImport (threading.Thread):
widget.set_label(u' _Stop Autoimport ') widget.set_label(u' _Stop Autoimport ')
if self.pipe_to_hud is None: if self.pipe_to_hud is None:
if os.name == 'nt': if os.name == 'nt':
command = "python HUD_main.py " + self.settings['cl_options'] command = "python "+sys.path[0]+"\\HUD_main.py " + self.settings['cl_options']
bs = 0 bs = 0
else: else:
command = os.path.join(sys.path[0], 'HUD_main.py') command = os.path.join(sys.path[0], 'HUD_main.py')

View File

@ -212,6 +212,7 @@ class HUD_main(object):
# get basic info about the new hand from the db # get basic info about the new hand from the db
# if there is a db error, complain, skip hand, and proceed # if there is a db error, complain, skip hand, and proceed
log.info("HUD_main.read_stdin: hand processing starting ...")
try: try:
(table_name, max, poker_game, type, site_id, site_name, num_seats, tour_number, tab_number) = \ (table_name, max, poker_game, type, site_id, site_name, num_seats, tour_number, tab_number) = \
self.db_connection.get_table_info(new_hand_id) self.db_connection.get_table_info(new_hand_id)
@ -237,6 +238,7 @@ class HUD_main(object):
try: try:
self.db_connection.init_hud_stat_vars( self.hud_dict[temp_key].hud_params['hud_days'] self.db_connection.init_hud_stat_vars( self.hud_dict[temp_key].hud_params['hud_days']
, self.hud_dict[temp_key].hud_params['h_hud_days']) , self.hud_dict[temp_key].hud_params['h_hud_days'])
t4 = time.time()
stat_dict = self.db_connection.get_stats_from_hand(new_hand_id, type, self.hud_dict[temp_key].hud_params, self.hero_ids[site_id]) stat_dict = self.db_connection.get_stats_from_hand(new_hand_id, type, self.hud_dict[temp_key].hud_params, self.hero_ids[site_id])
self.hud_dict[temp_key].stat_dict = stat_dict self.hud_dict[temp_key].stat_dict = stat_dict
except KeyError: # HUD instance has been killed off, key is stale except KeyError: # HUD instance has been killed off, key is stale
@ -245,6 +247,7 @@ class HUD_main(object):
# Unlocks table, copied from end of function # Unlocks table, copied from end of function
self.db_connection.connection.rollback() self.db_connection.connection.rollback()
return return
t5 = time.time()
cards = self.db_connection.get_cards(new_hand_id) cards = self.db_connection.get_cards(new_hand_id)
comm_cards = self.db_connection.get_common_cards(new_hand_id) comm_cards = self.db_connection.get_common_cards(new_hand_id)
if comm_cards != {}: # stud! if comm_cards != {}: # stud!
@ -257,10 +260,8 @@ class HUD_main(object):
else: else:
# get stats using default params--also get cards # get stats using default params--also get cards
self.db_connection.init_hud_stat_vars( self.hud_params['hud_days'], self.hud_params['h_hud_days'] ) self.db_connection.init_hud_stat_vars( self.hud_params['hud_days'], self.hud_params['h_hud_days'] )
t4 = time.time()
stat_dict = self.db_connection.get_stats_from_hand(new_hand_id, type, self.hud_params stat_dict = self.db_connection.get_stats_from_hand(new_hand_id, type, self.hud_params
,self.hero_ids[site_id], num_seats) ,self.hero_ids[site_id], num_seats)
t5 = time.time()
cards = self.db_connection.get_cards(new_hand_id) cards = self.db_connection.get_cards(new_hand_id)
comm_cards = self.db_connection.get_common_cards(new_hand_id) comm_cards = self.db_connection.get_common_cards(new_hand_id)
if comm_cards != {}: # stud! if comm_cards != {}: # stud!

View File

@ -229,8 +229,7 @@ db: a connected Database object"""
# TourneysPlayers # TourneysPlayers
else: else:
log.info("Hand.insert(): hid #: %s is a duplicate" % hh['siteHandNo']) log.info("Hand.insert(): hid #: %s is a duplicate" % hh['siteHandNo'])
#Raise Duplicate exception? raise FpdbHandDuplicate(hh['siteHandNo'])
pass
def updateHudCache(self, db): def updateHudCache(self, db):
db.storeHudCache(self.dbid_gt, self.dbid_pids, self.starttime, self.stats.getHandsPlayers()) db.storeHudCache(self.dbid_gt, self.dbid_pids, self.starttime, self.stats.getHandsPlayers())
@ -636,7 +635,7 @@ class HoldemOmahaHand(Hand):
if builtFrom == "HHC": if builtFrom == "HHC":
hhc.readHandInfo(self) hhc.readHandInfo(self)
if self.gametype['type'] == 'tour': if self.gametype['type'] == 'tour':
self.tablename = "%s %s" % (self.tourNo, self.tablename) self.tablename = "%s %s" % (self.tourNo, self.tablename)
hhc.readPlayerStacks(self) hhc.readPlayerStacks(self)
hhc.compilePlayerRegexs(self) hhc.compilePlayerRegexs(self)
hhc.markStreets(self) hhc.markStreets(self)
@ -932,7 +931,7 @@ class DrawHand(Hand):
if builtFrom == "HHC": if builtFrom == "HHC":
hhc.readHandInfo(self) hhc.readHandInfo(self)
if self.gametype['type'] == 'tour': if self.gametype['type'] == 'tour':
self.tablename = "%s %s" % (self.tourNo, self.tablename) self.tablename = "%s %s" % (self.tourNo, self.tablename)
hhc.readPlayerStacks(self) hhc.readPlayerStacks(self)
hhc.compilePlayerRegexs(self) hhc.compilePlayerRegexs(self)
hhc.markStreets(self) hhc.markStreets(self)
@ -1128,7 +1127,7 @@ class StudHand(Hand):
if builtFrom == "HHC": if builtFrom == "HHC":
hhc.readHandInfo(self) hhc.readHandInfo(self)
if self.gametype['type'] == 'tour': if self.gametype['type'] == 'tour':
self.tablename = "%s %s" % (self.tourNo, self.tablename) self.tablename = "%s %s" % (self.tourNo, self.tablename)
hhc.readPlayerStacks(self) hhc.readPlayerStacks(self)
hhc.compilePlayerRegexs(self) hhc.compilePlayerRegexs(self)
hhc.markStreets(self) hhc.markStreets(self)
@ -1220,7 +1219,7 @@ Add a complete on [street] by [player] to [amountTo]
# showdownPot INT, /* pot size at sd/street7 */ # showdownPot INT, /* pot size at sd/street7 */
return (0,0,0,0,0) return (0,0,0,0,0)
def writeHand(self, fh=sys.__stdout__): def writeHand(self, fh=sys.__stdout__):
# PokerStars format. # PokerStars format.
@ -1615,4 +1614,3 @@ ORDER BY
return h return h

View File

@ -128,7 +128,8 @@ class Stud_mucked(Aux_Window):
self.container.show_all() self.container.show_all()
def update_data(self, new_hand_id, db_connection): def update_data(self, new_hand_id, db_connection):
self.mucked_cards.update_data(new_hand_id, db_connection) # uncomment next line when action is available in the db
# self.mucked_cards.update_data(new_hand_id, db_connection)
self.mucked_list.update_data(new_hand_id, db_connection) self.mucked_list.update_data(new_hand_id, db_connection)
def update_gui(self, new_hand_id): def update_gui(self, new_hand_id):

View File

@ -769,7 +769,7 @@ class fpdb:
self.status_bar.show() self.status_bar.show()
if self.db is not None and self.db.connected: if self.db is not None and self.db.connected:
self.status_bar.set_text("Status: Connected to %s database named %s on host %s" self.status_bar.set_text("Status: Connected to %s database named %s on host %s"
% (self.db.get_backend_name(),self.db.database, self.db.host)) % (self.db.get_backend_name(),self.db.database, self.db.host))
# rollback to make sure any locks are cleared: # rollback to make sure any locks are cleared:
self.db.rollback() self.db.rollback()
@ -902,8 +902,8 @@ This program is licensed under the AGPL3, see docs"""+os.sep+"agpl-3.0.txt")
self.load_profile() self.load_profile()
self.statusIcon = gtk.StatusIcon() self.statusIcon = gtk.StatusIcon()
if os.path.exists('../gfx/fpdb-cards.png'): if os.path.exists(os.path.join(sys.path[0], '../gfx/fpdb-cards.png')):
self.statusIcon.set_from_file('../gfx/fpdb-cards.png') self.statusIcon.set_from_file(os.path.join(sys.path[0], '../gfx/fpdb-cards.png'))
elif os.path.exists('/usr/share/pixmaps/fpdb-cards.png'): elif os.path.exists('/usr/share/pixmaps/fpdb-cards.png'):
self.statusIcon.set_from_file('/usr/share/pixmaps/fpdb-cards.png') self.statusIcon.set_from_file('/usr/share/pixmaps/fpdb-cards.png')
else: else:

View File

@ -365,7 +365,7 @@ class Importer:
pass pass
(stored, duplicates, partial, errors, ttime) = self.import_file_dict(self.database, file, self.filelist[file][0], self.filelist[file][1], None) (stored, duplicates, partial, errors, ttime) = self.import_file_dict(self.database, file, self.filelist[file][0], self.filelist[file][1], None)
try: try:
if not os.path.isdir(file): if not os.path.isdir(file): # Note: This assumes that whatever calls us has an "addText" func
self.caller.addText(" %d stored, %d duplicates, %d partial, %d errors (time = %f)" % (stored, duplicates, partial, errors, ttime)) self.caller.addText(" %d stored, %d duplicates, %d partial, %d errors (time = %f)" % (stored, duplicates, partial, errors, ttime))
except KeyError: # TODO: Again, what error happens here? fix when we find out .. except KeyError: # TODO: Again, what error happens here? fix when we find out ..
pass pass
@ -402,7 +402,7 @@ class Importer:
return (0,0,0,0,0) return (0,0,0,0,0)
conv = None conv = None
(stored, duplicates, partial, errors, ttime) = (0, 0, 0, 0, 0) (stored, duplicates, partial, errors, ttime) = (0, 0, 0, 0, time())
file = file.decode(Configuration.LOCALE_ENCODING) file = file.decode(Configuration.LOCALE_ENCODING)
@ -437,12 +437,15 @@ class Importer:
for hand in handlist: for hand in handlist:
if hand is not None: if hand is not None:
#try, except duplicates here?
hand.prepInsert(self.database) hand.prepInsert(self.database)
hand.insert(self.database) try:
if self.callHud and hand.dbid_hands != 0: hand.insert(self.database)
to_hud.append(hand.dbid_hands) except Exceptions.FpdbHandDuplicate:
else: duplicates += 1
else:
if self.callHud and hand.dbid_hands != 0:
to_hud.append(hand.dbid_hands)
else: # TODO: Treat empty as an error, or just ignore?
log.error("Hand processed but empty") log.error("Hand processed but empty")
self.database.commit() self.database.commit()
# Call hudcache update if not in bulk import mode # Call hudcache update if not in bulk import mode
@ -460,13 +463,16 @@ class Importer:
errors = getattr(hhc, 'numErrors') errors = getattr(hhc, 'numErrors')
stored = getattr(hhc, 'numHands') stored = getattr(hhc, 'numHands')
stored -= duplicates
else: else:
# conversion didn't work # conversion didn't work
# TODO: appropriate response? # TODO: appropriate response?
return (0, 0, 0, 1, 0) return (0, 0, 0, 1, time() - ttime)
else: else:
log.warning("Unknown filter filter_name:'%s' in filter:'%s'" %(filter_name, filter)) log.warning("Unknown filter filter_name:'%s' in filter:'%s'" %(filter_name, filter))
return (0, 0, 0, 1, 0) return (0, 0, 0, 1, time() - ttime)
ttime = time() - ttime
#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)

View File

@ -24,7 +24,6 @@ sys.path[0] = sys.path[0]+os.sep+"pyfpdb"
os.chdir(sys.path[0]) os.chdir(sys.path[0])
#print "sys.path[0] =", sys.path[0], "cwd =", os.getcwd() #print "sys.path[0] =", sys.path[0], "cwd =", os.getcwd()
import fpdb import fpdb