Merge branch 'master' of git://git.assembla.com/fpdboz
This commit is contained in:
commit
9bbca552ea
|
@ -191,7 +191,7 @@ class Betfair(HandHistoryConverter):
|
|||
elif action.group('ATYPE') == 'checks':
|
||||
hand.addCheck( street, action.group('PNAME'))
|
||||
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):
|
||||
|
|
|
@ -67,7 +67,7 @@ class CarbonPoker(HandHistoryConverter):
|
|||
if(type == "Holdem"):
|
||||
gametype = gametype + ["hold"]
|
||||
else:
|
||||
print "Unknown gametype: '%s'" % (type)
|
||||
print "Carbon: Unknown gametype: '%s'" % (type)
|
||||
|
||||
stakes = desc_node[0].getAttribute("stakes")
|
||||
#TODO: no examples of anything except nlhe
|
||||
|
|
|
@ -44,14 +44,35 @@ except ConfigParser.NoSectionError: # debian package path
|
|||
|
||||
log = logging.getLogger("config")
|
||||
log.debug("config logger initialised")
|
||||
########################################################################
|
||||
# application wide consts
|
||||
|
||||
def fix_tf(x, default = True):
|
||||
# The xml parser doesn't translate "True" to True. Therefore, we never get
|
||||
# True or False from the parser only "True" or "False". So translate the
|
||||
# string to the python boolean representation.
|
||||
if x == "1" or x == 1 or string.lower(x) == "true" or string.lower(x) == "t":
|
||||
APPLICATION_NAME_SHORT = 'fpdb'
|
||||
APPLICATION_VERSION = 'xx.xx.xx'
|
||||
|
||||
DIR_SELF = os.path.dirname(os.path.abspath(__file__))
|
||||
#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
|
||||
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 default
|
||||
|
||||
|
@ -106,29 +127,22 @@ class Site:
|
|||
self.font = node.getAttribute("font")
|
||||
self.font_size = node.getAttribute("font_size")
|
||||
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.ypad = node.getAttribute("ypad")
|
||||
self.layout = {}
|
||||
|
||||
print self.site_name, self.HH_path
|
||||
print "Loading site", self.site_name
|
||||
|
||||
for layout_node in node.getElementsByTagName('layout'):
|
||||
lo = Layout(layout_node)
|
||||
self.layout[lo.max] = lo
|
||||
|
||||
# Site defaults
|
||||
if self.xpad == "": self.xpad = 1
|
||||
else: self.xpad = int(self.xpad)
|
||||
|
||||
if self.ypad == "": self.ypad = 0
|
||||
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)
|
||||
self.xpad = 1 if self.xpad == "" else 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)
|
||||
self.hudopacity = 1.0 if self.hudopacity == "" else float(self.hudopacity)
|
||||
|
||||
if self.use_frames == "": self.use_frames = False
|
||||
if self.font == "": self.font = "Sans"
|
||||
|
@ -208,14 +222,13 @@ class Game:
|
|||
class Database:
|
||||
def __init__(self, node):
|
||||
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_user = node.getAttribute("db_user")
|
||||
self.db_type = node.getAttribute("db_type")
|
||||
self.db_pass = node.getAttribute("db_pass")
|
||||
self.db_selected = fix_tf(node.getAttribute("default"),"False")
|
||||
log.debug("Database db_name:'%(name)s' db_server:'%(server)s' db_ip:'%(ip)s' db_user:'%(user)s' db_type:'%(type)s' db_pass (not logged) selected:'%(sel)s'" \
|
||||
% { 'name':self.db_name, 'server':self.db_server, 'ip':self.db_ip, 'user':self.db_user, 'type':self.db_type, 'sel':self.db_selected} )
|
||||
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_pass (not logged) selected:'%(sel)s'" \
|
||||
% { 'name':self.db_name, 'server':self.db_server, 'ip':self.db_ip, 'user':self.db_user, 'sel':self.db_selected} )
|
||||
|
||||
def __str__(self):
|
||||
temp = 'Database = ' + self.db_name + '\n'
|
||||
|
@ -277,8 +290,8 @@ class Import:
|
|||
self.interval = node.getAttribute("interval")
|
||||
self.callFpdbHud = node.getAttribute("callFpdbHud")
|
||||
self.hhArchiveBase = node.getAttribute("hhArchiveBase")
|
||||
self.saveActions = fix_tf(node.getAttribute("saveActions"), True)
|
||||
self.fastStoreHudCache = fix_tf(node.getAttribute("fastStoreHudCache"), False)
|
||||
self.saveActions = string_to_bool(node.getAttribute("saveActions"), default=True)
|
||||
self.fastStoreHudCache = string_to_bool(node.getAttribute("fastStoreHudCache"), default=False)
|
||||
|
||||
def __str__(self):
|
||||
return " interval = %s\n callFpdbHud = %s\n hhArchiveBase = %s\n saveActions = %s\n fastStoreHudCache = %s\n" \
|
||||
|
@ -289,14 +302,14 @@ class HudUI:
|
|||
self.node = node
|
||||
self.label = node.getAttribute('label')
|
||||
#
|
||||
self.aggregate_ring = fix_tf(node.getAttribute('aggregate_ring_game_stats'))
|
||||
self.aggregate_tour = fix_tf(node.getAttribute('aggregate_tourney_stats'))
|
||||
self.aggregate_ring = string_to_bool(node.getAttribute('aggregate_ring_game_stats'))
|
||||
self.aggregate_tour = string_to_bool(node.getAttribute('aggregate_tourney_stats'))
|
||||
self.hud_style = node.getAttribute('stat_aggregation_range')
|
||||
self.hud_days = node.getAttribute('aggregation_days')
|
||||
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_tour = fix_tf(node.getAttribute('aggregate_hero_tourney_stats'))
|
||||
self.h_aggregate_ring = string_to_bool(node.getAttribute('aggregate_hero_ring_game_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_days = node.getAttribute('hero_aggregation_days')
|
||||
self.h_agg_bb_mult = node.getAttribute('hero_aggregation_level_multiplier')
|
||||
|
@ -308,9 +321,9 @@ class HudUI:
|
|||
|
||||
class Tv:
|
||||
def __init__(self, node):
|
||||
self.combinedStealFold = node.getAttribute("combinedStealFold")
|
||||
self.combined2B3B = node.getAttribute("combined2B3B")
|
||||
self.combinedPostflop = node.getAttribute("combinedPostflop")
|
||||
self.combinedStealFold = string_to_bool(node.getAttribute("combinedStealFold"), default=True)
|
||||
self.combined2B3B = string_to_bool(node.getAttribute("combined2B3B"), default=True)
|
||||
self.combinedPostflop = string_to_bool(node.getAttribute("combinedPostflop"), default=True)
|
||||
|
||||
def __str__(self):
|
||||
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
|
||||
|
||||
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)
|
||||
if not os.path.exists(file):
|
||||
print "Configuration file %s not found. Using defaults." % (file)
|
||||
sys.stderr.write("Configuration file %s not found. Using defaults." % (file))
|
||||
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
|
||||
|
||||
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
|
||||
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"
|
||||
sys.stderr.write("No HUD_config_xml found after looking in current directory and "+self.default_config_path+"\nExiting")
|
||||
print "press enter to continue"
|
||||
|
@ -367,10 +378,13 @@ class Config:
|
|||
self.file = file
|
||||
self.supported_sites = {}
|
||||
self.supported_games = {}
|
||||
self.supported_databases = {}
|
||||
self.supported_databases = {} # databaseName --> Database instance
|
||||
self.aux_windows = {}
|
||||
self.hhcs = {}
|
||||
self.popup_windows = {}
|
||||
self.db_selected = None # database the user would like to use
|
||||
self.tv = None
|
||||
|
||||
|
||||
# s_sites = doc.getElementsByTagName("supported_sites")
|
||||
for site_node in doc.getElementsByTagName("site"):
|
||||
|
@ -382,29 +396,26 @@ class Config:
|
|||
game = Game(node = game_node)
|
||||
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")
|
||||
# select database from those defined in config by:
|
||||
# 1) command line option
|
||||
# or 2) selected="True" in config element
|
||||
# or 3) just choose the first we come across
|
||||
#TODO: do we want to take all <database> tags or all <database> tags contained in <supported_databases>
|
||||
# ..this may break stuff for some users. so leave it unchanged for now untill there is a decission
|
||||
for db_node in doc.getElementsByTagName("database"):
|
||||
try:
|
||||
db = Database(node=db_node)
|
||||
except:
|
||||
raise FpdbError("Unable to create database object")
|
||||
else:
|
||||
if db.db_name in self.supported_databases:
|
||||
raise FpdbError("Database names must be unique")
|
||||
# If there is only one Database node, or none are marked
|
||||
# default, use first
|
||||
if not self.supported_databases:
|
||||
raise ValueError("Database names must be unique")
|
||||
if self.db_selected is None or db.db_selected:
|
||||
self.db_selected = db.db_name
|
||||
self.supported_databases[db.db_name] = db
|
||||
if db.db_selected:
|
||||
self.db_selected = db.db_name
|
||||
|
||||
#TODO: if the user may passes '' (empty string) as database name via command line, his choice is ignored
|
||||
# ..when we parse the xml we allow for ''. there has to be a decission if to allow '' or not
|
||||
if dbname and dbname in self.supported_databases:
|
||||
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")
|
||||
for aw_node in doc.getElementsByTagName("aw"):
|
||||
|
@ -430,13 +441,12 @@ class Config:
|
|||
self.ui = hui
|
||||
|
||||
for tv_node in doc.getElementsByTagName("tv"):
|
||||
tv = Tv(node = tv_node)
|
||||
self.tv = tv
|
||||
self.tv = Tv(node = tv_node)
|
||||
|
||||
db = self.get_db_parameters()
|
||||
if db['db-password'] == 'YOUR MYSQL PASSWORD':
|
||||
df_file = self.find_default_conf()
|
||||
if df_file == None: # this is bad
|
||||
if df_file is None: # this is bad
|
||||
pass
|
||||
else:
|
||||
df_parms = self.read_default_conf(df_file)
|
||||
|
@ -527,7 +537,7 @@ class Config:
|
|||
|
||||
def get_layout_node(self, site_node, layout):
|
||||
for layout_node in site_node.getElementsByTagName("layout"):
|
||||
if layout_node.getAttribute("max") == None:
|
||||
if layout_node.getAttribute("max") is None:
|
||||
return None
|
||||
if int( layout_node.getAttribute("max") ) == int( layout ):
|
||||
return layout_node
|
||||
|
@ -543,19 +553,21 @@ class Config:
|
|||
return location_node
|
||||
|
||||
def save(self, file = None):
|
||||
if file != None:
|
||||
if file is not None:
|
||||
with open(file, 'w') as f:
|
||||
self.doc.writexml(f)
|
||||
else:
|
||||
shutil.move(self.file, self.file+".backup")
|
||||
with open(self.file, 'w') as f:
|
||||
with open(file, 'w') as f:
|
||||
self.doc.writexml(f)
|
||||
|
||||
def edit_layout(self, site_name, max, width = None, height = None,
|
||||
fav_seat = None, locations = None):
|
||||
site_node = self.get_site_node(site_name)
|
||||
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):
|
||||
location_node = self.get_location_node(layout_node, i)
|
||||
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):
|
||||
aux_node = self.get_aux_node(aux_name)
|
||||
layout_node = self.get_layout_node(aux_node, max)
|
||||
if layout_node == None:
|
||||
if layout_node is None:
|
||||
print "aux node not found"
|
||||
return
|
||||
print "editing locations =", locations
|
||||
|
@ -578,6 +590,13 @@ class Config:
|
|||
else:
|
||||
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):
|
||||
db = {}
|
||||
name = self.db_selected
|
||||
|
@ -597,33 +616,31 @@ class Config:
|
|||
try: db['db-server'] = self.supported_databases[name].db_server
|
||||
except: pass
|
||||
|
||||
try: db['db-type'] = self.supported_databases[name].db_type
|
||||
except: pass
|
||||
|
||||
if string.lower(self.supported_databases[name].db_server) == 'mysql':
|
||||
if self.supported_databases[name].db_server== DATABASE_TYPE_MYSQL:
|
||||
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
|
||||
elif string.lower(self.supported_databases[name].db_server) == 'sqlite':
|
||||
elif self.supported_databases[name].db_server== DATABASE_TYPE_SQLITE:
|
||||
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
|
||||
|
||||
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)
|
||||
if db_node != None:
|
||||
if db_ip != None: db_node.setAttribute("db_ip", db_ip)
|
||||
if db_user != None: db_node.setAttribute("db_user", db_user)
|
||||
if db_pass != None: db_node.setAttribute("db_pass", db_pass)
|
||||
if db_server != None: db_node.setAttribute("db_server", db_server)
|
||||
if db_type != None: db_node.setAttribute("db_type", db_type)
|
||||
if db_ip is not None: db_node.setAttribute("db_ip", db_ip)
|
||||
if db_user is not None: db_node.setAttribute("db_user", db_user)
|
||||
if db_pass is not None: db_node.setAttribute("db_pass", db_pass)
|
||||
if db_server is not None: db_node.setAttribute("db_server", db_server)
|
||||
if db_type is not None: db_node.setAttribute("db_type", db_type)
|
||||
if self.supported_databases.has_key(db_name):
|
||||
if db_ip != 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_pass != 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_type != None: self.supported_databases[db_name].dp_type = db_type
|
||||
if db_ip is not None: self.supported_databases[db_name].dp_ip = db_ip
|
||||
if db_user is not None: self.supported_databases[db_name].dp_user = db_user
|
||||
if db_pass is not None: self.supported_databases[db_name].dp_pass = db_pass
|
||||
if db_server is not None: self.supported_databases[db_name].dp_server = db_server
|
||||
if db_type is not None: self.supported_databases[db_name].dp_type = db_type
|
||||
return
|
||||
|
||||
def getDefaultSite(self):
|
||||
|
@ -634,16 +651,13 @@ class Config:
|
|||
return None
|
||||
|
||||
def get_tv_parameters(self):
|
||||
tv = {}
|
||||
try: tv['combinedStealFold'] = self.tv.combinedStealFold
|
||||
except: tv['combinedStealFold'] = True
|
||||
|
||||
try: tv['combined2B3B'] = self.tv.combined2B3B
|
||||
except: tv['combined2B3B'] = True
|
||||
|
||||
try: tv['combinedPostflop'] = self.tv.combinedPostflop
|
||||
except: tv['combinedPostflop'] = True
|
||||
return tv
|
||||
if self.tv is not None:
|
||||
return {
|
||||
'combinedStealFold': self.tv.combinedStealFold,
|
||||
'combined2B3B': self.tv.combined2B3B,
|
||||
'combinedPostflop': self.tv.combinedPostflop
|
||||
}
|
||||
return {}
|
||||
|
||||
# Allow to change the menu appearance
|
||||
def get_hud_ui_parameters(self):
|
||||
|
@ -742,29 +756,27 @@ class Config:
|
|||
return colors
|
||||
|
||||
def get_default_font(self, site='PokerStars'):
|
||||
(font, font_size) = ("Sans", "8")
|
||||
if site not in self.supported_sites:
|
||||
return ("Sans", "8")
|
||||
if self.supported_sites[site].font == "":
|
||||
font = "Sans"
|
||||
else:
|
||||
font = self.supported_sites[site].font
|
||||
|
||||
if self.supported_sites[site].font_size == "":
|
||||
font_size = "8"
|
||||
else:
|
||||
font_size = self.supported_sites[site].font_size
|
||||
return (font, font_size)
|
||||
site = self.supported_sites.get(site, None)
|
||||
if site is not None:
|
||||
if site.font:
|
||||
font = site.font
|
||||
if site.font_size:
|
||||
font_size = site.font_size
|
||||
return font, font_size
|
||||
|
||||
def get_locations(self, site = "PokerStars", max = "8"):
|
||||
|
||||
try:
|
||||
locations = self.supported_sites[site].layout[max].location
|
||||
except:
|
||||
locations = ( ( 0, 0), (684, 61), (689, 239), (692, 346),
|
||||
def get_locations(self, site_name="PokerStars", max=8):
|
||||
site = self.supported_sites.get(site_name, None)
|
||||
if site is not None:
|
||||
location = site.layout.get(max, None)
|
||||
if location is not None:
|
||||
return location.location
|
||||
return (
|
||||
( 0, 0), (684, 61), (689, 239), (692, 346),
|
||||
(586, 393), (421, 440), (267, 440), ( 0, 361),
|
||||
( 0, 280), (121, 280), ( 46, 30) )
|
||||
return locations
|
||||
( 0, 280), (121, 280), ( 46, 30)
|
||||
)
|
||||
|
||||
def get_aux_locations(self, aux = "mucked", max = "9"):
|
||||
|
||||
|
@ -778,12 +790,10 @@ class Config:
|
|||
|
||||
def get_supported_sites(self, all=False):
|
||||
"""Returns the list of supported sites."""
|
||||
the_sites = []
|
||||
for site in self.supported_sites.keys():
|
||||
params = self.get_site_parameters(site)
|
||||
if all or params['enabled']:
|
||||
the_sites.append(site)
|
||||
return the_sites
|
||||
if all:
|
||||
return self.supported_sites.keys()
|
||||
else:
|
||||
return [site_name for (site_name, site) in self.supported_sites.items() if site.enabled]
|
||||
|
||||
def get_site_parameters(self, site):
|
||||
"""Returns a dict of the site parameters for the specified site"""
|
||||
|
@ -814,27 +824,24 @@ class Config:
|
|||
font = None, font_size = None):
|
||||
"""Sets the specified site parameters for the specified site."""
|
||||
site_node = self.get_site_node(site_name)
|
||||
if db_node != None:
|
||||
if converter != None: site_node.setAttribute("converter", converter)
|
||||
if decoder != None: site_node.setAttribute("decoder", decoder)
|
||||
if hudbgcolor != None: site_node.setAttribute("hudbgcolor", hudbgcolor)
|
||||
if hudfgcolor != None: site_node.setAttribute("hudfgcolor", hudfgcolor)
|
||||
if hudopacity != None: site_node.setAttribute("hudopacity", hudopacity)
|
||||
if screen_name != None: site_node.setAttribute("screen_name", screen_name)
|
||||
if site_path != None: site_node.setAttribute("site_path", site_path)
|
||||
if table_finder != None: site_node.setAttribute("table_finder", table_finder)
|
||||
if HH_path != None: site_node.setAttribute("HH_path", HH_path)
|
||||
if enabled != None: site_node.setAttribute("enabled", enabled)
|
||||
if font != None: site_node.setAttribute("font", font)
|
||||
if font_size != None: site_node.setAttribute("font_size", font_size)
|
||||
if db_node is not None:
|
||||
if converter is not None: site_node.setAttribute("converter", converter)
|
||||
if decoder is not None: site_node.setAttribute("decoder", decoder)
|
||||
if hudbgcolor is not None: site_node.setAttribute("hudbgcolor", hudbgcolor)
|
||||
if hudfgcolor is not None: site_node.setAttribute("hudfgcolor", hudfgcolor)
|
||||
if hudopacity is not None: site_node.setAttribute("hudopacity", hudopacity)
|
||||
if screen_name is not None: site_node.setAttribute("screen_name", screen_name)
|
||||
if site_path is not None: site_node.setAttribute("site_path", site_path)
|
||||
if table_finder is not None: site_node.setAttribute("table_finder", table_finder)
|
||||
if HH_path is not None: site_node.setAttribute("HH_path", HH_path)
|
||||
if enabled is not None: site_node.setAttribute("enabled", enabled)
|
||||
if font is not None: site_node.setAttribute("font", font)
|
||||
if font_size is not None: site_node.setAttribute("font_size", font_size)
|
||||
return
|
||||
|
||||
def get_aux_windows(self):
|
||||
"""Gets the list of mucked window formats in the configuration."""
|
||||
mw = []
|
||||
for w in self.aux_windows.keys():
|
||||
mw.append(w)
|
||||
return mw
|
||||
return self.aux_windows.keys()
|
||||
|
||||
def get_aux_parameters(self, name):
|
||||
"""Gets a dict of mucked window parameters from the named mw."""
|
||||
|
|
|
@ -205,7 +205,7 @@ class Database:
|
|||
|
||||
# where possible avoid creating new SQL instance by using the global one passed in
|
||||
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:
|
||||
self.sql = sql
|
||||
|
||||
|
@ -249,7 +249,6 @@ class Database:
|
|||
|
||||
db_params = c.get_db_parameters()
|
||||
self.import_options = c.get_import_parameters()
|
||||
self.type = db_params['db-type']
|
||||
self.backend = db_params['db-backend']
|
||||
self.db_server = db_params['db-server']
|
||||
self.database = db_params['db-databaseName']
|
||||
|
@ -292,6 +291,21 @@ class Database:
|
|||
row = c.fetchone()
|
||||
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):
|
||||
c = self.connection.cursor()
|
||||
c.execute(self.sql.query['get_last_hand'])
|
||||
|
@ -353,7 +367,7 @@ class Database:
|
|||
# else:
|
||||
# cards += ranks[d['card' + str(i) + 'Value']] + d['card' +str(i) + 'Suit']
|
||||
cv = "card%dvalue" % i
|
||||
if cv not in d or d[cv] == None:
|
||||
if cv not in d or d[cv] is None:
|
||||
break
|
||||
elif d[cv] == 0:
|
||||
cards += "xx"
|
||||
|
@ -395,7 +409,7 @@ class Database:
|
|||
row = c.fetchone()
|
||||
except: # TODO: what error is a database error?!
|
||||
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:
|
||||
if row and row[0]:
|
||||
self.hand_1day_ago = int(row[0])
|
||||
|
@ -421,10 +435,10 @@ class Database:
|
|||
if row and row[0]:
|
||||
self.date_nhands_ago[str(playerid)] = row[0]
|
||||
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:
|
||||
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"
|
||||
, 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="%"):
|
||||
"""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
|
||||
c = self.get_cursor()
|
||||
c.execute(self.sql.query['get_player_names'], (like_player_name, site_id, site_id))
|
||||
|
@ -657,7 +671,7 @@ class Database:
|
|||
except:
|
||||
ret = -1
|
||||
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] )
|
||||
raise
|
||||
return ret
|
||||
|
@ -761,14 +775,18 @@ class Database:
|
|||
|
||||
hands_id = self.storeHands( self.backend, siteHandNo, gametypeId
|
||||
, 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
|
||||
, playerIds, startCashes, antes, cardValues, cardSuits
|
||||
, winnings, rakes, seatNos, tourneys_players_ids, tourneyTypeId)
|
||||
|
||||
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
|
||||
#end def tourney_stud
|
||||
|
@ -1179,7 +1197,7 @@ class Database:
|
|||
if p_id:
|
||||
self.hero_ids[site_id] = int(p_id)
|
||||
|
||||
if start == None:
|
||||
if start is None:
|
||||
start = self.hero_hudstart_def
|
||||
if self.hero_ids == {}:
|
||||
where = ""
|
||||
|
@ -1375,6 +1393,12 @@ class Database:
|
|||
pids[p],
|
||||
pdata[p]['startCash'],
|
||||
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]['street1Aggr'],
|
||||
pdata[p]['street2Aggr'],
|
||||
|
@ -1387,6 +1411,12 @@ class Database:
|
|||
playerId,
|
||||
startCash,
|
||||
seatNo,
|
||||
winnings,
|
||||
street0VPI,
|
||||
street1Seen,
|
||||
street2Seen,
|
||||
street3Seen,
|
||||
street4Seen,
|
||||
street0Aggr,
|
||||
street1Aggr,
|
||||
street2Aggr,
|
||||
|
@ -1395,7 +1425,8 @@ class Database:
|
|||
)
|
||||
VALUES (
|
||||
%s, %s, %s, %s, %s,
|
||||
%s, %s, %s, %s
|
||||
%s, %s, %s, %s, %s,
|
||||
%s, %s, %s, %s, %s
|
||||
)"""
|
||||
|
||||
# position,
|
||||
|
@ -1405,16 +1436,10 @@ class Database:
|
|||
# card3,
|
||||
# card4,
|
||||
# startCards,
|
||||
# winnings,
|
||||
# rake,
|
||||
# totalProfit,
|
||||
# street0VPI,
|
||||
# street0_3BChance,
|
||||
# street0_3BDone,
|
||||
# street1Seen,
|
||||
# street2Seen,
|
||||
# street3Seen,
|
||||
# street4Seen,
|
||||
# sawShowdown,
|
||||
# otherRaisedStreet1,
|
||||
# otherRaisedStreet2,
|
||||
|
@ -1946,7 +1971,7 @@ class Database:
|
|||
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):
|
||||
#stores hands_players for tourney stud/razz hands
|
||||
|
||||
return # TODO: stubbed out until someone updates it for current database structuring
|
||||
try:
|
||||
result=[]
|
||||
for i in xrange(len(player_ids)):
|
||||
|
|
|
@ -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 pygtk
|
||||
pygtk.require('2.0')
|
||||
import gtk
|
||||
import gobject
|
||||
|
||||
#*******************************************************************************************************
|
||||
class DatabaseManager(object):
|
||||
class DatabaseManager(gobject.GObject):
|
||||
DatabaseTypes = {}
|
||||
|
||||
@classmethod
|
||||
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)
|
||||
|
||||
def to_fpdb(self):
|
||||
pass
|
||||
|
||||
|
||||
def __init__(self, databases=None, defaultDatabaseType=None):
|
||||
gobject.GObject.__init__(self)
|
||||
|
||||
self._defaultDatabaseType = defaultDatabaseType
|
||||
self._databases = [] if databases is None else list(databases)
|
||||
self._activeDatabase = None
|
||||
def __iter__(self):
|
||||
return iter(self._databases)
|
||||
def set_default_database_type(self, databaseType):
|
||||
|
@ -31,7 +88,7 @@ class DatabaseManager(object):
|
|||
return self._defaultDatabaseType
|
||||
def database_from_id(self, idDatabase):
|
||||
for database in self._databases:
|
||||
if idDatabase == id(database):
|
||||
if idDatabase == self.database_id(database):
|
||||
return database
|
||||
def database_id(self, database):
|
||||
return id(database)
|
||||
|
@ -41,8 +98,26 @@ class DatabaseManager(object):
|
|||
self._databases.append(database)
|
||||
def remove_database(self, 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):
|
||||
def __new__(klass, name, bases, kws):
|
||||
|
@ -56,10 +131,25 @@ class DatabaseTypeMeta(type):
|
|||
class DatabaseTypeBase(object):
|
||||
__metaclass__ = DatabaseTypeMeta
|
||||
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):
|
||||
Type = 'postgres'
|
||||
Type = 'postgresql'
|
||||
@classmethod
|
||||
def display_name(klass):
|
||||
return 'Postgres'
|
||||
|
@ -70,6 +160,15 @@ class DatabaseTypePostgres(DatabaseTypeBase):
|
|||
self.user = user
|
||||
self.password = password
|
||||
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):
|
||||
Type = 'mysql'
|
||||
|
@ -83,6 +182,16 @@ class DatabaseTypeMysql(DatabaseTypeBase):
|
|||
self.user = user
|
||||
self.password = password
|
||||
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):
|
||||
Type = 'sqlite'
|
||||
|
@ -92,7 +201,26 @@ class DatabaseTypeSqLite(DatabaseTypeBase):
|
|||
def __init__(self, name='', host='', file='', database='fpdb'):
|
||||
self.name = name
|
||||
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?
|
||||
# ..uncomment to remove unsupported database types
|
||||
|
@ -104,6 +232,20 @@ class DatabaseTypeSqLite(DatabaseTypeBase):
|
|||
#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?
|
||||
class WidgetDatabaseProperties(gtk.VBox):
|
||||
|
||||
|
@ -158,7 +300,7 @@ class WidgetDatabaseProperties(gtk.VBox):
|
|||
dlg.destroy()
|
||||
|
||||
|
||||
|
||||
#TODO: bit ugly this thingy. try to find a better way to map database attrs to gtk widgets
|
||||
class FieldWidget(object):
|
||||
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,
|
||||
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(
|
||||
text='File:',
|
||||
attrDatabase='file',
|
||||
|
@ -272,6 +404,16 @@ class WidgetDatabaseProperties(gtk.VBox):
|
|||
canEdit=False,
|
||||
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
|
||||
|
@ -372,11 +514,22 @@ class DialogDatabaseProperties(gtk.Dialog):
|
|||
#TODO: derrive from gtk.VBox?
|
||||
# ..is there a way to derrive from gtk.Widget or similar? this would make parentWidget kw obsolete
|
||||
class WidgetDatabaseManager(gtk.VBox):
|
||||
"""
|
||||
"""
|
||||
|
||||
def __init__(self, databaseManager, parentWidget=None):
|
||||
gtk.VBox.__init__(self)
|
||||
|
||||
self.databaseManager = databaseManager
|
||||
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
|
||||
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
|
||||
# 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.set_tooltip_text('creates a new database')
|
||||
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.set_tooltip_text('removes the database from the list')
|
||||
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
|
||||
self.buttonDatabaseDelete = gtk.Button("Delete")
|
||||
self.buttonDatabaseDelete.set_tooltip_text('removes the database from the list and deletes it')
|
||||
self.buttonDatabaseDelete.set_sensitive(False)
|
||||
#self.buttonDatabaseDelete = gtk.Button("Delete")
|
||||
#self.buttonDatabaseDelete.set_tooltip_text('removes the database from the list and deletes it')
|
||||
#self.buttonDatabaseDelete.set_sensitive(False)
|
||||
|
||||
# init database tree
|
||||
self.treeDatabases = gtk.TreeView()
|
||||
self.treeDatabaseColumns = ( #NOTE: column names starting with '_' will be hidden
|
||||
'Name',
|
||||
'Status',
|
||||
'Type',
|
||||
'_id',
|
||||
treeDatabaseColumns = ( # name, displayName, dataType
|
||||
('name', 'Name', str),
|
||||
('status', 'Status', str),
|
||||
('type', 'Type', str),
|
||||
('_id', '', int),
|
||||
)
|
||||
|
||||
store = gtk.ListStore(str, str, str, int)
|
||||
self.treeDatabaseColumns = {} # name --> index
|
||||
store = gtk.ListStore( *[i[2] for i in treeDatabaseColumns] )
|
||||
self.treeDatabases.set_model(store)
|
||||
columns = ('Name', 'Status', 'Type', '_id')
|
||||
for i, column in enumerate(columns):
|
||||
col = gtk.TreeViewColumn(column, gtk.CellRendererText(), text=i)
|
||||
for i, (name, displayName, dataType) in enumerate(treeDatabaseColumns):
|
||||
col = gtk.TreeViewColumn(displayName, gtk.CellRendererText(), text=i)
|
||||
self.treeDatabases.append_column(col)
|
||||
if column.startswith('_'):
|
||||
if name.startswith('_'):
|
||||
col.set_visible(False)
|
||||
|
||||
self.treeDatabaseColumns = dict([(name, i) for (i, name) in enumerate(self.treeDatabaseColumns)])
|
||||
self.treeDatabaseColumns[name] = i
|
||||
self.treeDatabases.get_selection().connect('changed', self.on_tree_databases_selection_changed)
|
||||
|
||||
# layout widgets
|
||||
|
@ -438,11 +594,12 @@ class WidgetDatabaseManager(gtk.VBox):
|
|||
hbox.set_homogeneous(False)
|
||||
vbox = gtk.VBox()
|
||||
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.buttonDatabaseAdd, False, False, 2)
|
||||
vbox.pack_start(self.buttonDatabaseEdit, 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()
|
||||
vbox.pack_start(box, True, True, 0)
|
||||
|
||||
|
@ -452,48 +609,128 @@ class WidgetDatabaseManager(gtk.VBox):
|
|||
self.show_all()
|
||||
|
||||
# init widget
|
||||
model = self.treeDatabases.get_model()
|
||||
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
|
||||
def on_button_database_new_clicked(self, button):
|
||||
databaseType = self.databaseManager.get_default_database_type()
|
||||
if databaseType is None:
|
||||
raise ValueError('no defult database type set')
|
||||
databaseKlass = self.databaseManager.get_default_database_type()
|
||||
if databaseKlass is None:
|
||||
raise ValueError('no default database type set')
|
||||
database = databaseKlass()
|
||||
|
||||
while True:
|
||||
dlg = DialogDatabaseProperties(
|
||||
self.databaseManager,
|
||||
databaseType(),
|
||||
database,
|
||||
parent=self.parentWidget,
|
||||
mode=WidgetDatabaseProperties.ModeNew,
|
||||
title='[New database] - database properties'
|
||||
title='New database'
|
||||
)
|
||||
if dlg.run() == gtk.RESPONSE_REJECT:
|
||||
pass
|
||||
if dlg.run() == gtk.RESPONSE_ACCEPT:
|
||||
response = dlg.run()
|
||||
if response == gtk.RESPONSE_ACCEPT:
|
||||
database = dlg.get_widget_database_properties().get_database()
|
||||
#TODO: sanity checks + init databse if necessary
|
||||
self.databaseManager.add_database(database)
|
||||
self.treeDatabases.get_model().append( (database.name, 'foo', database.Type, self.databaseManager.database_id(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)
|
||||
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))
|
||||
|
||||
|
||||
def on_button_database_add_clicked(self, button):
|
||||
databaseType = self.databaseManager.get_default_database_type()
|
||||
if databaseType is None:
|
||||
databaseKlass = self.databaseManager.get_default_database_type()
|
||||
if databaseKlass is None:
|
||||
raise ValueError('no defult database type set')
|
||||
database = databaseKlass()
|
||||
|
||||
while True:
|
||||
dlg = DialogDatabaseProperties(
|
||||
self.databaseManager,
|
||||
databaseType(),
|
||||
database,
|
||||
parent=self.parentWidget,
|
||||
mode=WidgetDatabaseProperties.ModeAdd,
|
||||
title='[Add database] - database properties'
|
||||
title='Add database'
|
||||
)
|
||||
if dlg.run() == gtk.RESPONSE_REJECT:
|
||||
pass
|
||||
if dlg.run() == gtk.RESPONSE_ACCEPT:
|
||||
response = dlg.run()
|
||||
if response == gtk.RESPONSE_ACCEPT:
|
||||
database = dlg.get_widget_database_properties().get_database()
|
||||
#TODO: sanity checks
|
||||
#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.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()
|
||||
|
||||
def on_button_database_edit_clicked(self, button):
|
||||
|
@ -501,39 +738,52 @@ class WidgetDatabaseManager(gtk.VBox):
|
|||
if selection is None:
|
||||
return
|
||||
|
||||
model, iter = selection.get_selected()
|
||||
idDatabase = model.get_value(iter, self.treeDatabaseColumns['_id'])
|
||||
model, it = selection.get_selected()
|
||||
idDatabase = model.get_value(it, self.treeDatabaseColumns['_id'])
|
||||
database = self.databaseManager.database_from_id(idDatabase)
|
||||
dlg = DialogDatabaseProperties(
|
||||
self.databaseManager,
|
||||
database=database,
|
||||
database,
|
||||
parent=self.parentWidget,
|
||||
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
|
||||
if dlg.run() == gtk.RESPONSE_ACCEPT:
|
||||
elif response == gtk.RESPONSE_ACCEPT:
|
||||
database = dlg.get_database()
|
||||
selection = self.treeDatabases.get_selection()
|
||||
if selection is not None:
|
||||
model, iter = selection.get_selected()
|
||||
model.set_value(iter, 0, database.name)
|
||||
model, it = selection.get_selected()
|
||||
model.set_value(it, self.treeDatabaseColumns['name'], database.name)
|
||||
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):
|
||||
hasSelection = bool(treeSelection.count_selected_rows())
|
||||
|
||||
# enable/disable selection dependend widgets
|
||||
self.buttonDatabaseActivate.set_sensitive(hasSelection)
|
||||
self.buttonDatabaseEdit.set_sensitive(hasSelection)
|
||||
self.buttonDatabaseRemove.set_sensitive(hasSelection)
|
||||
self.buttonDatabaseDelete.set_sensitive(hasSelection)
|
||||
#self.buttonDatabaseDelete.set_sensitive(hasSelection)
|
||||
|
||||
|
||||
class DialogDatabaseManager(gtk.Dialog):
|
||||
def __init__(self, databaseManager, parent=None):
|
||||
gtk.Dialog.__init__(self,
|
||||
title="My dialog",
|
||||
title="Databases",
|
||||
parent=parent,
|
||||
flags=gtk.DIALOG_MODAL | gtk.DIALOG_DESTROY_WITH_PARENT,
|
||||
buttons=(
|
||||
|
|
|
@ -18,6 +18,13 @@
|
|||
#fpdb modules
|
||||
import Card
|
||||
|
||||
DEBUG = True
|
||||
|
||||
if DEBUG:
|
||||
import pprint
|
||||
pp = pprint.PrettyPrinter(indent=4)
|
||||
|
||||
|
||||
class DerivedStats():
|
||||
def __init__(self, hand):
|
||||
self.hand = hand
|
||||
|
@ -30,13 +37,19 @@ class DerivedStats():
|
|||
for player in hand.players:
|
||||
self.handsplayers[player[1]] = {}
|
||||
#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.assembleHands(self.hand)
|
||||
self.assembleHandsPlayers(self.hand)
|
||||
|
||||
print "hands =", self.hands
|
||||
print "handsplayers =", self.handsplayers
|
||||
if DEBUG:
|
||||
print "Hands:"
|
||||
pp.pprint(self.hands)
|
||||
print "HandsPlayers:"
|
||||
pp.pprint(self.handsplayers)
|
||||
|
||||
def getHands(self):
|
||||
return self.hands
|
||||
|
@ -85,11 +98,20 @@ class DerivedStats():
|
|||
# commentTs DATETIME
|
||||
|
||||
def assembleHandsPlayers(self, hand):
|
||||
#street0VPI/vpip already called in Hand
|
||||
#hand.players = [[seat, name, chips],[seat, name, chips]]
|
||||
for player in hand.players:
|
||||
self.handsplayers[player[1]]['seatNo'] = player[0]
|
||||
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:]):
|
||||
self.aggr(self.hand, i)
|
||||
|
||||
|
@ -794,9 +816,9 @@ class DerivedStats():
|
|||
|
||||
for player in hand.players:
|
||||
if player[1] in vpipers:
|
||||
self.handsplayers[player[1]]['vpip'] = True
|
||||
self.handsplayers[player[1]]['street0VPI'] = True
|
||||
else:
|
||||
self.handsplayers[player[1]]['vpip'] = False
|
||||
self.handsplayers[player[1]]['street0VPI'] = False
|
||||
|
||||
def playersAtStreetX(self, hand):
|
||||
""" 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['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):
|
||||
aggrers = set()
|
||||
for act in hand.actions[hand.actionStreets[i]]:
|
||||
|
|
|
@ -305,10 +305,10 @@ class Filters(threading.Thread):
|
|||
print "self.limit[%s] set to %s" %(limit, self.limits[limit])
|
||||
if limit.isdigit() or (len(limit) > 2 and limit[-2:] == 'nl'):
|
||||
if self.limits[limit]:
|
||||
if self.cbNoLimits != None:
|
||||
if self.cbNoLimits is not None:
|
||||
self.cbNoLimits.set_active(False)
|
||||
else:
|
||||
if self.cbAllLimits != None:
|
||||
if self.cbAllLimits is not None:
|
||||
self.cbAllLimits.set_active(False)
|
||||
if not self.limits[limit]:
|
||||
if limit.isdigit():
|
||||
|
@ -319,9 +319,9 @@ class Filters(threading.Thread):
|
|||
if self.limits[limit]:
|
||||
#for cb in self.cbLimits.values():
|
||||
# cb.set_active(True)
|
||||
if self.cbFL != None:
|
||||
if self.cbFL is not None:
|
||||
self.cbFL.set_active(True)
|
||||
if self.cbNL != None:
|
||||
if self.cbNL is not None:
|
||||
self.cbNL.set_active(True)
|
||||
elif limit == "none":
|
||||
if self.limits[limit]:
|
||||
|
|
|
@ -184,11 +184,11 @@ class Fulltilt(HandHistoryConverter):
|
|||
info['limitType'] = limits[mg['LIMIT']]
|
||||
info['sb'] = mg['SB']
|
||||
info['bb'] = mg['BB']
|
||||
if mg['GAME'] != None:
|
||||
if mg['GAME'] is not None:
|
||||
(info['base'], info['category']) = games[mg['GAME']]
|
||||
if mg['CURRENCY'] != None:
|
||||
if mg['CURRENCY'] is not None:
|
||||
info['currency'] = currencies[mg['CURRENCY']]
|
||||
if mg['TOURNO'] == None: info['type'] = "ring"
|
||||
if mg['TOURNO'] is None: info['type'] = "ring"
|
||||
else: info['type'] = "tour"
|
||||
# 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
|
||||
|
@ -196,7 +196,7 @@ class Fulltilt(HandHistoryConverter):
|
|||
|
||||
def readHandInfo(self, hand):
|
||||
m = self.re_HandInfo.search(hand.handText)
|
||||
if(m == None):
|
||||
if m is None:
|
||||
logging.info("Didn't match re_HandInfo")
|
||||
logging.info(hand.handText)
|
||||
return None
|
||||
|
@ -212,7 +212,7 @@ class Fulltilt(HandHistoryConverter):
|
|||
if m2: hand.maxseats = int(m2.group('MAX'))
|
||||
|
||||
hand.tourNo = m.group('TOURNO')
|
||||
if m.group('PLAY') != None:
|
||||
if m.group('PLAY') is not None:
|
||||
hand.gametype['currency'] = 'play'
|
||||
|
||||
# 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
|
||||
|
||||
|
||||
if hand.buyin == None:
|
||||
if hand.buyin is None:
|
||||
hand.buyin = "$0.00+$0.00"
|
||||
if hand.level == None:
|
||||
if hand.level is None:
|
||||
hand.level = "0"
|
||||
|
||||
# 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])
|
||||
for found in m:
|
||||
player = found.group('PNAME')
|
||||
if found.group('NEWCARDS') == None:
|
||||
if found.group('NEWCARDS') is None:
|
||||
newcards = []
|
||||
else:
|
||||
newcards = found.group('NEWCARDS').split(' ')
|
||||
if found.group('OLDCARDS') == None:
|
||||
if found.group('OLDCARDS') is None:
|
||||
oldcards = []
|
||||
else:
|
||||
oldcards = found.group('OLDCARDS').split(' ')
|
||||
|
@ -376,7 +376,7 @@ class Fulltilt(HandHistoryConverter):
|
|||
elif action.group('ATYPE') == ' checks':
|
||||
hand.addCheck( street, action.group('PNAME'))
|
||||
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):
|
||||
|
@ -416,7 +416,8 @@ class Fulltilt(HandHistoryConverter):
|
|||
|
||||
def readOther(self, hand):
|
||||
m = self.re_Mixed.search(self.in_path)
|
||||
if m == None: hand.mixed = None
|
||||
if m is None:
|
||||
hand.mixed = None
|
||||
else:
|
||||
hand.mixed = self.mixes[m.groupdict()['MIXED']]
|
||||
|
||||
|
@ -472,8 +473,10 @@ class Fulltilt(HandHistoryConverter):
|
|||
(info['base'], info['category']) = games[mg['GAME']]
|
||||
if mg['CURRENCY'] is not None:
|
||||
info['currency'] = currencies[mg['CURRENCY']]
|
||||
if mg['TOURNO'] == None: info['type'] = "ring"
|
||||
else: info['type'] = "tour"
|
||||
if mg['TOURNO'] is None:
|
||||
info['type'] = "ring"
|
||||
else:
|
||||
info['type'] = "tour"
|
||||
# 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
|
||||
|
@ -654,7 +657,7 @@ class Fulltilt(HandHistoryConverter):
|
|||
|
||||
tourney.addPlayer(rank, a.group('PNAME'), winnings, 0, 0, 0, 0)
|
||||
else:
|
||||
print "Player finishing stats unreadable : %s" % a
|
||||
print "FullTilt: Player finishing stats unreadable : %s" % a
|
||||
|
||||
# Find Hero
|
||||
n = self.re_TourneyHeroFinishingP.search(playersText)
|
||||
|
@ -663,9 +666,9 @@ class Fulltilt(HandHistoryConverter):
|
|||
tourney.hero = heroName
|
||||
# Is this really useful ?
|
||||
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'))):
|
||||
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
|
||||
|
||||
|
|
|
@ -33,7 +33,6 @@ import string
|
|||
|
||||
class GuiAutoImport (threading.Thread):
|
||||
def __init__(self, settings, config, sql):
|
||||
"""Constructor for GuiAutoImport"""
|
||||
self.importtimer = 0
|
||||
self.settings = settings
|
||||
self.config = config
|
||||
|
@ -41,8 +40,8 @@ class GuiAutoImport (threading.Thread):
|
|||
|
||||
imp = self.config.get_import_parameters()
|
||||
|
||||
print "Import parameters"
|
||||
print imp
|
||||
# print "Import parameters"
|
||||
# print imp
|
||||
|
||||
self.input_settings = {}
|
||||
self.pipe_to_hud = None
|
||||
|
@ -130,7 +129,8 @@ class GuiAutoImport (threading.Thread):
|
|||
data[1].set_text(dia_chooser.get_filename())
|
||||
self.input_settings[data[0]][0] = dia_chooser.get_filename()
|
||||
elif response == gtk.RESPONSE_CANCEL:
|
||||
print 'Closed, no files selected'
|
||||
#print 'Closed, no files selected'
|
||||
pass
|
||||
dia_chooser.destroy()
|
||||
#end def GuiAutoImport.browseClicked
|
||||
|
||||
|
@ -143,7 +143,6 @@ class GuiAutoImport (threading.Thread):
|
|||
sys.stdout.flush()
|
||||
gobject.timeout_add(1000, self.reset_startbutton)
|
||||
return True
|
||||
else:
|
||||
return False
|
||||
|
||||
def reset_startbutton(self):
|
||||
|
@ -184,18 +183,20 @@ class GuiAutoImport (threading.Thread):
|
|||
command = os.path.join(sys.path[0], 'HUD_main.py')
|
||||
command = [command, ] + string.split(self.settings['cl_options'])
|
||||
bs = 1
|
||||
|
||||
try:
|
||||
self.pipe_to_hud = subprocess.Popen(command, bufsize = bs, stdin = subprocess.PIPE,
|
||||
self.pipe_to_hud = subprocess.Popen(command, bufsize=bs,
|
||||
stdin=subprocess.PIPE,
|
||||
universal_newlines=True)
|
||||
except:
|
||||
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:
|
||||
for site in self.input_settings:
|
||||
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])
|
||||
self.do_import()
|
||||
|
||||
interval = int(self.intervalEntry.get_text())
|
||||
if self.importtimer != 0:
|
||||
gobject.source_remove(self.importtimer)
|
||||
|
@ -209,7 +210,7 @@ class GuiAutoImport (threading.Thread):
|
|||
self.doAutoImportBool = False # do_import will return this and stop the gobject callback timer
|
||||
print "Stopping autoimport - global lock released."
|
||||
if self.pipe_to_hud.poll() is not None:
|
||||
print "HUD already terminated"
|
||||
print " * Stop Autoimport: HUD already terminated"
|
||||
else:
|
||||
#print >>self.pipe_to_hud.stdin, "\n"
|
||||
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
|
||||
#expects a box to layout the line horizontally
|
||||
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)
|
||||
label.show()
|
||||
|
||||
|
@ -241,7 +242,7 @@ class GuiAutoImport (threading.Thread):
|
|||
hbox2.pack_start(browseButton, False, False, 3)
|
||||
browseButton.show()
|
||||
|
||||
label = gtk.Label(' ' + site + " filter:")
|
||||
label = gtk.Label("%s filter:" % site)
|
||||
hbox2.pack_start(label, False, False, 3)
|
||||
label.show()
|
||||
|
||||
|
|
|
@ -118,7 +118,7 @@ class GuiBulkImport():
|
|||
self.progressbar.set_fraction(0)
|
||||
except:
|
||||
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()
|
||||
else:
|
||||
print "bulk-import aborted - global lock not available"
|
||||
|
@ -148,26 +148,32 @@ class GuiBulkImport():
|
|||
|
||||
# checkbox - print start/stop?
|
||||
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.set_active(True)
|
||||
|
||||
# label - status
|
||||
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.set_justify(gtk.JUSTIFY_RIGHT)
|
||||
self.lab_status.set_alignment(1.0, 0.5)
|
||||
|
||||
# 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!
|
||||
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)
|
||||
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!
|
||||
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()
|
||||
|
||||
# label - 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()
|
||||
if not self.allowThreads:
|
||||
self.lab_threads.set_sensitive(False)
|
||||
|
@ -175,9 +181,11 @@ class GuiBulkImport():
|
|||
self.lab_threads.set_alignment(1.0, 0.5)
|
||||
|
||||
# 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.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()
|
||||
if not self.allowThreads:
|
||||
self.spin_threads.set_sensitive(False)
|
||||
|
@ -195,14 +203,17 @@ class GuiBulkImport():
|
|||
self.lab_hands.set_alignment(1.0, 0.5)
|
||||
|
||||
# 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.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()
|
||||
|
||||
# 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.set_justify(gtk.JUSTIFY_RIGHT)
|
||||
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('drop')
|
||||
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()
|
||||
|
||||
# label - 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.set_justify(gtk.JUSTIFY_RIGHT)
|
||||
self.lab_filter.set_alignment(1.0, 0.5)
|
||||
|
@ -229,12 +242,14 @@ class GuiBulkImport():
|
|||
print w
|
||||
self.cbfilter.append_text(w)
|
||||
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()
|
||||
|
||||
# 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.set_justify(gtk.JUSTIFY_RIGHT)
|
||||
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('drop')
|
||||
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()
|
||||
|
||||
# button - Import
|
||||
self.load_button = gtk.Button('Import') # todo: rename variables to import too
|
||||
self.load_button.connect('clicked', self.load_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()
|
||||
|
||||
# label - spacer (keeps rows 3 & 5 apart)
|
||||
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()
|
||||
|
||||
# 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.lab_info.show()
|
||||
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_fraction(0)
|
||||
self.progressbar.show()
|
||||
|
|
|
@ -310,7 +310,7 @@ class GuiSessionViewer (threading.Thread):
|
|||
except:
|
||||
pass
|
||||
|
||||
if self.fig != None:
|
||||
if self.fig is not None:
|
||||
self.fig.clear()
|
||||
self.fig = Figure(figsize=(5,4), dpi=100)
|
||||
if self.canvas is not None:
|
||||
|
|
|
@ -570,8 +570,8 @@ Left-Drag to Move"
|
|||
</hhcs>
|
||||
|
||||
<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_ip="localhost" db_name="fpdb" db_pass="fpdb" db_server="sqlite" db_type="fpdb" db_user="fpdb"/> -->
|
||||
<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_user="fpdb"/> -->
|
||||
</supported_databases>
|
||||
|
||||
</FreePokerToolsConfig>
|
||||
|
|
|
@ -109,7 +109,7 @@ class HUD_main(object):
|
|||
self.main_window.set_title("HUD Main Window")
|
||||
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()
|
||||
|
||||
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
|
||||
# if it is required.
|
||||
self.db_connection = Database.Database(self.config)
|
||||
tourny_finder = re.compile('(\d+) (\d+)')
|
||||
|
||||
# get hero's screen names and player ids
|
||||
self.hero, self.hero_ids = {}, {}
|
||||
|
@ -207,74 +206,56 @@ class HUD_main(object):
|
|||
if new_hand_id == "": # blank line means quit
|
||||
self.destroy()
|
||||
break # this thread is not always killed immediately with gtk.main_quit()
|
||||
|
||||
# get basic info about the new hand from the db
|
||||
# if there is a db error, complain, skip hand, and proceed
|
||||
try:
|
||||
(table_name, max, poker_game, type, site_id) = self.db_connection.get_table_name(new_hand_id)
|
||||
|
||||
cards = self.db_connection.get_cards(new_hand_id)
|
||||
comm_cards = self.db_connection.get_common_cards(new_hand_id)
|
||||
if comm_cards != {}: # stud!
|
||||
cards['common'] = comm_cards['common']
|
||||
(table_name, max, poker_game, type, site_id, tour_number, tab_number) = \
|
||||
self.db_connection.get_table_info(new_hand_id)
|
||||
except Exception, err:
|
||||
err = traceback.extract_tb(sys.exc_info()[2])[-1]
|
||||
print "db error: skipping "+str(new_hand_id)+" "+err[2]+"("+str(err[1])+"): "+str(sys.exc_info()[1])
|
||||
if new_hand_id: # new_hand_id is none if we had an error prior to the store
|
||||
sys.stderr.write("Database error %s in hand %d. Skipping.\n" % (err, int(new_hand_id)))
|
||||
print "db error: skipping %s" % new_hand_id
|
||||
sys.stderr.write("Database error: could not find hand %s.\n" % new_hand_id)
|
||||
continue
|
||||
|
||||
if type == "tour": # hand is from a tournament
|
||||
mat_obj = tourny_finder.search(table_name)
|
||||
if mat_obj:
|
||||
(tour_number, tab_number) = mat_obj.group(1, 2)
|
||||
temp_key = tour_number
|
||||
else: # tourney, but can't get number and table
|
||||
print "could not find tournament: skipping "
|
||||
#sys.stderr.write("Could not find tournament %d in hand %d. Skipping.\n" % (int(tour_number), int(new_hand_id)))
|
||||
continue
|
||||
|
||||
else:
|
||||
temp_key = table_name
|
||||
|
||||
# Update an existing HUD
|
||||
if temp_key in self.hud_dict:
|
||||
try:
|
||||
# get stats using hud's specific params
|
||||
# get stats using hud's specific params and get cards
|
||||
self.db_connection.init_hud_stat_vars( self.hud_dict[temp_key].hud_params['hud_days']
|
||||
, self.hud_dict[temp_key].hud_params['h_hud_days'])
|
||||
stat_dict = self.db_connection.get_stats_from_hand(new_hand_id, type, self.hud_dict[temp_key].hud_params, self.hero_ids[site_id])
|
||||
except:
|
||||
err = traceback.extract_tb(sys.exc_info()[2])[-1]
|
||||
print "db get_stats error: skipping "+str(new_hand_id)+" "+err[2]+"("+str(err[1])+"): "+str(sys.exc_info()[1])
|
||||
if new_hand_id: # new_hand_id is none if we had an error prior to the store
|
||||
sys.stderr.write("Database get_stats error %s in hand %d. Skipping.\n" % (err, int(new_hand_id)))
|
||||
continue
|
||||
self.hud_dict[temp_key].stat_dict = stat_dict
|
||||
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
|
||||
[aw.update_data(new_hand_id, self.db_connection) for aw in self.hud_dict[temp_key].aux_windows]
|
||||
self.update_HUD(new_hand_id, temp_key, self.config)
|
||||
|
||||
# Or create a new HUD
|
||||
else:
|
||||
try:
|
||||
# get stats using default params
|
||||
# get stats using default params--also get cards
|
||||
self.db_connection.init_hud_stat_vars( self.hud_params['hud_days'], self.hud_params['h_hud_days'] )
|
||||
stat_dict = self.db_connection.get_stats_from_hand(new_hand_id, type, self.hud_params, self.hero_ids[site_id])
|
||||
except:
|
||||
err = traceback.extract_tb(sys.exc_info()[2])[-1]
|
||||
print "db get_stats error: skipping "+str(new_hand_id)+" "+err[2]+"("+str(err[1])+"): "+str(sys.exc_info()[1])
|
||||
if new_hand_id: # new_hand_id is none if we had an error prior to the store
|
||||
sys.stderr.write("Database get_stats error %s in hand %d. Skipping.\n" % (err, int(new_hand_id)))
|
||||
continue
|
||||
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']
|
||||
|
||||
if type == "tour":
|
||||
tablewindow = Tables.discover_tournament_table(self.config, tour_number, tab_number)
|
||||
else:
|
||||
tablewindow = Tables.discover_table_by_name(self.config, table_name)
|
||||
if tablewindow == None:
|
||||
if tablewindow is None:
|
||||
# If no client window is found on the screen, complain and continue
|
||||
if type == "tour":
|
||||
table_name = "%s %s" % (tour_number, tab_number)
|
||||
sys.stderr.write("table name "+table_name+" not found, skipping.\n")
|
||||
sys.stderr.write("HUD create: table name "+table_name+" not found, skipping.\n")
|
||||
else:
|
||||
self.create_HUD(new_hand_id, tablewindow, temp_key, max, poker_game, type, stat_dict, cards)
|
||||
self.db_connection.connection.rollback()
|
||||
|
|
|
@ -37,7 +37,8 @@ if __name__== "__main__":
|
|||
HUD_main.config = Configuration.Config()
|
||||
|
||||
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.connect("destroy", destroy)
|
||||
|
|
|
@ -550,12 +550,12 @@ Map the tuple self.gametype onto the pokerstars string describing it
|
|||
"""Return the first HH line for the current hand."""
|
||||
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())
|
||||
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,
|
||||
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],
|
||||
self.getGameTypeAsString(), self.getStakesAsString())
|
||||
else: # non-mixed cash games
|
||||
|
@ -628,7 +628,7 @@ class HoldemOmahaHand(Hand):
|
|||
hhc.readShownCards(self)
|
||||
self.totalPot() # finalise it (total the pot)
|
||||
hhc.getRake(self)
|
||||
if self.maxseats == None:
|
||||
if self.maxseats is None:
|
||||
self.maxseats = hhc.guessMaxSeats(self)
|
||||
hhc.readOther(self)
|
||||
elif builtFrom == "DB":
|
||||
|
@ -897,7 +897,7 @@ class DrawHand(Hand):
|
|||
hhc.readShownCards(self)
|
||||
self.totalPot() # finalise it (total the pot)
|
||||
hhc.getRake(self)
|
||||
if self.maxseats == None:
|
||||
if self.maxseats is None:
|
||||
self.maxseats = hhc.guessMaxSeats(self)
|
||||
hhc.readOther(self)
|
||||
elif builtFrom == "DB":
|
||||
|
@ -1073,7 +1073,7 @@ class StudHand(Hand):
|
|||
hhc.readShownCards(self) # not done yet
|
||||
self.totalPot() # finalise it (total the pot)
|
||||
hhc.getRake(self)
|
||||
if self.maxseats == None:
|
||||
if self.maxseats is None:
|
||||
self.maxseats = hhc.guessMaxSeats(self)
|
||||
hhc.readOther(self)
|
||||
elif builtFrom == "DB":
|
||||
|
|
|
@ -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.
|
||||
|
||||
"""
|
||||
if self.in_path == '-': raise StopIteration
|
||||
if self.in_path == '-':
|
||||
raise StopIteration
|
||||
interval = 1.0 # seconds to sleep between reads for new data
|
||||
fd = codecs.open(self.in_path,'r', self.codepage)
|
||||
data = ''
|
||||
|
@ -256,7 +257,7 @@ which it expects to find at self.re_TailSplitHands -- see for e.g. Everleaf.py.
|
|||
self.readFile()
|
||||
self.obs = self.obs.strip()
|
||||
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.")
|
||||
return []
|
||||
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
|
||||
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"
|
||||
sane = False
|
||||
|
||||
|
@ -417,16 +418,19 @@ or None if we fail to get the info """
|
|||
for l in list:
|
||||
# print "'" + l + "'"
|
||||
hands = hands + [Hand.Hand(self.sitename, self.gametype, l)]
|
||||
# TODO: This looks like it could be replaced with a list comp.. ?
|
||||
return hands
|
||||
|
||||
def __listof(self, x):
|
||||
if isinstance(x, list) or isinstance(x, tuple): return x
|
||||
else: return [x]
|
||||
if isinstance(x, list) or isinstance(x, tuple):
|
||||
return x
|
||||
else:
|
||||
return [x]
|
||||
|
||||
def readFile(self):
|
||||
"""Open in_path according to self.codepage. Exceptions caught further up"""
|
||||
|
||||
if(self.filetype == "text"):
|
||||
if self.filetype == "text":
|
||||
if self.in_path == '-':
|
||||
# read from stdin
|
||||
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
|
||||
else:
|
||||
print "unable to read file with any codec in list!", self.in_path
|
||||
elif(self.filetype == "xml"):
|
||||
elif self.filetype == "xml":
|
||||
doc = xml.dom.minidom.parse(filename)
|
||||
self.doc = doc
|
||||
|
||||
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)
|
||||
|
||||
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):
|
||||
max = 0
|
||||
for player in hand.players:
|
||||
if player[0] > max: max = player[0]
|
||||
if player[0] > max:
|
||||
max = player[0]
|
||||
return max
|
||||
|
||||
def getStatus(self):
|
||||
|
|
|
@ -61,7 +61,7 @@ class Hud:
|
|||
def __init__(self, parent, table, max, poker_game, config, db_connection):
|
||||
# __init__ is (now) intended to be called from the stdin thread, so it
|
||||
# cannot touch the gui
|
||||
if parent == None: # running from cli ..
|
||||
if parent is None: # running from cli ..
|
||||
self.parent = self
|
||||
self.parent = parent
|
||||
self.table = table
|
||||
|
@ -87,11 +87,6 @@ class Hud:
|
|||
self.backgroundcolor = gtk.gdk.color_parse(self.colors['hudbgcolor'])
|
||||
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))
|
||||
# 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')
|
||||
menu.append(killitem)
|
||||
if self.parent != None:
|
||||
if self.parent is not None:
|
||||
killitem.connect("activate", self.parent.kill_hud, self.table_name)
|
||||
|
||||
saveitem = gtk.MenuItem('Save HUD Layout')
|
||||
|
@ -455,6 +450,9 @@ class Hud:
|
|||
# Need range here, not xrange -> need the actual list
|
||||
adj = range(0, self.max + 1) # default seat adjustments = no adjustment
|
||||
# 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:
|
||||
try:
|
||||
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)
|
||||
adj = self.adj_seats(hand, config)
|
||||
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
|
||||
for i in xrange(1, self.max + 1):
|
||||
|
|
|
@ -479,7 +479,7 @@ class Flop_Mucked(Aux_Seats):
|
|||
if i != "common":
|
||||
id = self.get_id_from_seat(i)
|
||||
# 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'])
|
||||
|
||||
def update_gui(self, new_hand_id):
|
||||
|
|
|
@ -164,7 +164,7 @@ class PokerStars(HandHistoryConverter):
|
|||
if 'CURRENCY' in mg:
|
||||
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'
|
||||
else:
|
||||
info['type'] = 'tour'
|
||||
|
@ -172,7 +172,6 @@ class PokerStars(HandHistoryConverter):
|
|||
# NB: SB, BB must be interpreted as blinds or bets depending on limit type.
|
||||
return info
|
||||
|
||||
|
||||
def readHandInfo(self, hand):
|
||||
info = {}
|
||||
m = self.re_HandInfo.search(hand.handText,re.DOTALL)
|
||||
|
@ -182,7 +181,8 @@ class PokerStars(HandHistoryConverter):
|
|||
else:
|
||||
pass # throw an exception here, eh?
|
||||
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)
|
||||
# if m: info.update(m.groupdict())
|
||||
# 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])
|
||||
|
||||
if key == 'MIXED':
|
||||
if info[key] == None: hand.mixed = None
|
||||
else: hand.mixed = self.mixes[info[key]]
|
||||
hand.mixed = self.mixes[info[key]] if info[key] is not None else None
|
||||
|
||||
if key == 'TOURNO':
|
||||
hand.tourNo = info[key]
|
||||
|
@ -214,7 +213,7 @@ class PokerStars(HandHistoryConverter):
|
|||
hand.buyin = info[key]
|
||||
if key == 'LEVEL':
|
||||
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.gametype['currency'] = 'play'
|
||||
|
||||
|
@ -304,11 +303,11 @@ class PokerStars(HandHistoryConverter):
|
|||
m = self.re_HeroCards.finditer(hand.streets[street])
|
||||
for found in m:
|
||||
player = found.group('PNAME')
|
||||
if found.group('NEWCARDS') == None:
|
||||
if found.group('NEWCARDS') is None:
|
||||
newcards = []
|
||||
else:
|
||||
newcards = found.group('NEWCARDS').split(' ')
|
||||
if found.group('OLDCARDS') == None:
|
||||
if found.group('OLDCARDS') is None:
|
||||
oldcards = []
|
||||
else:
|
||||
oldcards = found.group('OLDCARDS').split(' ')
|
||||
|
|
303
pyfpdb/SQL.py
303
pyfpdb/SQL.py
|
@ -33,12 +33,11 @@ import re
|
|||
|
||||
class Sql:
|
||||
|
||||
def __init__(self, game = 'holdem', type = 'fpdb', db_server = 'mysql'):
|
||||
def __init__(self, game = 'holdem', db_server = 'mysql'):
|
||||
self.query = {}
|
||||
###############################################################################3
|
||||
# Support for the Free Poker DataBase = fpdb http://fpdb.sourceforge.net/
|
||||
#
|
||||
if type == 'fpdb':
|
||||
|
||||
################################
|
||||
# List tables
|
||||
|
@ -213,7 +212,7 @@ class Sql:
|
|||
if db_server == 'mysql':
|
||||
self.query['createHandsTable'] = """CREATE TABLE Hands (
|
||||
id BIGINT UNSIGNED AUTO_INCREMENT NOT NULL, PRIMARY KEY (id),
|
||||
tableName VARCHAR(20) NOT NULL,
|
||||
tableName VARCHAR(22) NOT NULL,
|
||||
siteHandNo BIGINT NOT NULL,
|
||||
gametypeId SMALLINT UNSIGNED NOT NULL, FOREIGN KEY (gametypeId) REFERENCES Gametypes(id),
|
||||
handStart DATETIME NOT NULL,
|
||||
|
@ -248,7 +247,7 @@ class Sql:
|
|||
elif db_server == 'postgresql':
|
||||
self.query['createHandsTable'] = """CREATE TABLE Hands (
|
||||
id BIGSERIAL, PRIMARY KEY (id),
|
||||
tableName VARCHAR(20) NOT NULL,
|
||||
tableName VARCHAR(22) NOT NULL,
|
||||
siteHandNo BIGINT NOT NULL,
|
||||
gametypeId INT NOT NULL, FOREIGN KEY (gametypeId) REFERENCES Gametypes(id),
|
||||
handStart timestamp without time zone NOT NULL,
|
||||
|
@ -282,7 +281,7 @@ class Sql:
|
|||
elif db_server == 'sqlite':
|
||||
self.query['createHandsTable'] = """CREATE TABLE Hands (
|
||||
id INTEGER PRIMARY KEY,
|
||||
tableName TEXT(20) NOT NULL,
|
||||
tableName TEXT(22) NOT NULL,
|
||||
siteHandNo INT NOT NULL,
|
||||
gametypeId INT NOT NULL,
|
||||
handStart REAL NOT NULL,
|
||||
|
@ -1646,15 +1645,6 @@ class Sql:
|
|||
where Id = %s
|
||||
"""
|
||||
|
||||
self.query['get_action_from_hand'] = """
|
||||
SELECT street, Players.name, HandsActions.action, HandsActions.amount, actionno
|
||||
FROM Players, HandsActions, HandsPlayers
|
||||
WHERE HandsPlayers.handid = %s
|
||||
AND HandsPlayers.playerid = Players.id
|
||||
AND HandsActions.handsPlayerId = HandsPlayers.id
|
||||
ORDER BY street, actionno
|
||||
"""
|
||||
|
||||
if db_server == 'mysql':
|
||||
self.query['get_hand_1day_ago'] = """
|
||||
select coalesce(max(id),0)
|
||||
|
@ -1974,6 +1964,271 @@ class Sql:
|
|||
,s.name
|
||||
"""
|
||||
|
||||
if db_server == 'mysql':
|
||||
self.query['playerStats'] = """
|
||||
SELECT
|
||||
concat(upper(stats.limitType), ' '
|
||||
,concat(upper(substring(stats.category,1,1)),substring(stats.category,2) ), ' '
|
||||
,stats.name, ' '
|
||||
,cast(stats.bigBlindDesc as char)
|
||||
) AS Game
|
||||
,stats.n
|
||||
,stats.vpip
|
||||
,stats.pfr
|
||||
,stats.pf3
|
||||
,stats.steals
|
||||
,stats.saw_f
|
||||
,stats.sawsd
|
||||
,stats.wtsdwsf
|
||||
,stats.wmsd
|
||||
,stats.FlAFq
|
||||
,stats.TuAFq
|
||||
,stats.RvAFq
|
||||
,stats.PoFAFq
|
||||
,stats.Net
|
||||
,stats.BBper100
|
||||
,stats.Profitperhand
|
||||
,case when hprof2.variance = -999 then '-'
|
||||
else format(hprof2.variance, 2)
|
||||
end AS Variance
|
||||
,stats.AvgSeats
|
||||
FROM
|
||||
(select /* stats from hudcache */
|
||||
gt.base
|
||||
,gt.category
|
||||
,upper(gt.limitType) as limitType
|
||||
,s.name
|
||||
,<selectgt.bigBlind> AS bigBlindDesc
|
||||
,<hcgametypeId> AS gtId
|
||||
,sum(HDs) AS n
|
||||
,format(100.0*sum(street0VPI)/sum(HDs),1) AS vpip
|
||||
,format(100.0*sum(street0Aggr)/sum(HDs),1) AS pfr
|
||||
,case when sum(street0_3Bchance) = 0 then '0'
|
||||
else format(100.0*sum(street0_3Bdone)/sum(street0_3Bchance),1)
|
||||
end AS pf3
|
||||
,case when sum(stealattemptchance) = 0 then '-'
|
||||
else format(100.0*sum(stealattempted)/sum(stealattemptchance),1)
|
||||
end AS steals
|
||||
,format(100.0*sum(street1Seen)/sum(HDs),1) AS saw_f
|
||||
,format(100.0*sum(sawShowdown)/sum(HDs),1) AS sawsd
|
||||
,case when sum(street1Seen) = 0 then '-'
|
||||
else format(100.0*sum(sawShowdown)/sum(street1Seen),1)
|
||||
end AS wtsdwsf
|
||||
,case when sum(sawShowdown) = 0 then '-'
|
||||
else format(100.0*sum(wonAtSD)/sum(sawShowdown),1)
|
||||
end AS wmsd
|
||||
,case when sum(street1Seen) = 0 then '-'
|
||||
else format(100.0*sum(street1Aggr)/sum(street1Seen),1)
|
||||
end AS FlAFq
|
||||
,case when sum(street2Seen) = 0 then '-'
|
||||
else format(100.0*sum(street2Aggr)/sum(street2Seen),1)
|
||||
end AS TuAFq
|
||||
,case when sum(street3Seen) = 0 then '-'
|
||||
else format(100.0*sum(street3Aggr)/sum(street3Seen),1)
|
||||
end AS RvAFq
|
||||
,case when sum(street1Seen)+sum(street2Seen)+sum(street3Seen) = 0 then '-'
|
||||
else format(100.0*(sum(street1Aggr)+sum(street2Aggr)+sum(street3Aggr))
|
||||
/(sum(street1Seen)+sum(street2Seen)+sum(street3Seen)),1)
|
||||
end AS PoFAFq
|
||||
,format(sum(totalProfit)/100.0,2) AS Net
|
||||
,format((sum(totalProfit/(gt.bigBlind+0.0))) / (sum(HDs)/100.0),2)
|
||||
AS BBper100
|
||||
,format( (sum(totalProfit)/100.0) / sum(HDs), 4) AS Profitperhand
|
||||
,format( sum(activeSeats*HDs)/(sum(HDs)+0.0), 2) AS AvgSeats
|
||||
from Gametypes gt
|
||||
inner join Sites s on s.Id = gt.siteId
|
||||
inner join HudCache hc on hc.gameTypeId = gt.Id
|
||||
where hc.playerId in <player_test>
|
||||
and <gtbigBlind_test>
|
||||
and hc.activeSeats <seats_test>
|
||||
and concat( '20', substring(hc.styleKey,2,2), '-', substring(hc.styleKey,4,2), '-'
|
||||
, substring(hc.styleKey,6,2) ) <datestest>
|
||||
group by gt.base
|
||||
,gt.category
|
||||
<groupbyseats>
|
||||
,plposition
|
||||
,upper(gt.limitType)
|
||||
,s.name
|
||||
having 1 = 1 <havingclause>
|
||||
order by pname
|
||||
,gt.base
|
||||
,gt.category
|
||||
<orderbyseats>
|
||||
,case <position> when 'B' then 'B'
|
||||
when 'S' then 'S'
|
||||
else concat('Z', <position>)
|
||||
end
|
||||
<orderbyhgameTypeId>
|
||||
,upper(gt.limitType) desc
|
||||
,maxbigblind desc
|
||||
,s.name
|
||||
"""
|
||||
elif db_server == 'postgresql':
|
||||
self.query['playerDetailedStats'] = """
|
||||
select <hgameTypeId> AS hgametypeid
|
||||
,<playerName> AS pname
|
||||
,gt.base
|
||||
,gt.category
|
||||
,upper(gt.limitType) AS limittype
|
||||
,s.name
|
||||
,min(gt.bigBlind) AS minbigblind
|
||||
,max(gt.bigBlind) AS maxbigblind
|
||||
/*,<hcgametypeId> AS gtid*/
|
||||
,<position> AS plposition
|
||||
,count(1) AS n
|
||||
,100.0*sum(cast(hp.street0VPI as <signed>integer))/count(1) AS vpip
|
||||
,100.0*sum(cast(hp.street0Aggr as <signed>integer))/count(1) AS pfr
|
||||
,case when sum(cast(hp.street0_3Bchance as <signed>integer)) = 0 then -999
|
||||
else 100.0*sum(cast(hp.street0_3Bdone as <signed>integer))/sum(cast(hp.street0_3Bchance as <signed>integer))
|
||||
end AS pf3
|
||||
,case when sum(cast(hp.stealattemptchance as <signed>integer)) = 0 then -999
|
||||
else 100.0*sum(cast(hp.stealattempted as <signed>integer))/sum(cast(hp.stealattemptchance as <signed>integer))
|
||||
end AS steals
|
||||
,100.0*sum(cast(hp.street1Seen as <signed>integer))/count(1) AS saw_f
|
||||
,100.0*sum(cast(hp.sawShowdown as <signed>integer))/count(1) AS sawsd
|
||||
,case when sum(cast(hp.street1Seen as <signed>integer)) = 0 then -999
|
||||
else 100.0*sum(cast(hp.sawShowdown as <signed>integer))/sum(cast(hp.street1Seen as <signed>integer))
|
||||
end AS wtsdwsf
|
||||
,case when sum(cast(hp.sawShowdown as <signed>integer)) = 0 then -999
|
||||
else 100.0*sum(cast(hp.wonAtSD as <signed>integer))/sum(cast(hp.sawShowdown as <signed>integer))
|
||||
end AS wmsd
|
||||
,case when sum(cast(hp.street1Seen as <signed>integer)) = 0 then -999
|
||||
else 100.0*sum(cast(hp.street1Aggr as <signed>integer))/sum(cast(hp.street1Seen as <signed>integer))
|
||||
end AS flafq
|
||||
,case when sum(cast(hp.street2Seen as <signed>integer)) = 0 then -999
|
||||
else 100.0*sum(cast(hp.street2Aggr as <signed>integer))/sum(cast(hp.street2Seen as <signed>integer))
|
||||
end AS tuafq
|
||||
,case when sum(cast(hp.street3Seen as <signed>integer)) = 0 then -999
|
||||
else 100.0*sum(cast(hp.street3Aggr as <signed>integer))/sum(cast(hp.street3Seen as <signed>integer))
|
||||
end AS rvafq
|
||||
,case when sum(cast(hp.street1Seen as <signed>integer))+sum(cast(hp.street2Seen as <signed>integer))+sum(cast(hp.street3Seen as <signed>integer)) = 0 then -999
|
||||
else 100.0*(sum(cast(hp.street1Aggr as <signed>integer))+sum(cast(hp.street2Aggr as <signed>integer))+sum(cast(hp.street3Aggr as <signed>integer)))
|
||||
/(sum(cast(hp.street1Seen as <signed>integer))+sum(cast(hp.street2Seen as <signed>integer))+sum(cast(hp.street3Seen as <signed>integer)))
|
||||
end AS pofafq
|
||||
,sum(hp.totalProfit)/100.0 AS net
|
||||
,sum(hp.rake)/100.0 AS rake
|
||||
,100.0*avg(hp.totalProfit/(gt.bigBlind+0.0)) AS bbper100
|
||||
,avg(hp.totalProfit)/100.0 AS profitperhand
|
||||
,100.0*avg((hp.totalProfit+hp.rake)/(gt.bigBlind+0.0)) AS bb100xr
|
||||
,avg((hp.totalProfit+hp.rake)/100.0) AS profhndxr
|
||||
,avg(h.seats+0.0) AS avgseats
|
||||
,variance(hp.totalProfit/100.0) AS variance
|
||||
from HandsPlayers hp
|
||||
inner join Hands h on (h.id = hp.handId)
|
||||
inner join Gametypes gt on (gt.Id = h.gameTypeId)
|
||||
inner join Sites s on (s.Id = gt.siteId)
|
||||
inner join Players p on (p.Id = hp.playerId)
|
||||
where hp.playerId in <player_test>
|
||||
/*and hp.tourneysPlayersId IS NULL*/
|
||||
and h.seats <seats_test>
|
||||
<flagtest>
|
||||
<gtbigBlind_test>
|
||||
and to_char(h.handStart, 'YYYY-MM-DD') <datestest>
|
||||
group by hgameTypeId
|
||||
,pname
|
||||
,gt.base
|
||||
,gt.category
|
||||
<groupbyseats>
|
||||
,plposition
|
||||
,upper(gt.limitType)
|
||||
,s.name
|
||||
having 1 = 1 <havingclause>
|
||||
order by pname
|
||||
,gt.base
|
||||
,gt.category
|
||||
<orderbyseats>
|
||||
,case <position> when 'B' then 'B'
|
||||
when 'S' then 'S'
|
||||
when '0' then 'Y'
|
||||
else 'Z'||<position>
|
||||
end
|
||||
<orderbyhgameTypeId>
|
||||
,upper(gt.limitType) desc
|
||||
,maxbigblind desc
|
||||
,s.name
|
||||
"""
|
||||
elif db_server == 'sqlite':
|
||||
self.query['playerDetailedStats'] = """
|
||||
select <hgameTypeId> AS hgametypeid
|
||||
,gt.base
|
||||
,gt.category
|
||||
,upper(gt.limitType) AS limittype
|
||||
,s.name
|
||||
,min(gt.bigBlind) AS minbigblind
|
||||
,max(gt.bigBlind) AS maxbigblind
|
||||
/*,<hcgametypeId> AS gtid*/
|
||||
,<position> AS plposition
|
||||
,count(1) AS n
|
||||
,100.0*sum(cast(hp.street0VPI as <signed>integer))/count(1) AS vpip
|
||||
,100.0*sum(cast(hp.street0Aggr as <signed>integer))/count(1) AS pfr
|
||||
,case when sum(cast(hp.street0_3Bchance as <signed>integer)) = 0 then -999
|
||||
else 100.0*sum(cast(hp.street0_3Bdone as <signed>integer))/sum(cast(hp.street0_3Bchance as <signed>integer))
|
||||
end AS pf3
|
||||
,case when sum(cast(hp.stealattemptchance as <signed>integer)) = 0 then -999
|
||||
else 100.0*sum(cast(hp.stealattempted as <signed>integer))/sum(cast(hp.stealattemptchance as <signed>integer))
|
||||
end AS steals
|
||||
,100.0*sum(cast(hp.street1Seen as <signed>integer))/count(1) AS saw_f
|
||||
,100.0*sum(cast(hp.sawShowdown as <signed>integer))/count(1) AS sawsd
|
||||
,case when sum(cast(hp.street1Seen as <signed>integer)) = 0 then -999
|
||||
else 100.0*sum(cast(hp.sawShowdown as <signed>integer))/sum(cast(hp.street1Seen as <signed>integer))
|
||||
end AS wtsdwsf
|
||||
,case when sum(cast(hp.sawShowdown as <signed>integer)) = 0 then -999
|
||||
else 100.0*sum(cast(hp.wonAtSD as <signed>integer))/sum(cast(hp.sawShowdown as <signed>integer))
|
||||
end AS wmsd
|
||||
,case when sum(cast(hp.street1Seen as <signed>integer)) = 0 then -999
|
||||
else 100.0*sum(cast(hp.street1Aggr as <signed>integer))/sum(cast(hp.street1Seen as <signed>integer))
|
||||
end AS flafq
|
||||
,case when sum(cast(hp.street2Seen as <signed>integer)) = 0 then -999
|
||||
else 100.0*sum(cast(hp.street2Aggr as <signed>integer))/sum(cast(hp.street2Seen as <signed>integer))
|
||||
end AS tuafq
|
||||
,case when sum(cast(hp.street3Seen as <signed>integer)) = 0 then -999
|
||||
else 100.0*sum(cast(hp.street3Aggr as <signed>integer))/sum(cast(hp.street3Seen as <signed>integer))
|
||||
end AS rvafq
|
||||
,case when sum(cast(hp.street1Seen as <signed>integer))+sum(cast(hp.street2Seen as <signed>integer))+sum(cast(hp.street3Seen as <signed>integer)) = 0 then -999
|
||||
else 100.0*(sum(cast(hp.street1Aggr as <signed>integer))+sum(cast(hp.street2Aggr as <signed>integer))+sum(cast(hp.street3Aggr as <signed>integer)))
|
||||
/(sum(cast(hp.street1Seen as <signed>integer))+sum(cast(hp.street2Seen as <signed>integer))+sum(cast(hp.street3Seen as <signed>integer)))
|
||||
end AS pofafq
|
||||
,sum(hp.totalProfit)/100.0 AS net
|
||||
,sum(hp.rake)/100.0 AS rake
|
||||
,100.0*avg(hp.totalProfit/(gt.bigBlind+0.0)) AS bbper100
|
||||
,avg(hp.totalProfit)/100.0 AS profitperhand
|
||||
,100.0*avg((hp.totalProfit+hp.rake)/(gt.bigBlind+0.0)) AS bb100xr
|
||||
,avg((hp.totalProfit+hp.rake)/100.0) AS profhndxr
|
||||
,avg(h.seats+0.0) AS avgseats
|
||||
,variance(hp.totalProfit/100.0) AS variance
|
||||
from HandsPlayers hp
|
||||
inner join Hands h on (h.id = hp.handId)
|
||||
inner join Gametypes gt on (gt.Id = h.gameTypeId)
|
||||
inner join Sites s on (s.Id = gt.siteId)
|
||||
where hp.playerId in <player_test>
|
||||
/*and hp.tourneysPlayersId IS NULL*/
|
||||
and h.seats <seats_test>
|
||||
<flagtest>
|
||||
<gtbigBlind_test>
|
||||
and to_char(h.handStart, 'YYYY-MM-DD') <datestest>
|
||||
group by hgameTypeId
|
||||
,hp.playerId
|
||||
,gt.base
|
||||
,gt.category
|
||||
<groupbyseats>
|
||||
,plposition
|
||||
,upper(gt.limitType)
|
||||
,s.name
|
||||
order by hp.playerId
|
||||
,gt.base
|
||||
,gt.category
|
||||
<orderbyseats>
|
||||
,case <position> when 'B' then 'B'
|
||||
when 'S' then 'S'
|
||||
when '0' then 'Y'
|
||||
else 'Z'||<position>
|
||||
end
|
||||
<orderbyhgameTypeId>
|
||||
,upper(gt.limitType) desc
|
||||
,maxbigblind desc
|
||||
,s.name
|
||||
"""
|
||||
|
||||
if db_server == 'mysql':
|
||||
self.query['playerStats'] = """
|
||||
SELECT
|
||||
|
@ -2476,6 +2731,25 @@ class Sql:
|
|||
GROUP BY h.handStart, hp.handId, hp.totalProfit
|
||||
ORDER BY h.handStart"""
|
||||
|
||||
####################################
|
||||
# Session stats query
|
||||
####################################
|
||||
if db_server == 'mysql':
|
||||
self.query['sessionStats'] = """
|
||||
SELECT UNIX_TIMESTAMP(h.handStart) as time, hp.handId, hp.startCash, hp.winnings, hp.totalProfit
|
||||
FROM HandsPlayers hp
|
||||
INNER JOIN Players pl ON (pl.id = hp.playerId)
|
||||
INNER JOIN Hands h ON (h.id = hp.handId)
|
||||
INNER JOIN Gametypes gt ON (gt.id = h.gametypeId)
|
||||
WHERE pl.id in <player_test>
|
||||
AND pl.siteId in <site_test>
|
||||
AND h.handStart > '<startdate_test>'
|
||||
AND h.handStart < '<enddate_test>'
|
||||
<limit_test>
|
||||
AND hp.tourneysPlayersId IS NULL
|
||||
GROUP BY h.handStart, hp.handId, hp.totalProfit
|
||||
ORDER BY h.handStart"""
|
||||
|
||||
####################################
|
||||
# Session stats query
|
||||
####################################
|
||||
|
@ -2668,6 +2942,7 @@ class Sql:
|
|||
,hc_position
|
||||
,hp.tourneyTypeId
|
||||
,date_format(h.handStart, 'd%y%m%d')
|
||||
>>>>>>> 28ca49d592c8e706ad6ee58dd26655bcc33fc5fb:pyfpdb/SQL.py
|
||||
"""
|
||||
elif db_server == 'postgresql':
|
||||
self.query['rebuildHudCache'] = """
|
||||
|
|
|
@ -68,14 +68,14 @@ def do_tip(widget, tip):
|
|||
|
||||
def do_stat(stat_dict, player = 24, stat = 'vpip'):
|
||||
match = re_Places.search(stat)
|
||||
if match == None:
|
||||
if match is None:
|
||||
result = eval("%(stat)s(stat_dict, %(player)d)" % {'stat': stat, 'player': player})
|
||||
else:
|
||||
base = stat[0:-2]
|
||||
places = int(stat[-1:])
|
||||
result = eval("%(stat)s(stat_dict, %(player)d)" % {'stat': base, 'player': player})
|
||||
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])
|
||||
else:
|
||||
result = (result[0], "%.*f%%" % (places, 100*result[0]), result[2], result[3], result[4], result[5])
|
||||
|
|
|
@ -95,12 +95,12 @@ gobject.signal_new("client_destroyed", gtk.Window,
|
|||
class Table_Window(object):
|
||||
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
|
||||
self.name = table_name
|
||||
self.tournament = 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)
|
||||
self.tournament = int(tournament)
|
||||
self.table = int(table_number)
|
||||
|
@ -133,7 +133,7 @@ class Table_Window(object):
|
|||
def check_geometry(self):
|
||||
new_geo = self.get_geometry()
|
||||
|
||||
if new_geo == None: # window destroyed
|
||||
if new_geo is None: # window destroyed
|
||||
return "client_destroyed"
|
||||
|
||||
elif self.x != new_geo['x'] or self.y != new_geo['y']: # window moved
|
||||
|
|
|
@ -105,7 +105,7 @@ def discover_table_by_name(c, tablename):
|
|||
info = discover_mac_by_name(c, tablename)
|
||||
else:
|
||||
return None
|
||||
if info == None:
|
||||
if info is None:
|
||||
return None
|
||||
return Table_Window(info)
|
||||
|
||||
|
@ -141,7 +141,7 @@ def discover_posix(c):
|
|||
if 'History for table:' in listing: continue
|
||||
if 'has no name' in listing: continue
|
||||
info = decode_xwininfo(c, listing)
|
||||
if info['site'] == None: continue
|
||||
if info['site'] is None: continue
|
||||
if info['title'] == info['exe']: continue
|
||||
# this appears to be a poker client, so make a table object for it
|
||||
tw = Table_Window(info)
|
||||
|
|
|
@ -289,7 +289,7 @@ class ttracker_main(object):
|
|||
tablewindow = Tables.discover_tournament_table(self.config, tour_number, tab_number)
|
||||
else:
|
||||
tablewindow = Tables.discover_table_by_name(self.config, table_name)
|
||||
if tablewindow == None:
|
||||
if tablewindow is None:
|
||||
# If no client window is found on the screen, complain and continue
|
||||
if type == "tour":
|
||||
table_name = "%s %s" % (tour_number, tab_number)
|
||||
|
|
|
@ -447,10 +447,10 @@ class fpdb:
|
|||
self.settings.update(self.config.get_import_parameters())
|
||||
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.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:
|
||||
self.db = Database.Database(self.config, sql = self.sql)
|
||||
except FpdbMySQLFailedError:
|
||||
|
@ -487,7 +487,7 @@ class fpdb:
|
|||
response = diaDbVersionWarning.run()
|
||||
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.main_vbox.pack_end(self.status_bar, False, True, 0)
|
||||
self.status_bar.show()
|
||||
|
@ -513,10 +513,10 @@ class fpdb:
|
|||
# self.lock.release()
|
||||
|
||||
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"
|
||||
#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()
|
||||
# hide icon as it doesn't go away immediately in Windows - is this ok in Linux Eric?
|
||||
self.statusIcon.set_visible(False)
|
||||
gtk.main_quit()
|
||||
|
||||
|
|
|
@ -33,12 +33,12 @@ except ImportError:
|
|||
|
||||
import fpdb_simple
|
||||
import FpdbSQLQueries
|
||||
import Configuration
|
||||
|
||||
class fpdb_db:
|
||||
MYSQL_INNODB = 2
|
||||
PGSQL = 3
|
||||
SQLITE = 4
|
||||
sqlite_db_dir = ".." + os.sep + "database"
|
||||
|
||||
def __init__(self):
|
||||
"""Simple constructor, doesnt really do anything"""
|
||||
|
@ -123,10 +123,10 @@ class fpdb_db:
|
|||
else:
|
||||
logging.warning("SQLite won't work well without 'sqlalchemy' installed.")
|
||||
|
||||
if not os.path.isdir(self.sqlite_db_dir):
|
||||
print "Creating directory: '%s'" % (self.sqlite_db_dir)
|
||||
os.mkdir(self.sqlite_db_dir)
|
||||
self.db = sqlite3.connect( self.sqlite_db_dir + os.sep + database
|
||||
if not os.path.isdir(Configuration.DIR_DATABASES):
|
||||
print "Creating directory: '%s'" % (Configuration.DIR_DATABASES)
|
||||
os.mkdir(Configuration.DIR_DATABASES)
|
||||
self.db = sqlite3.connect( os.path.join(Configuration.DIR_DATABASES, database)
|
||||
, detect_types=sqlite3.PARSE_DECLTYPES )
|
||||
sqlite3.register_converter("bool", lambda x: bool(int(x)))
|
||||
sqlite3.register_adapter(bool, lambda x: "1" if x else "0")
|
||||
|
|
|
@ -182,7 +182,8 @@ class Importer:
|
|||
if os.path.isdir(inputPath):
|
||||
for subdir in os.walk(inputPath):
|
||||
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:
|
||||
self.addImportFile(inputPath, site=site, filter=filter)
|
||||
#Add a directory of files to filelist
|
||||
|
@ -203,7 +204,7 @@ class Importer:
|
|||
#print " adding file ", file
|
||||
self.addImportFile(os.path.join(dir, file), site, filter)
|
||||
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):
|
||||
""""Run full import on self.filelist. This is called from GuiBulkImport.py"""
|
||||
|
@ -250,6 +251,9 @@ class Importer:
|
|||
#self.writeq.join()
|
||||
#using empty() might be more reliable:
|
||||
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)
|
||||
print " ... writers finished"
|
||||
|
||||
|
@ -400,7 +404,7 @@ class Importer:
|
|||
file = file.decode(fpdb_simple.LOCALE_ENCODING)
|
||||
|
||||
# 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()) + ")")
|
||||
else:
|
||||
log.info("Converting " + file)
|
||||
|
@ -418,9 +422,9 @@ class Importer:
|
|||
obj = getattr(mod, filter_name, None)
|
||||
if callable(obj):
|
||||
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)
|
||||
elif (hhc.getStatus() and self.NEWIMPORT == True):
|
||||
elif hhc.getStatus() and self.NEWIMPORT == True:
|
||||
#This code doesn't do anything yet
|
||||
handlist = hhc.getProcessedHands()
|
||||
self.pos_in_file[file] = hhc.getLastCharacterRead()
|
||||
|
@ -458,7 +462,7 @@ class Importer:
|
|||
loc = self.pos_in_file[file]
|
||||
#size = os.path.getsize(file)
|
||||
#print "loc =", loc, 'size =', size
|
||||
except:
|
||||
except KeyError:
|
||||
pass
|
||||
# Read input file into class and close file
|
||||
inputFile.seek(loc)
|
||||
|
@ -475,7 +479,7 @@ class Importer:
|
|||
|
||||
db.commit()
|
||||
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())
|
||||
|
||||
if not stored:
|
||||
|
@ -508,7 +512,7 @@ class Importer:
|
|||
#print "DEBUG: import_fpdb_file: failed on lines[0]: '%s' '%s' '%s' '%s' " %( file, site, lines, loc)
|
||||
return (0,0,0,1,0,0)
|
||||
|
||||
if firstline.find("Tournament Summary")!=-1:
|
||||
if "Tournament Summary" in firstline:
|
||||
print "TODO: implement importing tournament summaries"
|
||||
#self.faobs = readfile(inputFile)
|
||||
#self.parseTourneyHistory()
|
||||
|
@ -525,15 +529,14 @@ class Importer:
|
|||
handsId = 0
|
||||
|
||||
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
|
||||
hand = lines[startpos:endpos]
|
||||
|
||||
if (len(hand[0])<2):
|
||||
if len(hand[0]) < 2:
|
||||
hand=hand[1:]
|
||||
|
||||
|
||||
if (len(hand)<3):
|
||||
if len(hand) < 3:
|
||||
pass
|
||||
#TODO: This is ugly - we didn't actually find the start of the
|
||||
# hand with the outer loop so we test again...
|
||||
|
@ -553,7 +556,7 @@ class Importer:
|
|||
if self.callHud:
|
||||
#print "call to HUD here. handsId:",handsId
|
||||
#pipe the Hands.id out to the HUD
|
||||
print "sending hand to hud", handsId, "pipe =", self.caller.pipe_to_hud
|
||||
print "fpdb_import: sending hand to hud", handsId, "pipe =", self.caller.pipe_to_hud
|
||||
self.caller.pipe_to_hud.stdin.write("%s" % (handsId) + os.linesep)
|
||||
except Exceptions.DuplicateError:
|
||||
duplicates += 1
|
||||
|
|
|
@ -30,7 +30,7 @@ def mainParser(settings, siteID, category, hand, config, db = None, writeq = Non
|
|||
backend = settings['db-backend']
|
||||
# Ideally db connection is passed in, if not use sql list if passed in,
|
||||
# otherwise start from scratch
|
||||
if db == None:
|
||||
if db is None:
|
||||
db = Database.Database(c = config, sql = None)
|
||||
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)
|
||||
|
||||
# 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)
|
||||
else:
|
||||
writeq.put(htw)
|
||||
|
|
|
@ -60,13 +60,9 @@ class InterProcessLockBase:
|
|||
self._has_lock = False
|
||||
|
||||
def locked(self):
|
||||
if self._has_lock:
|
||||
return True
|
||||
try:
|
||||
self.acquire()
|
||||
if self.acquire():
|
||||
self.release()
|
||||
return False
|
||||
except SingleInstanceError:
|
||||
return True
|
||||
|
||||
LOCK_FILE_DIRECTORY = '/tmp'
|
||||
|
@ -162,38 +158,33 @@ def test_construct():
|
|||
|
||||
>>> lock1 = InterProcessLock(name=test_name)
|
||||
>>> lock1.acquire()
|
||||
True
|
||||
|
||||
>>> lock2 = InterProcessLock(name=test_name)
|
||||
>>> lock3 = InterProcessLock(name=test_name)
|
||||
|
||||
# Since lock1 is locked, other attempts to acquire it fail.
|
||||
>>> lock2.acquire()
|
||||
Traceback (most recent call last):
|
||||
...
|
||||
SingleInstanceError: Could not acquire exclusive lock on /tmp/test.lck
|
||||
False
|
||||
|
||||
>>> lock3.acquire()
|
||||
Traceback (most recent call last):
|
||||
...
|
||||
SingleInstanceError: Could not acquire exclusive lock on /tmp/test.lck
|
||||
False
|
||||
|
||||
# Release the lock and let lock2 have it.
|
||||
>>> lock1.release()
|
||||
>>> lock2.acquire()
|
||||
True
|
||||
|
||||
>>> lock3.acquire()
|
||||
Traceback (most recent call last):
|
||||
...
|
||||
SingleInstanceError: Could not acquire exclusive lock on /tmp/test.lck
|
||||
False
|
||||
|
||||
# Release it and give it back to lock1
|
||||
>>> lock2.release()
|
||||
>>> lock1.acquire()
|
||||
True
|
||||
|
||||
>>> lock2.acquire()
|
||||
Traceback (most recent call last):
|
||||
...
|
||||
SingleInstanceError: Could not acquire exclusive lock on /tmp/test.lck
|
||||
False
|
||||
|
||||
# Test lock status
|
||||
>>> lock2.locked()
|
||||
|
@ -224,7 +215,7 @@ def test_construct():
|
|||
... import win32con
|
||||
... import pywintypes
|
||||
... 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.
|
||||
>>> def execute(cmd):
|
||||
|
@ -237,15 +228,14 @@ def test_construct():
|
|||
>>> pid = execute('import interlocks;a=interlocks.InterProcessLock(name=\\''+test_name+ '\\');a.acquire();')
|
||||
|
||||
>>> lock1.acquire()
|
||||
Traceback (most recent call last):
|
||||
...
|
||||
SingleInstanceError: Could not acquire exclusive lock on /tmp/test.lck
|
||||
False
|
||||
|
||||
>>> os_independent_kill(pid)
|
||||
|
||||
>>> time.sleep(1)
|
||||
|
||||
>>> lock1.acquire()
|
||||
True
|
||||
>>> lock1.release()
|
||||
|
||||
# Testing wait
|
||||
|
@ -253,13 +243,12 @@ def test_construct():
|
|||
>>> pid = execute('import interlocks;a=interlocks.InterProcessLock(name=\\''+test_name+ '\\');a.acquire();')
|
||||
|
||||
>>> lock1.acquire()
|
||||
Traceback (most recent call last):
|
||||
...
|
||||
SingleInstanceError: Could not acquire exclusive lock on /tmp/test.lck
|
||||
False
|
||||
|
||||
>>> os_independent_kill(pid)
|
||||
|
||||
>>> lock1.acquire(True)
|
||||
True
|
||||
>>> lock1.release()
|
||||
|
||||
"""
|
||||
|
|
Loading…
Reference in New Issue
Block a user