Merge branch 'master' of git://git.assembla.com/fpdb-eric

This commit is contained in:
Ray 2009-01-05 10:53:31 -05:00
commit d994f04e01
8 changed files with 449 additions and 162 deletions

View File

@ -154,8 +154,11 @@ class GuiAutoImport (threading.Thread):
else: # toggled off else: # toggled off
self.doAutoImportBool = False # do_import will return this and stop the gobject callback timer self.doAutoImportBool = False # do_import will return this and stop the gobject callback timer
print "Stopping autoimport" print "Stopping autoimport"
print >>self.pipe_to_hud.stdin, "\n" if self.pipe_to_hud.poll() is not None:
#self.pipe_to_hud.communicate('\n') # waits for process to terminate print "HUD already terminated"
else:
#print >>self.pipe_to_hud.stdin, "\n"
self.pipe_to_hud.communicate('\n') # waits for process to terminate
self.pipe_to_hud = None self.pipe_to_hud = None
self.startButton.set_label(u'Start Autoimport') self.startButton.set_label(u'Start Autoimport')

View File

@ -52,6 +52,7 @@ import Hud
# global dict for keeping the huds # global dict for keeping the huds
hud_dict = {} hud_dict = {}
eb = 0 # our former event-box
db_connection = 0; db_connection = 0;
config = 0; config = 0;
@ -61,11 +62,18 @@ def destroy(*args): # call back for terminating the main eventloop
def create_HUD(new_hand_id, table, db_name, table_name, max, poker_game, db_connection, config, stat_dict): def create_HUD(new_hand_id, table, db_name, table_name, max, poker_game, db_connection, config, stat_dict):
global hud_dict global hud_dict
global eb
def idle_func(): def idle_func():
global hud_dict global hud_dict
global eb
gtk.gdk.threads_enter() gtk.gdk.threads_enter()
try: try:
newlabel = gtk.Label(table_name)
eb.add(newlabel)
newlabel.show()
hud_dict[table_name] = Hud.Hud(table, max, poker_game, config, db_connection) hud_dict[table_name] = Hud.Hud(table, max, poker_game, config, db_connection)
hud_dict[table_name].tablehudlabel = newlabel
hud_dict[table_name].create(new_hand_id, config) hud_dict[table_name].create(new_hand_id, config)
for m in hud_dict[table_name].aux_windows: for m in hud_dict[table_name].aux_windows:
m.update_data(new_hand_id, db_connection) m.update_data(new_hand_id, db_connection)
@ -92,6 +100,7 @@ def update_HUD(new_hand_id, table_name, config, stat_dict):
def read_stdin(): # This is the thread function def read_stdin(): # This is the thread function
global hud_dict global hud_dict
global eb
db_connection = Database.Database(config, db_name, 'temp') db_connection = Database.Database(config, db_name, 'temp')
tourny_finder = re.compile('(\d+) (\d+)') tourny_finder = re.compile('(\d+) (\d+)')
@ -105,6 +114,7 @@ def read_stdin(): # This is the thread function
# delete hud_dict entries for any HUD destroyed since last iteration # delete hud_dict entries for any HUD destroyed since last iteration
for h in hud_dict.keys(): for h in hud_dict.keys():
if hud_dict[h].deleted: if hud_dict[h].deleted:
eb.remove(hud_dict[h].tablehudlabel)
del(hud_dict[h]) del(hud_dict[h])
# get basic info about the new hand from the db # get basic info about the new hand from the db
@ -162,10 +172,11 @@ if __name__== "__main__":
main_window = gtk.Window() main_window = gtk.Window()
main_window.connect("destroy", destroy) main_window.connect("destroy", destroy)
eb = gtk.EventBox() eb = gtk.VBox()
label = gtk.Label('Closing this window will exit from the HUD.') label = gtk.Label('Closing this window will exit from the HUD.')
eb.add(label) eb.add(label)
main_window.add(eb) main_window.add(eb)
main_window.set_title("HUD Main Window") main_window.set_title("HUD Main Window")
main_window.show_all() main_window.show_all()

View File

@ -576,5 +576,7 @@ class Pot(object):
elif len(self.pots) == 3: elif len(self.pots) == 3:
return "Total pot $%.2f Main pot $%.2f. Side pot-1 $%2.2f. Side pot-2 $%.2f." % (self.total, self.pots[0], self.pots[1], self.pots[2]) return "Total pot $%.2f Main pot $%.2f. Side pot-1 $%2.2f. Side pot-2 $%.2f." % (self.total, self.pots[0], self.pots[1], self.pots[2])
else: else:
return "too many pots.. fix me.", self.pots return "maybe no pot.. or too many pots.. no small blind and walk in bb?."
# I don't know stars format for a walk in the bb when sb doesn't post.
# The thing to do here is raise a Hand error like fpdb import does and file it into errors.txt

View File

