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

This commit is contained in:
sqlcoder 2009-11-09 20:44:05 +00:00
commit 9bbca552ea
29 changed files with 4197 additions and 3601 deletions

View File

@ -191,7 +191,7 @@ class Betfair(HandHistoryConverter):
elif action.group('ATYPE') == 'checks': elif action.group('ATYPE') == 'checks':
hand.addCheck( street, action.group('PNAME')) hand.addCheck( street, action.group('PNAME'))
else: else:
print "DEBUG: unimplemented readAction: '%s' '%s'" %(action.group('PNAME'),action.group('ATYPE'),) sys.stderr.write( "DEBUG: unimplemented readAction: '%s' '%s'" %(action.group('PNAME'),action.group('ATYPE'),))
def readShowdownActions(self, hand): def readShowdownActions(self, hand):

View File

@ -67,7 +67,7 @@ class CarbonPoker(HandHistoryConverter):
if(type == "Holdem"): if(type == "Holdem"):
gametype = gametype + ["hold"] gametype = gametype + ["hold"]
else: else:
print "Unknown gametype: '%s'" % (type) print "Carbon: Unknown gametype: '%s'" % (type)
stakes = desc_node[0].getAttribute("stakes") stakes = desc_node[0].getAttribute("stakes")
#TODO: no examples of anything except nlhe #TODO: no examples of anything except nlhe

View File