@ -69,27 +69,30 @@ class Hud:
print "Setting font to ", font + " " + font_size print "Setting font to ", font + " " + font_size
self.font = pango.FontDescription(font + " " + font_size) self.font = pango.FontDescription(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?
# Set up a main window for this this instance of the HUD # Set up a main window for this this instance of the HUD
self.main_window = gtk.Window() self.main_window = gtk.Window()
# self.window.set_decorated(0)
self.main_window.set_gravity(gtk.gdk.GRAVITY_STATIC) self.main_window.set_gravity(gtk.gdk.GRAVITY_STATIC)
self.main_window.set_title(table.name + " FPDBHUD") self.main_window.set_title(table.name + " FPDBHUD")
self.main_window.connect("destroy", self.kill_hud) self.main_window.connect("destroy", self.kill_hud)
self.main_window.set_decorated(False) self.main_window.set_decorated(False)
self.main_window.set_opacity(self.colors["hudopacity"]) self.main_window.set_opacity(self.colors["hudopacity"])
#self.main_window.set_transient_for(parent.get_toplevel())
self.ebox = gtk.EventBox() self.ebox = gtk.EventBox()
# self.label = gtk.Label("Right click to close HUD for %s\nor Save Stat Positions." % (table.name))
self.label = gtk.Label("FPDB Menu (Right Click)\nLeft-drag to move") self.label = gtk.Label("FPDB Menu (Right Click)\nLeft-drag to move")
self.label.modify_bg(gtk.STATE_NORMAL, gtk.gdk.color_parse(self.colors['hudbgcolor'])) self.backgroundcolor = gtk.gdk.color_parse(self.colors['hudbgcolor'])
self.label.modify_fg(gtk.STATE_NORMAL, gtk.gdk.color_parse(self.colors['hudfgcolor'])) self.foregroundcolor = gtk.gdk.color_parse(self.colors['hudfgcolor'])
self.label.modify_bg(gtk.STATE_NORMAL, self.backgroundcolor)
self.label.modify_fg(gtk.STATE_NORMAL, self.foregroundcolor)
self.main_window.add(self.ebox) self.main_window.add(self.ebox)
self.ebox.add(self.label) self.ebox.add(self.label)
self.ebox.modify_bg(gtk.STATE_NORMAL, gtk.gdk.color_parse(self.colors['hudbgcolor']))
self.ebox.modify_fg(gtk.STATE_NORMAL, gtk.gdk.color_parse(self.colors['hudfgcolor'])) self.ebox.modify_bg(gtk.STATE_NORMAL, self.backgroundcolor)
self.ebox.modify_fg(gtk.STATE_NORMAL, self.foregroundcolor)
self.main_window.move(self.table.x, self.table.y) self.main_window.move(self.table.x, self.table.y)
@ -118,7 +121,7 @@ class Hud:
self.ebox.connect_object("button-press-event", self.on_button_press, self.menu) self.ebox.connect_object("button-press-event", self.on_button_press, self.menu)
self.main_window.show_all() self.main_window.show_all()
# set_keep_above(1) for windows
if os.name == 'nt': if os.name == 'nt':
self.topify_window(self.main_window) self.topify_window(self.main_window)
else: else:
@ -126,15 +129,12 @@ class Hud:
self.main_window.gdkhandle = gtk.gdk.window_foreign_new(self.main_window.window.xid) # gets a gdk handle for the hud table window self.main_window.gdkhandle = gtk.gdk.window_foreign_new(self.main_window.window.xid) # gets a gdk handle for the hud table window
self.main_window.gdkhandle.set_transient_for(self.main_window.parentgdkhandle) # self.main_window.gdkhandle.set_transient_for(self.main_window.parentgdkhandle) #
self.main_window.set_destroy_with_parent(True)
def update_table_position(self): def update_table_position(self):
# self.main_window.parentgdkhandle = gtk.gdk.window_foreign_new(self.table.number)
# if self.main_window.parentgdkhandle == None:
if os.name == 'nt': if os.name == 'nt':
if not win32gui.IsWindow(self.table.number): if not win32gui.IsWindow(self.table.number):
self.kill_hud() self.kill_hud()
return False return False
# anyone know how to do this in unix, or better yet, trap the X11 error that is triggered when executing the get_origin() for a closed window?
(x, y) = self.main_window.parentgdkhandle.get_origin() (x, y) = self.main_window.parentgdkhandle.get_origin()
if self.table.x != x or self.table.y != y: if self.table.x != x or self.table.y != y:
@ -147,7 +147,6 @@ class Hud:
(x, y) = loc[adj[i]] (x, y) = loc[adj[i]]
if self.stat_windows.has_key(i): if self.stat_windows.has_key(i):
self.stat_windows[i].relocate(x, y) self.stat_windows[i].relocate(x, y)
return True return True
def on_button_press(self, widget, event): def on_button_press(self, widget, event):
@ -176,7 +175,6 @@ class Hud:
def save_layout(self, *args): def save_layout(self, *args):
new_layout = [(0, 0)] * self.max new_layout = [(0, 0)] * self.max
# todo: have the hud track the poker table's window position regularly, don't forget to update table.x and table.y.
for sw in self.stat_windows: for sw in self.stat_windows:
loc = self.stat_windows[sw].window.get_position() loc = self.stat_windows[sw].window.get_position()
new_loc = (loc[0] - self.table.x, loc[1] - self.table.y) new_loc = (loc[0] - self.table.x, loc[1] - self.table.y)
@ -267,8 +265,9 @@ class Hud:
self.stat_windows[stat_dict[s]['seat']].label[r][c].modify_fg(gtk.STATE_NORMAL, gtk.gdk.color_parse(this_stat.hudcolor)) self.stat_windows[stat_dict[s]['seat']].label[r][c].modify_fg(gtk.STATE_NORMAL, gtk.gdk.color_parse(this_stat.hudcolor))
self.stat_windows[stat_dict[s]['seat']].label[r][c].set_text(statstring) self.stat_windows[stat_dict[s]['seat']].label[r][c].set_text(statstring)
if statstring != "xxx": if statstring != "xxx": # is there a way to tell if this particular stat window is visible already, or no?
self.stat_windows[stat_dict[s]['seat']].window.show_all() self.stat_windows[stat_dict[s]['seat']].window.show_all()
self.reposition_windows()
tip = stat_dict[s]['screen_name'] + "\n" + number[5] + "\n" + \ tip = stat_dict[s]['screen_name'] + "\n" + number[5] + "\n" + \
number[3] + ", " + number[4] number[3] + ", " + number[4]
Stats.do_tip(self.stat_windows[stat_dict[s]['seat']].e_box[r][c], tip) Stats.do_tip(self.stat_windows[stat_dict[s]['seat']].e_box[r][c], tip)
@ -291,29 +290,13 @@ class Hud:
for w in tl_windows: for w in tl_windows:
if w[1] == unique_name: if w[1] == unique_name:
#win32gui.ShowWindow(w[0], win32con.SW_HIDE)
self.main_window.parentgdkhandle = gtk.gdk.window_foreign_new(long(self.table.number)) self.main_window.parentgdkhandle = gtk.gdk.window_foreign_new(long(self.table.number))
self.main_window.gdkhandle = gtk.gdk.window_foreign_new(w[0]) self.main_window.gdkhandle = gtk.gdk.window_foreign_new(w[0])
self.main_window.gdkhandle.set_transient_for(self.main_window.parentgdkhandle) self.main_window.gdkhandle.set_transient_for(self.main_window.parentgdkhandle)
#win32gui.ShowWindow(w[0], win32con.SW_SHOW)
style = win32gui.GetWindowLong(self.table.number, win32con.GWL_EXSTYLE) style = win32gui.GetWindowLong(self.table.number, win32con.GWL_EXSTYLE)
#style |= win32con.WS_EX_TOOLWINDOW
#style &= ~win32con.WS_EX_APPWINDOW
style |= win32con.WS_CLIPCHILDREN style |= win32con.WS_CLIPCHILDREN
win32gui.SetWindowLong(self.table.number, win32con.GWL_EXSTYLE, style) win32gui.SetWindowLong(self.table.number, win32con.GWL_EXSTYLE, style)
#win32gui.SetWindowPos(w[0], win32con.HWND_TOPMOST, 0, 0, 0, 0, win32con.SWP_NOMOVE|win32con.SWP_NOSIZE)
# notify_id = (w[0],
# 0,
# win32gui.NIF_ICON | win32gui.NIF_MESSAGE | win32gui.NIF_TIP,
# win32con.WM_USER+20,
# 0,
# '')
# win32gui.Shell_NotifyIcon(win32gui.NIM_DELETE, notify_id)
#
window.set_title(real_name) window.set_title(real_name)
class Stat_Window: class Stat_Window:
@ -335,7 +318,6 @@ class Stat_Window:
if event.button == 2: # middle button event if event.button == 2: # middle button event
self.window.hide() self.window.hide()
# print "middle button clicked"
pass pass
if event.button == 1: # left button event if event.button == 1: # left button event
@ -349,7 +331,6 @@ class Stat_Window:
# Callback from the timeout in the single-click finding part of the # Callback from the timeout in the single-click finding part of the
# button press call back. This needs to be modified to get all the # button press call back. This needs to be modified to get all the
# arguments from the call. # arguments from the call.
# print "left button clicked"
self.sb_click = 0 self.sb_click = 0
Popup_window(widget, self) Popup_window(widget, self)
return False return False
@ -404,19 +385,18 @@ class Stat_Window:
for c in range(self.game.cols): for c in range(self.game.cols):
self.e_box[r].append( gtk.EventBox() ) self.e_box[r].append( gtk.EventBox() )
self.e_box[r][c].modify_bg(gtk.STATE_NORMAL, gtk.gdk.color_parse(parent.colors['hudbgcolor'])) self.e_box[r][c].modify_bg(gtk.STATE_NORMAL, parent.backgroundcolor)
self.e_box[r][c].modify_fg(gtk.STATE_NORMAL, gtk.gdk.color_parse(parent.colors['hudfgcolor'])) self.e_box[r][c].modify_fg(gtk.STATE_NORMAL, parent.foregroundcolor)
Stats.do_tip(self.e_box[r][c], 'farts') Stats.do_tip(self.e_box[r][c], 'farts')
self.grid.attach(self.e_box[r][c], c, c+1, r, r+1, xpadding = 0, ypadding = 0) self.grid.attach(self.e_box[r][c], c, c+1, r, r+1, xpadding = 0, ypadding = 0)
self.label[r].append( gtk.Label('xxx') ) self.label[r].append( gtk.Label('xxx') )
self.label[r][c].modify_bg(gtk.STATE_NORMAL, gtk.gdk.color_parse(parent.colors['hudbgcolor'])) self.label[r][c].modify_bg(gtk.STATE_NORMAL, parent.backgroundcolor)
self.label[r][c].modify_fg(gtk.STATE_NORMAL, gtk.gdk.color_parse(parent.colors['hudfgcolor'])) self.label[r][c].modify_fg(gtk.STATE_NORMAL, parent.foregroundcolor)
self.e_box[r][c].add(self.label[r][c]) self.e_box[r][c].add(self.label[r][c])
self.e_box[r][c].connect("button_press_event", self.button_press_cb) self.e_box[r][c].connect("button_press_event", self.button_press_cb)
# font = pango.FontDescription(self.font)
self.label[r][c].modify_font(font) self.label[r][c].modify_font(font)
self.window.set_opacity(parent.colors['hudopacity']) self.window.set_opacity(parent.colors['hudopacity'])
@ -436,7 +416,6 @@ class Popup_window:
self.window = gtk.Window() self.window = gtk.Window()
self.window.set_decorated(0) self.window.set_decorated(0)
self.window.set_gravity(gtk.gdk.GRAVITY_STATIC) self.window.set_gravity(gtk.gdk.GRAVITY_STATIC)
# self.window.set_keep_above(1)
self.window.set_title("popup") self.window.set_title("popup")
self.window.set_property("skip-taskbar-hint", True) self.window.set_property("skip-taskbar-hint", True)
self.window.set_transient_for(parent.get_toplevel()) self.window.set_transient_for(parent.get_toplevel())
@ -451,14 +430,12 @@ class Popup_window:
self.window.add(self.ebox) self.window.add(self.ebox)
self.ebox.add(self.lab) self.ebox.add(self.lab)
self.ebox.modify_bg(gtk.STATE_NORMAL, gtk.gdk.color_parse(stat_window.parent.colors['hudbgcolor'])) self.ebox.modify_bg(gtk.STATE_NORMAL, stat_window.parent.backgroundcolor)
self.ebox.modify_fg(gtk.STATE_NORMAL, gtk.gdk.color_parse(stat_window.parent.colors['hudfgcolor'])) self.ebox.modify_fg(gtk.STATE_NORMAL, stat_window.parent.foregroundcolor)
self.window.modify_bg(gtk.STATE_NORMAL, gtk.gdk.color_parse(stat_window.parent.colors['hudbgcolor'])) self.window.modify_bg(gtk.STATE_NORMAL, stat_window.parent.backgroundcolor)
self.window.modify_fg(gtk.STATE_NORMAL, gtk.gdk.color_parse(stat_window.parent.colors['hudfgcolor'])) self.window.modify_fg(gtk.STATE_NORMAL, stat_window.parent.foregroundcolor)
self.lab.modify_bg(gtk.STATE_NORMAL, gtk.gdk.color_parse(stat_window.parent.colors['hudbgcolor'])) self.lab.modify_bg(gtk.STATE_NORMAL, stat_window.parent.backgroundcolor)
self.lab.modify_fg(gtk.STATE_NORMAL, gtk.gdk.color_parse(stat_window.parent.colors['hudfgcolor'])) self.lab.modify_fg(gtk.STATE_NORMAL, stat_window.parent.foregroundcolor)
# self.window.realize()
# figure out the row, col address of the click that activated the popup # figure out the row, col address of the click that activated the popup
row = 0 row = 0
@ -502,8 +479,8 @@ class Popup_window:
self.window.set_transient_for(stat_window.window) self.window.set_transient_for(stat_window.window)
# set_keep_above(1) for windows if os.name == 'nt':
if os.name == 'nt': self.topify_window(self.window) self.topify_window(self.window)
def button_press_cb(self, widget, event, *args): def button_press_cb(self, widget, event, *args):
# This handles all callbacks from button presses on the event boxes in # This handles all callbacks from button presses on the event boxes in
@ -521,11 +498,9 @@ class Popup_window:
if event.button == 2: # middle button event if event.button == 2: # middle button event
pass pass
# print "middle button clicked"
if event.button == 3: # right button event if event.button == 3: # right button event
pass pass
# print "right button clicked"
def single_click(self, widget): def single_click(self, widget):
# Callback from the timeout in the single-click finding part of the # Callback from the timeout in the single-click finding part of the
@ -564,22 +539,8 @@ class Popup_window:
for w in tl_windows: for w in tl_windows:
if w[1] == unique_name: if w[1] == unique_name:
# win32gui.ShowWindow(w[0], win32con.SW_HIDE)
# style = win32gui.GetWindowLong(w[0], win32con.GWL_EXSTYLE)
# style |= win32con.WS_EX_TOOLWINDOW
# style &= ~win32con.WS_EX_APPWINDOW
# win32gui.SetWindowLong(w[0], win32con.GWL_EXSTYLE, style)
# win32gui.ShowWindow(w[0], win32con.SW_SHOW)
win32gui.SetWindowPos(w[0], win32con.HWND_TOPMOST, 0, 0, 0, 0, win32con.SWP_NOMOVE|win32con.SWP_NOSIZE) win32gui.SetWindowPos(w[0], win32con.HWND_TOPMOST, 0, 0, 0, 0, win32con.SWP_NOMOVE|win32con.SWP_NOSIZE)
# notify_id = (w[0],
# 0,
# win32gui.NIF_ICON | win32gui.NIF_MESSAGE | win32gui.NIF_TIP,
# win32con.WM_USER+20,
# 0,
# '')
# win32gui.Shell_NotifyIcon(win32gui.NIM_DELETE, notify_id)
#
window.set_title(real_name) window.set_title(real_name)
if __name__== "__main__": if __name__== "__main__":

View File

@ -281,13 +281,7 @@ def steal(stat_dict, player):
'% steal attempted' '% steal attempted'
) )
except: except:
return (stat, return (stat, 'NA', 'st=NA', 'steal=NA', '(0/0)', '% steal attempted')
'%3.1f' % (0) + '%',
'st=%3.1f' % (0) + '%',
'steal=%3.1f' % (0) + '%',
'(%d/%d)' % (0, 0),
'% steal attempted'
)
def f_SB_steal(stat_dict, player): def f_SB_steal(stat_dict, player):
""" Folded SB to steal.""" """ Folded SB to steal."""
@ -306,7 +300,7 @@ def f_SB_steal(stat_dict, player):
'NA', 'NA',
'fSB=NA', 'fSB=NA',
'fSB_s=NA', 'fSB_s=NA',
'0/0', '(0/0)',
'% folded SB to steal') '% folded SB to steal')
def f_BB_steal(stat_dict, player): def f_BB_steal(stat_dict, player):
@ -326,7 +320,7 @@ def f_BB_steal(stat_dict, player):
'NA', 'NA',
'fBB=NA', 'fBB=NA',
'fBB_s=NA', 'fBB_s=NA',
'0/0', '(0/0)',
'% folded BB to steal') '% folded BB to steal')
def three_B_0(stat_dict, player): def three_B_0(stat_dict, player):

View File

@ -152,7 +152,7 @@ def discover_posix_by_name(c, tablename):
info = decode_xwininfo(c, listing) info = decode_xwininfo(c, listing)
if not info['name'] == tablename: continue if not info['name'] == tablename: continue
return info return info
return False return None
def discover_posix_tournament(c, t_number, s_number): def discover_posix_tournament(c, t_number, s_number):
"""Finds the X window for a client, given tournament and table nos.""" """Finds the X window for a client, given tournament and table nos."""
@ -160,7 +160,7 @@ def discover_posix_tournament(c, t_number, s_number):
for listing in os.popen('xwininfo -root -tree').readlines(): for listing in os.popen('xwininfo -root -tree').readlines():
if re.search(search_string, listing): if re.search(search_string, listing):
return decode_xwininfo(c, listing) return decode_xwininfo(c, listing)
return False return None
def decode_xwininfo(c, info_string): def decode_xwininfo(c, info_string):
"""Gets window parameters from xwinifo string--XWindows.""" """Gets window parameters from xwinifo string--XWindows."""
@ -231,7 +231,7 @@ def discover_nt_by_name(c, tablename):
if titles[hwnd].find("HUD:") > -1: continue if titles[hwnd].find("HUD:") > -1: continue
if titles[hwnd].find("Chat:") > -1: continue if titles[hwnd].find("Chat:") > -1: continue
return decode_windows(c, titles[hwnd], hwnd) return decode_windows(c, titles[hwnd], hwnd)
return False return None
def discover_nt_tournament(c, tour_number, tab_number): def discover_nt_tournament(c, tour_number, tab_number):
"""Finds the Windows window handle for the given tournament/table.""" """Finds the Windows window handle for the given tournament/table."""
@ -242,7 +242,7 @@ def discover_nt_tournament(c, tour_number, tab_number):
for hwnd in titles.keys(): for hwnd in titles.keys():
if re.search(search_string, titles[hwnd]): if re.search(search_string, titles[hwnd]):
return decode_windows(c, titles[hwnd], hwnd) return decode_windows(c, titles[hwnd], hwnd)
return False return None
def get_nt_exe(hwnd): def get_nt_exe(hwnd):
"""Finds the name of the executable that the given window handle belongs to.""" """Finds the name of the executable that the given window handle belongs to."""