@ -44,21 +44,42 @@ except ConfigParser.NoSectionError: # debian package path
log = logging.getLogger("config") log = logging.getLogger("config")
log.debug("config logger initialised") log.debug("config logger initialised")
########################################################################
# application wide consts
def fix_tf(x, default = True): APPLICATION_NAME_SHORT = 'fpdb'
# The xml parser doesn't translate "True" to True. Therefore, we never get APPLICATION_VERSION = 'xx.xx.xx'
# True or False from the parser only "True" or "False". So translate the
# string to the python boolean representation. DIR_SELF = os.path.dirname(os.path.abspath(__file__))
if x == "1" or x == 1 or string.lower(x) == "true" or string.lower(x) == "t": #TODO: imo no good idea to place 'database' in parent dir
DIR_DATABASES = os.path.join(os.path.dirname(DIR_SELF), 'database')
DATABASE_TYPE_POSTGRESQL = 'postgresql'
DATABASE_TYPE_SQLITE = 'sqlite'
DATABASE_TYPE_MYSQL = 'mysql'
DATABASE_TYPES = (
DATABASE_TYPE_POSTGRESQL,
DATABASE_TYPE_SQLITE,
DATABASE_TYPE_MYSQL,
)
########################################################################
def string_to_bool(string, default=True):
"""converts a string representation of a boolean value to boolean True or False
@param string: (str) the string to convert
@param default: value to return if the string can not be converted to a boolean value
"""
string = string.lower()
if string in ('1', 'true', 't'):
return True return True
if x == "0" or x == 0 or string.lower(x) == "false" or string.lower(x) == "f": elif string in ('0', 'false', 'f'):
return False return False
return default return default
class Layout: class Layout:
def __init__(self, node): def __init__(self, node):
self.max = int( node.getAttribute('max') ) self.max = int( node.getAttribute('max') )
if node.hasAttribute('fav_seat'): self.fav_seat = int( node.getAttribute('fav_seat') ) if node.hasAttribute('fav_seat'): self.fav_seat = int( node.getAttribute('fav_seat') )
self.width = int( node.getAttribute('width') ) self.width = int( node.getAttribute('width') )
self.height = int( node.getAttribute('height') ) self.height = int( node.getAttribute('height') )
@ -96,39 +117,32 @@ class Site:
self.table_finder = node.getAttribute("table_finder") self.table_finder = node.getAttribute("table_finder")
self.screen_name = node.getAttribute("screen_name") self.screen_name = node.getAttribute("screen_name")
self.site_path = normalizePath(node.getAttribute("site_path")) self.site_path = normalizePath(node.getAttribute("site_path"))
self.HH_path = normalizePath(node.getAttribute("HH_path")) self.HH_path = normalizePath(node.getAttribute("HH_path"))
self.decoder = node.getAttribute("decoder") self.decoder = node.getAttribute("decoder")
self.hudopacity = node.getAttribute("hudopacity") self.hudopacity = node.getAttribute("hudopacity")
self.hudbgcolor = node.getAttribute("bgcolor") self.hudbgcolor = node.getAttribute("bgcolor")
self.hudfgcolor = node.getAttribute("fgcolor") self.hudfgcolor = node.getAttribute("fgcolor")
self.converter = node.getAttribute("converter") self.converter = node.getAttribute("converter")
self.aux_window = node.getAttribute("aux_window") self.aux_window = node.getAttribute("aux_window")
self.font = node.getAttribute("font") self.font = node.getAttribute("font")
self.font_size = node.getAttribute("font_size") self.font_size = node.getAttribute("font_size")
self.use_frames = node.getAttribute("use_frames") self.use_frames = node.getAttribute("use_frames")
self.enabled = fix_tf(node.getAttribute("enabled"), default = True) self.enabled = string_to_bool(node.getAttribute("enabled"), default=True)
self.xpad = node.getAttribute("xpad") self.xpad = node.getAttribute("xpad")
self.ypad = node.getAttribute("ypad") self.ypad = node.getAttribute("ypad")
self.layout = {} self.layout = {}
print self.site_name, self.HH_path print "Loading site", self.site_name
for layout_node in node.getElementsByTagName('layout'): for layout_node in node.getElementsByTagName('layout'):
lo = Layout(layout_node) lo = Layout(layout_node)
self.layout[lo.max] = lo self.layout[lo.max] = lo
# Site defaults # Site defaults
if self.xpad == "": self.xpad = 1 self.xpad = 1 if self.xpad == "" else int(self.xpad)
else: self.xpad = int(self.xpad) self.ypad = 0 if self.ypad == "" else int(self.ypad)
self.font_size = 7 if self.font_size == "" else int(self.font_size)
if self.ypad == "": self.ypad = 0 self.hudopacity = 1.0 if self.hudopacity == "" else float(self.hudopacity)
else: self.ypad = int(self.ypad)
if self.font_size == "": self.font_size = 7
else: self.font_size = int(self.font_size)
if self.hudopacity == "": self.hudopacity = 1.0
else: self.hudopacity = float(self.hudopacity)
if self.use_frames == "": self.use_frames = False if self.use_frames == "": self.use_frames = False
if self.font == "": self.font = "Sans" if self.font == "": self.font = "Sans"
@ -160,10 +174,10 @@ class Stat:
class Game: class Game:
def __init__(self, node): def __init__(self, node):
self.game_name = node.getAttribute("game_name") self.game_name = node.getAttribute("game_name")
self.rows = int( node.getAttribute("rows") ) self.rows = int( node.getAttribute("rows") )
self.cols = int( node.getAttribute("cols") ) self.cols = int( node.getAttribute("cols") )
self.xpad = node.getAttribute("xpad") self.xpad = node.getAttribute("xpad")
self.ypad = node.getAttribute("ypad") self.ypad = node.getAttribute("ypad")
# Defaults # Defaults
if self.xpad == "": self.xpad = 1 if self.xpad == "": self.xpad = 1
@ -177,15 +191,15 @@ class Game:
aux_list[i] = aux_list[i].strip() aux_list[i] = aux_list[i].strip()
self.aux = aux_list self.aux = aux_list
self.stats = {} self.stats = {}
for stat_node in node.getElementsByTagName('stat'): for stat_node in node.getElementsByTagName('stat'):
stat = Stat() stat = Stat()
stat.stat_name = stat_node.getAttribute("stat_name") stat.stat_name = stat_node.getAttribute("stat_name")
stat.row = int( stat_node.getAttribute("row") ) stat.row = int( stat_node.getAttribute("row") )
stat.col = int( stat_node.getAttribute("col") ) stat.col = int( stat_node.getAttribute("col") )
stat.tip = stat_node.getAttribute("tip") stat.tip = stat_node.getAttribute("tip")
stat.click = stat_node.getAttribute("click") stat.click = stat_node.getAttribute("click")
stat.popup = stat_node.getAttribute("popup") stat.popup = stat_node.getAttribute("popup")
stat.hudprefix = stat_node.getAttribute("hudprefix") stat.hudprefix = stat_node.getAttribute("hudprefix")
stat.hudsuffix = stat_node.getAttribute("hudsuffix") stat.hudsuffix = stat_node.getAttribute("hudsuffix")
stat.hudcolor = stat_node.getAttribute("hudcolor") stat.hudcolor = stat_node.getAttribute("hudcolor")
@ -208,14 +222,13 @@ class Game:
class Database: class Database:
def __init__(self, node): def __init__(self, node):
self.db_name = node.getAttribute("db_name") self.db_name = node.getAttribute("db_name")
self.db_server = node.getAttribute("db_server") self.db_server = node.getAttribute("db_server").lower()
self.db_ip = node.getAttribute("db_ip") self.db_ip = node.getAttribute("db_ip")
self.db_user = node.getAttribute("db_user") self.db_user = node.getAttribute("db_user")
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") self.db_selected = string_to_bool(node.getAttribute("default"), 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'" \ log.debug("Database db_name:'%(name)s' db_server:'%(server)s' db_ip:'%(ip)s' db_user:'%(user)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} ) % { 'name':self.db_name, 'server':self.db_server, 'ip':self.db_ip, 'user':self.db_user, 'sel':self.db_selected} )
def __str__(self): def __str__(self):
temp = 'Database = ' + self.db_name + '\n' temp = 'Database = ' + self.db_name + '\n'
@ -251,7 +264,7 @@ class Aux_window:
class HHC: class HHC:
def __init__(self, node): def __init__(self, node):
self.site = node.getAttribute("site") self.site = node.getAttribute("site")
self.converter = node.getAttribute("converter") self.converter = node.getAttribute("converter")
def __str__(self): def __str__(self):
@ -261,7 +274,7 @@ class HHC:
class Popup: class Popup:
def __init__(self, node): def __init__(self, node):
self.name = node.getAttribute("pu_name") self.name = node.getAttribute("pu_name")
self.pu_stats = [] self.pu_stats = []
for stat_node in node.getElementsByTagName('pu_stat'): for stat_node in node.getElementsByTagName('pu_stat'):
self.pu_stats.append(stat_node.getAttribute("pu_stat_name")) self.pu_stats.append(stat_node.getAttribute("pu_stat_name"))
@ -274,32 +287,32 @@ class Popup:
class Import: class Import:
def __init__(self, node): def __init__(self, node):
self.node = 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")
self.saveActions = fix_tf(node.getAttribute("saveActions"), True) self.saveActions = string_to_bool(node.getAttribute("saveActions"), default=True)
self.fastStoreHudCache = fix_tf(node.getAttribute("fastStoreHudCache"), False) self.fastStoreHudCache = string_to_bool(node.getAttribute("fastStoreHudCache"), default=False)
def __str__(self): def __str__(self):
return " interval = %s\n callFpdbHud = %s\n hhArchiveBase = %s\n saveActions = %s\n fastStoreHudCache = %s\n" \ return " interval = %s\n callFpdbHud = %s\n hhArchiveBase = %s\n saveActions = %s\n fastStoreHudCache = %s\n" \
% (self.interval, self.callFpdbHud, self.hhArchiveBase, self.saveActions, self.fastStoreHudCache) % (self.interval, self.callFpdbHud, self.hhArchiveBase, self.saveActions, self.fastStoreHudCache)
class HudUI: class HudUI:
def __init__(self, node): def __init__(self, node):
self.node = node self.node = node
self.label = node.getAttribute('label') self.label = node.getAttribute('label')
# #
self.aggregate_ring = fix_tf(node.getAttribute('aggregate_ring_game_stats')) self.aggregate_ring = string_to_bool(node.getAttribute('aggregate_ring_game_stats'))
self.aggregate_tour = fix_tf(node.getAttribute('aggregate_tourney_stats')) self.aggregate_tour = string_to_bool(node.getAttribute('aggregate_tourney_stats'))
self.hud_style = node.getAttribute('stat_aggregation_range') self.hud_style = node.getAttribute('stat_aggregation_range')
self.hud_days = node.getAttribute('aggregation_days') self.hud_days = node.getAttribute('aggregation_days')
self.agg_bb_mult = node.getAttribute('aggregation_level_multiplier') self.agg_bb_mult = node.getAttribute('aggregation_level_multiplier')
# #
self.h_aggregate_ring = fix_tf(node.getAttribute('aggregate_hero_ring_game_stats')) self.h_aggregate_ring = string_to_bool(node.getAttribute('aggregate_hero_ring_game_stats'))
self.h_aggregate_tour = fix_tf(node.getAttribute('aggregate_hero_tourney_stats')) self.h_aggregate_tour = string_to_bool(node.getAttribute('aggregate_hero_tourney_stats'))
self.h_hud_style = node.getAttribute('hero_stat_aggregation_range') self.h_hud_style = node.getAttribute('hero_stat_aggregation_range')
self.h_hud_days = node.getAttribute('hero_aggregation_days') self.h_hud_days = node.getAttribute('hero_aggregation_days')
self.h_agg_bb_mult = node.getAttribute('hero_aggregation_level_multiplier') self.h_agg_bb_mult = node.getAttribute('hero_aggregation_level_multiplier')
def __str__(self): def __str__(self):
@ -308,9 +321,9 @@ class HudUI:
class Tv: class Tv:
def __init__(self, node): def __init__(self, node):
self.combinedStealFold = node.getAttribute("combinedStealFold") self.combinedStealFold = string_to_bool(node.getAttribute("combinedStealFold"), default=True)
self.combined2B3B = node.getAttribute("combined2B3B") self.combined2B3B = string_to_bool(node.getAttribute("combined2B3B"), default=True)
self.combinedPostflop = node.getAttribute("combinedPostflop") self.combinedPostflop = string_to_bool(node.getAttribute("combinedPostflop"), default=True)
def __str__(self): def __str__(self):
return (" combinedStealFold = %s\n combined2B3B = %s\n combinedPostflop = %s\n" % return (" combinedStealFold = %s\n combined2B3B = %s\n combinedPostflop = %s\n" %
@ -323,22 +336,20 @@ class Config:
# 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.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 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):
print "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)) sys.stderr.write("Configuration file %s not found. Using defaults." % (file))
file = None file = None
if file == None: # configuration file path not passed or invalid if file is None: # configuration file path not passed or invalid
file = self.find_config() #Look for a config file in the normal places file = self.find_config() #Look for a config file in the normal places
if file == None: # no config file in the normal places if file is None: # no config file in the normal places
file = self.find_example_config() #Look for an example file to edit file = self.find_example_config() #Look for an example file to edit
if file != None:
pass
if file == None: # that didn't work either, just die if file is None: # that didn't work either, just die
print "No HUD_config_xml found after looking in current directory and "+self.default_config_path+"\nExiting" print "No HUD_config_xml found after looking in current directory and "+self.default_config_path+"\nExiting"
sys.stderr.write("No HUD_config_xml found after looking in current directory and "+self.default_config_path+"\nExiting") sys.stderr.write("No HUD_config_xml found after looking in current directory and "+self.default_config_path+"\nExiting")
print "press enter to continue" print "press enter to continue"
@ -367,10 +378,13 @@ class Config:
self.file = file self.file = file
self.supported_sites = {} self.supported_sites = {}
self.supported_games = {} self.supported_games = {}
self.supported_databases = {} self.supported_databases = {} # databaseName --> Database instance
self.aux_windows = {} self.aux_windows = {}
self.hhcs = {} self.hhcs = {}
self.popup_windows = {} self.popup_windows = {}
self.db_selected = None # database the user would like to use
self.tv = None
# s_sites = doc.getElementsByTagName("supported_sites") # s_sites = doc.getElementsByTagName("supported_sites")
for site_node in doc.getElementsByTagName("site"): for site_node in doc.getElementsByTagName("site"):
@ -382,36 +396,33 @@ class Config:
game = Game(node = game_node) game = Game(node = game_node)
self.supported_games[game.game_name] = game self.supported_games[game.game_name] = game
# parse databases defined by user in the <supported_databases> section
# the user may select the actual database to use via commandline or by setting the selected="bool"
# attribute of the tag. if no database is explicitely selected, we use the first one we come across
# s_dbs = doc.getElementsByTagName("supported_databases") # s_dbs = doc.getElementsByTagName("supported_databases")
# select database from those defined in config by: #TODO: do we want to take all <database> tags or all <database> tags contained in <supported_databases>
# 1) command line option # ..this may break stuff for some users. so leave it unchanged for now untill there is a decission
# 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:
except: raise ValueError("Database names must be unique")
raise FpdbError("Unable to create database object") if self.db_selected is None or db.db_selected:
else: self.db_selected = db.db_name
if db.db_name in self.supported_databases: self.supported_databases[db.db_name] = db
raise FpdbError("Database names must be unique") #TODO: if the user may passes '' (empty string) as database name via command line, his choice is ignored
# If there is only one Database node, or none are marked # ..when we parse the xml we allow for ''. there has to be a decission if to allow '' or not
# default, use first
if not self.supported_databases:
self.db_selected = db.db_name
self.supported_databases[db.db_name] = db
if db.db_selected:
self.db_selected = db.db_name
if dbname and dbname in self.supported_databases: if dbname and dbname in self.supported_databases:
self.db_selected = dbname self.db_selected = dbname
#NOTE: fpdb can not handle the case when no database is defined in xml, so we throw an exception for now
if self.db_selected is None:
raise ValueError('There must be at least one database defined')
# 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"):
aw = Aux_window(node = aw_node) aw = Aux_window(node = aw_node)
self.aux_windows[aw.name] = aw self.aux_windows[aw.name] = aw
# s_dbs = doc.getElementsByTagName("mucked_windows") # s_dbs = doc.getElementsByTagName("mucked_windows")
for hhc_node in doc.getElementsByTagName("hhc"): for hhc_node in doc.getElementsByTagName("hhc"):
hhc = HHC(node = hhc_node) hhc = HHC(node = hhc_node)
self.hhcs[hhc.site] = hhc self.hhcs[hhc.site] = hhc
@ -430,19 +441,18 @@ class Config:
self.ui = hui self.ui = hui
for tv_node in doc.getElementsByTagName("tv"): for tv_node in doc.getElementsByTagName("tv"):
tv = Tv(node = tv_node) self.tv = Tv(node = tv_node)
self.tv = tv
db = self.get_db_parameters() db = self.get_db_parameters()
if db['db-password'] == 'YOUR MYSQL PASSWORD': if db['db-password'] == 'YOUR MYSQL PASSWORD':
df_file = self.find_default_conf() df_file = self.find_default_conf()
if df_file == None: # this is bad if df_file is None: # this is bad
pass pass
else: else:
df_parms = self.read_default_conf(df_file) df_parms = self.read_default_conf(df_file)
self.set_db_parameters(db_name = 'fpdb', db_ip = df_parms['db-host'], self.set_db_parameters(db_name = 'fpdb', db_ip = df_parms['db-host'],
db_user = df_parms['db-user'], db_user = df_parms['db-user'],
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"))
print "" print ""
@ -453,7 +463,7 @@ class Config:
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."""
if os.path.exists('HUD_config.xml'): # there is a HUD_config in the cwd if os.path.exists('HUD_config.xml'): # there is a HUD_config in the cwd
file = 'HUD_config.xml' # so we use it file = 'HUD_config.xml' # so we use it
else: # no HUD_config in the cwd, look where it should be in the first place else: # no HUD_config in the cwd, look where it should be in the first place
config_path = os.path.join(self.default_config_path, 'HUD_config.xml') config_path = os.path.join(self.default_config_path, 'HUD_config.xml')
if os.path.exists(config_path): if os.path.exists(config_path):
@ -496,7 +506,7 @@ class Config:
def find_example_config(self): def find_example_config(self):
if os.path.exists('HUD_config.xml.example'): # there is a HUD_config in the cwd if os.path.exists('HUD_config.xml.example'): # there is a HUD_config in the cwd
file = 'HUD_config.xml' # so we use it file = 'HUD_config.xml' # so we use it
try: try:
shutil.copyfile(file+'.example', file) shutil.copyfile(file+'.example', file)
except: except:
@ -527,7 +537,7 @@ class Config:
def get_layout_node(self, site_node, layout): def get_layout_node(self, site_node, layout):
for layout_node in site_node.getElementsByTagName("layout"): for layout_node in site_node.getElementsByTagName("layout"):
if layout_node.getAttribute("max") == None: if layout_node.getAttribute("max") is None:
return None return None
if int( layout_node.getAttribute("max") ) == int( layout ): if int( layout_node.getAttribute("max") ) == int( layout ):
return layout_node return layout_node
@ -543,19 +553,21 @@ class Config:
return location_node return location_node
def save(self, file = None): def save(self, file = None):
if file != None: if file is not None:
with open(file, 'w') as f: with open(file, 'w') as f:
self.doc.writexml(f) self.doc.writexml(f)
else: else:
shutil.move(self.file, self.file+".backup") shutil.move(self.file, self.file+".backup")
with open(self.file, 'w') as f: with open(file, 'w') as f:
self.doc.writexml(f) self.doc.writexml(f)
def edit_layout(self, site_name, max, width = None, height = None, def edit_layout(self, site_name, max, width = None, height = None,
fav_seat = None, locations = None): fav_seat = None, locations = None):
site_node = self.get_site_node(site_name) site_node = self.get_site_node(site_name)
layout_node = self.get_layout_node(site_node, max) layout_node = self.get_layout_node(site_node, max)
if layout_node == None: return # TODO: how do we support inserting new layouts?
if layout_node is None:
return
for i in range(1, max + 1): for i in range(1, max + 1):
location_node = self.get_location_node(layout_node, i) location_node = self.get_location_node(layout_node, i)
location_node.setAttribute("x", str( locations[i-1][0] )) location_node.setAttribute("x", str( locations[i-1][0] ))
@ -565,7 +577,7 @@ class Config:
def edit_aux_layout(self, aux_name, max, width = None, height = None, locations = None): def edit_aux_layout(self, aux_name, max, width = None, height = None, locations = None):
aux_node = self.get_aux_node(aux_name) aux_node = self.get_aux_node(aux_name)
layout_node = self.get_layout_node(aux_node, max) layout_node = self.get_layout_node(aux_node, max)
if layout_node == None: if layout_node is None:
print "aux node not found" print "aux node not found"
return return
print "editing locations =", locations print "editing locations =", locations
@ -578,6 +590,13 @@ class Config:
else: else:
self.aux_windows[aux_name].layout[max].location[i] = ( locations[i][0], locations[i][1] ) self.aux_windows[aux_name].layout[max].location[i] = ( locations[i][0], locations[i][1] )
#NOTE: we got a nice Database class, so why map it again here?
# user input validation should be done when initializing the Database class. this allows to give appropriate feddback when something goes wrong
# try ..except is evil here. it swallows all kinds of errors. dont do this
# naming database types 2, 3, 4 on the fly is no good idea. i see this all over the code. better use some globally defined consts (see DATABASE_TYPE_*)
# i would like to drop this method entirely and replace it by get_selected_database() or better get_active_database(), returning one of our Database instances
# thus we can drop self.db_selected (holding database name) entirely and replace it with self._active_database = Database, avoiding to define the same
# thing multiple times
def get_db_parameters(self): def get_db_parameters(self):
db = {} db = {}
name = self.db_selected name = self.db_selected
@ -597,33 +616,31 @@ class Config:
try: db['db-server'] = self.supported_databases[name].db_server try: db['db-server'] = self.supported_databases[name].db_server
except: pass except: pass
try: db['db-type'] = self.supported_databases[name].db_type if self.supported_databases[name].db_server== DATABASE_TYPE_MYSQL:
except: pass
if string.lower(self.supported_databases[name].db_server) == 'mysql':
db['db-backend'] = 2 db['db-backend'] = 2
elif string.lower(self.supported_databases[name].db_server) == 'postgresql': elif self.supported_databases[name].db_server== DATABASE_TYPE_POSTGRESQL:
db['db-backend'] = 3 db['db-backend'] = 3
elif string.lower(self.supported_databases[name].db_server) == 'sqlite': elif self.supported_databases[name].db_server== DATABASE_TYPE_SQLITE:
db['db-backend'] = 4 db['db-backend'] = 4
else: db['db-backend'] = None # this is big trouble else:
raise ValueError('Unsupported database backend: %s' % self.supported_databases[name].db_server)
return db return db
def set_db_parameters(self, db_name = 'fpdb', db_ip = None, db_user = None, def set_db_parameters(self, db_name = 'fpdb', db_ip = None, db_user = None,
db_pass = None, db_server = None, db_type = None): db_pass = None, db_server = None):
db_node = self.get_db_node(db_name) db_node = self.get_db_node(db_name)
if db_node != None: if db_node != None:
if db_ip != None: db_node.setAttribute("db_ip", db_ip) if db_ip is not None: db_node.setAttribute("db_ip", db_ip)
if db_user != None: db_node.setAttribute("db_user", db_user) if db_user is not None: db_node.setAttribute("db_user", db_user)
if db_pass != None: db_node.setAttribute("db_pass", db_pass) if db_pass is not None: db_node.setAttribute("db_pass", db_pass)
if db_server != None: db_node.setAttribute("db_server", db_server) if db_server is not None: db_node.setAttribute("db_server", db_server)
if db_type != None: db_node.setAttribute("db_type", db_type) if db_type is not None: db_node.setAttribute("db_type", db_type)
if self.supported_databases.has_key(db_name): if self.supported_databases.has_key(db_name):
if db_ip != None: self.supported_databases[db_name].dp_ip = db_ip if db_ip is not None: self.supported_databases[db_name].dp_ip = db_ip
if db_user != None: self.supported_databases[db_name].dp_user = db_user if db_user is not None: self.supported_databases[db_name].dp_user = db_user
if db_pass != None: self.supported_databases[db_name].dp_pass = db_pass if db_pass is not None: self.supported_databases[db_name].dp_pass = db_pass
if db_server != None: self.supported_databases[db_name].dp_server = db_server if db_server is not None: self.supported_databases[db_name].dp_server = db_server
if db_type != None: self.supported_databases[db_name].dp_type = db_type if db_type is not None: self.supported_databases[db_name].dp_type = db_type
return return
def getDefaultSite(self): def getDefaultSite(self):
@ -634,16 +651,13 @@ class Config:
return None return None
def get_tv_parameters(self): def get_tv_parameters(self):
tv = {} if self.tv is not None:
try: tv['combinedStealFold'] = self.tv.combinedStealFold return {
except: tv['combinedStealFold'] = True 'combinedStealFold': self.tv.combinedStealFold,
'combined2B3B': self.tv.combined2B3B,
try: tv['combined2B3B'] = self.tv.combined2B3B 'combinedPostflop': self.tv.combinedPostflop
except: tv['combined2B3B'] = True }
return {}
try: tv['combinedPostflop'] = self.tv.combinedPostflop
except: tv['combinedPostflop'] = True
return tv
# Allow to change the menu appearance # Allow to change the menu appearance
def get_hud_ui_parameters(self): def get_hud_ui_parameters(self):
@ -652,7 +666,7 @@ class Config:
default_text = 'FPDB Menu - Right click\nLeft-Drag to Move' default_text = 'FPDB Menu - Right click\nLeft-Drag to Move'
try: try:
hui['label'] = self.ui.label hui['label'] = self.ui.label
if self.ui.label == '': # Empty menu label is a big no-no if self.ui.label == '': # Empty menu label is a big no-no
hui['label'] = default_text hui['label'] = default_text
except: except:
hui['label'] = default_text hui['label'] = default_text
@ -666,11 +680,11 @@ class Config:
try: hui['hud_style'] = self.ui.hud_style try: hui['hud_style'] = self.ui.hud_style
except: hui['hud_style'] = 'A' except: hui['hud_style'] = 'A'
try: hui['hud_days'] = int(self.ui.hud_days) try: hui['hud_days'] = int(self.ui.hud_days)
except: hui['hud_days'] = 90 except: hui['hud_days'] = 90
try: hui['agg_bb_mult'] = self.ui.agg_bb_mult try: hui['agg_bb_mult'] = self.ui.agg_bb_mult
except: hui['agg_bb_mult'] = 1 except: hui['agg_bb_mult'] = 1
# Hero specific # Hero specific
@ -680,11 +694,11 @@ class Config:
try: hui['h_aggregate_tour'] = self.ui.h_aggregate_tour try: hui['h_aggregate_tour'] = self.ui.h_aggregate_tour
except: hui['h_aggregate_tour'] = True except: hui['h_aggregate_tour'] = True
try: hui['h_hud_style'] = self.ui.h_hud_style try: hui['h_hud_style'] = self.ui.h_hud_style
except: hui['h_hud_style'] = 'S' except: hui['h_hud_style'] = 'S'
try: hui['h_hud_days'] = int(self.ui.h_hud_days) try: hui['h_hud_days'] = int(self.ui.h_hud_days)
except: hui['h_hud_days'] = 30 except: hui['h_hud_days'] = 30
try: hui['h_agg_bb_mult'] = self.ui.h_agg_bb_mult try: hui['h_agg_bb_mult'] = self.ui.h_agg_bb_mult
except: hui['h_agg_bb_mult'] = 1 except: hui['h_agg_bb_mult'] = 1
@ -694,19 +708,19 @@ class Config:
def get_import_parameters(self): def get_import_parameters(self):
imp = {} imp = {}
try: imp['callFpdbHud'] = self.imp.callFpdbHud try: imp['callFpdbHud'] = self.imp.callFpdbHud
except: imp['callFpdbHud'] = True except: imp['callFpdbHud'] = True
try: imp['interval'] = self.imp.interval try: imp['interval'] = self.imp.interval
except: imp['interval'] = 10 except: imp['interval'] = 10
try: imp['hhArchiveBase'] = self.imp.hhArchiveBase try: imp['hhArchiveBase'] = self.imp.hhArchiveBase
except: imp['hhArchiveBase'] = "~/.fpdb/HandHistories/" except: imp['hhArchiveBase'] = "~/.fpdb/HandHistories/"
try: imp['saveActions'] = self.imp.saveActions try: imp['saveActions'] = self.imp.saveActions
except: imp['saveActions'] = True except: imp['saveActions'] = True
try: imp['fastStoreHudCache'] = self.imp.fastStoreHudCache try: imp['fastStoreHudCache'] = self.imp.fastStoreHudCache
except: imp['fastStoreHudCache'] = True except: imp['fastStoreHudCache'] = True
return imp return imp
@ -741,30 +755,28 @@ class Config:
colors['hudfgcolor'] = self.supported_sites[site].hudfgcolor colors['hudfgcolor'] = self.supported_sites[site].hudfgcolor
return colors return colors
def get_default_font(self, site = 'PokerStars'): def get_default_font(self, site='PokerStars'):
(font, font_size) = ("Sans", "8") font = "Sans"
if site not in self.supported_sites: font_size = "8"
return ("Sans", "8") site = self.supported_sites.get(site, None)
if self.supported_sites[site].font == "": if site is not None:
font = "Sans" if site.font:
else: font = site.font
font = self.supported_sites[site].font if site.font_size:
font_size = site.font_size
return font, font_size
if self.supported_sites[site].font_size == "": def get_locations(self, site_name="PokerStars", max=8):
font_size = "8" site = self.supported_sites.get(site_name, None)
else: if site is not None:
font_size = self.supported_sites[site].font_size location = site.layout.get(max, None)
return (font, font_size) if location is not None:
return location.location
def get_locations(self, site = "PokerStars", max = "8"): return (
( 0, 0), (684, 61), (689, 239), (692, 346),
try: (586, 393), (421, 440), (267, 440), ( 0, 361),
locations = self.supported_sites[site].layout[max].location ( 0, 280), (121, 280), ( 46, 30)
except: )
locations = ( ( 0, 0), (684, 61), (689, 239), (692, 346),
(586, 393), (421, 440), (267, 440), ( 0, 361),
( 0, 280), (121, 280), ( 46, 30) )
return locations
def get_aux_locations(self, aux = "mucked", max = "9"): def get_aux_locations(self, aux = "mucked", max = "9"):
@ -772,38 +784,36 @@ class Config:
locations = self.aux_windows[aux].layout[max].location locations = self.aux_windows[aux].layout[max].location
except: except:
locations = ( ( 0, 0), (684, 61), (689, 239), (692, 346), locations = ( ( 0, 0), (684, 61), (689, 239), (692, 346),
(586, 393), (421, 440), (267, 440), ( 0, 361), (586, 393), (421, 440), (267, 440), ( 0, 361),
( 0, 280), (121, 280), ( 46, 30) ) ( 0, 280), (121, 280), ( 46, 30) )
return locations return locations
def get_supported_sites(self, all = False): def get_supported_sites(self, all=False):
"""Returns the list of supported sites.""" """Returns the list of supported sites."""
the_sites = [] if all:
for site in self.supported_sites.keys(): return self.supported_sites.keys()
params = self.get_site_parameters(site) else:
if all or params['enabled']: return [site_name for (site_name, site) in self.supported_sites.items() if site.enabled]
the_sites.append(site)
return the_sites
def get_site_parameters(self, site): def get_site_parameters(self, site):
"""Returns a dict of the site parameters for the specified site""" """Returns a dict of the site parameters for the specified site"""
parms = {} parms = {}
parms["converter"] = self.supported_sites[site].converter parms["converter"] = self.supported_sites[site].converter
parms["decoder"] = self.supported_sites[site].decoder parms["decoder"] = self.supported_sites[site].decoder
parms["hudbgcolor"] = self.supported_sites[site].hudbgcolor parms["hudbgcolor"] = self.supported_sites[site].hudbgcolor
parms["hudfgcolor"] = self.supported_sites[site].hudfgcolor parms["hudfgcolor"] = self.supported_sites[site].hudfgcolor
parms["hudopacity"] = self.supported_sites[site].hudopacity parms["hudopacity"] = self.supported_sites[site].hudopacity
parms["screen_name"] = self.supported_sites[site].screen_name parms["screen_name"] = self.supported_sites[site].screen_name
parms["site_path"] = self.supported_sites[site].site_path parms["site_path"] = self.supported_sites[site].site_path
parms["table_finder"] = self.supported_sites[site].table_finder parms["table_finder"] = self.supported_sites[site].table_finder
parms["HH_path"] = self.supported_sites[site].HH_path parms["HH_path"] = self.supported_sites[site].HH_path
parms["site_name"] = self.supported_sites[site].site_name parms["site_name"] = self.supported_sites[site].site_name
parms["aux_window"] = self.supported_sites[site].aux_window parms["aux_window"] = self.supported_sites[site].aux_window
parms["font"] = self.supported_sites[site].font parms["font"] = self.supported_sites[site].font
parms["font_size"] = self.supported_sites[site].font_size parms["font_size"] = self.supported_sites[site].font_size
parms["enabled"] = self.supported_sites[site].enabled parms["enabled"] = self.supported_sites[site].enabled
parms["xpad"] = self.supported_sites[site].xpad parms["xpad"] = self.supported_sites[site].xpad
parms["ypad"] = self.supported_sites[site].ypad parms["ypad"] = self.supported_sites[site].ypad
return parms return parms
def set_site_parameters(self, site_name, converter = None, decoder = None, def set_site_parameters(self, site_name, converter = None, decoder = None,
@ -814,27 +824,24 @@ class Config:
font = None, font_size = None): font = None, font_size = None):
"""Sets the specified site parameters for the specified site.""" """Sets the specified site parameters for the specified site."""
site_node = self.get_site_node(site_name) site_node = self.get_site_node(site_name)
if db_node != None: if db_node is not None:
if converter != None: site_node.setAttribute("converter", converter) if converter is not None: site_node.setAttribute("converter", converter)
if decoder != None: site_node.setAttribute("decoder", decoder) if decoder is not None: site_node.setAttribute("decoder", decoder)
if hudbgcolor != None: site_node.setAttribute("hudbgcolor", hudbgcolor) if hudbgcolor is not None: site_node.setAttribute("hudbgcolor", hudbgcolor)
if hudfgcolor != None: site_node.setAttribute("hudfgcolor", hudfgcolor) if hudfgcolor is not None: site_node.setAttribute("hudfgcolor", hudfgcolor)
if hudopacity != None: site_node.setAttribute("hudopacity", hudopacity) if hudopacity is not None: site_node.setAttribute("hudopacity", hudopacity)
if screen_name != None: site_node.setAttribute("screen_name", screen_name) if screen_name is not None: site_node.setAttribute("screen_name", screen_name)
if site_path != None: site_node.setAttribute("site_path", site_path) if site_path is not None: site_node.setAttribute("site_path", site_path)
if table_finder != None: site_node.setAttribute("table_finder", table_finder) if table_finder is not None: site_node.setAttribute("table_finder", table_finder)
if HH_path != None: site_node.setAttribute("HH_path", HH_path) if HH_path is not None: site_node.setAttribute("HH_path", HH_path)
if enabled != None: site_node.setAttribute("enabled", enabled) if enabled is not None: site_node.setAttribute("enabled", enabled)
if font != None: site_node.setAttribute("font", font) if font is not None: site_node.setAttribute("font", font)
if font_size != None: site_node.setAttribute("font_size", font_size) if font_size is not None: site_node.setAttribute("font_size", font_size)
return return
def get_aux_windows(self): def get_aux_windows(self):
"""Gets the list of mucked window formats in the configuration.""" """Gets the list of mucked window formats in the configuration."""
mw = [] return self.aux_windows.keys()
for w in self.aux_windows.keys():
mw.append(w)
return mw
def get_aux_parameters(self, name): def get_aux_parameters(self, name):
"""Gets a dict of mucked window parameters from the named mw.""" """Gets a dict of mucked window parameters from the named mw."""
@ -854,11 +861,11 @@ class Config:
param = {} param = {}
if self.supported_games.has_key(name): if self.supported_games.has_key(name):
param['game_name'] = self.supported_games[name].game_name param['game_name'] = self.supported_games[name].game_name
param['rows'] = self.supported_games[name].rows param['rows'] = self.supported_games[name].rows
param['cols'] = self.supported_games[name].cols param['cols'] = self.supported_games[name].cols
param['xpad'] = self.supported_games[name].xpad param['xpad'] = self.supported_games[name].xpad
param['ypad'] = self.supported_games[name].ypad param['ypad'] = self.supported_games[name].ypad
param['aux'] = self.supported_games[name].aux param['aux'] = self.supported_games[name].aux
return param return param
def get_supported_games(self): def get_supported_games(self):
@ -918,8 +925,8 @@ if __name__== "__main__":
c.edit_layout("PokerStars", 6, locations=( (1, 1), (2, 2), (3, 3), (4, 4), (5, 5), (6, 6) )) c.edit_layout("PokerStars", 6, locations=( (1, 1), (2, 2), (3, 3), (4, 4), (5, 5), (6, 6) ))
c.save(file="testout.xml") c.save(file="testout.xml")
print "db = ", c.get_db_parameters() print "db = ", c.get_db_parameters()
# print "tv = ", c.get_tv_parameters() # print "tv = ", c.get_tv_parameters()
# print "imp = ", c.get_import_parameters() # print "imp = ", c.get_import_parameters()
print "paths = ", c.get_default_paths("PokerStars") print "paths = ", c.get_default_paths("PokerStars")
print "colors = ", c.get_default_colors("PokerStars") print "colors = ", c.get_default_colors("PokerStars")

View File

@ -205,7 +205,7 @@ class Database:
# 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 is None: if sql is None:
self.sql = SQL.Sql(type = self.type, db_server = self.db_server) self.sql = SQL.Sql(db_server = self.db_server)
else: else:
self.sql = sql self.sql = sql
@ -249,7 +249,6 @@ class Database:
db_params = c.get_db_parameters() db_params = c.get_db_parameters()
self.import_options = c.get_import_parameters() self.import_options = c.get_import_parameters()
self.type = db_params['db-type']
self.backend = db_params['db-backend'] self.backend = db_params['db-backend']
self.db_server = db_params['db-server'] self.db_server = db_params['db-server']
self.database = db_params['db-databaseName'] self.database = db_params['db-databaseName']
@ -292,6 +291,21 @@ class Database:
row = c.fetchone() row = c.fetchone()
return row return row
def get_table_info(self, hand_id):
c = self.connection.cursor()
c.execute(self.sql.query['get_table_name'], (hand_id, ))
row = c.fetchone()
l = list(row)
if row[3] == "ring": # cash game
l.append(None)
l.append(None)
return l
else: # tournament
tour_no, tab_no = re.split(" ", row[0])
l.append(tour_no)
l.append(tab_no)
return l
def get_last_hand(self): def get_last_hand(self):
c = self.connection.cursor() c = self.connection.cursor()
c.execute(self.sql.query['get_last_hand']) c.execute(self.sql.query['get_last_hand'])
@ -353,7 +367,7 @@ class Database:
# else: # else:
# cards += ranks[d['card' + str(i) + 'Value']] + d['card' +str(i) + 'Suit'] # cards += ranks[d['card' + str(i) + 'Value']] + d['card' +str(i) + 'Suit']
cv = "card%dvalue" % i cv = "card%dvalue" % i
if cv not in d or d[cv] == None: if cv not in d or d[cv] is None:
break break
elif d[cv] == 0: elif d[cv] == 0:
cards += "xx" cards += "xx"
@ -395,7 +409,7 @@ class Database:
row = c.fetchone() row = c.fetchone()
except: # TODO: what error is a database error?! except: # TODO: what error is a database error?!
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 "*** Database Error: " + err[2] + "(" + str(err[1]) + "): " + str(sys.exc_info()[1])
else: else:
if row and row[0]: if row and row[0]:
self.hand_1day_ago = int(row[0]) self.hand_1day_ago = int(row[0])
@ -421,10 +435,10 @@ class Database:
if row and row[0]: if row and row[0]:
self.date_nhands_ago[str(playerid)] = row[0] self.date_nhands_ago[str(playerid)] = row[0]
c.close() c.close()
print "date n hands ago = " + self.date_nhands_ago[str(playerid)] + "(playerid "+str(playerid)+")" print "Database: date n hands ago = " + self.date_nhands_ago[str(playerid)] + "(playerid "+str(playerid)+")"
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 "*** Database Error: "+err[2]+"("+str(err[1])+"): "+str(sys.exc_info()[1])
def get_stats_from_hand( self, hand, type # type is "ring" or "tour" def get_stats_from_hand( self, hand, type # type is "ring" or "tour"
, hud_params = {'aggregate_tour':False, 'aggregate_ring':False, 'hud_style':'A', 'hud_days':30, 'agg_bb_mult':100 , hud_params = {'aggregate_tour':False, 'aggregate_ring':False, 'hud_style':'A', 'hud_days':30, 'agg_bb_mult':100
@ -551,7 +565,7 @@ class Database:
def get_player_names(self, config, site_id=None, like_player_name="%"): def get_player_names(self, config, site_id=None, like_player_name="%"):
"""Fetch player names from players. Use site_id and like_player_name if provided""" """Fetch player names from players. Use site_id and like_player_name if provided"""
if site_id == None: if site_id is None:
site_id = -1 site_id = -1
c = self.get_cursor() c = self.get_cursor()
c.execute(self.sql.query['get_player_names'], (like_player_name, site_id, site_id)) c.execute(self.sql.query['get_player_names'], (like_player_name, site_id, site_id))
@ -657,7 +671,7 @@ class Database:
except: except:
ret = -1 ret = -1
err = traceback.extract_tb(sys.exc_info()[2]) err = traceback.extract_tb(sys.exc_info()[2])
print "***get_last_insert_id error: " + str(sys.exc_info()[1]) print "*** Database get_last_insert_id error: " + str(sys.exc_info()[1])
print "\n".join( [e[0]+':'+str(e[1])+" "+e[2] for e in err] ) print "\n".join( [e[0]+':'+str(e[1])+" "+e[2] for e in err] )
raise raise
return ret return ret
@ -761,14 +775,18 @@ class Database:
hands_id = self.storeHands( self.backend, siteHandNo, gametypeId hands_id = self.storeHands( self.backend, siteHandNo, gametypeId
, handStartTime, names, tableName, maxSeats , handStartTime, names, tableName, maxSeats
, hudImportData, board_values, board_suits ) , hudImportData, (None, None, None, None, None), (None, None, None, None, None) )
# changed board_values and board_suits to arrays of None, just like the
# cash game version of this function does - i don't believe this to be
# the correct thing to do (tell me if i'm wrong) but it should keep the
# importer from crashing
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, tourneyTypeId) , 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, handStartTime, playerIds, hudImportData)
return hands_id return hands_id
#end def tourney_stud #end def tourney_stud
@ -1179,7 +1197,7 @@ class Database:
if p_id: if p_id:
self.hero_ids[site_id] = int(p_id) self.hero_ids[site_id] = int(p_id)
if start == None: if start is None:
start = self.hero_hudstart_def start = self.hero_hudstart_def
if self.hero_ids == {}: if self.hero_ids == {}:
where = "" where = ""
@ -1375,6 +1393,12 @@ class Database:
pids[p], pids[p],
pdata[p]['startCash'], pdata[p]['startCash'],
pdata[p]['seatNo'], pdata[p]['seatNo'],
pdata[p]['winnings'],
pdata[p]['street0VPI'],
pdata[p]['street1Seen'],
pdata[p]['street2Seen'],
pdata[p]['street3Seen'],
pdata[p]['street4Seen'],
pdata[p]['street0Aggr'], pdata[p]['street0Aggr'],
pdata[p]['street1Aggr'], pdata[p]['street1Aggr'],
pdata[p]['street2Aggr'], pdata[p]['street2Aggr'],
@ -1387,6 +1411,12 @@ class Database:
playerId, playerId,
startCash, startCash,
seatNo, seatNo,
winnings,
street0VPI,
street1Seen,
street2Seen,
street3Seen,
street4Seen,
street0Aggr, street0Aggr,
street1Aggr, street1Aggr,
street2Aggr, street2Aggr,
@ -1395,7 +1425,8 @@ class Database:
) )
VALUES ( VALUES (
%s, %s, %s, %s, %s, %s, %s, %s, %s, %s,
%s, %s, %s, %s %s, %s, %s, %s, %s,
%s, %s, %s, %s, %s
)""" )"""
# position, # position,
@ -1405,16 +1436,10 @@ class Database:
# card3, # card3,
# card4, # card4,
# startCards, # startCards,
# winnings,
# rake, # rake,
# totalProfit, # totalProfit,
# street0VPI,
# street0_3BChance, # street0_3BChance,
# street0_3BDone, # street0_3BDone,
# street1Seen,
# street2Seen,
# street3Seen,
# street4Seen,
# sawShowdown, # sawShowdown,
# otherRaisedStreet1, # otherRaisedStreet1,
# otherRaisedStreet2, # otherRaisedStreet2,
@ -1946,7 +1971,7 @@ class Database:
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, tourneyTypeId): 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
return # TODO: stubbed out until someone updates it for current database structuring
try: try:
result=[] result=[]
for i in xrange(len(player_ids)): for i in xrange(len(player_ids)):

View File

@ -1,28 +1,85 @@
"""Database manager
@todo: (gtk) how to validate user input in gtk.Dialog? as soon as the user clicks ok the dialog is dead. we use a while loop as workaround. not nice
@todo: (fpdb) we need the application name 'fpdb' from somewhere to put it in dialog titles
@todo: (fpdb) config object should be initialized globally and accessible from all modules via Configuration.py
@todo: (all dialogs) save/restore size and pos
@todo: (WidgetDatabaseManager) give database status meaningful colors
@todo: (WidgetDatabaseManager) implement database purging
@todo: (WidgetDatabaseManager) implement database export
@todo: (WidgetDatabaseManager) what to do on database doubleclick?
@todo: (WidgetDatabaseManager) context menu for database tree
@todo: (WidgetDatabaseManager) initializing/validating databases may take a while. how to give feedback?
"""
import os import os
import pygtk import pygtk
pygtk.require('2.0') pygtk.require('2.0')
import gtk import gtk
import gobject
#******************************************************************************************************* #*******************************************************************************************************
class DatabaseManager(object): class DatabaseManager(gobject.GObject):
DatabaseTypes = {} DatabaseTypes = {}
@classmethod @classmethod
def from_fpdb(klass, data, defaultDatabaseType=None): def from_fpdb(klass, data, defaultDatabaseType=None):
#TODO: parse whatever data is
#TODO: sort out unsupported databases passed by user and log
databases = (
DatabaseTypeSqLite(name='myDb'),
DatabaseTypeSqLite(name='myDb2'),
) #NOTE: if no databases are present in config fpdb fails with
# Traceback (most recent call last):
# File "/home/me2/Scr/Repos/fpdb-mme/pyfpdb/DatabaseManager.py", line 783, in <module>
# databaseManager = DatabaseManager.from_fpdb('', defaultDatabaseType=DatabaseTypeSqLite)
# File "/home/me2/Scr/Repos/fpdb-mme/pyfpdb/DatabaseManager.py", line 36, in from_fpdb
# config = Configuration.Config(file=options.config, dbname=options.dbname)
# File "/home/me2/Scr/Repos/fpdb-mme/pyfpdb/Configuration.py", line 436, in __init__
# db = self.get_db_parameters()
# File "/home/me2/Scr/Repos/fpdb-mme/pyfpdb/Configuration.py", line 583, in get_db_parameters
# name = self.db_selected
# AttributeError: Config instance has no attribute 'db_selected'
import sys
import Options
import Configuration
#NOTE: fpdb should perform this globally
(options, sys.argv) = Options.fpdb_options()
config = Configuration.Config(file=options.config, dbname=options.dbname)
#TODO: handle no database present
defaultDatabaseName = config.get_db_parameters().get('db-databaseName', None)
#TODO: fpdb stores databases in no particular order. this has to be fixed somehow
databases = []
for name, fpdbDatabase in config.supported_databases.items():
databaseKlass = klass.DatabaseTypes.get(fpdbDatabase.db_server, None)
#NOTE: Config does not seem to validate user input, so anything may end up here
if databaseKlass is None:
raise ValueError('Unknown databasetype: %s' % fpdbDatabase.db_server)
database = databaseKlass()
if database.Type == 'sqlite':
database.name = fpdbDatabase.db_name
database.file = fpdbDatabase.db_server
else:
database.name = fpdbDatabase.db_name
database.host = fpdbDatabase.db_server
#NOTE: fpdbDatabase.db_ip is no is a string
database.port = int(fpdbDatabase.db_ip)
database.user = fpdbDatabase.db_user
database.password = fpdbDatabase.db_pass
databases.append(database)
return klass(databases=databases, defaultDatabaseType=defaultDatabaseType) return klass(databases=databases, defaultDatabaseType=defaultDatabaseType)
def to_fpdb(self):
pass
def __init__(self, databases=None, defaultDatabaseType=None): def __init__(self, databases=None, defaultDatabaseType=None):
gobject.GObject.__init__(self)
self._defaultDatabaseType = defaultDatabaseType self._defaultDatabaseType = defaultDatabaseType
self._databases = [] if databases is None else list(databases) self._databases = [] if databases is None else list(databases)
self._activeDatabase = None
def __iter__(self): def __iter__(self):
return iter(self._databases) return iter(self._databases)
def set_default_database_type(self, databaseType): def set_default_database_type(self, databaseType):
@ -31,7 +88,7 @@ class DatabaseManager(object):
return self._defaultDatabaseType return self._defaultDatabaseType
def database_from_id(self, idDatabase): def database_from_id(self, idDatabase):
for database in self._databases: for database in self._databases:
if idDatabase == id(database): if idDatabase == self.database_id(database):
return database return database
def database_id(self, database): def database_id(self, database):
return id(database) return id(database)
@ -41,8 +98,26 @@ class DatabaseManager(object):
self._databases.append(database) self._databases.append(database)
def remove_database(self, database): def remove_database(self, database):
self._databases.remove(database) self._databases.remove(database)
def init_database(self, database):
pass def activate_database(self, database):
if self._activeDatabase is not None:
self._activeDatabase.status = self._activeDatabase.StatusInactive
#TODO: finalize database
self.emit('database-deactivated', self.database_id(self._activeDatabase) )
database.status = database.StatusActive
#TODO: activate database
self._activeDatabase = database
self.emit('database-activated', self.database_id(database) )
def active_database(self):
return self._activeDatabase
# register DatabaseManager signals
gobject.type_register(DatabaseManager)
gobject.signal_new('database-activated', DatabaseManager, gobject.SIGNAL_RUN_FIRST, gobject.TYPE_NONE, (int, ))
gobject.signal_new('database-deactivated', DatabaseManager, gobject.SIGNAL_RUN_FIRST, gobject.TYPE_NONE, (int, ))
gobject.signal_new('database-error', DatabaseManager, gobject.SIGNAL_RUN_FIRST, gobject.TYPE_NONE, (int, ))
class DatabaseTypeMeta(type): class DatabaseTypeMeta(type):
def __new__(klass, name, bases, kws): def __new__(klass, name, bases, kws):
@ -56,10 +131,25 @@ class DatabaseTypeMeta(type):
class DatabaseTypeBase(object): class DatabaseTypeBase(object):
__metaclass__ = DatabaseTypeMeta __metaclass__ = DatabaseTypeMeta
Type = None Type = None
Params = () StatusActive = 'active'
StatusInactive = 'inactive'
StatusError = 'error' #TODO: not implemented
#TODO: not happy with returning error string. just being too lazy to impl dozens of error codes for later translation
def init_new_database(self):
"""initializes a new empty database
@return: (str) error if something goes wrong, None otherwise
"""
raise NotImplementedError()
def validate_database(self):
"""checks if the database is valid
@return: (str) error if something goes wrong, None otherwise
"""
raise NotImplementedError()
class DatabaseTypePostgres(DatabaseTypeBase): class DatabaseTypePostgres(DatabaseTypeBase):
Type = 'postgres' Type = 'postgresql'
@classmethod @classmethod
def display_name(klass): def display_name(klass):
return 'Postgres' return 'Postgres'
@ -70,6 +160,15 @@ class DatabaseTypePostgres(DatabaseTypeBase):
self.user = user self.user = user
self.password = password self.password = password
self.database = database self.database = database
self.status = self.StatusInactive
#TODO: implement
def init_new_database(self):
pass
#TODO: implement
def validate_database(self):
pass
class DatabaseTypeMysql(DatabaseTypeBase): class DatabaseTypeMysql(DatabaseTypeBase):
Type = 'mysql' Type = 'mysql'
@ -83,6 +182,16 @@ class DatabaseTypeMysql(DatabaseTypeBase):
self.user = user self.user = user
self.password = password self.password = password
self.database = database self.database = database
self.status = self.StatusInactive
#TODO: implement
def init_new_database(self):
pass
#TODO: implement
def validate_database(self):
pass
class DatabaseTypeSqLite(DatabaseTypeBase): class DatabaseTypeSqLite(DatabaseTypeBase):
Type = 'sqlite' Type = 'sqlite'
@ -92,7 +201,26 @@ class DatabaseTypeSqLite(DatabaseTypeBase):
def __init__(self, name='', host='', file='', database='fpdb'): def __init__(self, name='', host='', file='', database='fpdb'):
self.name = name self.name = name
self.file = file self.file = file
self.database = database self.status = self.StatusInactive
def init_new_database(self):
# make shure all attrs are specified
if not self.file:
return 'no database file specified'
# create file if necessary (this will truncate file if it exists)
try:
open(self.file, 'w').close()
except IOError:
return 'can not write file'
#TODO: init tables (...)
def validate_database(self):
pass
#TODO: check if tables (...) exist
#TODO: how do we want to handle unsupported database types? #TODO: how do we want to handle unsupported database types?
# ..uncomment to remove unsupported database types # ..uncomment to remove unsupported database types
@ -104,6 +232,20 @@ class DatabaseTypeSqLite(DatabaseTypeBase):
#except ImportError: del DatabaseManager.DatabaseTypes['sqlite'] #except ImportError: del DatabaseManager.DatabaseTypes['sqlite']
#*************************************************************************************************************************** #***************************************************************************************************************************
#TODO: there is no title (on linux), wtf?
def DialogError(parent=None, msg=''):
dlg = gtk.MessageDialog(
parent=parent,
flags=gtk.DIALOG_MODAL|gtk.DIALOG_DESTROY_WITH_PARENT,
type=gtk.MESSAGE_ERROR,
buttons=gtk.BUTTONS_OK,
message_format=msg,
)
dlg.run()
dlg.destroy()
return None
#TODO: derrive from gtk.VBox? #TODO: derrive from gtk.VBox?
class WidgetDatabaseProperties(gtk.VBox): class WidgetDatabaseProperties(gtk.VBox):
@ -158,7 +300,7 @@ class WidgetDatabaseProperties(gtk.VBox):
dlg.destroy() dlg.destroy()
#TODO: bit ugly this thingy. try to find a better way to map database attrs to gtk widgets
class FieldWidget(object): class FieldWidget(object):
def __init__(self, text='', attrDatabase='', widget=None, attrGet=None, attrSet=None, defaultValue=None, canEdit=False, tooltip=''): def __init__(self, text='', attrDatabase='', widget=None, attrGet=None, attrSet=None, defaultValue=None, canEdit=False, tooltip=''):
""" """
@ -212,16 +354,6 @@ class WidgetDatabaseProperties(gtk.VBox):
canEdit=True, canEdit=True,
tooltip='Any name you like to name the database ' tooltip='Any name you like to name the database '
), ),
self.FieldWidget(
text='Db:',
attrDatabase='database',
widget=gtk.Entry(),
defaultValue='',
attrGet='get_text',
attrSet='set_text',
canEdit=False,
tooltip='Name of the database to create'
),
self.FieldWidget( self.FieldWidget(
text='File:', text='File:',
attrDatabase='file', attrDatabase='file',
@ -272,6 +404,16 @@ class WidgetDatabaseProperties(gtk.VBox):
canEdit=False, canEdit=False,
tooltip='Password used to login to the host' tooltip='Password used to login to the host'
), ),
self.FieldWidget(
text='Db:',
attrDatabase='database',
widget=gtk.Entry(),
defaultValue='',
attrGet='get_text',
attrSet='set_text',
canEdit=False,
tooltip='Name of the database'
),
) )
# setup database type combo # setup database type combo
@ -372,11 +514,22 @@ class DialogDatabaseProperties(gtk.Dialog):
#TODO: derrive from gtk.VBox? #TODO: derrive from gtk.VBox?
# ..is there a way to derrive from gtk.Widget or similar? this would make parentWidget kw obsolete # ..is there a way to derrive from gtk.Widget or similar? this would make parentWidget kw obsolete
class WidgetDatabaseManager(gtk.VBox): class WidgetDatabaseManager(gtk.VBox):
"""
"""
def __init__(self, databaseManager, parentWidget=None): def __init__(self, databaseManager, parentWidget=None):
gtk.VBox.__init__(self) gtk.VBox.__init__(self)
self.databaseManager = databaseManager
self.parentWidget = parentWidget self.parentWidget = parentWidget
self.databaseManager = databaseManager
self.databaseManager.connect('database-activated', self.on_database_manager_database_activated)
self.databaseManager.connect('database-deactivated', self.on_database_manager_database_deactivated)
self.databaseStatusNames = {
DatabaseTypeBase.StatusActive: 'Active',
DatabaseTypeBase.StatusInactive: 'Inactive',
DatabaseTypeBase.StatusError: 'Error',
}
#TODO: dono how to make word wrap work as expected #TODO: dono how to make word wrap work as expected
self.labelInfo = gtk.Label('database management') self.labelInfo = gtk.Label('database management')
@ -389,6 +542,10 @@ class WidgetDatabaseManager(gtk.VBox):
#TODO: bit messy the distinction New/Add/Edit. we'd have to pass three flags to DialogDatabaseProperties #TODO: bit messy the distinction New/Add/Edit. we'd have to pass three flags to DialogDatabaseProperties
# to handle this. maybe drop Edit (is just a Remove + Add), to keep things simple # to handle this. maybe drop Edit (is just a Remove + Add), to keep things simple
self.buttonDatabaseActivate = gtk.Button("Activate")
self.buttonDatabaseActivate.set_tooltip_text('activates the database')
self.buttonDatabaseActivate.connect('clicked', self.on_button_database_activate_clicked)
self.buttonDatabaseActivate.set_sensitive(False)
self.buttonDatabaseNew = gtk.Button("New..") self.buttonDatabaseNew = gtk.Button("New..")
self.buttonDatabaseNew.set_tooltip_text('creates a new database') self.buttonDatabaseNew.set_tooltip_text('creates a new database')
self.buttonDatabaseNew.connect('clicked', self.on_button_database_new_clicked) self.buttonDatabaseNew.connect('clicked', self.on_button_database_new_clicked)
@ -402,31 +559,30 @@ class WidgetDatabaseManager(gtk.VBox):
self.buttonDatabaseRemove = gtk.Button("Remove") self.buttonDatabaseRemove = gtk.Button("Remove")
self.buttonDatabaseRemove.set_tooltip_text('removes the database from the list') self.buttonDatabaseRemove.set_tooltip_text('removes the database from the list')
self.buttonDatabaseRemove.set_sensitive(False) self.buttonDatabaseRemove.set_sensitive(False)
self.buttonDatabaseRemove.connect('clicked', self.on_button_database_remove_clicked)
#TODO: i dont think we should do any real database management here. maybe drop it #TODO: i dont think we should do any real database management here. maybe drop it
self.buttonDatabaseDelete = gtk.Button("Delete") #self.buttonDatabaseDelete = gtk.Button("Delete")
self.buttonDatabaseDelete.set_tooltip_text('removes the database from the list and deletes it') #self.buttonDatabaseDelete.set_tooltip_text('removes the database from the list and deletes it')
self.buttonDatabaseDelete.set_sensitive(False) #self.buttonDatabaseDelete.set_sensitive(False)
# init database tree # init database tree
self.treeDatabases = gtk.TreeView() self.treeDatabases = gtk.TreeView()
self.treeDatabaseColumns = ( #NOTE: column names starting with '_' will be hidden treeDatabaseColumns = ( # name, displayName, dataType
'Name', ('name', 'Name', str),
'Status', ('status', 'Status', str),
'Type', ('type', 'Type', str),
'_id', ('_id', '', int),
) )
self.treeDatabaseColumns = {} # name --> index
store = gtk.ListStore(str, str, str, int) store = gtk.ListStore( *[i[2] for i in treeDatabaseColumns] )
self.treeDatabases.set_model(store) self.treeDatabases.set_model(store)
columns = ('Name', 'Status', 'Type', '_id') for i, (name, displayName, dataType) in enumerate(treeDatabaseColumns):
for i, column in enumerate(columns): col = gtk.TreeViewColumn(displayName, gtk.CellRendererText(), text=i)
col = gtk.TreeViewColumn(column, gtk.CellRendererText(), text=i)
self.treeDatabases.append_column(col) self.treeDatabases.append_column(col)
if column.startswith('_'): if name.startswith('_'):
col.set_visible(False) col.set_visible(False)
self.treeDatabaseColumns[name] = i
self.treeDatabaseColumns = dict([(name, i) for (i, name) in enumerate(self.treeDatabaseColumns)])
self.treeDatabases.get_selection().connect('changed', self.on_tree_databases_selection_changed) self.treeDatabases.get_selection().connect('changed', self.on_tree_databases_selection_changed)
# layout widgets # layout widgets
@ -438,11 +594,12 @@ class WidgetDatabaseManager(gtk.VBox):
hbox.set_homogeneous(False) hbox.set_homogeneous(False)
vbox = gtk.VBox() vbox = gtk.VBox()
hbox.pack_start(vbox, False, False, 2) hbox.pack_start(vbox, False, False, 2)
vbox.pack_start(self.buttonDatabaseActivate, False, False, 2)
vbox.pack_start(self.buttonDatabaseNew, False, False, 2) vbox.pack_start(self.buttonDatabaseNew, False, False, 2)
vbox.pack_start(self.buttonDatabaseAdd, False, False, 2) vbox.pack_start(self.buttonDatabaseAdd, False, False, 2)
vbox.pack_start(self.buttonDatabaseEdit, False, False, 2) vbox.pack_start(self.buttonDatabaseEdit, False, False, 2)
vbox.pack_start(self.buttonDatabaseRemove, False, False, 2) vbox.pack_start(self.buttonDatabaseRemove, False, False, 2)
vbox.pack_start(self.buttonDatabaseDelete, False, False, 2) #vbox.pack_start(self.buttonDatabaseDelete, False, False, 2)
box = gtk.VBox() box = gtk.VBox()
vbox.pack_start(box, True, True, 0) vbox.pack_start(box, True, True, 0)
@ -452,48 +609,128 @@ class WidgetDatabaseManager(gtk.VBox):
self.show_all() self.show_all()
# init widget # init widget
model = self.treeDatabases.get_model()
for database in self.databaseManager: for database in self.databaseManager:
self.treeDatabases.get_model().append( (database.name, 'foo', database.Type, self.databaseManager.database_id(database)) ) it = model.append()
model.set_value(it, self.treeDatabaseColumns['name'], database.name)
model.set_value(it, self.treeDatabaseColumns['status'], self.databaseStatusNames[database.status] )
model.set_value(it, self.treeDatabaseColumns['type'], database.display_name() )
model.set_value(it, self.treeDatabaseColumns['_id'], self.databaseManager.database_id(database))
def on_database_manager_database_activated(self, databaseManager, idDatabase):
database = self.databaseManager.database_from_id(idDatabase)
model = self.treeDatabases.get_model()
for row in iter(model):
if row[self.treeDatabaseColumns['_id']] == idDatabase:
row[self.treeDatabaseColumns['status']] = self.databaseStatusNames[database.StatusActive]
break
else:
raise ValueError('database not found')
def on_database_manager_database_deactivated(self, databaseManager, idDatabase):
database = self.databaseManager.database_from_id(idDatabase)
model = self.treeDatabases.get_model()
for row in iter(model):
if row[self.treeDatabaseColumns['_id']] == idDatabase:
row[self.treeDatabaseColumns['status']] = self.databaseStatusNames[database.StatusInactive]
break
else:
raise ValueError('database not found')
def on_button_database_activate_clicked(self, button):
selection = self.treeDatabases.get_selection()
if selection is None:
return
model, it = selection.get_selected()
idDatabase = model.get_value(it, self.treeDatabaseColumns['_id'])
database = self.databaseManager.database_from_id(idDatabase)
self.databaseManager.activate_database(database)
#TODO: for some reason i have to click OK/Cancel twice to close the dialog #TODO: for some reason i have to click OK/Cancel twice to close the dialog
def on_button_database_new_clicked(self, button): def on_button_database_new_clicked(self, button):
databaseType = self.databaseManager.get_default_database_type() databaseKlass = self.databaseManager.get_default_database_type()
if databaseType is None: if databaseKlass is None:
raise ValueError('no defult database type set') raise ValueError('no default database type set')
dlg = DialogDatabaseProperties( database = databaseKlass()
self.databaseManager,
databaseType(), while True:
parent=self.parentWidget, dlg = DialogDatabaseProperties(
mode=WidgetDatabaseProperties.ModeNew, self.databaseManager,
title='[New database] - database properties' database,
) parent=self.parentWidget,
if dlg.run() == gtk.RESPONSE_REJECT: mode=WidgetDatabaseProperties.ModeNew,
pass title='New database'
if dlg.run() == gtk.RESPONSE_ACCEPT: )
database = dlg.get_widget_database_properties().get_database() response = dlg.run()
#TODO: sanity checks + init databse if necessary if response == gtk.RESPONSE_ACCEPT:
database = dlg.get_widget_database_properties().get_database()
#TODO: initing may or may not take a while. how to handle?
error = database.init_new_database()
if error:
DialogError(parent=dlg, msg=error)
dlg.destroy()
continue
else:
database = None
dlg.destroy()
break
if database is None:
return
self.databaseManager.add_database(database) self.databaseManager.add_database(database)
self.treeDatabases.get_model().append( (database.name, 'foo', database.Type, self.databaseManager.database_id(database)) ) model = self.treeDatabases.get_model()
dlg.destroy() it = model.append()
model.set_value(it, self.treeDatabaseColumns['name'], database.name)
model.set_value(it, self.treeDatabaseColumns['status'], self.databaseStatusNames[database.status] )
model.set_value(it, self.treeDatabaseColumns['type'], database.display_name() )
model.set_value(it, self.treeDatabaseColumns['_id'], self.databaseManager.database_id(database))
def on_button_database_add_clicked(self, button): def on_button_database_add_clicked(self, button):
databaseType = self.databaseManager.get_default_database_type() databaseKlass = self.databaseManager.get_default_database_type()
if databaseType is None: if databaseKlass is None:
raise ValueError('no defult database type set') raise ValueError('no defult database type set')
dlg = DialogDatabaseProperties( database = databaseKlass()
self.databaseManager,
databaseType(), while True:
parent=self.parentWidget, dlg = DialogDatabaseProperties(
mode=WidgetDatabaseProperties.ModeAdd, self.databaseManager,
title='[Add database] - database properties' database,
) parent=self.parentWidget,
if dlg.run() == gtk.RESPONSE_REJECT: mode=WidgetDatabaseProperties.ModeAdd,
pass title='Add database'
if dlg.run() == gtk.RESPONSE_ACCEPT: )
database = dlg.get_widget_database_properties().get_database() response = dlg.run()
#TODO: sanity checks if response == gtk.RESPONSE_ACCEPT:
database = dlg.get_widget_database_properties().get_database()
#TODO: validating may or may not take a while. how to handle?
error = database.validate_database()
if error:
DialogError(parent=self.parentWidget, msg=error)
dlg.destroy()
continue
else:
database = None
dlg.destroy()
break
if database is None:
return
self.databaseManager.add_database(database) self.databaseManager.add_database(database)
self.treeDatabases.get_model().append( (database.name, 'foo', database.Type, self.databaseManager.database_id(database)) ) model = self.treeDatabases.get_model()
it = model.append()
model.set_value(it, self.treeDatabaseColumns['name'], database.name)
model.set_value(it, self.treeDatabaseColumns['status'], self.databaseStatusNames[database.status] )
model.set_value(it, self.treeDatabaseColumns['type'], database.display_name() )
model.set_value(it, self.treeDatabaseColumns['_id'], self.databaseManager.database_id(database))
dlg.destroy() dlg.destroy()
def on_button_database_edit_clicked(self, button): def on_button_database_edit_clicked(self, button):
@ -501,39 +738,52 @@ class WidgetDatabaseManager(gtk.VBox):
if selection is None: if selection is None:
return return
model, iter = selection.get_selected() model, it = selection.get_selected()
idDatabase = model.get_value(iter, self.treeDatabaseColumns['_id']) idDatabase = model.get_value(it, self.treeDatabaseColumns['_id'])
database = self.databaseManager.database_from_id(idDatabase) database = self.databaseManager.database_from_id(idDatabase)
dlg = DialogDatabaseProperties( dlg = DialogDatabaseProperties(
self.databaseManager, self.databaseManager,
database=database, database,
parent=self.parentWidget, parent=self.parentWidget,
mode=WidgetDatabaseProperties.ModeEdit, mode=WidgetDatabaseProperties.ModeEdit,
title='[Edit database] - database properties' title='Edit database'
) )
if dlg.run() == gtk.RESPONSE_REJECT: response = dlg.run()
if response == gtk.RESPONSE_REJECT:
pass pass
if dlg.run() == gtk.RESPONSE_ACCEPT: elif response == gtk.RESPONSE_ACCEPT:
database = dlg.get_database() database = dlg.get_database()
selection = self.treeDatabases.get_selection() selection = self.treeDatabases.get_selection()
if selection is not None: if selection is not None:
model, iter = selection.get_selected() model, it = selection.get_selected()
model.set_value(iter, 0, database.name) model.set_value(it, self.treeDatabaseColumns['name'], database.name)
dlg.destroy() dlg.destroy()
def on_button_database_remove_clicked(self, button):
selection = self.treeDatabases.get_selection()
if selection is None:
return
model, it = selection.get_selected()
#TODO: finalize database
model.remove(it)
def on_tree_databases_selection_changed(self, treeSelection): def on_tree_databases_selection_changed(self, treeSelection):
hasSelection = bool(treeSelection.count_selected_rows()) hasSelection = bool(treeSelection.count_selected_rows())
# enable/disable selection dependend widgets # enable/disable selection dependend widgets
self.buttonDatabaseActivate.set_sensitive(hasSelection)
self.buttonDatabaseEdit.set_sensitive(hasSelection) self.buttonDatabaseEdit.set_sensitive(hasSelection)
self.buttonDatabaseRemove.set_sensitive(hasSelection) self.buttonDatabaseRemove.set_sensitive(hasSelection)
self.buttonDatabaseDelete.set_sensitive(hasSelection) #self.buttonDatabaseDelete.set_sensitive(hasSelection)
class DialogDatabaseManager(gtk.Dialog): class DialogDatabaseManager(gtk.Dialog):
def __init__(self, databaseManager, parent=None): def __init__(self, databaseManager, parent=None):
gtk.Dialog.__init__(self, gtk.Dialog.__init__(self,
title="My dialog", title="Databases",
parent=parent, parent=parent,
flags=gtk.DIALOG_MODAL | gtk.DIALOG_DESTROY_WITH_PARENT, flags=gtk.DIALOG_MODAL | gtk.DIALOG_DESTROY_WITH_PARENT,
buttons=( buttons=(

View File

@ -18,6 +18,13 @@
#fpdb modules #fpdb modules
import Card import Card
DEBUG = True
if DEBUG:
import pprint
pp = pprint.PrettyPrinter(indent=4)
class DerivedStats(): class DerivedStats():
def __init__(self, hand): def __init__(self, hand):
self.hand = hand self.hand = hand
@ -30,13 +37,19 @@ class DerivedStats():
for player in hand.players: for player in hand.players:
self.handsplayers[player[1]] = {} self.handsplayers[player[1]] = {}
#Init vars that may not be used, but still need to be inserted. #Init vars that may not be used, but still need to be inserted.
# All stud street4 need this when importing holdem
self.handsplayers[player[1]]['winnings'] = 0
self.handsplayers[player[1]]['street4Seen'] = False
self.handsplayers[player[1]]['street4Aggr'] = False self.handsplayers[player[1]]['street4Aggr'] = False
self.assembleHands(self.hand) self.assembleHands(self.hand)
self.assembleHandsPlayers(self.hand) self.assembleHandsPlayers(self.hand)
print "hands =", self.hands if DEBUG:
print "handsplayers =", self.handsplayers print "Hands:"
pp.pprint(self.hands)
print "HandsPlayers:"
pp.pprint(self.handsplayers)
def getHands(self): def getHands(self):
return self.hands return self.hands
@ -85,11 +98,20 @@ class DerivedStats():
# commentTs DATETIME # commentTs DATETIME
def assembleHandsPlayers(self, hand): def assembleHandsPlayers(self, hand):
#street0VPI/vpip already called in Hand
#hand.players = [[seat, name, chips],[seat, name, chips]] #hand.players = [[seat, name, chips],[seat, name, chips]]
for player in hand.players: for player in hand.players:
self.handsplayers[player[1]]['seatNo'] = player[0] self.handsplayers[player[1]]['seatNo'] = player[0]
self.handsplayers[player[1]]['startCash'] = player[2] self.handsplayers[player[1]]['startCash'] = player[2]
# Winnings is a non-negative value of money collected from the pot, which already includes the
# rake taken out. hand.collectees is Decimal, database requires cents
for player in hand.collectees:
self.handsplayers[player]['winnings'] = int(100 * hand.collectees[player])
for i, street in enumerate(hand.actionStreets[2:]):
self.seen(self.hand, i+1)
for i, street in enumerate(hand.actionStreets[1:]): for i, street in enumerate(hand.actionStreets[1:]):
self.aggr(self.hand, i) self.aggr(self.hand, i)
@ -794,9 +816,9 @@ class DerivedStats():
for player in hand.players: for player in hand.players:
if player[1] in vpipers: if player[1] in vpipers:
self.handsplayers[player[1]]['vpip'] = True self.handsplayers[player[1]]['street0VPI'] = True
else: else:
self.handsplayers[player[1]]['vpip'] = False self.handsplayers[player[1]]['street0VPI'] = False
def playersAtStreetX(self, hand): def playersAtStreetX(self, hand):
""" playersAtStreet1 SMALLINT NOT NULL, /* num of players seeing flop/street4/draw1 */""" """ playersAtStreet1 SMALLINT NOT NULL, /* num of players seeing flop/street4/draw1 */"""
@ -833,6 +855,17 @@ class DerivedStats():
self.hands['street3Raises'] = 0 # /* num big bets paid to see sd/street7 */ self.hands['street3Raises'] = 0 # /* num big bets paid to see sd/street7 */
self.hands['street4Raises'] = 0 # /* num big bets paid to see showdown */ self.hands['street4Raises'] = 0 # /* num big bets paid to see showdown */
def seen(self, hand, i):
pas = set()
for act in hand.actions[hand.actionStreets[i+1]]:
pas.add(act[0])
for player in hand.players:
if player[1] in pas:
self.handsplayers[player[1]]['street%sSeen' % i] = True
else:
self.handsplayers[player[1]]['street%sSeen' % i] = False
def aggr(self, hand, i): def aggr(self, hand, i):
aggrers = set() aggrers = set()
for act in hand.actions[hand.actionStreets[i]]: for act in hand.actions[hand.actionStreets[i]]:

View File

@ -305,10 +305,10 @@ class Filters(threading.Thread):
print "self.limit[%s] set to %s" %(limit, self.limits[limit]) print "self.limit[%s] set to %s" %(limit, self.limits[limit])
if limit.isdigit() or (len(limit) > 2 and limit[-2:] == 'nl'): if limit.isdigit() or (len(limit) > 2 and limit[-2:] == 'nl'):
if self.limits[limit]: if self.limits[limit]:
if self.cbNoLimits != None: if self.cbNoLimits is not None:
self.cbNoLimits.set_active(False) self.cbNoLimits.set_active(False)
else: else:
if self.cbAllLimits != None: if self.cbAllLimits is not None:
self.cbAllLimits.set_active(False) self.cbAllLimits.set_active(False)
if not self.limits[limit]: if not self.limits[limit]:
if limit.isdigit(): if limit.isdigit():
@ -319,9 +319,9 @@ class Filters(threading.Thread):
if self.limits[limit]: if self.limits[limit]:
#for cb in self.cbLimits.values(): #for cb in self.cbLimits.values():
# cb.set_active(True) # cb.set_active(True)
if self.cbFL != None: if self.cbFL is not None:
self.cbFL.set_active(True) self.cbFL.set_active(True)
if self.cbNL != None: if self.cbNL is not None:
self.cbNL.set_active(True) self.cbNL.set_active(True)
elif limit == "none": elif limit == "none":
if self.limits[limit]: if self.limits[limit]:

View File

@ -184,11 +184,11 @@ class Fulltilt(HandHistoryConverter):
info['limitType'] = limits[mg['LIMIT']] info['limitType'] = limits[mg['LIMIT']]
info['sb'] = mg['SB'] info['sb'] = mg['SB']
info['bb'] = mg['BB'] info['bb'] = mg['BB']
if mg['GAME'] != None: if mg['GAME'] is not None:
(info['base'], info['category']) = games[mg['GAME']] (info['base'], info['category']) = games[mg['GAME']]
if mg['CURRENCY'] != None: if mg['CURRENCY'] is not None:
info['currency'] = currencies[mg['CURRENCY']] info['currency'] = currencies[mg['CURRENCY']]
if mg['TOURNO'] == None: info['type'] = "ring" if mg['TOURNO'] is None: info['type'] = "ring"
else: info['type'] = "tour" else: 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['type'] == "tour": return None # importer is screwed on tournies, pass on those hands so we don't interrupt other autoimporting # if info['type'] == "tour": return None # importer is screwed on tournies, pass on those hands so we don't interrupt other autoimporting
@ -196,7 +196,7 @@ class Fulltilt(HandHistoryConverter):
def readHandInfo(self, hand): def readHandInfo(self, hand):
m = self.re_HandInfo.search(hand.handText) m = self.re_HandInfo.search(hand.handText)
if(m == None): if m is None:
logging.info("Didn't match re_HandInfo") logging.info("Didn't match re_HandInfo")
logging.info(hand.handText) logging.info(hand.handText)
return None return None
@ -212,7 +212,7 @@ class Fulltilt(HandHistoryConverter):
if m2: hand.maxseats = int(m2.group('MAX')) if m2: hand.maxseats = int(m2.group('MAX'))
hand.tourNo = m.group('TOURNO') hand.tourNo = m.group('TOURNO')
if m.group('PLAY') != None: if m.group('PLAY') is not None:
hand.gametype['currency'] = 'play' hand.gametype['currency'] = 'play'
# Done: 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
@ -240,9 +240,9 @@ class Fulltilt(HandHistoryConverter):
hand.isShootout = True hand.isShootout = True
if hand.buyin == None: if hand.buyin is None:
hand.buyin = "$0.00+$0.00" hand.buyin = "$0.00+$0.00"
if hand.level == None: if hand.level is None:
hand.level = "0" hand.level = "0"
# These work, but the info is already in the Hand class - should be used for tourneys though. # These work, but the info is already in the Hand class - should be used for tourneys though.
@ -343,11 +343,11 @@ class Fulltilt(HandHistoryConverter):
m = self.re_HeroCards.finditer(hand.streets[street]) m = self.re_HeroCards.finditer(hand.streets[street])
for found in m: for found in m:
player = found.group('PNAME') player = found.group('PNAME')
if found.group('NEWCARDS') == None: if found.group('NEWCARDS') is None:
newcards = [] newcards = []
else: else:
newcards = found.group('NEWCARDS').split(' ') newcards = found.group('NEWCARDS').split(' ')
if found.group('OLDCARDS') == None: if found.group('OLDCARDS') is None:
oldcards = [] oldcards = []
else: else:
oldcards = found.group('OLDCARDS').split(' ') oldcards = found.group('OLDCARDS').split(' ')
@ -376,7 +376,7 @@ class Fulltilt(HandHistoryConverter):
elif action.group('ATYPE') == ' checks': elif action.group('ATYPE') == ' checks':
hand.addCheck( street, action.group('PNAME')) hand.addCheck( street, action.group('PNAME'))
else: else:
print "DEBUG: unimplemented readAction: '%s' '%s'" %(action.group('PNAME'),action.group('ATYPE'),) print "FullTilt: DEBUG: unimplemented readAction: '%s' '%s'" %(action.group('PNAME'),action.group('ATYPE'),)
def readShowdownActions(self, hand): def readShowdownActions(self, hand):
@ -416,7 +416,8 @@ class Fulltilt(HandHistoryConverter):
def readOther(self, hand): def readOther(self, hand):
m = self.re_Mixed.search(self.in_path) m = self.re_Mixed.search(self.in_path)
if m == None: hand.mixed = None if m is None:
hand.mixed = None
else: else:
hand.mixed = self.mixes[m.groupdict()['MIXED']] hand.mixed = self.mixes[m.groupdict()['MIXED']]
@ -472,8 +473,10 @@ class Fulltilt(HandHistoryConverter):
(info['base'], info['category']) = games[mg['GAME']] (info['base'], info['category']) = games[mg['GAME']]
if mg['CURRENCY'] is not None: if mg['CURRENCY'] is not None:
info['currency'] = currencies[mg['CURRENCY']] info['currency'] = currencies[mg['CURRENCY']]
if mg['TOURNO'] == None: info['type'] = "ring" if mg['TOURNO'] is None:
else: info['type'] = "tour" info['type'] = "ring"
else:
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.
# Info is now ready to be copied in the tourney object # Info is now ready to be copied in the tourney object
@ -654,7 +657,7 @@ class Fulltilt(HandHistoryConverter):
tourney.addPlayer(rank, a.group('PNAME'), winnings, 0, 0, 0, 0) tourney.addPlayer(rank, a.group('PNAME'), winnings, 0, 0, 0, 0)
else: else:
print "Player finishing stats unreadable : %s" % a print "FullTilt: Player finishing stats unreadable : %s" % a
# Find Hero # Find Hero
n = self.re_TourneyHeroFinishingP.search(playersText) n = self.re_TourneyHeroFinishingP.search(playersText)
@ -663,9 +666,9 @@ class Fulltilt(HandHistoryConverter):
tourney.hero = heroName tourney.hero = heroName
# Is this really useful ? # Is this really useful ?
if heroName not in tourney.finishPositions: if heroName not in tourney.finishPositions:
print heroName, "not found in tourney.finishPositions ..." print "FullTilt:", heroName, "not found in tourney.finishPositions ..."
elif (tourney.finishPositions[heroName] != Decimal(n.group('HERO_FINISHING_POS'))): elif (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 "FullTilt: Bad parsing : finish position incoherent : %s / %s" % (tourney.finishPositions[heroName], n.group('HERO_FINISHING_POS'))
return True return True

View File

@ -33,16 +33,15 @@ 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"""
self.importtimer = 0 self.importtimer = 0
self.settings=settings self.settings = settings
self.config=config self.config = config
self.sql = sql self.sql = sql
imp = self.config.get_import_parameters() imp = self.config.get_import_parameters()
print "Import parameters" # print "Import parameters"
print imp # print imp
self.input_settings = {} self.input_settings = {}
self.pipe_to_hud = None self.pipe_to_hud = None
@ -55,12 +54,12 @@ class GuiAutoImport (threading.Thread):
self.importer.setHandCount(0) self.importer.setHandCount(0)
# self.importer.setWatchTime() # self.importer.setWatchTime()
self.server=settings['db-host'] self.server = settings['db-host']
self.user=settings['db-user'] self.user = settings['db-user']
self.password=settings['db-password'] self.password = settings['db-password']
self.database=settings['db-databaseName'] self.database = settings['db-databaseName']
self.mainVBox=gtk.VBox(False,1) self.mainVBox = gtk.VBox(False,1)
hbox = gtk.HBox(True, 0) # contains 2 equal vboxes hbox = gtk.HBox(True, 0) # contains 2 equal vboxes
self.mainVBox.pack_start(hbox, False, False, 0) self.mainVBox.pack_start(hbox, False, False, 0)
@ -130,7 +129,8 @@ class GuiAutoImport (threading.Thread):
data[1].set_text(dia_chooser.get_filename()) data[1].set_text(dia_chooser.get_filename())
self.input_settings[data[0]][0] = dia_chooser.get_filename() self.input_settings[data[0]][0] = dia_chooser.get_filename()
elif response == gtk.RESPONSE_CANCEL: elif response == gtk.RESPONSE_CANCEL:
print 'Closed, no files selected' #print 'Closed, no files selected'
pass
dia_chooser.destroy() dia_chooser.destroy()
#end def GuiAutoImport.browseClicked #end def GuiAutoImport.browseClicked
@ -143,8 +143,7 @@ class GuiAutoImport (threading.Thread):
sys.stdout.flush() sys.stdout.flush()
gobject.timeout_add(1000, self.reset_startbutton) gobject.timeout_add(1000, self.reset_startbutton)
return True return True
else: return False
return False
def reset_startbutton(self): def reset_startbutton(self):
if self.pipe_to_hud is not None: if self.pipe_to_hud is not None:
@ -184,22 +183,24 @@ class GuiAutoImport (threading.Thread):
command = os.path.join(sys.path[0], 'HUD_main.py') command = os.path.join(sys.path[0], 'HUD_main.py')
command = [command, ] + string.split(self.settings['cl_options']) command = [command, ] + string.split(self.settings['cl_options'])
bs = 1 bs = 1
try: try:
self.pipe_to_hud = subprocess.Popen(command, bufsize = bs, stdin = subprocess.PIPE, self.pipe_to_hud = subprocess.Popen(command, bufsize=bs,
universal_newlines = True) stdin=subprocess.PIPE,
universal_newlines=True)
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 "*** GuiAutoImport Error opening pipe: " + err[2] + "(" + str(err[1]) + "): " + str(sys.exc_info()[1])
else: else:
for site in self.input_settings: for site in self.input_settings:
self.importer.addImportDirectory(self.input_settings[site][0], True, site, self.input_settings[site][1]) self.importer.addImportDirectory(self.input_settings[site][0], True, site, self.input_settings[site][1])
print " * Add", site, " import directory", str(self.input_settings[site][0])
print "+Import directory - Site: " + site + " dir: " + str(self.input_settings[site][0]) print "+Import directory - Site: " + site + " dir: " + str(self.input_settings[site][0])
self.do_import() self.do_import()
interval = int(self.intervalEntry.get_text()) interval = int(self.intervalEntry.get_text())
if self.importtimer != 0: if self.importtimer != 0:
gobject.source_remove(self.importtimer) gobject.source_remove(self.importtimer)
self.importtimer = gobject.timeout_add(interval*1000, self.do_import) 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"
@ -209,7 +210,7 @@ class GuiAutoImport (threading.Thread):
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."
if self.pipe_to_hud.poll() is not None: if self.pipe_to_hud.poll() is not None:
print "HUD already terminated" print " * Stop Autoimport: HUD already terminated"
else: else:
#print >>self.pipe_to_hud.stdin, "\n" #print >>self.pipe_to_hud.stdin, "\n"
self.pipe_to_hud.communicate('\n') # waits for process to terminate self.pipe_to_hud.communicate('\n') # waits for process to terminate
@ -227,7 +228,7 @@ class GuiAutoImport (threading.Thread):
#enabling and disabling sites from this interface not possible #enabling and disabling sites from this interface not possible
#expects a box to layout the line horizontally #expects a box to layout the line horizontally
def createSiteLine(self, hbox1, hbox2, site, iconpath, hhpath, filter_name, active = True): def createSiteLine(self, hbox1, hbox2, site, iconpath, hhpath, filter_name, active = True):
label = gtk.Label(site + " auto-import:") label = gtk.Label("%s auto-import:" % site)
hbox1.pack_start(label, False, False, 3) hbox1.pack_start(label, False, False, 3)
label.show() label.show()
@ -241,7 +242,7 @@ class GuiAutoImport (threading.Thread):
hbox2.pack_start(browseButton, False, False, 3) hbox2.pack_start(browseButton, False, False, 3)
browseButton.show() browseButton.show()
label = gtk.Label(' ' + site + " filter:") label = gtk.Label("%s filter:" % site)
hbox2.pack_start(label, False, False, 3) hbox2.pack_start(label, False, False, 3)
label.show() label.show()

View File

@ -118,7 +118,7 @@ class GuiBulkImport():
self.progressbar.set_fraction(0) 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 "*** BulkImport Error: "+err[2]+"("+str(err[1])+"): "+str(sys.exc_info()[1])
self.settings['global_lock'].release() self.settings['global_lock'].release()
else: else:
print "bulk-import aborted - global lock not available" print "bulk-import aborted - global lock not available"
@ -142,32 +142,38 @@ class GuiBulkImport():
self.chooser.show() self.chooser.show()
# Table widget to hold the settings # Table widget to hold the settings
self.table = gtk.Table(rows = 5, columns = 5, homogeneous = False) self.table = gtk.Table(rows=5, columns=5, homogeneous=False)
self.vbox.add(self.table) self.vbox.add(self.table)
self.table.show() self.table.show()
# checkbox - print start/stop? # checkbox - print start/stop?
self.chk_st_st = gtk.CheckButton('Print Start/Stop Info') self.chk_st_st = gtk.CheckButton('Print Start/Stop Info')
self.table.attach(self.chk_st_st, 0, 1, 0, 1, xpadding = 10, ypadding = 0, yoptions=gtk.SHRINK) self.table.attach(self.chk_st_st, 0, 1, 0, 1, xpadding=10, ypadding=0,
yoptions=gtk.SHRINK)
self.chk_st_st.show() self.chk_st_st.show()
self.chk_st_st.set_active(True) self.chk_st_st.set_active(True)
# label - status # label - status
self.lab_status = gtk.Label("Hands/status print:") self.lab_status = gtk.Label("Hands/status print:")
self.table.attach(self.lab_status, 1, 2, 0, 1, xpadding = 0, ypadding = 0, yoptions=gtk.SHRINK) self.table.attach(self.lab_status, 1, 2, 0, 1, xpadding=0, ypadding=0,
yoptions=gtk.SHRINK)
self.lab_status.show() self.lab_status.show()
self.lab_status.set_justify(gtk.JUSTIFY_RIGHT) self.lab_status.set_justify(gtk.JUSTIFY_RIGHT)
self.lab_status.set_alignment(1.0, 0.5) self.lab_status.set_alignment(1.0, 0.5)
# spin button - status # spin button - status
status_adj = gtk.Adjustment(value=100, lower=0, upper=300, step_incr=10, page_incr=1, page_size=0) #not sure what upper value should be! status_adj = gtk.Adjustment(value=100, lower=0, upper=300, step_incr=10,
self.spin_status = gtk.SpinButton(adjustment=status_adj, climb_rate=0.0, digits=0) page_incr=1, page_size=0) #not sure what upper value should be!
self.table.attach(self.spin_status, 2, 3, 0, 1, xpadding = 10, ypadding = 0, yoptions=gtk.SHRINK) self.spin_status = gtk.SpinButton(adjustment=status_adj, climb_rate=0.0,
digits=0)
self.table.attach(self.spin_status, 2, 3, 0, 1, xpadding=10, ypadding=0,
yoptions=gtk.SHRINK)
self.spin_status.show() self.spin_status.show()
# label - threads # label - threads
self.lab_threads = gtk.Label("Number of threads:") self.lab_threads = gtk.Label("Number of threads:")
self.table.attach(self.lab_threads, 3, 4, 0, 1, xpadding = 0, ypadding = 0, yoptions=gtk.SHRINK) self.table.attach(self.lab_threads, 3, 4, 0, 1, xpadding=0, ypadding=0,
yoptions=gtk.SHRINK)
self.lab_threads.show() self.lab_threads.show()
if not self.allowThreads: if not self.allowThreads:
self.lab_threads.set_sensitive(False) self.lab_threads.set_sensitive(False)
@ -175,34 +181,39 @@ class GuiBulkImport():
self.lab_threads.set_alignment(1.0, 0.5) self.lab_threads.set_alignment(1.0, 0.5)
# spin button - threads # spin button - threads
threads_adj = gtk.Adjustment(value=0, lower=0, upper=32, step_incr=1, page_incr=1, page_size=0) #not sure what upper value should be! threads_adj = gtk.Adjustment(value=0, lower=0, upper=32, step_incr=1,
page_incr=1, page_size=0) #not sure what upper value should be!
self.spin_threads = gtk.SpinButton(adjustment=threads_adj, climb_rate=0.0, digits=0) self.spin_threads = gtk.SpinButton(adjustment=threads_adj, climb_rate=0.0, digits=0)
self.table.attach(self.spin_threads, 4, 5, 0, 1, xpadding = 10, ypadding = 0, yoptions=gtk.SHRINK) self.table.attach(self.spin_threads, 4, 5, 0, 1, xpadding=10, ypadding=0,
yoptions=gtk.SHRINK)
self.spin_threads.show() self.spin_threads.show()
if not self.allowThreads: if not self.allowThreads:
self.spin_threads.set_sensitive(False) self.spin_threads.set_sensitive(False)
# checkbox - fail on error? # checkbox - fail on error?
self.chk_fail = gtk.CheckButton('Fail on error') self.chk_fail = gtk.CheckButton('Fail on error')
self.table.attach(self.chk_fail, 0, 1, 1, 2, xpadding = 10, ypadding = 0, yoptions=gtk.SHRINK) self.table.attach(self.chk_fail, 0, 1, 1, 2, xpadding=10, ypadding=0, yoptions=gtk.SHRINK)
self.chk_fail.show() self.chk_fail.show()
# label - hands # label - hands
self.lab_hands = gtk.Label("Hands/file:") self.lab_hands = gtk.Label("Hands/file:")
self.table.attach(self.lab_hands, 1, 2, 1, 2, xpadding = 0, ypadding = 0, yoptions=gtk.SHRINK) self.table.attach(self.lab_hands, 1, 2, 1, 2, xpadding=0, ypadding=0, yoptions=gtk.SHRINK)
self.lab_hands.show() self.lab_hands.show()
self.lab_hands.set_justify(gtk.JUSTIFY_RIGHT) self.lab_hands.set_justify(gtk.JUSTIFY_RIGHT)
self.lab_hands.set_alignment(1.0, 0.5) self.lab_hands.set_alignment(1.0, 0.5)
# spin button - hands to import # spin button - hands to import
hands_adj = gtk.Adjustment(value=0, lower=0, upper=10, step_incr=1, page_incr=1, page_size=0) #not sure what upper value should be! hands_adj = gtk.Adjustment(value=0, lower=0, upper=10, step_incr=1,
page_incr=1, page_size=0) #not sure what upper value should be!
self.spin_hands = gtk.SpinButton(adjustment=hands_adj, climb_rate=0.0, digits=0) self.spin_hands = gtk.SpinButton(adjustment=hands_adj, climb_rate=0.0, digits=0)
self.table.attach(self.spin_hands, 2, 3, 1, 2, xpadding = 10, ypadding = 0, yoptions=gtk.SHRINK) self.table.attach(self.spin_hands, 2, 3, 1, 2, xpadding=10, ypadding=0,
yoptions=gtk.SHRINK)
self.spin_hands.show() self.spin_hands.show()
# label - drop indexes # label - drop indexes
self.lab_drop = gtk.Label("Drop indexes:") self.lab_drop = gtk.Label("Drop indexes:")
self.table.attach(self.lab_drop, 3, 4, 1, 2, xpadding = 0, ypadding = 0, yoptions=gtk.SHRINK) self.table.attach(self.lab_drop, 3, 4, 1, 2, xpadding=0, ypadding=0,
yoptions=gtk.SHRINK)
self.lab_drop.show() self.lab_drop.show()
self.lab_drop.set_justify(gtk.JUSTIFY_RIGHT) self.lab_drop.set_justify(gtk.JUSTIFY_RIGHT)
self.lab_drop.set_alignment(1.0, 0.5) self.lab_drop.set_alignment(1.0, 0.5)
@ -213,12 +224,14 @@ class GuiBulkImport():
self.cb_dropindexes.append_text("don't drop") self.cb_dropindexes.append_text("don't drop")
self.cb_dropindexes.append_text('drop') self.cb_dropindexes.append_text('drop')
self.cb_dropindexes.set_active(0) self.cb_dropindexes.set_active(0)
self.table.attach(self.cb_dropindexes, 4, 5, 1, 2, xpadding = 10, ypadding = 0, yoptions=gtk.SHRINK) self.table.attach(self.cb_dropindexes, 4, 5, 1, 2, xpadding=10,
ypadding=0, yoptions=gtk.SHRINK)
self.cb_dropindexes.show() self.cb_dropindexes.show()
# label - filter # label - filter
self.lab_filter = gtk.Label("Site filter:") self.lab_filter = gtk.Label("Site filter:")
self.table.attach(self.lab_filter, 1, 2, 2, 3, xpadding = 0, ypadding = 0, yoptions=gtk.SHRINK) self.table.attach(self.lab_filter, 1, 2, 2, 3, xpadding=0, ypadding=0,
yoptions=gtk.SHRINK)
self.lab_filter.show() self.lab_filter.show()
self.lab_filter.set_justify(gtk.JUSTIFY_RIGHT) self.lab_filter.set_justify(gtk.JUSTIFY_RIGHT)
self.lab_filter.set_alignment(1.0, 0.5) self.lab_filter.set_alignment(1.0, 0.5)
@ -229,12 +242,14 @@ class GuiBulkImport():
print w print w
self.cbfilter.append_text(w) self.cbfilter.append_text(w)
self.cbfilter.set_active(0) self.cbfilter.set_active(0)
self.table.attach(self.cbfilter, 2, 3, 2, 3, xpadding = 10, ypadding = 1, yoptions=gtk.SHRINK) self.table.attach(self.cbfilter, 2, 3, 2, 3, xpadding=10, ypadding=1,
yoptions=gtk.SHRINK)
self.cbfilter.show() self.cbfilter.show()
# label - drop hudcache # label - drop hudcache
self.lab_hdrop = gtk.Label("Drop HudCache:") self.lab_hdrop = gtk.Label("Drop HudCache:")
self.table.attach(self.lab_hdrop, 3, 4, 2, 3, xpadding = 0, ypadding = 0, yoptions=gtk.SHRINK) self.table.attach(self.lab_hdrop, 3, 4, 2, 3, xpadding=0, ypadding=0,
yoptions=gtk.SHRINK)
self.lab_hdrop.show() self.lab_hdrop.show()
self.lab_hdrop.set_justify(gtk.JUSTIFY_RIGHT) self.lab_hdrop.set_justify(gtk.JUSTIFY_RIGHT)
self.lab_hdrop.set_alignment(1.0, 0.5) self.lab_hdrop.set_alignment(1.0, 0.5)
@ -245,19 +260,22 @@ class GuiBulkImport():
self.cb_drophudcache.append_text("don't drop") self.cb_drophudcache.append_text("don't drop")
self.cb_drophudcache.append_text('drop') self.cb_drophudcache.append_text('drop')
self.cb_drophudcache.set_active(0) self.cb_drophudcache.set_active(0)
self.table.attach(self.cb_drophudcache, 4, 5, 2, 3, xpadding = 10, ypadding = 0, yoptions=gtk.SHRINK) self.table.attach(self.cb_drophudcache, 4, 5, 2, 3, xpadding=10,
ypadding=0, yoptions=gtk.SHRINK)
self.cb_drophudcache.show() self.cb_drophudcache.show()
# button - Import # button - Import
self.load_button = gtk.Button('Import') # todo: rename variables to import too self.load_button = gtk.Button('Import') # todo: rename variables to import too
self.load_button.connect('clicked', self.load_clicked, self.load_button.connect('clicked', self.load_clicked,
'Import clicked') 'Import clicked')
self.table.attach(self.load_button, 2, 3, 4, 5, xpadding = 0, ypadding = 0, yoptions=gtk.SHRINK) self.table.attach(self.load_button, 2, 3, 4, 5, xpadding=0, ypadding=0,
yoptions=gtk.SHRINK)
self.load_button.show() self.load_button.show()
# label - spacer (keeps rows 3 & 5 apart) # label - spacer (keeps rows 3 & 5 apart)
self.lab_spacer = gtk.Label() self.lab_spacer = gtk.Label()
self.table.attach(self.lab_spacer, 3, 5, 3, 4, xpadding = 0, ypadding = 0, yoptions=gtk.SHRINK) self.table.attach(self.lab_spacer, 3, 5, 3, 4, xpadding=0, ypadding=0,
yoptions=gtk.SHRINK)
self.lab_spacer.show() self.lab_spacer.show()
# label - info # label - info
@ -265,7 +283,8 @@ class GuiBulkImport():
# 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.progressbar = gtk.ProgressBar()
self.table.attach(self.progressbar, 3, 5, 4, 5, xpadding = 0, ypadding = 0, yoptions = gtk.SHRINK) self.table.attach(self.progressbar, 3, 5, 4, 5, xpadding=0, ypadding=0,
yoptions=gtk.SHRINK)
self.progressbar.set_text("Waiting...") self.progressbar.set_text("Waiting...")
self.progressbar.set_fraction(0) self.progressbar.set_fraction(0)
self.progressbar.show() self.progressbar.show()

View File

@ -310,7 +310,7 @@ class GuiSessionViewer (threading.Thread):
except: except:
pass pass
if self.fig != None: if self.fig is not None:
self.fig.clear() self.fig.clear()
self.fig = Figure(figsize=(5,4), dpi=100) self.fig = Figure(figsize=(5,4), dpi=100)
if self.canvas is not None: if self.canvas is not None:

View File

@ -570,8 +570,8 @@ Left-Drag to Move"
</hhcs> </hhcs>
<supported_databases> <supported_databases>
<database db_name="fpdb" db_server="mysql" db_ip="localhost" db_user="fpdb" db_pass="YOUR MYSQL PASSWORD" db_type="fpdb"></database> <database db_name="fpdb" db_server="mysql" db_ip="localhost" db_user="fpdb" db_pass="YOUR MYSQL PASSWORD"></database>
<!-- <database db_ip="localhost" db_name="fpdb" db_pass="fpdb" db_server="sqlite" db_type="fpdb" db_user="fpdb"/> --> <!-- <database db_ip="localhost" db_name="fpdb" db_pass="fpdb" db_server="sqlite" db_user="fpdb"/> -->
</supported_databases> </supported_databases>
</FreePokerToolsConfig> </FreePokerToolsConfig>

View File

@ -109,7 +109,7 @@ class HUD_main(object):
self.main_window.set_title("HUD Main Window") self.main_window.set_title("HUD Main Window")
self.main_window.show_all() self.main_window.show_all()
def destroy(*args): # call back for terminating the main eventloop def destroy(self, *args): # call back for terminating the main eventloop
gtk.main_quit() gtk.main_quit()
def kill_hud(self, event, table): def kill_hud(self, event, table):
@ -190,7 +190,6 @@ class HUD_main(object):
# need their own access to the database, but should open their own # need their own access to the database, but should open their own
# if it is required. # if it is required.
self.db_connection = Database.Database(self.config) self.db_connection = Database.Database(self.config)
tourny_finder = re.compile('(\d+) (\d+)')
# get hero's screen names and player ids # get hero's screen names and player ids
self.hero, self.hero_ids = {}, {} self.hero, self.hero_ids = {}, {}
@ -207,74 +206,56 @@ class HUD_main(object):
if new_hand_id == "": # blank line means quit if new_hand_id == "": # blank line means quit
self.destroy() self.destroy()
break # this thread is not always killed immediately with gtk.main_quit() break # this thread is not always killed immediately with gtk.main_quit()
# get basic info about the new hand from the db # get basic info about the new hand from the db
# if there is a db error, complain, skip hand, and proceed # if there is a db error, complain, skip hand, and proceed
try: try:
(table_name, max, poker_game, type, site_id) = self.db_connection.get_table_name(new_hand_id) (table_name, max, poker_game, type, site_id, tour_number, tab_number) = \
self.db_connection.get_table_info(new_hand_id)
cards = self.db_connection.get_cards(new_hand_id)
comm_cards = self.db_connection.get_common_cards(new_hand_id)
if comm_cards != {}: # stud!
cards['common'] = comm_cards['common']
except Exception, err: except Exception, err:
err = traceback.extract_tb(sys.exc_info()[2])[-1] print "db error: skipping %s" % new_hand_id
print "db error: skipping "+str(new_hand_id)+" "+err[2]+"("+str(err[1])+"): "+str(sys.exc_info()[1]) sys.stderr.write("Database error: could not find hand %s.\n" % new_hand_id)
if new_hand_id: # new_hand_id is none if we had an error prior to the store
sys.stderr.write("Database error %s in hand %d. Skipping.\n" % (err, int(new_hand_id)))
continue continue
if type == "tour": # hand is from a tournament if type == "tour": # hand is from a tournament
mat_obj = tourny_finder.search(table_name) temp_key = tour_number
if mat_obj:
(tour_number, tab_number) = mat_obj.group(1, 2)
temp_key = tour_number
else: # tourney, but can't get number and table
print "could not find tournament: skipping "
#sys.stderr.write("Could not find tournament %d in hand %d. Skipping.\n" % (int(tour_number), int(new_hand_id)))
continue
else: else:
temp_key = table_name temp_key = table_name
# Update an existing HUD # Update an existing HUD
if temp_key in self.hud_dict: if temp_key in self.hud_dict:
try: # get stats using hud's specific params and get cards
# get stats using hud's specific params 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']) 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])
except:
err = traceback.extract_tb(sys.exc_info()[2])[-1]
print "db get_stats error: skipping "+str(new_hand_id)+" "+err[2]+"("+str(err[1])+"): "+str(sys.exc_info()[1])
if new_hand_id: # new_hand_id is none if we had an error prior to the store
sys.stderr.write("Database get_stats error %s in hand %d. Skipping.\n" % (err, int(new_hand_id)))
continue
self.hud_dict[temp_key].stat_dict = stat_dict self.hud_dict[temp_key].stat_dict = stat_dict
cards = self.db_connection.get_cards(new_hand_id)
comm_cards = self.db_connection.get_common_cards(new_hand_id)
if comm_cards != {}: # stud!
cards['common'] = comm_cards['common']
self.hud_dict[temp_key].cards = cards self.hud_dict[temp_key].cards = cards
[aw.update_data(new_hand_id, self.db_connection) for aw in self.hud_dict[temp_key].aux_windows] [aw.update_data(new_hand_id, self.db_connection) for aw in self.hud_dict[temp_key].aux_windows]
self.update_HUD(new_hand_id, temp_key, self.config) self.update_HUD(new_hand_id, temp_key, self.config)
# Or create a new HUD # Or create a new HUD
else: else:
try: # get stats using default params--also get cards
# get stats using default params 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'] ) stat_dict = self.db_connection.get_stats_from_hand(new_hand_id, type, self.hud_params, self.hero_ids[site_id])
stat_dict = self.db_connection.get_stats_from_hand(new_hand_id, type, self.hud_params, self.hero_ids[site_id]) cards = self.db_connection.get_cards(new_hand_id)
except: comm_cards = self.db_connection.get_common_cards(new_hand_id)
err = traceback.extract_tb(sys.exc_info()[2])[-1] if comm_cards != {}: # stud!
print "db get_stats error: skipping "+str(new_hand_id)+" "+err[2]+"("+str(err[1])+"): "+str(sys.exc_info()[1]) cards['common'] = comm_cards['common']
if new_hand_id: # new_hand_id is none if we had an error prior to the store
sys.stderr.write("Database get_stats error %s in hand %d. Skipping.\n" % (err, int(new_hand_id)))
continue
if type == "tour": if type == "tour":
tablewindow = Tables.discover_tournament_table(self.config, tour_number, tab_number) tablewindow = Tables.discover_tournament_table(self.config, tour_number, tab_number)
else: else:
tablewindow = Tables.discover_table_by_name(self.config, table_name) tablewindow = Tables.discover_table_by_name(self.config, table_name)
if tablewindow == None: if tablewindow is None:
# If no client window is found on the screen, complain and continue # If no client window is found on the screen, complain and continue
if type == "tour": if type == "tour":
table_name = "%s %s" % (tour_number, tab_number) table_name = "%s %s" % (tour_number, tab_number)
sys.stderr.write("table name "+table_name+" not found, skipping.\n") sys.stderr.write("HUD create: table name "+table_name+" not found, skipping.\n")
else: else:
self.create_HUD(new_hand_id, tablewindow, temp_key, max, poker_game, type, stat_dict, cards) self.create_HUD(new_hand_id, tablewindow, temp_key, max, poker_game, type, stat_dict, cards)
self.db_connection.connection.rollback() self.db_connection.connection.rollback()

View File

@ -37,7 +37,8 @@ if __name__== "__main__":
HUD_main.config = Configuration.Config() HUD_main.config = Configuration.Config()
gobject.threads_init() # this is required gobject.threads_init() # this is required
thread.start_new_thread(HUD_main.read_stdin, ()) # starts the thread hud = HUD_main.HUD_main()
thread.start_new_thread(hud.read_stdin, ()) # starts the thread
HUD_main.main_window = gtk.Window() HUD_main.main_window = gtk.Window()
HUD_main.main_window.connect("destroy", destroy) HUD_main.main_window.connect("destroy", destroy)

View File

@ -550,12 +550,12 @@ Map the tuple self.gametype onto the pokerstars string describing it
"""Return the first HH line for the current hand.""" """Return the first HH line for the current hand."""
gs = "PokerStars Game #%s: " % self.handid gs = "PokerStars Game #%s: " % self.handid
if self.tourNo != None and self.mixed != None: # mixed tournament if self.tourNo is not None and self.mixed is not None: # mixed tournament
gs = gs + "Tournament #%s, %s %s (%s) - Level %s (%s) - " % (self.tourNo, self.buyin, self.MS[self.mixed], self.getGameTypeAsString(), self.level, self.getStakesAsString()) gs = gs + "Tournament #%s, %s %s (%s) - Level %s (%s) - " % (self.tourNo, self.buyin, self.MS[self.mixed], self.getGameTypeAsString(), self.level, self.getStakesAsString())
elif self.tourNo != None: # all other tournaments elif self.tourNo is not None: # all other tournaments
gs = gs + "Tournament #%s, %s %s - Level %s (%s) - " % (self.tourNo, gs = gs + "Tournament #%s, %s %s - Level %s (%s) - " % (self.tourNo,
self.buyin, self.getGameTypeAsString(), self.level, self.getStakesAsString()) self.buyin, self.getGameTypeAsString(), self.level, self.getStakesAsString())
elif self.mixed != None: # all other mixed games elif self.mixed is not None: # all other mixed games
gs = gs + " %s (%s, %s) - " % (self.MS[self.mixed], gs = gs + " %s (%s, %s) - " % (self.MS[self.mixed],
self.getGameTypeAsString(), self.getStakesAsString()) self.getGameTypeAsString(), self.getStakesAsString())
else: # non-mixed cash games else: # non-mixed cash games
@ -628,7 +628,7 @@ class HoldemOmahaHand(Hand):
hhc.readShownCards(self) hhc.readShownCards(self)
self.totalPot() # finalise it (total the pot) self.totalPot() # finalise it (total the pot)
hhc.getRake(self) hhc.getRake(self)
if self.maxseats == None: if self.maxseats is None:
self.maxseats = hhc.guessMaxSeats(self) self.maxseats = hhc.guessMaxSeats(self)
hhc.readOther(self) hhc.readOther(self)
elif builtFrom == "DB": elif builtFrom == "DB":
@ -897,7 +897,7 @@ class DrawHand(Hand):
hhc.readShownCards(self) hhc.readShownCards(self)
self.totalPot() # finalise it (total the pot) self.totalPot() # finalise it (total the pot)
hhc.getRake(self) hhc.getRake(self)
if self.maxseats == None: if self.maxseats is None:
self.maxseats = hhc.guessMaxSeats(self) self.maxseats = hhc.guessMaxSeats(self)
hhc.readOther(self) hhc.readOther(self)
elif builtFrom == "DB": elif builtFrom == "DB":
@ -1073,7 +1073,7 @@ class StudHand(Hand):
hhc.readShownCards(self) # not done yet hhc.readShownCards(self) # not done yet
self.totalPot() # finalise it (total the pot) self.totalPot() # finalise it (total the pot)
hhc.getRake(self) hhc.getRake(self)
if self.maxseats == None: if self.maxseats is None:
self.maxseats = hhc.guessMaxSeats(self) self.maxseats = hhc.guessMaxSeats(self)
hhc.readOther(self) hhc.readOther(self)
elif builtFrom == "DB": elif builtFrom == "DB":

View File

@ -150,9 +150,9 @@ Otherwise, finish at EOF.
for handText in self.tailHands(): for handText in self.tailHands():
try: try:
self.processHand(handText) self.processHand(handText)
numHands+=1 numHands += 1
except FpdbParseError, e: except FpdbParseError, e:
numErrors+=1 numErrors += 1
log.warning("Failed to convert hand %s" % e.hid) log.warning("Failed to convert hand %s" % e.hid)
log.debug(handText) log.debug(handText)
else: else:
@ -166,7 +166,7 @@ Otherwise, finish at EOF.
try: try:
self.processedHands.append(self.processHand(handText)) self.processedHands.append(self.processHand(handText))
except FpdbParseError, e: except FpdbParseError, e:
numErrors+=1 numErrors += 1
log.warning("Failed to convert hand %s" % e.hid) log.warning("Failed to convert hand %s" % e.hid)
log.debug(handText) log.debug(handText)
numHands = len(handsList) numHands = len(handsList)
@ -195,7 +195,8 @@ This requires a regex that greedily groups and matches the 'splitter' between ha
which it expects to find at self.re_TailSplitHands -- see for e.g. Everleaf.py. which it expects to find at self.re_TailSplitHands -- see for e.g. Everleaf.py.
""" """
if self.in_path == '-': raise StopIteration if self.in_path == '-':
raise StopIteration
interval = 1.0 # seconds to sleep between reads for new data interval = 1.0 # seconds to sleep between reads for new data
fd = codecs.open(self.in_path,'r', self.codepage) fd = codecs.open(self.in_path,'r', self.codepage)
data = '' data = ''
@ -256,7 +257,7 @@ which it expects to find at self.re_TailSplitHands -- see for e.g. Everleaf.py.
self.readFile() self.readFile()
self.obs = self.obs.strip() self.obs = self.obs.strip()
self.obs = self.obs.replace('\r\n', '\n') self.obs = self.obs.replace('\r\n', '\n')
if self.obs == "" or self.obs == None: if self.obs is None or self.obs == "":
log.info("Read no hands.") log.info("Read no hands.")
return [] return []
return re.split(self.re_SplitHands, self.obs) return re.split(self.re_SplitHands, self.obs)
@ -396,7 +397,7 @@ or None if we fail to get the info """
if True: # basically.. I don't know if True: # basically.. I don't know
sane = True sane = True
if(self.in_path != '-' and self.out_path == self.in_path): if self.in_path != '-' and self.out_path == self.in_path:
print "HH Sanity Check: output and input files are the same, check config" print "HH Sanity Check: output and input files are the same, check config"
sane = False sane = False
@ -417,16 +418,19 @@ or None if we fail to get the info """
for l in list: for l in list:
# print "'" + l + "'" # print "'" + l + "'"
hands = hands + [Hand.Hand(self.sitename, self.gametype, l)] hands = hands + [Hand.Hand(self.sitename, self.gametype, l)]
# TODO: This looks like it could be replaced with a list comp.. ?
return hands return hands
def __listof(self, x): def __listof(self, x):
if isinstance(x, list) or isinstance(x, tuple): return x if isinstance(x, list) or isinstance(x, tuple):
else: return [x] return x
else:
return [x]
def readFile(self): def readFile(self):
"""Open in_path according to self.codepage. Exceptions caught further up""" """Open in_path according to self.codepage. Exceptions caught further up"""
if(self.filetype == "text"): if self.filetype == "text":
if self.in_path == '-': if self.in_path == '-':
# read from stdin # read from stdin
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?
@ -446,12 +450,15 @@ or None if we fail to get the info """
pass pass
else: else:
print "unable to read file with any codec in list!", self.in_path 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
def guessMaxSeats(self, hand): def guessMaxSeats(self, hand):
"""Return a guess at max_seats when not specified in HH.""" """Return a guess at maxseats when not specified in HH."""
# if some other code prior to this has already set it, return it
if maxseats > 1 and maxseats < 11:
return maxseats
mo = self.maxOccSeat(hand) mo = self.maxOccSeat(hand)
if mo == 10: return 10 #that was easy if mo == 10: return 10 #that was easy
@ -471,7 +478,8 @@ or None if we fail to get the info """
def maxOccSeat(self, hand): def maxOccSeat(self, hand):
max = 0 max = 0
for player in hand.players: for player in hand.players:
if player[0] > max: max = player[0] if player[0] > max:
max = player[0]
return max return max
def getStatus(self): def getStatus(self):

View File

@ -61,7 +61,7 @@ class Hud:
def __init__(self, parent, table, max, poker_game, config, db_connection): def __init__(self, parent, table, max, poker_game, config, db_connection):
# __init__ is (now) intended to be called from the stdin thread, so it # __init__ is (now) intended to be called from the stdin thread, so it
# cannot touch the gui # cannot touch the gui
if parent == None: # running from cli .. if parent is None: # running from cli ..
self.parent = self self.parent = self
self.parent = parent self.parent = parent
self.table = table self.table = table
@ -87,11 +87,6 @@ class Hud:
self.backgroundcolor = gtk.gdk.color_parse(self.colors['hudbgcolor']) self.backgroundcolor = gtk.gdk.color_parse(self.colors['hudbgcolor'])
self.foregroundcolor = gtk.gdk.color_parse(self.colors['hudfgcolor']) self.foregroundcolor = gtk.gdk.color_parse(self.colors['hudfgcolor'])
if font == None:
font = "Sans"
if font_size == None:
font_size = "8"
self.font = pango.FontDescription("%s %s" % (font, font_size)) self.font = pango.FontDescription("%s %s" % (font, font_size))
# do we need to add some sort of condition here for dealing with a request for a font that doesn't exist? # do we need to add some sort of condition here for dealing with a request for a font that doesn't exist?
@ -136,7 +131,7 @@ class Hud:
killitem = gtk.MenuItem('Kill This HUD') killitem = gtk.MenuItem('Kill This HUD')
menu.append(killitem) menu.append(killitem)
if self.parent != None: if self.parent is not None:
killitem.connect("activate", self.parent.kill_hud, self.table_name) killitem.connect("activate", self.parent.kill_hud, self.table_name)
saveitem = gtk.MenuItem('Save HUD Layout') saveitem = gtk.MenuItem('Save HUD Layout')
@ -455,6 +450,9 @@ class Hud:
# Need range here, not xrange -> need the actual list # Need range here, not xrange -> need the actual list
adj = range(0, self.max + 1) # default seat adjustments = no adjustment adj = range(0, self.max + 1) # default seat adjustments = no adjustment
# does the user have a fav_seat? # does the user have a fav_seat?
if self.max not in config.supported_sites[self.table.site].layout:
sys.stderr.write("No layout found for %d-max games for site %s\n" % (self.max, self.table.site) )
return adj
if self.table.site != None and int(config.supported_sites[self.table.site].layout[self.max].fav_seat) > 0: if self.table.site != None and int(config.supported_sites[self.table.site].layout[self.max].fav_seat) > 0:
try: try:
fav_seat = config.supported_sites[self.table.site].layout[self.max].fav_seat fav_seat = config.supported_sites[self.table.site].layout[self.max].fav_seat
@ -494,6 +492,10 @@ class Hud:
sys.stderr.write("------------------------------------------------------------\nCreating hud from hand %s\n" % hand) sys.stderr.write("------------------------------------------------------------\nCreating hud from hand %s\n" % hand)
adj = self.adj_seats(hand, config) adj = self.adj_seats(hand, config)
loc = self.config.get_locations(self.table.site, self.max) loc = self.config.get_locations(self.table.site, self.max)
if loc is None and self.max != 10:
loc = self.config.get_locations(self.table.site, 10)
if loc is None and self.max != 9:
loc = self.config.get_locations(self.table.site, 9)
# create the stat windows # create the stat windows
for i in xrange(1, self.max + 1): for i in xrange(1, self.max + 1):

View File

@ -479,7 +479,7 @@ class Flop_Mucked(Aux_Seats):
if i != "common": if i != "common":
id = self.get_id_from_seat(i) id = self.get_id_from_seat(i)
# sc: had KeyError here with new table so added id != None test as a guess: # sc: had KeyError here with new table so added id != None test as a guess:
if id != None: if id is not None:
self.m_windows[i].eb.set_tooltip_text(self.hud.stat_dict[id]['screen_name']) self.m_windows[i].eb.set_tooltip_text(self.hud.stat_dict[id]['screen_name'])
def update_gui(self, new_hand_id): def update_gui(self, new_hand_id):

View File

@ -164,7 +164,7 @@ class PokerStars(HandHistoryConverter):
if 'CURRENCY' in mg: if 'CURRENCY' in mg:
info['currency'] = currencies[mg['CURRENCY']] info['currency'] = currencies[mg['CURRENCY']]
if 'TOURNO' in mg and mg['TOURNO'] == None: if 'TOURNO' in mg and mg['TOURNO'] is None:
info['type'] = 'ring' info['type'] = 'ring'
else: else:
info['type'] = 'tour' info['type'] = 'tour'
@ -172,7 +172,6 @@ class PokerStars(HandHistoryConverter):
# 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.
return info return info
def readHandInfo(self, hand): def readHandInfo(self, hand):
info = {} info = {}
m = self.re_HandInfo.search(hand.handText,re.DOTALL) m = self.re_HandInfo.search(hand.handText,re.DOTALL)
@ -182,7 +181,8 @@ class PokerStars(HandHistoryConverter):
else: else:
pass # throw an exception here, eh? pass # throw an exception here, eh?
m = self.re_GameInfo.search(hand.handText) m = self.re_GameInfo.search(hand.handText)
if m: info.update(m.groupdict()) if m:
info.update(m.groupdict())
# m = self.re_Button.search(hand.handText) # m = self.re_Button.search(hand.handText)
# if m: info.update(m.groupdict()) # if m: info.update(m.groupdict())
# TODO : I rather like the idea of just having this dict as hand.info # TODO : I rather like the idea of just having this dict as hand.info
@ -205,8 +205,7 @@ class PokerStars(HandHistoryConverter):
hand.maxseats = int(info[key]) hand.maxseats = int(info[key])
if key == 'MIXED': if key == 'MIXED':
if info[key] == None: hand.mixed = None hand.mixed = self.mixes[info[key]] if info[key] is not None else None
else: hand.mixed = self.mixes[info[key]]
if key == 'TOURNO': if key == 'TOURNO':
hand.tourNo = info[key] hand.tourNo = info[key]
@ -214,7 +213,7 @@ class PokerStars(HandHistoryConverter):
hand.buyin = info[key] hand.buyin = info[key]
if key == 'LEVEL': if key == 'LEVEL':
hand.level = info[key] hand.level = info[key]
if key == 'PLAY' and info['PLAY'] != None: if key == 'PLAY' and info['PLAY'] is not None:
# hand.currency = 'play' # overrides previously set value # hand.currency = 'play' # overrides previously set value
hand.gametype['currency'] = 'play' hand.gametype['currency'] = 'play'
@ -304,11 +303,11 @@ class PokerStars(HandHistoryConverter):
m = self.re_HeroCards.finditer(hand.streets[street]) m = self.re_HeroCards.finditer(hand.streets[street])
for found in m: for found in m:
player = found.group('PNAME') player = found.group('PNAME')
if found.group('NEWCARDS') == None: if found.group('NEWCARDS') is None:
newcards = [] newcards = []
else: else:
newcards = found.group('NEWCARDS').split(' ') newcards = found.group('NEWCARDS').split(' ')
if found.group('OLDCARDS') == None: if found.group('OLDCARDS') is None:
oldcards = [] oldcards = []
else: else:
oldcards = found.group('OLDCARDS').split(' ') oldcards = found.group('OLDCARDS').split(' ')

File diff suppressed because it is too large Load Diff

View File

@ -68,14 +68,14 @@ def do_tip(widget, tip):
def do_stat(stat_dict, player = 24, stat = 'vpip'): def do_stat(stat_dict, player = 24, stat = 'vpip'):
match = re_Places.search(stat) match = re_Places.search(stat)
if match == None: if match is None:
result = eval("%(stat)s(stat_dict, %(player)d)" % {'stat': stat, 'player': player}) result = eval("%(stat)s(stat_dict, %(player)d)" % {'stat': stat, 'player': player})
else: else:
base = stat[0:-2] base = stat[0:-2]
places = int(stat[-1:]) places = int(stat[-1:])
result = eval("%(stat)s(stat_dict, %(player)d)" % {'stat': base, 'player': player}) result = eval("%(stat)s(stat_dict, %(player)d)" % {'stat': base, 'player': player})
match = re_Percent.search(result[1]) match = re_Percent.search(result[1])
if match == None: if match is None:
result = (result[0], "%.*f" % (places, result[0]), result[2], result[3], result[4], result[5]) result = (result[0], "%.*f" % (places, result[0]), result[2], result[3], result[4], result[5])
else: else:
result = (result[0], "%.*f%%" % (places, 100*result[0]), result[2], result[3], result[4], result[5]) result = (result[0], "%.*f%%" % (places, 100*result[0]), result[2], result[3], result[4], result[5])

View File

@ -95,12 +95,12 @@ gobject.signal_new("client_destroyed", gtk.Window,
class Table_Window(object): class Table_Window(object):
def __init__(self, table_name = None, tournament = None, table_number = None): def __init__(self, table_name = None, tournament = None, table_number = None):
if table_name != None: if table_name is not None:
search_string = table_name search_string = table_name
self.name = table_name self.name = table_name
self.tournament = None self.tournament = None
self.table = None self.table = None
elif tournament != None and table_number != None: elif tournament is not None and table_number is not None:
print "tournament %s, table %s" % (tournament, table_number) print "tournament %s, table %s" % (tournament, table_number)
self.tournament = int(tournament) self.tournament = int(tournament)
self.table = int(table_number) self.table = int(table_number)
@ -133,7 +133,7 @@ class Table_Window(object):
def check_geometry(self): def check_geometry(self):
new_geo = self.get_geometry() new_geo = self.get_geometry()
if new_geo == None: # window destroyed if new_geo is None: # window destroyed
return "client_destroyed" return "client_destroyed"
elif self.x != new_geo['x'] or self.y != new_geo['y']: # window moved elif self.x != new_geo['x'] or self.y != new_geo['y']: # window moved

View File

@ -105,7 +105,7 @@ def discover_table_by_name(c, tablename):
info = discover_mac_by_name(c, tablename) info = discover_mac_by_name(c, tablename)
else: else:
return None return None
if info == None: if info is None:
return None return None
return Table_Window(info) return Table_Window(info)
@ -141,7 +141,7 @@ def discover_posix(c):
if 'History for table:' in listing: continue if 'History for table:' in listing: continue
if 'has no name' in listing: continue if 'has no name' in listing: continue
info = decode_xwininfo(c, listing) info = decode_xwininfo(c, listing)
if info['site'] == None: continue if info['site'] is None: continue
if info['title'] == info['exe']: continue if info['title'] == info['exe']: continue
# this appears to be a poker client, so make a table object for it # this appears to be a poker client, so make a table object for it
tw = Table_Window(info) tw = Table_Window(info)

View File

@ -289,7 +289,7 @@ class ttracker_main(object):
tablewindow = Tables.discover_tournament_table(self.config, tour_number, tab_number) tablewindow = Tables.discover_tournament_table(self.config, tour_number, tab_number)
else: else:
tablewindow = Tables.discover_table_by_name(self.config, table_name) tablewindow = Tables.discover_table_by_name(self.config, table_name)
if tablewindow == None: if tablewindow is None:
# If no client window is found on the screen, complain and continue # If no client window is found on the screen, complain and continue
if type == "tour": if type == "tour":
table_name = "%s %s" % (tour_number, tab_number) table_name = "%s %s" % (tour_number, tab_number)

View File

@ -447,10 +447,10 @@ class fpdb:
self.settings.update(self.config.get_import_parameters()) self.settings.update(self.config.get_import_parameters())
self.settings.update(self.config.get_default_paths()) self.settings.update(self.config.get_default_paths())
if self.db != None and self.db.fdb != None: if self.db is not None and self.db.fdb is not None:
self.db.disconnect() self.db.disconnect()
self.sql = SQL.Sql(type = self.settings['db-type'], db_server = self.settings['db-server']) self.sql = SQL.Sql(db_server = self.settings['db-server'])
try: try:
self.db = Database.Database(self.config, sql = self.sql) self.db = Database.Database(self.config, sql = self.sql)
except FpdbMySQLFailedError: except FpdbMySQLFailedError:
@ -487,7 +487,7 @@ class fpdb:
response = diaDbVersionWarning.run() response = diaDbVersionWarning.run()
diaDbVersionWarning.destroy() diaDbVersionWarning.destroy()
if self.status_bar == None: if self.status_bar is None:
self.status_bar = gtk.Label("Status: Connected to %s database named %s on host %s"%(self.db.get_backend_name(),self.db.database, self.db.host)) self.status_bar = gtk.Label("Status: Connected to %s database named %s on host %s"%(self.db.get_backend_name(),self.db.database, self.db.host))
self.main_vbox.pack_end(self.status_bar, False, True, 0) self.main_vbox.pack_end(self.status_bar, False, True, 0)
self.status_bar.show() self.status_bar.show()
@ -513,10 +513,10 @@ class fpdb:
# self.lock.release() # self.lock.release()
def quit(self, widget, data=None): def quit(self, widget, data=None):
# TODO: can we get some / all of the stuff done in this function to execute on any kind of abort?
print "Quitting normally" print "Quitting normally"
#check if current settings differ from profile, if so offer to save or abort # TODO: check if current settings differ from profile, if so offer to save or abort
self.db.disconnect() self.db.disconnect()
# hide icon as it doesn't go away immediately in Windows - is this ok in Linux Eric?
self.statusIcon.set_visible(False) self.statusIcon.set_visible(False)
gtk.main_quit() gtk.main_quit()

View File

@ -33,12 +33,12 @@ except ImportError:
import fpdb_simple import fpdb_simple
import FpdbSQLQueries import FpdbSQLQueries
import Configuration
class fpdb_db: class fpdb_db:
MYSQL_INNODB = 2 MYSQL_INNODB = 2
PGSQL = 3 PGSQL = 3
SQLITE = 4 SQLITE = 4
sqlite_db_dir = ".." + os.sep + "database"
def __init__(self): def __init__(self):
"""Simple constructor, doesnt really do anything""" """Simple constructor, doesnt really do anything"""
@ -123,10 +123,10 @@ class fpdb_db:
else: else:
logging.warning("SQLite won't work well without 'sqlalchemy' installed.") logging.warning("SQLite won't work well without 'sqlalchemy' installed.")
if not os.path.isdir(self.sqlite_db_dir): if not os.path.isdir(Configuration.DIR_DATABASES):
print "Creating directory: '%s'" % (self.sqlite_db_dir) print "Creating directory: '%s'" % (Configuration.DIR_DATABASES)
os.mkdir(self.sqlite_db_dir) os.mkdir(Configuration.DIR_DATABASES)
self.db = sqlite3.connect( self.sqlite_db_dir + os.sep + database self.db = sqlite3.connect( os.path.join(Configuration.DIR_DATABASES, database)
, detect_types=sqlite3.PARSE_DECLTYPES ) , 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")

View File

@ -182,14 +182,15 @@ 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(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
#Only one import directory per site supported. #Only one import directory per site supported.
#dirlist is a hash of lists: #dirlist is a hash of lists:
#dirlist{ 'PokerStars' => ["/path/to/import/", "filtername"] } #dirlist{ 'PokerStars' => ["/path/to/import/", "filtername"] }
def addImportDirectory(self,dir,monitor = False, site = "default", filter = "passthrough"): def addImportDirectory(self,dir,monitor=False, site="default", filter="passthrough"):
#gets called by GuiAutoImport. #gets called by GuiAutoImport.
#This should really be using os.walk #This should really be using os.walk
#http://docs.python.org/library/os.html #http://docs.python.org/library/os.html
@ -203,7 +204,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:
log.warning("Attempted to add non-directory: '" + str(dir) + "' as an import directory") log.warning("Attempted to add non-directory: '%s' as an import directory" % str(dir))
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"""
@ -250,6 +251,9 @@ class Importer:
#self.writeq.join() #self.writeq.join()
#using empty() might be more reliable: #using empty() might be more reliable:
while not self.writeq.empty() and len(threading.enumerate()) > 1: while not self.writeq.empty() and len(threading.enumerate()) > 1:
# TODO: Do we need to actually tell the progress indicator to move, or is it already moving, and we just need to process events...
while gtk.events_pending(): # see http://faq.pygtk.org/index.py?req=index for more hints (3.7)
gtk.main_iteration(False)
sleep(0.5) sleep(0.5)
print " ... writers finished" print " ... writers finished"
@ -400,7 +404,7 @@ class Importer:
file = file.decode(fpdb_simple.LOCALE_ENCODING) file = file.decode(fpdb_simple.LOCALE_ENCODING)
# 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 is not None:
log.info("Converting " + file + " (" + str(q.qsize()) + ")") log.info("Converting " + file + " (" + str(q.qsize()) + ")")
else: else:
log.info("Converting " + file) log.info("Converting " + file)
@ -418,9 +422,9 @@ class Importer:
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.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:
#This code doesn't do anything yet #This code doesn't do anything yet
handlist = hhc.getProcessedHands() handlist = hhc.getProcessedHands()
self.pos_in_file[file] = hhc.getLastCharacterRead() self.pos_in_file[file] = hhc.getLastCharacterRead()
@ -458,7 +462,7 @@ class Importer:
loc = self.pos_in_file[file] loc = self.pos_in_file[file]
#size = os.path.getsize(file) #size = os.path.getsize(file)
#print "loc =", loc, 'size =', size #print "loc =", loc, 'size =', size
except: except KeyError:
pass pass
# Read input file into class and close file # Read input file into class and close file
inputFile.seek(loc) inputFile.seek(loc)
@ -475,20 +479,20 @@ class Importer:
db.commit() db.commit()
ttime = time() - starttime ttime = time() - starttime
if q == None: if q is None:
log.info("Total stored: %(stored)d\tduplicates:%(duplicates)d\terrors:%(errors)d\ttime:%(ttime)s" % locals()) 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:
for line_no in xrange(len(self.lines)): for line_no in xrange(len(self.lines)):
if self.lines[line_no].find("Game #")!=-1: if self.lines[line_no].find("Game #") != -1:
final_game_line=self.lines[line_no] final_game_line = self.lines[line_no]
handsId=fpdb_simple.parseSiteHandNo(final_game_line) handsId=fpdb_simple.parseSiteHandNo(final_game_line)
else: else:
print "failed to read a single hand from file:", inputFile print "failed to read a single hand from file:", inputFile
handsId=0 handsId = 0
#todo: this will cause return of an unstored hand number if the last hand was error #todo: this will cause return of an unstored hand number if the last hand was error
self.handsId=handsId self.handsId = handsId
return (stored, duplicates, partial, errors, ttime) return (stored, duplicates, partial, errors, ttime)
# end def import_fpdb_file # end def import_fpdb_file
@ -508,13 +512,13 @@ class Importer:
#print "DEBUG: import_fpdb_file: failed on lines[0]: '%s' '%s' '%s' '%s' " %( file, site, lines, loc) #print "DEBUG: import_fpdb_file: failed on lines[0]: '%s' '%s' '%s' '%s' " %( file, site, lines, loc)
return (0,0,0,1,0,0) return (0,0,0,1,0,0)
if firstline.find("Tournament Summary")!=-1: if "Tournament Summary" in firstline:
print "TODO: implement importing tournament summaries" print "TODO: implement importing tournament summaries"
#self.faobs = readfile(inputFile) #self.faobs = readfile(inputFile)
#self.parseTourneyHistory() #self.parseTourneyHistory()
return (0,0,0,1,0,0) return (0,0,0,1,0,0)
category=fpdb_simple.recogniseCategory(firstline) category = fpdb_simple.recogniseCategory(firstline)
startpos = 0 startpos = 0
stored = 0 #counter stored = 0 #counter
@ -524,24 +528,23 @@ class Importer:
ttime = 0 ttime = 0
handsId = 0 handsId = 0
for i in xrange (len(lines)): for i in xrange(len(lines)):
if (len(lines[i])<2): #Wierd way to detect for '\r\n' or '\n' if len(lines[i]) < 2: #Wierd way to detect for '\r\n' or '\n'
endpos=i endpos = i
hand=lines[startpos:endpos] hand = lines[startpos:endpos]
if (len(hand[0])<2): if len(hand[0]) < 2:
hand=hand[1:] hand=hand[1:]
if len(hand) < 3:
if (len(hand)<3):
pass pass
#TODO: This is ugly - we didn't actually find the start of the #TODO: This is ugly - we didn't actually find the start of the
# hand with the outer loop so we test again... # hand with the outer loop so we test again...
else: else:
isTourney=fpdb_simple.isTourney(hand[0]) isTourney = fpdb_simple.isTourney(hand[0])
if not isTourney: if not isTourney:
hand = fpdb_simple.filterAnteBlindFold(hand) hand = fpdb_simple.filterAnteBlindFold(hand)
self.hand=hand self.hand = hand
try: try:
handsId = fpdb_parse_logic.mainParser( self.settings, self.siteIds[site] handsId = fpdb_parse_logic.mainParser( self.settings, self.siteIds[site]
@ -553,7 +556,7 @@ class Importer:
if self.callHud: if self.callHud:
#print "call to HUD here. handsId:",handsId #print "call to HUD here. handsId:",handsId
#pipe the Hands.id out to the HUD #pipe the Hands.id out to the HUD
print "sending hand to hud", handsId, "pipe =", self.caller.pipe_to_hud print "fpdb_import: sending hand to hud", handsId, "pipe =", self.caller.pipe_to_hud
self.caller.pipe_to_hud.stdin.write("%s" % (handsId) + os.linesep) self.caller.pipe_to_hud.stdin.write("%s" % (handsId) + os.linesep)
except Exceptions.DuplicateError: except Exceptions.DuplicateError:
duplicates += 1 duplicates += 1

View File

@ -30,7 +30,7 @@ def mainParser(settings, siteID, category, hand, config, db = None, writeq = Non
backend = settings['db-backend'] backend = settings['db-backend']
# Ideally db connection is passed in, if not use sql list if passed in, # Ideally db connection is passed in, if not use sql list if passed in,
# otherwise start from scratch # otherwise start from scratch
if db == None: if db is None:
db = Database.Database(c = config, sql = None) db = Database.Database(c = config, sql = None)
category = fpdb_simple.recogniseCategory(hand[0]) category = fpdb_simple.recogniseCategory(hand[0])
@ -222,7 +222,7 @@ def mainParser(settings, siteID, category, hand, config, db = None, writeq = Non
, actionNos, hudImportData, maxSeats, tableName, seatNos) , actionNos, hudImportData, maxSeats, tableName, seatNos)
# save hand in db via direct call or via q if in a thread # save hand in db via direct call or via q if in a thread
if writeq == None: if writeq is None:
result = db.store_the_hand(htw) result = db.store_the_hand(htw)
else: else:
writeq.put(htw) writeq.put(htw)

View File

@ -60,14 +60,10 @@ class InterProcessLockBase:
self._has_lock = False self._has_lock = False
def locked(self): def locked(self):
if self._has_lock: if self.acquire():
return True
try:
self.acquire()
self.release() self.release()
return False return False
except SingleInstanceError: return True
return True
LOCK_FILE_DIRECTORY = '/tmp' LOCK_FILE_DIRECTORY = '/tmp'
@ -162,38 +158,33 @@ def test_construct():
>>> lock1 = InterProcessLock(name=test_name) >>> lock1 = InterProcessLock(name=test_name)
>>> lock1.acquire() >>> lock1.acquire()
True
>>> lock2 = InterProcessLock(name=test_name) >>> lock2 = InterProcessLock(name=test_name)
>>> lock3 = InterProcessLock(name=test_name) >>> lock3 = InterProcessLock(name=test_name)
# Since lock1 is locked, other attempts to acquire it fail. # Since lock1 is locked, other attempts to acquire it fail.
>>> lock2.acquire() >>> lock2.acquire()
Traceback (most recent call last): False
...
SingleInstanceError: Could not acquire exclusive lock on /tmp/test.lck
>>> lock3.acquire() >>> lock3.acquire()
Traceback (most recent call last): False
...
SingleInstanceError: Could not acquire exclusive lock on /tmp/test.lck
# Release the lock and let lock2 have it. # Release the lock and let lock2 have it.
>>> lock1.release() >>> lock1.release()
>>> lock2.acquire() >>> lock2.acquire()
True
>>> lock3.acquire() >>> lock3.acquire()
Traceback (most recent call last): False
...
SingleInstanceError: Could not acquire exclusive lock on /tmp/test.lck
# Release it and give it back to lock1 # Release it and give it back to lock1
>>> lock2.release() >>> lock2.release()
>>> lock1.acquire() >>> lock1.acquire()
True
>>> lock2.acquire() >>> lock2.acquire()
Traceback (most recent call last): False
...
SingleInstanceError: Could not acquire exclusive lock on /tmp/test.lck
# Test lock status # Test lock status
>>> lock2.locked() >>> lock2.locked()
@ -224,7 +215,7 @@ def test_construct():
... import win32con ... import win32con
... import pywintypes ... import pywintypes
... handle = win32api.OpenProcess(win32con.PROCESS_TERMINATE , pywintypes.FALSE, pid) ... handle = win32api.OpenProcess(win32con.PROCESS_TERMINATE , pywintypes.FALSE, pid)
... return (0 != win32api.TerminateProcess(handle, 0)) ... #return (0 != win32api.TerminateProcess(handle, 0))
# Test to acquire the lock in another process. # Test to acquire the lock in another process.
>>> def execute(cmd): >>> def execute(cmd):
@ -237,15 +228,14 @@ def test_construct():
>>> pid = execute('import interlocks;a=interlocks.InterProcessLock(name=\\''+test_name+ '\\');a.acquire();') >>> pid = execute('import interlocks;a=interlocks.InterProcessLock(name=\\''+test_name+ '\\');a.acquire();')
>>> lock1.acquire() >>> lock1.acquire()
Traceback (most recent call last): False
...
SingleInstanceError: Could not acquire exclusive lock on /tmp/test.lck
>>> os_independent_kill(pid) >>> os_independent_kill(pid)
>>> time.sleep(1) >>> time.sleep(1)
>>> lock1.acquire() >>> lock1.acquire()
True
>>> lock1.release() >>> lock1.release()
# Testing wait # Testing wait
@ -253,13 +243,12 @@ def test_construct():
>>> pid = execute('import interlocks;a=interlocks.InterProcessLock(name=\\''+test_name+ '\\');a.acquire();') >>> pid = execute('import interlocks;a=interlocks.InterProcessLock(name=\\''+test_name+ '\\');a.acquire();')
>>> lock1.acquire() >>> lock1.acquire()
Traceback (most recent call last): False
...
SingleInstanceError: Could not acquire exclusive lock on /tmp/test.lck
>>> os_independent_kill(pid) >>> os_independent_kill(pid)
>>> lock1.acquire(True) >>> lock1.acquire(True)
True
>>> lock1.release() >>> lock1.release()
""" """