View File

@ -282,14 +282,12 @@ class Importer:
self.fdb.db.commit() self.fdb.db.commit()
self.handsId=handsId self.handsId=handsId
return handsId return handsId
#end def import_file_dict
def parseTourneyHistory(self): def parseTourneyHistory(self):
print "Tourney history parser stub" print "Tourney history parser stub"
#Find tournament boundaries. #Find tournament boundaries.
#print self.foabs #print self.foabs
def printEmailErrorMessage(self, errors, filename, line): def printEmailErrorMessage(self, errors, filename, line):
traceback.print_exc(file=sys.stderr) traceback.print_exc(file=sys.stderr)
print "Error No.",errors,", please send the hand causing this to steffen@sycamoretest.info so I can fix it." print "Error No.",errors,", please send the hand causing this to steffen@sycamoretest.info so I can fix it."

View File

@ -329,6 +329,307 @@ def analyzeDB(fdb):
#end def analyzeDB #end def analyzeDB
# Data Structures for index and foreign key creation
# drop_code is an int with possible values: 0 - don't drop for bulk import
# 1 - drop during bulk import
# db differences:
# - note that mysql automatically creates indexes on constrained columns when
# foreign keys are created, while postgres does not. Hence the much longer list
# of indexes is required for postgres.
# all primary keys are left on all the time
#
# table column drop_code
indexes = [
[ ] # no db with index 0
, [ ] # no db with index 1
, [ # indexes for mysql (list index 2)
{'tab':'Players', 'col':'name', 'drop':0}
, {'tab':'Hands', 'col':'siteHandNo', 'drop':0}
, {'tab':'Tourneys', 'col':'siteTourneyNo', 'drop':0}
]
, [ # indexes for postgres (list index 3)
{'tab':'Boardcards', 'col':'handId', 'drop':0}
, {'tab':'Gametypes', 'col':'siteId', 'drop':0}
, {'tab':'Hands', 'col':'gametypeId', 'drop':1}
, {'tab':'Hands', 'col':'siteHandNo', 'drop':0}
, {'tab':'HandsActions', 'col':'handplayerId', 'drop':0}
, {'tab':'HandsPlayers', 'col':'handId', 'drop':1}
, {'tab':'HandsPlayers', 'col':'playerId', 'drop':1}
, {'tab':'HandsPlayers', 'col':'tourneysPlayersId', 'drop':0}
, {'tab':'HudCache', 'col':'gametypeId', 'drop':1}
, {'tab':'HudCache', 'col':'playerId', 'drop':0}
, {'tab':'HudCache', 'col':'tourneyTypeId', 'drop':0}
, {'tab':'Players', 'col':'siteId', 'drop':1}
, {'tab':'Players', 'col':'name', 'drop':0}
, {'tab':'Tourneys', 'col':'tourneyTypeId', 'drop':1}
, {'tab':'Tourneys', 'col':'siteTourneyNo', 'drop':0}
, {'tab':'TourneysPlayers', 'col':'playerId', 'drop':0}
, {'tab':'TourneysPlayers', 'col':'tourneyId', 'drop':0}
, {'tab':'TourneyTypes', 'col':'siteId', 'drop':0}
]
]
foreignKeys = [
[ ] # no db with index 0
, [ ] # no db with index 1
, [ # foreign keys for mysql
{'fktab':'Hands', 'fkcol':'gametypeId', 'rtab':'Gametypes', 'rcol':'id', 'drop':1}
, {'fktab':'HandsPlayers', 'fkcol':'handId', 'rtab':'Hands', 'rcol':'id', 'drop':1}
, {'fktab':'HandsPlayers', 'fkcol':'playerId', 'rtab':'Players', 'rcol':'id', 'drop':1}
, {'fktab':'HandsActions', 'fkcol':'handPlayerId', 'rtab':'HandsPlayers', 'rcol':'id', 'drop':1}
, {'fktab':'HudCache', 'fkcol':'gametypeId', 'rtab':'Gametypes', 'rcol':'id', 'drop':1}
, {'fktab':'HudCache', 'fkcol':'playerId', 'rtab':'Players', 'rcol':'id', 'drop':0}
, {'fktab':'HudCache', 'fkcol':'tourneyTypeId', 'rtab':'TourneyTypes', 'rcol':'id', 'drop':1}
]
, [ # foreign keys for postgres
{'fktab':'Hands', 'fkcol':'gametypeId', 'rtab':'Gametypes', 'rcol':'id', 'drop':1}
, {'fktab':'HandsPlayers', 'fkcol':'handId', 'rtab':'Hands', 'rcol':'id', 'drop':1}
, {'fktab':'HandsPlayers', 'fkcol':'playerId', 'rtab':'Players', 'rcol':'id', 'drop':1}
, {'fktab':'HandsActions', 'fkcol':'handPlayerId', 'rtab':'HandsPlayers', 'rcol':'id', 'drop':1}
, {'fktab':'HudCache', 'fkcol':'gametypeId', 'rtab':'Gametypes', 'rcol':'id', 'drop':1}
, {'fktab':'HudCache', 'fkcol':'playerId', 'rtab':'Players', 'rcol':'id', 'drop':0}
, {'fktab':'HudCache', 'fkcol':'tourneyTypeId', 'rtab':'TourneyTypes', 'rcol':'id', 'drop':1}
]
]
# MySQL Notes:
# "FOREIGN KEY (handId) REFERENCES Hands(id)" - requires index on Hands.id
# - creates index handId on <thistable>.handId
# alter table t drop foreign key fk
# alter table t add foreign key (fkcol) references tab(rcol)
# alter table t add constraint c foreign key (fkcol) references tab(rcol)
# (fkcol is used for foreigh key name)
# mysql to list indexes:
# SELECT table_name, index_name, non_unique, column_name
# FROM INFORMATION_SCHEMA.STATISTICS
# WHERE table_name = 'tbl_name'
# AND table_schema = 'db_name'
# ORDER BY table_name, index_name, seq_in_index
#
# ALTER TABLE Tourneys ADD INDEX siteTourneyNo(siteTourneyNo)
# ALTER TABLE tab DROP INDEX idx
# mysql to list fks:
# SELECT constraint_name, table_name, column_name, referenced_table_name, referenced_column_name
# FROM information_schema.KEY_COLUMN_USAGE
# WHERE REFERENCED_TABLE_SCHEMA = (your schema name here)
# AND REFERENCED_TABLE_NAME is not null
# ORDER BY TABLE_NAME, COLUMN_NAME;
# this may indicate missing object
# _mysql_exceptions.OperationalError: (1025, "Error on rename of '.\\fpdb\\hands' to '.\\fpdb\\#sql2-7f0-1b' (errno: 152)")
# PG notes:
# To add a foreign key constraint to a table:
# ALTER TABLE tab ADD CONSTRAINT c FOREIGN KEY (col) REFERENCES t2(col2) MATCH FULL;
# ALTER TABLE tab DROP CONSTRAINT zipchk
#
# Note: index names must be unique across a schema
# CREATE INDEX idx ON tab(col)
# DROP INDEX idx
def prepareBulkImport(fdb):
"""Drop some indexes/foreign keys to prepare for bulk import.
Currently keeping the standalone indexes as needed to import quickly"""
# fdb is a fpdb_db object including backend, db, cursor, sql variables
if fdb.backend == PGSQL:
fdb.db.set_isolation_level(0) # allow table/index operations to work
for fk in foreignKeys[fdb.backend]:
if fk['drop'] == 1:
if fdb.backend == MYSQL_INNODB:
fdb.cursor.execute("SELECT constraint_name " +
"FROM information_schema.KEY_COLUMN_USAGE " +
#"WHERE REFERENCED_TABLE_SCHEMA = 'fpdb'
"WHERE 1=1 " +
"AND table_name = %s AND column_name = %s " +
"AND referenced_table_name = %s " +
"AND referenced_column_name = %s ",
(fk['fktab'], fk['fkcol'], fk['rtab'], fk['rcol']) )
cons = fdb.cursor.fetchone()
print "preparebulk: cons=", cons
if cons:
print "dropping mysql fk", cons[0], fk['fktab'], fk['fkcol']
try:
fdb.cursor.execute("alter table " + fk['fktab'] + " drop foreign key " + cons[0])
except:
pass
elif fdb.backend == PGSQL:
print "dropping pg fk", fk['fktab'], fk['fkcol']
try:
fdb.cursor.execute("alter table " + fk['fktab'] + " drop constraint "
+ fk['fktab'] + '_' + fk['fkcol'] + '_fkey')
except:
pass
else:
print "Only MySQL and Postgres supported so far"
return -1
for idx in indexes[fdb.backend]:
if idx['drop'] == 1:
if fdb.backend == MYSQL_INNODB:
print "dropping mysql index ", idx['tab'], idx['col']
try:
fdb.cursor.execute( "alter table %s drop index %s", (idx['tab'],idx['col']) )
except:
pass
elif fdb.backend == PGSQL:
print "dropping pg index ", idx['tab'], idx['col']
# mod to use tab_col for index name?
try:
fdb.cursor.execute( "drop index %s_%s_idx" % (idx['tab'],idx['col']) )
except:
pass
else:
print "Only MySQL and Postgres supported so far"
return -1
if fdb.backend == PGSQL:
fdb.db.set_isolation_level(1) # go back to normal isolation level
fdb.db.commit() # seems to clear up errors if there were any in postgres
#end def prepareBulkImport
def afterBulkImport(fdb):
"""Re-create any dropped indexes/foreign keys after bulk import"""
# fdb is a fpdb_db object including backend, db, cursor, sql variables
if fdb.backend == PGSQL:
fdb.db.set_isolation_level(0) # allow table/index operations to work
for fk in foreignKeys[fdb.backend]:
if fk['drop'] == 1:
if fdb.backend == MYSQL_INNODB:
fdb.cursor.execute("SELECT constraint_name " +
"FROM information_schema.KEY_COLUMN_USAGE " +
#"WHERE REFERENCED_TABLE_SCHEMA = 'fpdb'
"WHERE 1=1 " +
"AND table_name = %s AND column_name = %s " +
"AND referenced_table_name = %s " +
"AND referenced_column_name = %s ",
(fk['fktab'], fk['fkcol'], fk['rtab'], fk['rcol']) )
cons = fdb.cursor.fetchone()
print "afterbulk: cons=", cons
if cons:
pass
else:
print "creating fk ", fk['fktab'], fk['fkcol'], "->", fk['rtab'], fk['rcol']
try:
fdb.cursor.execute("alter table " + fk['fktab'] + " add foreign key ("
+ fk['fkcol'] + ") references " + fk['rtab'] + "("
+ fk['rcol'] + ")")
except:
pass
elif fdb.backend == PGSQL:
print "creating fk ", fk['fktab'], fk['fkcol'], "->", fk['rtab'], fk['rcol']
try:
fdb.cursor.execute("alter table " + fk['fktab'] + " add constraint "
+ fk['fktab'] + '_' + fk['fkcol'] + '_fkey'
+ " foreign key (" + fk['fkcol']
+ ") references " + fk['rtab'] + "(" + fk['rcol'] + ")")
except:
pass
else:
print "Only MySQL and Postgres supported so far"
return -1
for idx in indexes[fdb.backend]:
if idx['drop'] == 1:
if fdb.backend == MYSQL_INNODB:
print "creating mysql index ", idx['tab'], idx['col']
try:
fdb.cursor.execute( "alter table %s add index %s(%s)"
, (idx['tab'],idx['col'],idx['col']) )
except:
pass
elif fdb.backend == PGSQL:
# mod to use tab_col for index name?
print "creating pg index ", idx['tab'], idx['col']
try:
print "create index %s_%s_idx on %s(%s)" % (idx['tab'], idx['col'], idx['tab'], idx['col'])
fdb.cursor.execute( "create index %s_%s_idx on %s(%s)"
% (idx['tab'], idx['col'], idx['tab'], idx['col']) )
except:
print " ERROR! :-("
pass
else:
print "Only MySQL and Postgres supported so far"
return -1
if fdb.backend == PGSQL:
fdb.db.set_isolation_level(1) # go back to normal isolation level
fdb.db.commit() # seems to clear up errors if there were any in postgres
#end def afterBulkImport
def createAllIndexes(fdb):
"""Create new indexes"""
if fdb.backend == PGSQL:
fdb.db.set_isolation_level(0) # allow table/index operations to work
for idx in indexes[fdb.backend]:
if fdb.backend == MYSQL_INNODB:
print "creating mysql index ", idx['tab'], idx['col']
try:
fdb.cursor.execute( "alter table %s add index %s(%s)"
, (idx['tab'],idx['col'],idx['col']) )
except:
pass
elif fdb.backend == PGSQL:
# mod to use tab_col for index name?
print "creating pg index ", idx['tab'], idx['col']
try:
print "create index %s_%s_idx on %s(%s)" % (idx['tab'], idx['col'], idx['tab'], idx['col'])
fdb.cursor.execute( "create index %s_%s_idx on %s(%s)"
% (idx['tab'], idx['col'], idx['tab'], idx['col']) )
except:
print " ERROR! :-("
pass
else:
print "Only MySQL and Postgres supported so far"
return -1
if fdb.backend == PGSQL:
fdb.db.set_isolation_level(1) # go back to normal isolation level
#end def createAllIndexes
def dropAllIndexes(fdb):
"""Drop all standalone indexes (i.e. not including primary keys or foreign keys)
using list of indexes in indexes data structure"""
# maybe upgrade to use data dictionary?? (but take care to exclude PK and FK)
if fdb.backend == PGSQL:
fdb.db.set_isolation_level(0) # allow table/index operations to work
for idx in indexes[fdb.backend]:
if fdb.backend == MYSQL_INNODB:
print "dropping mysql index ", idx['tab'], idx['col']
try:
fdb.cursor.execute( "alter table %s drop index %s"
, (idx['tab'],idx['col']) )
except:
pass
elif fdb.backend == PGSQL:
print "dropping pg index ", idx['tab'], idx['col']
# mod to use tab_col for index name?
try:
fdb.cursor.execute( "drop index %s_%s_idx"
% (idx['tab'],idx['col']) )
except:
pass
else:
print "Only MySQL and Postgres supported so far"
return -1
if fdb.backend == PGSQL:
fdb.db.set_isolation_level(1) # go back to normal isolation level
#end def dropAllIndexes
def analyzeDB(fdb):
"""Do whatever the DB can offer to update index/table statistics"""
if fdb.backend == PGSQL:
fdb.db.set_isolation_level(0) # allow vacuum to work
try:
fdb.cursor.execute("vacuum analyze")
except:
print "Error during vacuum"
fdb.db.set_isolation_level(1) # go back to normal isolation level
#end def analyzeDB
class DuplicateError(Exception): class DuplicateError(Exception):
def __init__(self, value): def __init__(self, value):
@ -392,7 +693,8 @@ def checkPositions(positions):
pass pass
### RHH modified to allow for "position 9" here (pos==9 is when you're a dead hand before the BB ### RHH modified to allow for "position 9" here (pos==9 is when you're a dead hand before the BB
if (pos!="B" and pos!="S" and pos!=0 and pos!=1 and pos!=2 and pos!=3 and pos!=4 and pos!=5 and pos!=6 and pos!=7 and pos != 8 and pos!=9): ### eric - position 8 could be valid - if only one blind is posted, but there's still 10 people, ie a sitout is present, and the small is dead...
if not (pos == "B" or pos == "S" or (pos >= 0 and pos <= 9)):
raise FpdbError("invalid position found in checkPositions. i: "+str(i)+" position: "+str(pos)) raise FpdbError("invalid position found in checkPositions. i: "+str(i)+" position: "+str(pos))
#end def fpdb_simple.checkPositions #end def fpdb_simple.checkPositions
@ -1232,11 +1534,17 @@ def parsePositions (hand, names):
if (bb!=-1): if (bb!=-1):
bb=recognisePlayerNo(bb, names, "bet") bb=recognisePlayerNo(bb, names, "bet")
# print "sb = ", sb, "bb = ", bb
if bb == sb:
sbExists = False
sb = -1
#write blinds into array #write blinds into array
if (sbExists): if (sbExists):
positions[sb]="S" positions[sb]="S"
positions[bb]="B" positions[bb]="B"
#fill up rest of array #fill up rest of array
if (sbExists): if (sbExists):
arraypos=sb-1 arraypos=sb-1
@ -1249,15 +1557,24 @@ def parsePositions (hand, names):
arraypos-=1 arraypos-=1
distFromBtn+=1 distFromBtn+=1
# eric - this takes into account dead seats between blinds
if sbExists:
i = bb - 1
while positions[i] < 0 and i != sb:
positions[i] = 9
i -= 1
### RHH - Changed to set the null seats before BB to "9" ### RHH - Changed to set the null seats before BB to "9"
i=bb-1 if sbExists:
i = sb-1
else:
i = bb-1
while positions[i] < 0: while positions[i] < 0:
positions[i]=9 positions[i]=9
i-=1 i-=1
arraypos=len(names)-1 arraypos=len(names)-1
if (bb!=0 or (bb==0 and sbExists==False)): if (bb!=0 or (bb==0 and sbExists==False) or (bb == 1 and sb != arraypos) ):
while (arraypos>bb): while (arraypos>bb and arraypos > sb):
positions[arraypos]=distFromBtn positions[arraypos]=distFromBtn
arraypos-=1 arraypos-=1
distFromBtn+=1 distFromBtn+=1
@ -1267,6 +1584,7 @@ def parsePositions (hand, names):
print "parsePositions names:",names print "parsePositions names:",names
print "result:",positions print "result:",positions
raise FpdbError ("failed to read positions") raise FpdbError ("failed to read positions")
# print str(positions), "\n"
return positions return positions
#end def parsePositions #end def parsePositions
@ -2048,7 +2366,7 @@ sure to also change the following storage method and table_viewer.prepare_data i
hudDataPositions.append('C') hudDataPositions.append('C')
elif pos>=2 and pos<=4: elif pos>=2 and pos<=4:
hudDataPositions.append('M') hudDataPositions.append('M')
elif pos>=5 and pos<=7: elif pos>=5 and pos<=8:
hudDataPositions.append('E') hudDataPositions.append('E')
### RHH Added this elif to handle being a dead hand before the BB (pos==9) ### RHH Added this elif to handle being a dead hand before the BB (pos==9)
elif pos==9: elif pos==9: