From e880fb89546f9cbb2f36e519ee445fc843fedeb8 Mon Sep 17 00:00:00 2001 From: eblade Date: Thu, 2 Apr 2009 05:02:24 -0400 Subject: [PATCH 01/57] add a giant tooltip temporarily to the popup stats window --- pyfpdb/Hud.py | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/pyfpdb/Hud.py b/pyfpdb/Hud.py index cf96893f..122e94a9 100644 --- a/pyfpdb/Hud.py +++ b/pyfpdb/Hud.py @@ -529,11 +529,15 @@ class Popup_window: # db_connection.close_connection() stat_dict = stat_window.parent.stat_dict pu_text = "" + mo_text = "" for s in stat_list: number = Stats.do_stat(stat_dict, player = int(stat_window.player_id), stat = s) + mo_text += number[5] + " " + number[4] + "\n" pu_text += number[3] + "\n" + - self.lab.set_text(pu_text) + self.lab.set_text(pu_text) + Stats.do_tip(self.lab, mo_text) self.window.show_all() self.window.set_transient_for(stat_window.window) From f1230c459c77aeed94442e5c5b88d692774b151a Mon Sep 17 00:00:00 2001 From: eblade Date: Sat, 30 May 2009 12:02:31 -0400 Subject: [PATCH 02/57] Apparently I made a comment and a change that I didn't realise before 0.11, and forgot to commit. oopsie. --- pyfpdb/Hud.py | 1 + pyfpdb/Tables.py | 4 ++++ 2 files changed, 5 insertions(+) diff --git a/pyfpdb/Hud.py b/pyfpdb/Hud.py index 87cf9f14..8360dc20 100644 --- a/pyfpdb/Hud.py +++ b/pyfpdb/Hud.py @@ -473,6 +473,7 @@ class Popup_window: def __init__(self, parent, stat_window): self.sb_click = 0 self.stat_window = stat_window + self.parent = parent # create the popup window self.window = gtk.Window() diff --git a/pyfpdb/Tables.py b/pyfpdb/Tables.py index ffc50b01..7bc22710 100755 --- a/pyfpdb/Tables.py +++ b/pyfpdb/Tables.py @@ -309,6 +309,10 @@ def get_site_from_exe(c, exe): return params['site_name'] return None +def everleaf_decode_table(tw): +# 2 - Tournament ID: 573256 - NL Hold'em - 150/300 blinds - Good luck ! - [Connection is ...] + pass + def pokerstars_decode_table(tw): # Extract poker information from the window title. This is not needed for # fpdb, since all that information is available in the db via new_hand_number. From 6e63e2a5e945db4f2f49c2a8ac85840813d5bdac Mon Sep 17 00:00:00 2001 From: eblade Date: Wed, 10 Jun 2009 12:58:14 -0400 Subject: [PATCH 03/57] fix some junk related to determining window height/width, b_width and tb_height, comment out the window_foreign_new() that's screwing up the window right now --- pyfpdb/Tables_Demo.py | 2 ++ pyfpdb/WinTables.py | 17 +++++++++++++---- 2 files changed, 15 insertions(+), 4 deletions(-) diff --git a/pyfpdb/Tables_Demo.py b/pyfpdb/Tables_Demo.py index ffc8d412..e141cab1 100644 --- a/pyfpdb/Tables_Demo.py +++ b/pyfpdb/Tables_Demo.py @@ -92,6 +92,8 @@ if __name__=="__main__": print "game =", table.get_game() fake = fake_hud(table) + print "fake =", fake gobject.timeout_add(100, check_on_table, table, fake) + print "calling main" gtk.main() diff --git a/pyfpdb/WinTables.py b/pyfpdb/WinTables.py index b867b83d..cb449a52 100644 --- a/pyfpdb/WinTables.py +++ b/pyfpdb/WinTables.py @@ -65,8 +65,11 @@ class Table(Table_Window): print "x = %s y = %s width = %s height = %s" % (x, y, width, height) self.x = int(x) + b_width self.y = int(y) + tb_height - self.height = int(height) - b_width - tb_height - self.width = int(width) - 2*b_width + self.width = width - x + self.height = height - y + print "x = %s y = %s width = %s height = %s" % (self.x, self.y, self.width, self.height) + #self.height = int(height) - b_width - tb_height + #self.width = int(width) - 2*b_width self.exe = self.get_nt_exe(hwnd) self.title = titles[hwnd] @@ -82,6 +85,8 @@ class Table(Table_Window): try: (x, y, width, height) = win32gui.GetWindowRect(hwnd) + width = width - x + height = height - y return {'x' : int(x) + b_width, 'y' : int(y) + tb_height, 'width' : int(height) - b_width - tb_height, @@ -128,8 +133,12 @@ class Table(Table_Window): for w in tl_windows: if w[1] == unique_name: - hud.main_window.gdkhandle = gtk.gdk.window_foreign_new(w[0]) - hud.main_window.gdkhandle.set_transient_for(self.gdkhandle) +# hud.main_window.gdkhandle = gtk.gdk.window_foreign_new(w[0]) +# hud.main_window.gdkhandle.set_transient_for(self.gdkhandle) + rect = self.gdkhandle.get_frame_extents() + (innerx, innery) = self.gdkhandle.get_origin() + b_width = rect.x - innerx + tb_height = rect.y - innery # # style = win32gui.GetWindowLong(self.number, win32con.GWL_EXSTYLE) # style |= win32con.WS_CLIPCHILDREN From eb37de359477c092098660cb0fe439c5f9797746 Mon Sep 17 00:00:00 2001 From: eblade Date: Wed, 10 Jun 2009 13:47:07 -0400 Subject: [PATCH 04/57] fix get_geometry to use the correct parameters to IsWindow and GetWindowRect (too much error trapping will create pitfalls), use main_window.window instead of window_foreign_new() to get gdkhandle for gtkwindow, remove process enumeration in topify() for windows --- pyfpdb/WinTables.py | 44 ++++++++++++++++++++++---------------------- 1 file changed, 22 insertions(+), 22 deletions(-) diff --git a/pyfpdb/WinTables.py b/pyfpdb/WinTables.py index cb449a52..d8f138eb 100644 --- a/pyfpdb/WinTables.py +++ b/pyfpdb/WinTables.py @@ -79,12 +79,11 @@ class Table(Table_Window): self.gdkhandle = gtk.gdk.window_foreign_new(long(self.window)) def get_geometry(self): - - if not win32gui.IsWindow(self.window): # window closed + if not win32gui.IsWindow(self.number): # window closed return None try: - (x, y, width, height) = win32gui.GetWindowRect(hwnd) + (x, y, width, height) = win32gui.GetWindowRect(self.number) width = width - x height = height - y return {'x' : int(x) + b_width, @@ -121,31 +120,32 @@ class Table(Table_Window): def topify(self, hud): """Set the specified gtk window to stayontop in MS Windows.""" - def windowEnumerationHandler(hwnd, resultList): - '''Callback for win32gui.EnumWindows() to generate list of window handles.''' - resultList.append((hwnd, win32gui.GetWindowText(hwnd))) - - unique_name = 'unique name for finding this window' - real_name = hud.main_window.get_title() - hud.main_window.set_title(unique_name) - tl_windows = [] - win32gui.EnumWindows(windowEnumerationHandler, tl_windows) - - for w in tl_windows: - if w[1] == unique_name: +# def windowEnumerationHandler(hwnd, resultList): +# '''Callback for win32gui.EnumWindows() to generate list of window handles.''' +# resultList.append((hwnd, win32gui.GetWindowText(hwnd))) +# +# unique_name = 'unique name for finding this window' +# real_name = hud.main_window.get_title() +# hud.main_window.set_title(unique_name) +# tl_windows = [] +# win32gui.EnumWindows(windowEnumerationHandler, tl_windows) +# +# for w in tl_windows: +# if w[1] == unique_name: # hud.main_window.gdkhandle = gtk.gdk.window_foreign_new(w[0]) -# hud.main_window.gdkhandle.set_transient_for(self.gdkhandle) - rect = self.gdkhandle.get_frame_extents() - (innerx, innery) = self.gdkhandle.get_origin() - b_width = rect.x - innerx - tb_height = rect.y - innery + hud.main_window.gdkhandle = hud.main_window.window + hud.main_window.gdkhandle.set_transient_for(self.gdkhandle) + rect = self.gdkhandle.get_frame_extents() + (innerx, innery) = self.gdkhandle.get_origin() + b_width = rect.x - innerx + tb_height = rect.y - innery # # style = win32gui.GetWindowLong(self.number, win32con.GWL_EXSTYLE) # style |= win32con.WS_CLIPCHILDREN # win32gui.SetWindowLong(self.number, win32con.GWL_EXSTYLE, style) - break +# break - hud.main_window.set_title(real_name) +# hud.main_window.set_title(real_name) def win_enum_handler(hwnd, titles): titles[hwnd] = win32gui.GetWindowText(hwnd) From c63e0ab46165b6991b44691dad2e500a627de2bf Mon Sep 17 00:00:00 2001 From: eblade Date: Wed, 10 Jun 2009 14:11:20 -0400 Subject: [PATCH 05/57] Q&D change for old Hud code to remove the loop from one topify_window(), as we found out how to get it when working on the new Hud stuff --- pyfpdb/Hud.py | 34 +++++++++++++++++----------------- 1 file changed, 17 insertions(+), 17 deletions(-) diff --git a/pyfpdb/Hud.py b/pyfpdb/Hud.py index 5ff2c9d7..73f1f82c 100644 --- a/pyfpdb/Hud.py +++ b/pyfpdb/Hud.py @@ -339,30 +339,30 @@ class Hud: Stats.do_tip(window.e_box[r][c], tip) def topify_window(self, window): - """Set the specified gtk window to stayontop in MS Windows.""" - - def windowEnumerationHandler(hwnd, resultList): - '''Callback for win32gui.EnumWindows() to generate list of window handles.''' - resultList.append((hwnd, win32gui.GetWindowText(hwnd))) - - unique_name = 'unique name for finding this window' - real_name = window.get_title() - window.set_title(unique_name) - tl_windows = [] - win32gui.EnumWindows(windowEnumerationHandler, tl_windows) - - for w in tl_windows: - if w[1] == unique_name: +# """Set the specified gtk window to stayontop in MS Windows.""" +# +# def windowEnumerationHandler(hwnd, resultList): +# '''Callback for win32gui.EnumWindows() to generate list of window handles.''' +# resultList.append((hwnd, win32gui.GetWindowText(hwnd))) +# unique_name = 'unique name for finding this window' +# real_name = window.get_title() +# window.set_title(unique_name) +# tl_windows = [] +# win32gui.EnumWindows(windowEnumerationHandler, tl_windows) +# +# for w in tl_windows: +# if w[1] == unique_name: self.main_window.parentgdkhandle = gtk.gdk.window_foreign_new(long(self.table.number)) - self.main_window.gdkhandle = gtk.gdk.window_foreign_new(w[0]) +# self.main_window.gdkhandle = gtk.gdk.window_foreign_new(w[0]) + self.main_window.gdkhandle = self.main_window.window self.main_window.gdkhandle.set_transient_for(self.main_window.parentgdkhandle) style = win32gui.GetWindowLong(self.table.number, win32con.GWL_EXSTYLE) style |= win32con.WS_CLIPCHILDREN win32gui.SetWindowLong(self.table.number, win32con.GWL_EXSTYLE, style) - break +# break - window.set_title(real_name) +# window.set_title(real_name) class Stat_Window: From 93172a1a03330fc1b4d03f6d9ae3f025f806d15a Mon Sep 17 00:00:00 2001 From: eblade Date: Fri, 12 Jun 2009 02:30:14 -0400 Subject: [PATCH 06/57] remove the loop from the other topify function (doesn't look like we've needed that in there in months.. oops) --- pyfpdb/Hud.py | 32 ++++++++++++++++---------------- 1 file changed, 16 insertions(+), 16 deletions(-) diff --git a/pyfpdb/Hud.py b/pyfpdb/Hud.py index 73f1f82c..d7f26304 100644 --- a/pyfpdb/Hud.py +++ b/pyfpdb/Hud.py @@ -577,25 +577,25 @@ class Popup_window: def topify_window(self, window): """Set the specified gtk window to stayontop in MS Windows.""" - def windowEnumerationHandler(hwnd, resultList): - '''Callback for win32gui.EnumWindows() to generate list of window handles.''' - resultList.append((hwnd, win32gui.GetWindowText(hwnd))) +# def windowEnumerationHandler(hwnd, resultList): +# '''Callback for win32gui.EnumWindows() to generate list of window handles.''' +# resultList.append((hwnd, win32gui.GetWindowText(hwnd))) - unique_name = 'unique name for finding this window' - real_name = window.get_title() - window.set_title(unique_name) - tl_windows = [] - win32gui.EnumWindows(windowEnumerationHandler, tl_windows) +# unique_name = 'unique name for finding this window' +# real_name = window.get_title() +# window.set_title(unique_name) +# tl_windows = [] +# win32gui.EnumWindows(windowEnumerationHandler, tl_windows) - for w in tl_windows: - if w[1] == unique_name: - window.set_transient_for(self.parent.main_window) - style = win32gui.GetWindowLong(self.table.number, win32con.GWL_EXSTYLE) - style |= win32con.WS_CLIPCHILDREN - win32gui.SetWindowLong(self.table.number, win32con.GWL_EXSTYLE, style) - break +# for w in tl_windows: +# if w[1] == unique_name: + window.set_transient_for(self.parent.main_window) + style = win32gui.GetWindowLong(self.table.number, win32con.GWL_EXSTYLE) + style |= win32con.WS_CLIPCHILDREN + win32gui.SetWindowLong(self.table.number, win32con.GWL_EXSTYLE, style) +# break - window.set_title(real_name) +# window.set_title(real_name) if __name__== "__main__": main_window = gtk.Window() From e00887b865d4d58e31e0441a6d8900b50959769f Mon Sep 17 00:00:00 2001 From: Ray Date: Fri, 19 Jun 2009 15:47:26 -0400 Subject: [PATCH 07/57] Make Flop_Mucked work with the 0-52 card encoding. --- pyfpdb/Mucked.py | 52 +++++++++++++++++++++++++++++------------------- 1 file changed, 32 insertions(+), 20 deletions(-) diff --git a/pyfpdb/Mucked.py b/pyfpdb/Mucked.py index 8ae6bc60..be9228d3 100755 --- a/pyfpdb/Mucked.py +++ b/pyfpdb/Mucked.py @@ -37,7 +37,7 @@ import Configuration import Database import Card -class Aux_Window: +class Aux_Window(object): def __init__(self, hud, params, config): self.hud = hud self.params = params @@ -94,9 +94,11 @@ class Aux_Window: return (card[0], card[1].upper()) def has_cards(self, cards): + """Returns the number of cards in the list.""" + n = 0 for c in cards: - if c in set('shdc'): return True - return False + if c != None and c > 0: n = n + 1 + return n class Stud_mucked(Aux_Window): def __init__(self, hud, config, params): @@ -329,21 +331,26 @@ class Stud_cards: self.seen_cards[(c, r)].set_from_pixbuf(self.card_images[0]) self.eb[(c, r)].set_tooltip_text('') -class Flop_Mucked(Aux_Window): - """Aux_Window class for displaying mucked cards for flop games.""" +class Aux_Seats(Aux_Window): + """A super class to display an aux_window at each seat.""" def __init__(self, hud, config, params): self.hud = hud # hud object that this aux window supports self.config = config # configuration object for this aux window to use self.params = params # dict aux params from config self.positions = {} # dict of window positions -# self.rel_positions = {} # dict of window positions, relative to the table origin - self.displayed_cards = False + self.displayed = False self.timer_on = False # bool = Ture if the timeout for removing the cards is on + +class Flop_Mucked(Aux_Seats): + """Aux_Window class for displaying mucked cards for flop games.""" + + def __init__(self, hud, config, params): + super(Flop_Mucked, self).__init__(hud, config, params) self.card_images = self.get_card_images() def create(self): - self.adj = self.hud.adj_seats(0, self.config) + self.adj = self.hud.adj_seats(0, self.config) # move adj_seats to aux and get rid of it in Hud.py loc = self.config.get_aux_locations(self.params['name'], int(self.hud.max)) self.m_windows = {} # windows to put the card images in @@ -364,7 +371,7 @@ class Flop_Mucked(Aux_Window): self.eb[i].connect("button_press_event", self.button_press_cb) self.m_windows[i].connect("configure_event", self.configure_event_cb, i) self.m_windows[i].add(self.eb[i]) - self.seen_cards[i] = gtk.image_new_from_pixbuf(self.card_images[('B', 'H')]) + self.seen_cards[i] = gtk.image_new_from_pixbuf(self.card_images[0]) self.eb[i].add(self.seen_cards[i]) self.positions[i] = (int(x) + self.hud.table.x, int(y) + self.hud.table.y) # self.rel_positions[i] = (int(x), int(y)) @@ -373,35 +380,40 @@ class Flop_Mucked(Aux_Window): self.m_windows[i].show_all() self.m_windows[i].hide() + def create_contents(self, i): + """Create the widgets for showing the contents of the Aux_seats window.""" + def update_gui(self, new_hand_id): """Prepare and show the mucked cards.""" - if self.displayed_cards: + if self.displayed: self.hide_mucked_cards() - self.displayed_cards = False + self.displayed = False for (i, cards) in self.hud.cards.iteritems(): - if self.has_cards(cards): + n_cards = self.has_cards(cards) + if n_cards > 0: # scratch is a working pixbuf, used to assemble the image scratch = gtk.gdk.Pixbuf(gtk.gdk.COLORSPACE_RGB, True, 8, - int(self.params['card_wd'])*len(cards)/2, + int(self.params['card_wd'])*n_cards, int(self.params['card_ht'])) x = 0 # x coord where the next card starts in scratch - for card in [cards[k:k+2] for k in xrange(0, len(cards), 2)]: + for card in cards: # concatenate each card image to scratch - self.card_images[self.split_cards(card)].copy_area(0, 0, + if card == None or card ==0: + break + self.card_images[card].copy_area(0, 0, int(self.params['card_wd']), int(self.params['card_ht']), scratch, x, 0) x = x + int(self.params['card_wd']) self.seen_cards[i].set_from_pixbuf(scratch) -# self.m_windows[i].show_all() self.m_windows[i].resize(1,1) self.m_windows[i].show() self.m_windows[i].move(self.positions[i][0], self.positions[i][1]) # here is where I move back - self.displayed_cards = True + self.displayed = True for stats in self.hud.stat_dict.itervalues(): self.eb[stats['seat']].set_tooltip_text(stats['screen_name']) - if self.displayed_cards and float(self.params['timeout']) > 0: + if self.displayed and float(self.params['timeout']) > 0: self.timer_on = True gobject.timeout_add(int(1000*float(self.params['timeout'])), self.timed_out) @@ -425,7 +437,7 @@ class Flop_Mucked(Aux_Window): """Hide the mucked card windows.""" for (i, w) in self.m_windows.iteritems(): w.hide() - self.displayed_cards = False + self.displayed = False def button_press_cb(self, widget, event, *args): """Handle button clicks in the event boxes.""" @@ -458,7 +470,7 @@ class Flop_Mucked(Aux_Window): for (i, cards) in self.hud.cards.iteritems(): self.m_windows[i].show() self.m_windows[i].move(self.positions[i][0], self.positions[i][1]) # here is where I move back - self.displayed_cards = True + self.displayed = True def save_layout(self, *args): """Save new layout back to the aux element in the config file.""" From a30708157462b66788432daf1fe66ef3b28d327d Mon Sep 17 00:00:00 2001 From: Ray Date: Fri, 19 Jun 2009 15:51:56 -0400 Subject: [PATCH 08/57] More for Flop_Mucked with 0-52 encoding. --- pyfpdb/Database.py | 8 ++------ pyfpdb/SQL.py | 21 ++++++++------------- 2 files changed, 10 insertions(+), 19 deletions(-) diff --git a/pyfpdb/Database.py b/pyfpdb/Database.py index b6c97a29..d3abfa06 100755 --- a/pyfpdb/Database.py +++ b/pyfpdb/Database.py @@ -170,12 +170,8 @@ class Database: cards = {} c = self.connection.cursor() c.execute(self.sql.query['get_common_cards'], [hand]) - colnames = [desc[0] for desc in c.description] - for row in c.fetchall(): - s_dict = {} - for name, val in zip(colnames, row): - s_dict[name] = val - cards['common'] = (self.convert_cards(s_dict)) +# row = c.fetchone() + cards['common'] = c.fetchone() return cards def convert_cards(self, d): diff --git a/pyfpdb/SQL.py b/pyfpdb/SQL.py index 1a9deb60..77115c50 100644 --- a/pyfpdb/SQL.py +++ b/pyfpdb/SQL.py @@ -541,19 +541,14 @@ class Sql: """ self.query['get_common_cards'] = """ - select - card1Value AS card1value, - card1Suit AS card1suit, - card2Value AS card2value, - card2Suit AS card2suit, - card3Value AS card3value, - card3Suit AS card3suit, - card4Value AS card4value, - card4Suit AS card4suit, - card5Value AS card5value, - card5Suit AS card5suit - from BoardCards - where handId = %s + select + boardcard1, + boardcard2, + boardcard3, + boardcard4, + boardcard5 + from Hands + where Id = %s """ self.query['get_action_from_hand'] = """ From c9572129a655ce6ae5773588fc895141f7dd7569 Mon Sep 17 00:00:00 2001 From: Ray Date: Fri, 19 Jun 2009 16:48:42 -0400 Subject: [PATCH 09/57] Fix passing settings in import chain. --- pyfpdb/fpdb_import.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pyfpdb/fpdb_import.py b/pyfpdb/fpdb_import.py index 99330bb9..3fa20b40 100644 --- a/pyfpdb/fpdb_import.py +++ b/pyfpdb/fpdb_import.py @@ -394,7 +394,7 @@ class Importer: self.hand=hand try: - handsId = fpdb_parse_logic.mainParser(self.settings['db-backend'], self.fdb.db + handsId = fpdb_parse_logic.mainParser(self.settings, self.fdb.db ,self.fdb.cursor, self.siteIds[site], category, hand, self.config) self.fdb.db.commit() From 462ff87596648dc2ea41327543b705263dc4f4da Mon Sep 17 00:00:00 2001 From: Ray Date: Sat, 20 Jun 2009 09:43:05 -0400 Subject: [PATCH 10/57] Add xpad and ypad to site and game elements. Cleanup some defaults. --- pyfpdb/Configuration.py | 39 +++++++++++++++++++++++++++++++++++---- 1 file changed, 35 insertions(+), 4 deletions(-) diff --git a/pyfpdb/Configuration.py b/pyfpdb/Configuration.py index 0ea4b371..13e7cd28 100755 --- a/pyfpdb/Configuration.py +++ b/pyfpdb/Configuration.py @@ -86,14 +86,34 @@ class Site: self.aux_window = node.getAttribute("aux_window") self.font = node.getAttribute("font") self.font_size = node.getAttribute("font_size") - self.use_frames = node.getAttribute("use_frames") + self.use_frames = node.getAttribute("use_frames") self.enabled = fix_tf(node.getAttribute("enabled"), default = True) + self.xpad = node.getAttribute("xpad") + self.ypad = node.getAttribute("ypad") self.layout = {} 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) + + if self.use_frames == "": self.use_frames = False + if self.font == "": self.font = "Sans" + if self.hudbgcolor == "": self.hudbgcolor = "000000" + if self.hudfgcolor == "": self.hudfgcolor = "FFFFFF" + def __str__(self): temp = "Site = " + self.site_name + "\n" for key in dir(self): @@ -119,9 +139,16 @@ class Stat: class Game: def __init__(self, node): self.game_name = node.getAttribute("game_name") - self.db = node.getAttribute("db") self.rows = int( node.getAttribute("rows") ) self.cols = int( node.getAttribute("cols") ) + self.xpad = node.getAttribute("xpad") + self.ypad = node.getAttribute("ypad") + +# 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) aux_text = node.getAttribute("aux") aux_list = aux_text.split(',') @@ -146,9 +173,10 @@ class Game: def __str__(self): temp = "Game = " + self.game_name + "\n" - temp = temp + " db = %s\n" % self.db temp = temp + " rows = %d\n" % self.rows temp = temp + " cols = %d\n" % self.cols + temp = temp + " xpad = %d\n" % self.xpad + temp = temp + " ypad = %d\n" % self.ypad temp = temp + " aux = %s\n" % self.aux for stat in self.stats.keys(): @@ -631,6 +659,8 @@ class Config: parms["font"] = self.supported_sites[site].font parms["font_size"] = self.supported_sites[site].font_size parms["enabled"] = self.supported_sites[site].enabled + parms["xpad"] = self.supported_sites[site].xpad + parms["ypad"] = self.supported_sites[site].ypad return parms def set_site_parameters(self, site_name, converter = None, decoder = None, @@ -681,9 +711,10 @@ class Config: param = {} if self.supported_games.has_key(name): param['game_name'] = self.supported_games[name].game_name - param['db'] = self.supported_games[name].db param['rows'] = self.supported_games[name].rows param['cols'] = self.supported_games[name].cols + param['xpad'] = self.supported_games[name].xpad + param['ypad'] = self.supported_games[name].ypad param['aux'] = self.supported_games[name].aux return param From 287394c97dfcb4e764684973ae0dde0ab88ee289 Mon Sep 17 00:00:00 2001 From: Ray Date: Sat, 20 Jun 2009 10:01:52 -0400 Subject: [PATCH 11/57] Use xpad and ypad from game element. --- pyfpdb/Hud.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pyfpdb/Hud.py b/pyfpdb/Hud.py index 56ad08f3..77381749 100644 --- a/pyfpdb/Hud.py +++ b/pyfpdb/Hud.py @@ -445,10 +445,10 @@ class Stat_Window: Stats.do_tip(e_box[r][c], 'stuff') if usegtkframes: - grid.attach(self.frame[r][c], c, c+1, r, r+1, xpadding = 0, ypadding = 0) + grid.attach(self.frame[r][c], c, c+1, r, r+1, xpadding = game.xpad, ypadding = game.ypad) self.frame[r][c].add(e_box[r][c]) else: - grid.attach(e_box[r][c], c, c+1, r, r+1, xpadding = 0, ypadding = 0) + grid.attach(e_box[r][c], c, c+1, r, r+1, xpadding = game.xpad, ypadding = game.ypad) label[r].append( gtk.Label('xxx') ) if usegtkframes: From ac30e912c76bc3f6a731d5657850d1ee1133a0a4 Mon Sep 17 00:00:00 2001 From: sqlcoder Date: Mon, 22 Jun 2009 21:39:14 +0100 Subject: [PATCH 12/57] smarten up positional stats tab (still needs configurable columns) --- pyfpdb/GuiPositionalStats.py | 184 ++++++++++++++++++++++------------- 1 file changed, 119 insertions(+), 65 deletions(-) diff --git a/pyfpdb/GuiPositionalStats.py b/pyfpdb/GuiPositionalStats.py index 0e20e632..dce7cb77 100644 --- a/pyfpdb/GuiPositionalStats.py +++ b/pyfpdb/GuiPositionalStats.py @@ -62,17 +62,46 @@ class GuiPositionalStats (threading.Thread): self.filters.registerButton1Name("Refresh") self.filters.registerButton1Callback(self.refreshStats) + # ToDo: store in config + # ToDo: create popup to adjust column config + # columns to display, keys match column name returned by sql, values in tuple are: + # is column displayed, column heading, xalignment, formatting + self.columns = [ ["game", True, "Game", 0.0, "%s"] + , ["hand", False, "Hand", 0.0, "%s"] # true not allowed for this line + , ["plposition", False, "Posn", 1.0, "%s"] # true not allowed for this line (set in code) + , ["n", True, "Hds", 1.0, "%d"] + , ["avgseats", True, "Seats", 1.0, "%3.1f"] + , ["vpip", True, "VPIP", 1.0, "%3.1f"] + , ["pfr", True, "PFR", 1.0, "%3.1f"] + , ["pf3", True, "PF3", 1.0, "%3.1f"] + , ["steals", True, "Steals", 1.0, "%3.1f"] + , ["saw_f", True, "Saw_F", 1.0, "%3.1f"] + , ["sawsd", True, "SawSD", 1.0, "%3.1f"] + , ["wtsdwsf", True, "WtSDwsF", 1.0, "%3.1f"] + , ["wmsd", True, "W$SD", 1.0, "%3.1f"] + , ["flafq", True, "FlAFq", 1.0, "%3.1f"] + , ["tuafq", True, "TuAFq", 1.0, "%3.1f"] + , ["rvafq", True, "RvAFq", 1.0, "%3.1f"] + , ["pofafq", False, "PoFAFq", 1.0, "%3.1f"] + , ["net", True, "Net($)", 1.0, "%6.2f"] + , ["bbper100", True, "bb/100", 1.0, "%4.2f"] + , ["rake", True, "Rake($)", 1.0, "%6.2f"] + , ["bb100xr", True, "bbxr/100", 1.0, "%4.2f"] + , ["variance", True, "Variance", 1.0, "%5.2f"] + ] + self.stat_table = None self.stats_frame = None + self.stats_vbox = None self.main_hbox = gtk.HBox(False, 0) self.main_hbox.show() - statsFrame = gtk.Frame("Stats:") - statsFrame.set_label_align(0.0, 0.0) - statsFrame.show() - self.stats_frame = gtk.VBox(False, 0) + self.stats_frame = gtk.Frame() + self.stats_frame.set_label_align(0.0, 0.0) self.stats_frame.show() + self.stats_vbox = gtk.VBox(False, 0) + self.stats_vbox.show() # This could be stored in config eventually, or maybe configured in this window somehow. # Each posncols element is the name of a column returned by the sql @@ -90,11 +119,11 @@ class GuiPositionalStats (threading.Thread): , "PoFAFq", "Net($)", "bb/100", "$/hand", "Variance", "Hds" ) - self.fillStatsFrame(self.stats_frame) - statsFrame.add(self.stats_frame) + self.fillStatsFrame(self.stats_vbox) + self.stats_frame.add(self.stats_vbox) self.main_hbox.pack_start(self.filters.get_vbox()) - self.main_hbox.pack_start(statsFrame) + self.main_hbox.pack_start(self.stats_frame) def get_vbox(self): @@ -107,9 +136,12 @@ class GuiPositionalStats (threading.Thread): print "DEBUG: activesite set to %s" %(self.activesite) def refreshStats(self, widget, data): - try: self.stats_table.destroy() + try: self.stats_vbox.destroy() except AttributeError: pass - self.fillStatsFrame(self.stats_frame) + self.stats_vbox = gtk.VBox(False, 0) + self.stats_vbox.show() + self.stats_frame.add(self.stats_vbox) + self.fillStatsFrame(self.stats_vbox) def fillStatsFrame(self, vbox): sites = self.filters.getSites() @@ -144,66 +176,103 @@ class GuiPositionalStats (threading.Thread): self.createStatsTable(vbox, playerids, sitenos, limits, seats, dates) def createStatsTable(self, vbox, playerids, sitenos, limits, seats, dates): - self.stats_table = gtk.Table(1, 1, False) # gtk table expands as required - self.stats_table.set_col_spacings(4) - self.stats_table.show() - vbox.add(self.stats_table) + colalias,colshow,colheading,colxalign,colformat = 0,1,2,3,4 row = 0 col = 0 - for t in self.posnheads: - l = gtk.Label(self.posnheads[col]) - l.show() - self.stats_table.attach(l, col, col+1, row, row+1, yoptions=gtk.SHRINK) - col +=1 tmp = self.sql.query['playerStatsByPosition'] tmp = self.refineQuery(tmp, playerids, sitenos, limits, seats, dates) self.cursor.execute(tmp) result = self.cursor.fetchall() + colnames = [desc[0].lower() for desc in self.cursor.description] + + liststore = gtk.ListStore(*([str] * len(colnames))) + view = gtk.TreeView(model=liststore) + view.set_grid_lines(gtk.TREE_VIEW_GRID_LINES_BOTH) + vbox.pack_start(view, expand=False, padding=3) + # left-aligned cells: + textcell = gtk.CellRendererText() + # centred cells: + textcell50 = gtk.CellRendererText() + textcell50.set_property('xalign', 0.5) + # right-aligned cells: + numcell = gtk.CellRendererText() + numcell.set_property('xalign', 1.0) + listcols = [] + + for t in self.posnheads: + listcols.append(gtk.TreeViewColumn(self.posnheads[col])) + view.append_column(listcols[col]) + if col == 0: + listcols[col].pack_start(textcell, expand=True) + listcols[col].add_attribute(textcell, 'text', col) + listcols[col].set_expand(True) + elif col in (1, 2): + listcols[col].pack_start(textcell50, expand=True) + listcols[col].add_attribute(textcell50, 'text', col) + listcols[col].set_expand(True) + else: + listcols[col].pack_start(numcell, expand=True) + listcols[col].add_attribute(numcell, 'text', col) + listcols[col].set_expand(True) + col +=1 + + # Code below to be used when full column data structures implemented like in player stats: + + # Create header row eg column: ("game", True, "Game", 0.0, "%s") + #for col, column in enumerate(cols_to_show): + # if column[colalias] == 'game' and holecards: + # s = [x for x in self.columns if x[colalias] == 'hand'][0][colheading] + # else: + # s = column[colheading] + # listcols.append(gtk.TreeViewColumn(s)) + # view.append_column(listcols[col]) + # if column[colformat] == '%s': + # if column[colxalign] == 0.0: + # listcols[col].pack_start(textcell, expand=True) + # listcols[col].add_attribute(textcell, 'text', col) + # else: + # listcols[col].pack_start(textcell50, expand=True) + # listcols[col].add_attribute(textcell50, 'text', col) + # listcols[col].set_expand(True) + # else: + # listcols[col].pack_start(numcell, expand=True) + # listcols[col].add_attribute(numcell, 'text', col) + # listcols[col].set_expand(True) + # #listcols[col].set_alignment(column[colxalign]) # no effect? rows = len(result) - colnames = [desc[0].lower() for desc in self.cursor.description] last_game,last_seats,sqlrow = "","",0 while sqlrow < rows: - if(row%2 == 0): - bgcolor = "white" - else: - bgcolor = "lightgrey" rowprinted=0 + treerow = [] avgcol = colnames.index('avgseats') for col,colname in enumerate(self.posncols): if colname in colnames: sqlcol = colnames.index(colname) else: continue - eb = gtk.EventBox() - eb.modify_bg(gtk.STATE_NORMAL, gtk.gdk.color_parse(bgcolor)) - # print blank row between levels: if result[sqlrow][sqlcol]: if sqlrow == 0: - l = gtk.Label(result[sqlrow][sqlcol]) + value = result[sqlrow][sqlcol] rowprinted=1 elif result[sqlrow][0] != last_game: - l = gtk.Label(' ') + value = ' ' elif 'show' in seats and seats['show'] and result[sqlrow][avgcol] != last_seats: - l = gtk.Label(' ') + value = ' ' else: - l = gtk.Label(result[sqlrow][sqlcol]) + value = result[sqlrow][sqlcol] rowprinted=1 else: l = gtk.Label(' ') - if col == 0: - l.set_alignment(xalign=0.0, yalign=0.5) - elif col == 1: - l.set_alignment(xalign=0.5, yalign=0.5) + value = ' ' + if value and value != -999: + treerow.append(value) else: - l.set_alignment(xalign=1.0, yalign=0.5) - eb.add(l) - self.stats_table.attach(eb, col, col+1, row+1, row+2, yoptions=gtk.SHRINK) - l.show() - eb.show() + treerow.append(' ') + iter = liststore.append(treerow) last_game = result[sqlrow][0] last_seats = result[sqlrow][avgcol] if rowprinted: @@ -220,48 +289,33 @@ class GuiPositionalStats (threading.Thread): # blank row between main stats and totals: col = 0 - if(row%2 == 0): - bgcolor = "white" - else: - bgcolor = "lightgrey" - eb = gtk.EventBox() - eb.modify_bg(gtk.STATE_NORMAL, gtk.gdk.color_parse(bgcolor)) - l = gtk.Label(' ') - eb.add(l) - self.stats_table.attach(eb, col, col+1, row+1, row+2, yoptions=gtk.SHRINK) - l.show() - eb.show() + treerow = [' ' for x in self.posncols] + iter = liststore.append(treerow) row = row + 1 for sqlrow in range(rows): - if(row%2 == 0): - bgcolor = "white" - else: - bgcolor = "lightgrey" + treerow = [] for col,colname in enumerate(self.posncols): if colname in colnames: sqlcol = colnames.index(colname) elif colname != "plposition": continue - eb = gtk.EventBox() - eb.modify_bg(gtk.STATE_NORMAL, gtk.gdk.color_parse(bgcolor)) if colname == 'plposition': l = gtk.Label('Totals') + value = 'Totals' elif result[sqlrow][sqlcol]: l = gtk.Label(result[sqlrow][sqlcol]) + value = result[sqlrow][sqlcol] else: l = gtk.Label(' ') - if col == 0: - l.set_alignment(xalign=0.0, yalign=0.5) - elif col == 1: - l.set_alignment(xalign=0.5, yalign=0.5) + value = ' ' + if value and value != -999: + treerow.append(value) else: - l.set_alignment(xalign=1.0, yalign=0.5) - eb.add(l) - self.stats_table.attach(eb, col, col+1, row+1, row+2, yoptions=gtk.SHRINK) - l.show() - eb.show() + treerow.append(' ') + iter = liststore.append(treerow) row = row + 1 + vbox.show_all() self.db.db.rollback() #end def fillStatsFrame(self, vbox): From 1fbb7d166c2ec32c2a02fbbeeb0f122df121ef22 Mon Sep 17 00:00:00 2001 From: sqlcoder Date: Mon, 22 Jun 2009 21:41:41 +0100 Subject: [PATCH 13/57] remove redundant code --- pyfpdb/GuiPlayerStats.py | 9 --------- 1 file changed, 9 deletions(-) diff --git a/pyfpdb/GuiPlayerStats.py b/pyfpdb/GuiPlayerStats.py index 268aeab3..79ab75a4 100644 --- a/pyfpdb/GuiPlayerStats.py +++ b/pyfpdb/GuiPlayerStats.py @@ -227,11 +227,6 @@ class GuiPlayerStats (threading.Thread): if not flags: holecards = False else: holecards = flags[0] - - self.stats_table = gtk.Table(1, 1, False) - self.stats_table.set_col_spacings(4) - self.stats_table.show() - tmp = self.sql.query[query] tmp = self.refineQuery(tmp, flags, playerids, sitenos, limits, seats, groups, dates) self.cursor.execute(tmp) @@ -279,10 +274,6 @@ class GuiPlayerStats (threading.Thread): while sqlrow < rows: treerow = [] - if(row%2 == 0): - bgcolor = "white" - else: - bgcolor = "lightgrey" for col,column in enumerate(cols_to_show): if column[colalias] in colnames: value = result[sqlrow][colnames.index(column[colalias])] From 699f79722b99b073ce7fc27a5bfd8d83fda0dcf5 Mon Sep 17 00:00:00 2001 From: sqlcoder Date: Mon, 22 Jun 2009 22:05:28 +0100 Subject: [PATCH 14/57] add time print for positional stats tab --- pyfpdb/GuiPositionalStats.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/pyfpdb/GuiPositionalStats.py b/pyfpdb/GuiPositionalStats.py index dce7cb77..21a3bc9a 100644 --- a/pyfpdb/GuiPositionalStats.py +++ b/pyfpdb/GuiPositionalStats.py @@ -20,6 +20,7 @@ import pygtk pygtk.require('2.0') import gtk import os +from time import time, strftime import fpdb_import import fpdb_db @@ -177,6 +178,7 @@ class GuiPositionalStats (threading.Thread): def createStatsTable(self, vbox, playerids, sitenos, limits, seats, dates): + starttime = time() colalias,colshow,colheading,colxalign,colformat = 0,1,2,3,4 row = 0 col = 0 @@ -318,6 +320,7 @@ class GuiPositionalStats (threading.Thread): vbox.show_all() self.db.db.rollback() + print "Positional Stats page displayed in %4.2f seconds" % (time() - starttime) #end def fillStatsFrame(self, vbox): def refineQuery(self, query, playerids, sitenos, limits, seats, dates): From 45a9358cbd67a111ac42a056712fbc1995f9d000 Mon Sep 17 00:00:00 2001 From: sqlcoder Date: Mon, 22 Jun 2009 23:16:34 +0100 Subject: [PATCH 15/57] set defaults for unused params to allow new calls without needing to set them --- pyfpdb/Database.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pyfpdb/Database.py b/pyfpdb/Database.py index 932a8578..5bc8afe9 100755 --- a/pyfpdb/Database.py +++ b/pyfpdb/Database.py @@ -39,7 +39,7 @@ import SQL import Card class Database: - def __init__(self, c, db_name, game): + def __init__(self, c, db_name = None, game = None): # db_name and game not used any more self.fdb = fpdb_db.fpdb_db() # sets self.fdb.db self.fdb.cursor and self.fdb.sql self.fdb.do_connect(c) self.connection = self.fdb.db @@ -48,7 +48,7 @@ class Database: self.import_options = c.get_import_parameters() self.type = db_params['db-type'] self.backend = db_params['db-backend'] - self.sql = SQL.Sql(game = game, type = self.type, db_server = db_params['db-server']) + self.sql = SQL.Sql(type = self.type, db_server = db_params['db-server']) self.connection.rollback() # To add to config: From 456ddb3e91ceda9d9305d562a56769f38a9ddc23 Mon Sep 17 00:00:00 2001 From: sqlcoder Date: Mon, 22 Jun 2009 23:19:03 +0100 Subject: [PATCH 16/57] use do_connect() instead of connect() and remove settings parameter (config includes them) --- pyfpdb/Filters.py | 20 ++++---------------- pyfpdb/GuiGraphViewer.py | 2 +- pyfpdb/GuiPlayerStats.py | 2 +- pyfpdb/GuiPositionalStats.py | 2 +- 4 files changed, 7 insertions(+), 19 deletions(-) diff --git a/pyfpdb/Filters.py b/pyfpdb/Filters.py index 4846b998..9ded56b4 100644 --- a/pyfpdb/Filters.py +++ b/pyfpdb/Filters.py @@ -30,12 +30,11 @@ import fpdb_db import FpdbSQLQueries class Filters(threading.Thread): - def __init__(self, db, settings, config, qdict, display = {},debug=True): + def __init__(self, db, config, qdict, display = {}, debug=True): self.debug=debug #print "start of GraphViewer constructor" self.db=db self.cursor=db.cursor - self.settings=settings self.sql=qdict self.conf = config self.display = display @@ -235,7 +234,7 @@ class Filters(threading.Thread): def __set_hero_name(self, w, site): self.heroes[site] = w.get_text() -# print "DEBUG: settings heroes[%s]: %s"%(site, self.heroes[site]) +# print "DEBUG: setting heroes[%s]: %s"%(site, self.heroes[site]) def createSiteLine(self, hbox, site): cb = gtk.CheckButton(site) @@ -556,23 +555,12 @@ def main(argv=None): config = Configuration.Config() db = None - settings = {} - - settings.update(config.get_db_parameters()) - settings.update(config.get_tv_parameters()) - settings.update(config.get_import_parameters()) - settings.update(config.get_default_paths()) - db = fpdb_db.fpdb_db() - db.connect(settings['db-backend'], - settings['db-host'], - settings['db-databaseName'], - settings['db-user'], - settings['db-password']) + db.do_connect(config) qdict = FpdbSQLQueries.FpdbSQLQueries(db.get_backend_name()) - i = Filters(db, settings, config, qdict) + i = Filters(db, config, qdict) main_window = gtk.Window() main_window.connect('destroy', destroy) main_window.add(i.get_vbox()) diff --git a/pyfpdb/GuiGraphViewer.py b/pyfpdb/GuiGraphViewer.py index cec91e61..fc14a536 100644 --- a/pyfpdb/GuiGraphViewer.py +++ b/pyfpdb/GuiGraphViewer.py @@ -63,7 +63,7 @@ class GuiGraphViewer (threading.Thread): "Button2" : True } - self.filters = Filters.Filters(db, settings, config, querylist, display = filters_display) + self.filters = Filters.Filters(db, config, querylist, display = filters_display) self.filters.registerButton1Name("Refresh Graph") self.filters.registerButton1Callback(self.generateGraph) self.filters.registerButton2Name("Export to File") diff --git a/pyfpdb/GuiPlayerStats.py b/pyfpdb/GuiPlayerStats.py index 79ab75a4..4ad21764 100644 --- a/pyfpdb/GuiPlayerStats.py +++ b/pyfpdb/GuiPlayerStats.py @@ -66,7 +66,7 @@ class GuiPlayerStats (threading.Thread): "Button2" : True } - self.filters = Filters.Filters(self.db, settings, config, querylist, display = filters_display) + self.filters = Filters.Filters(self.db, config, querylist, display = filters_display) self.filters.registerButton1Name("_Filters") self.filters.registerButton1Callback(self.showDetailFilter) self.filters.registerButton2Name("_Refresh") diff --git a/pyfpdb/GuiPositionalStats.py b/pyfpdb/GuiPositionalStats.py index 21a3bc9a..6fde0617 100644 --- a/pyfpdb/GuiPositionalStats.py +++ b/pyfpdb/GuiPositionalStats.py @@ -59,7 +59,7 @@ class GuiPositionalStats (threading.Thread): "Button2" : False } - self.filters = Filters.Filters(self.db, settings, config, querylist, display = filters_display) + self.filters = Filters.Filters(self.db, config, querylist, display = filters_display) self.filters.registerButton1Name("Refresh") self.filters.registerButton1Callback(self.refreshStats) From 14561043828eed31639787a7751a3e54b28e79d2 Mon Sep 17 00:00:00 2001 From: sqlcoder Date: Mon, 22 Jun 2009 23:30:54 +0100 Subject: [PATCH 17/57] make graph viewer use its own db connection --- pyfpdb/GuiGraphViewer.py | 16 ++++++++-------- pyfpdb/fpdb.py | 5 ++++- 2 files changed, 12 insertions(+), 9 deletions(-) diff --git a/pyfpdb/GuiGraphViewer.py b/pyfpdb/GuiGraphViewer.py index fc14a536..811b1e82 100644 --- a/pyfpdb/GuiGraphViewer.py +++ b/pyfpdb/GuiGraphViewer.py @@ -43,14 +43,14 @@ import Filters class GuiGraphViewer (threading.Thread): - def __init__(self, db, settings, querylist, config, debug=True): + def __init__(self, querylist, config, debug=True): """Constructor for GraphViewer""" self.debug=debug #print "start of GraphViewer constructor" - self.db=db - self.cursor=db.cursor - self.settings=settings - self.sql=querylist + self.db = fpdb_db.fpdb_db() # sets self.fdb.db self.fdb.cursor and self.fdb.sql + self.db.do_connect(config) + + self.sql = querylist self.conf = config filters_display = { "Heroes" : True, @@ -63,7 +63,7 @@ class GuiGraphViewer (threading.Thread): "Button2" : True } - self.filters = Filters.Filters(db, config, querylist, display = filters_display) + self.filters = Filters.Filters(self.db, config, querylist, display = filters_display) self.filters.registerButton1Name("Refresh Graph") self.filters.registerButton1Callback(self.generateGraph) self.filters.registerButton2Name("Export to File") @@ -146,7 +146,7 @@ class GuiGraphViewer (threading.Thread): for site in sites: if sites[site] == True: sitenos.append(siteids[site]) - self.cursor.execute(self.sql.query['getPlayerId'], (heroes[site],)) + self.db.cursor.execute(self.sql.query['getPlayerId'], (heroes[site],)) result = self.db.cursor.fetchall() if len(result) == 1: playerids.append(result[0][0]) @@ -226,7 +226,7 @@ class GuiGraphViewer (threading.Thread): #print "DEBUG: sql query:" #print tmp - self.cursor.execute(tmp) + self.db.cursor.execute(tmp) #returns (HandId,Winnings,Costs,Profit) winnings = self.db.cursor.fetchall() self.db.db.rollback() diff --git a/pyfpdb/fpdb.py b/pyfpdb/fpdb.py index b03e8424..172eedee 100755 --- a/pyfpdb/fpdb.py +++ b/pyfpdb/fpdb.py @@ -41,6 +41,7 @@ import GuiTableViewer import GuiAutoImport import GuiGraphViewer import GuiSessionViewer +import Database import FpdbSQLQueries import Configuration @@ -388,6 +389,8 @@ class fpdb: # Database connected to successfully, load queries to pass on to other classes self.querydict = FpdbSQLQueries.FpdbSQLQueries(self.db.get_backend_name()) + self.dbi = Database.Database(self.config) # dbi for db interface and to avoid clashes with db/database/etc + # can rename later if required self.db.db.rollback() #end def load_profile @@ -474,7 +477,7 @@ This program is licensed under the AGPL3, see docs"""+os.sep+"agpl-3.0.txt") def tabGraphViewer(self, widget, data=None): """opens a graph viewer tab""" #print "start of tabGraphViewer" - new_gv_thread=GuiGraphViewer.GuiGraphViewer(self.db, self.settings, self.querydict, self.config) + new_gv_thread = GuiGraphViewer.GuiGraphViewer(self.querydict, self.config) self.threads.append(new_gv_thread) gv_tab=new_gv_thread.get_vbox() self.add_and_display_tab(gv_tab, "Graphs") From 0afd8e2e707dba139d879242564604f48bbcb26d Mon Sep 17 00:00:00 2001 From: sqlcoder Date: Mon, 22 Jun 2009 23:43:11 +0100 Subject: [PATCH 18/57] use do_connect() instead of connect() --- pyfpdb/fpdb.py | 12 ++---------- 1 file changed, 2 insertions(+), 10 deletions(-) diff --git a/pyfpdb/fpdb.py b/pyfpdb/fpdb.py index 172eedee..b36c62bb 100755 --- a/pyfpdb/fpdb.py +++ b/pyfpdb/fpdb.py @@ -364,11 +364,7 @@ class fpdb: self.db = fpdb_db.fpdb_db() #print "end of fpdb.load_profile, databaseName:",self.settings['db-databaseName'] - self.db.connect(self.settings['db-backend'], - self.settings['db-host'], - self.settings['db-databaseName'], - self.settings['db-user'], - self.settings['db-password']) + self.db.do_connect(self.config) if self.db.wrongDbVersion: diaDbVersionWarning = gtk.Dialog(title="Strong Warning - Invalid database version", parent=None, flags=0, buttons=(gtk.STOCK_OK,gtk.RESPONSE_OK)) @@ -401,11 +397,7 @@ class fpdb: def obtain_global_lock(self): print "\nTaking global lock ..." self.fdb_lock = fpdb_db.fpdb_db() - self.fdb_lock.connect(self.settings['db-backend'], - self.settings['db-host'], - self.settings['db-databaseName'], - self.settings['db-user'], - self.settings['db-password']) + self.fdb_lock.do_connect(self.config) return self.fdb_lock.get_global_lock() #end def obtain_global_lock From 8cdac245179503f597cab5ef508e14e2eebb2bd3 Mon Sep 17 00:00:00 2001 From: Ray Date: Tue, 23 Jun 2009 09:56:29 -0400 Subject: [PATCH 19/57] Subclass Aux_Seats from Aux_Windows. Flop_mucked now a Aux_Seats. --- pyfpdb/Mucked.py | 176 +++++++++++++++++++++-------------------------- 1 file changed, 77 insertions(+), 99 deletions(-) diff --git a/pyfpdb/Mucked.py b/pyfpdb/Mucked.py index be9228d3..eb1d7c86 100755 --- a/pyfpdb/Mucked.py +++ b/pyfpdb/Mucked.py @@ -43,21 +43,12 @@ class Aux_Window(object): self.params = params self.config = config - def update_data(self, *args): - pass - - def update_gui(self, *args): - pass - - def create(self, *args): - pass - - def relocate(self, *args): - pass - - def save_layout(self, *args): - pass - +# Override these methods as needed + def update_data(self, *args): pass + def update_gui(self, *args): pass + def create(self, *args): pass + def relocate(self, *args): pass + def save_layout(self, *args): pass def destroy(self): try: self.container.destroy() @@ -89,10 +80,6 @@ class Aux_Window(object): pb.copy_area(30*j, 42*i, 30, 42, temp_pb, 0, 0) return temp_pb - def split_cards(self, card): - if card == 'xx': return ('B', 'S') - return (card[0], card[1].upper()) - def has_cards(self, cards): """Returns the number of cards in the list.""" n = 0 @@ -331,6 +318,9 @@ class Stud_cards: self.seen_cards[(c, r)].set_from_pixbuf(self.card_images[0]) self.eb[(c, r)].set_tooltip_text('') +class Seat_Window(gtk.Window): + """Subclass gtk.Window for the seat windows.""" + class Aux_Seats(Aux_Window): """A super class to display an aux_window at each seat.""" @@ -339,55 +329,83 @@ class Aux_Seats(Aux_Window): self.config = config # configuration object for this aux window to use self.params = params # dict aux params from config self.positions = {} # dict of window positions - self.displayed = False + self.displayed = False # the seat windows are displayed + self.uses_timer = False # the Aux_seats object uses a timer to control hiding self.timer_on = False # bool = Ture if the timeout for removing the cards is on +# placeholders that should be overridden--so we don't throw errors + def create_contents(self): pass + + def create(self): + self.adj = self.hud.adj_seats(0, self.config) # move adj_seats to aux and get rid of it in Hud.py + loc = self.config.get_aux_locations(self.params['name'], int(self.hud.max)) + + self.m_windows = {} # windows to put the card images in + + for i in (range(1, self.hud.max + 1) + ['common']): + if i == 'common': + (x, y) = self.params['layout'][self.hud.max].common + else: + (x, y) = loc[self.adj[i]] + self.m_windows[i] = Seat_Window() + self.m_windows[i].set_decorated(False) + self.m_windows[i].set_property("skip-taskbar-hint", True) + self.m_windows[i].set_transient_for(self.hud.main_window) + self.m_windows[i].set_focus_on_map(False) + self.m_windows[i].connect("configure_event", self.configure_event_cb, i) + self.positions[i] = (int(x) + self.hud.table.x, int(y) + self.hud.table.y) + self.m_windows[i].move(self.positions[i][0], self.positions[i][1]) + self.m_windows[i].set_opacity(float(self.params['opacity'])) + +# the create_contents method is supplied by the subclass + self.create_contents(self.m_windows[i], i) + + self.m_windows[i].show_all() + self.m_windows[i].hide() + +# Methods likely to be of use for any Seat_Window implementation + def destroy(self): + """Destroy all of the seat windows.""" + for i in self.m_windows.keys(): + self.m_windows[i].destroy() + del(self.m_windows[i]) + +# Methods likely to be useful for mucked card windows (or similar) only + def hide(self): + """Hide the seat windows.""" + for (i, w) in self.m_windows.iteritems(): + w.hide() + self.displayed = False + class Flop_Mucked(Aux_Seats): """Aux_Window class for displaying mucked cards for flop games.""" def __init__(self, hud, config, params): super(Flop_Mucked, self).__init__(hud, config, params) self.card_images = self.get_card_images() + self.uses_timer = True # this Aux_seats object uses a timer to control hiding - def create(self): - self.adj = self.hud.adj_seats(0, self.config) # move adj_seats to aux and get rid of it in Hud.py - loc = self.config.get_aux_locations(self.params['name'], int(self.hud.max)) - - self.m_windows = {} # windows to put the card images in - self.eb = {} # event boxes so we can interact with the mucked cards - self.seen_cards = {} # image objects to stash the cards in - - for i in (range(1, self.hud.max + 1) + ['common']): - if i == 'common': - (x, y) = self.params['layout'][self.hud.max].common - else: - (x, y) = loc[self.adj[i]] - self.m_windows[i] = gtk.Window() - self.m_windows[i].set_decorated(False) - self.m_windows[i].set_property("skip-taskbar-hint", True) - self.m_windows[i].set_transient_for(self.hud.main_window) - self.m_windows[i].set_focus_on_map(False) - self.eb[i] = gtk.EventBox() - self.eb[i].connect("button_press_event", self.button_press_cb) - self.m_windows[i].connect("configure_event", self.configure_event_cb, i) - self.m_windows[i].add(self.eb[i]) - self.seen_cards[i] = gtk.image_new_from_pixbuf(self.card_images[0]) - self.eb[i].add(self.seen_cards[i]) - self.positions[i] = (int(x) + self.hud.table.x, int(y) + self.hud.table.y) -# self.rel_positions[i] = (int(x), int(y)) - self.m_windows[i].move(self.positions[i][0], self.positions[i][1]) - self.m_windows[i].set_opacity(float(self.params['opacity'])) - self.m_windows[i].show_all() - self.m_windows[i].hide() - - def create_contents(self, i): + def create_contents(self, container, i): """Create the widgets for showing the contents of the Aux_seats window.""" + container.eb = gtk.EventBox() + container.eb.connect("button_press_event", self.button_press_cb) + container.add(container.eb) + container.seen_cards = gtk.image_new_from_pixbuf(self.card_images[0]) + container.eb.add(container.seen_cards) def update_gui(self, new_hand_id): """Prepare and show the mucked cards.""" - if self.displayed: - self.hide_mucked_cards() - self.displayed = False + if self.displayed: self.hide() + +# See how many players showed a hand. Skip if only 1 shows (= hero) + n_sd = 0 + for (i, cards) in self.hud.cards.iteritems(): + n_cards = self.has_cards(cards) + if n_cards > 0: + n_sd = n_sd + 1 + if n_sd < 2: return + +# More than 1 player showed, so display the hole cards for (i, cards) in self.hud.cards.iteritems(): n_cards = self.has_cards(cards) if n_cards > 0: @@ -404,24 +422,19 @@ class Flop_Mucked(Aux_Seats): int(self.params['card_wd']), int(self.params['card_ht']), scratch, x, 0) x = x + int(self.params['card_wd']) - self.seen_cards[i].set_from_pixbuf(scratch) + self.m_windows[i].seen_cards.set_from_pixbuf(scratch) self.m_windows[i].resize(1,1) self.m_windows[i].show() self.m_windows[i].move(self.positions[i][0], self.positions[i][1]) # here is where I move back self.displayed = True for stats in self.hud.stat_dict.itervalues(): - self.eb[stats['seat']].set_tooltip_text(stats['screen_name']) + self.m_windows[i].eb.set_tooltip_text(stats['screen_name']) if self.displayed and float(self.params['timeout']) > 0: self.timer_on = True gobject.timeout_add(int(1000*float(self.params['timeout'])), self.timed_out) - def destroy(self): - """Destroy all of the mucked windows.""" - for w in self.m_windows.values(): - w.destroy() - def timed_out(self): # this is the callback from the timeout @@ -430,15 +443,9 @@ class Flop_Mucked(Aux_Seats): if not self.timer_on: return False else: - self.hide_mucked_cards() + self.hide() return False - def hide_mucked_cards(self): - """Hide the mucked card windows.""" - for (i, w) in self.m_windows.iteritems(): - w.hide() - self.displayed = False - def button_press_cb(self, widget, event, *args): """Handle button clicks in the event boxes.""" @@ -456,7 +463,7 @@ class Flop_Mucked(Aux_Seats): self.timer_on = False else: self.timer_on = False - self.hide_mucked_cards() + self.hide() elif event.button == 1: # left button event window = widget.get_parent() @@ -482,32 +489,3 @@ class Flop_Mucked(Aux_Seats): else: new_locs[i] = (pos[0] - self.hud.table.x, pos[1] - self.hud.table.y) self.config.edit_aux_layout(self.params['name'], self.hud.max, locations = new_locs) - -# This test program doesn't work - -#if __name__== "__main__": -# -# def destroy(*args): # call back for terminating the main eventloop -# gtk.main_quit() # used only for testing -# -# def process_new_hand(source, condition, db_connection): #callback from stdin watch -- testing only -## there is a new hand_id to be processed -## just read it and pass it to update -# new_hand_id = sys.stdin.readline() -# new_hand_id = new_hand_id.rstrip() # remove trailing whitespace -# m.update_data(new_hand_id, db_connection) -# m.update_gui(new_hand_id) -# return(True) -# -# config = Configuration.Config() -# db_connection = Database.Database(config, 'fpdbTEST', '') -# main_window = gtk.Window() -# main_window.set_keep_above(True) -# main_window.connect("destroy", destroy) -# -# aux_to_call = "stud_mucked" -# aux_params = config.get_aux_parameters(aux_to_call) -# m = eval("%s(None, config, aux_params)" % aux_params['class']) -# -# s_id = gobject.io_add_watch(sys.stdin, gobject.IO_IN, process_new_hand, db_connection) -# gtk.main() From 2f0c7e8167f8380349db0d4148104b91b2666327 Mon Sep 17 00:00:00 2001 From: sqlcoder Date: Tue, 23 Jun 2009 20:45:11 +0100 Subject: [PATCH 20/57] make load_profile reload HUD_config.xml and update status bar --- pyfpdb/fpdb.py | 53 ++++++++++++++++++++++++++++---------------------- 1 file changed, 30 insertions(+), 23 deletions(-) diff --git a/pyfpdb/fpdb.py b/pyfpdb/fpdb.py index b36c62bb..6c982002 100755 --- a/pyfpdb/fpdb.py +++ b/pyfpdb/fpdb.py @@ -41,6 +41,7 @@ import GuiTableViewer import GuiAutoImport import GuiGraphViewer import GuiSessionViewer +import SQL import Database import FpdbSQLQueries import Configuration @@ -179,20 +180,21 @@ class fpdb: def dia_load_profile(self, widget, data=None): """Dialogue to select a file to load a profile from""" if self.obtain_global_lock() == 0: # returns 0 if successful - try: - chooser = gtk.FileChooserDialog(title="Please select a profile file to load", - action=gtk.FILE_CHOOSER_ACTION_OPEN, - buttons=(gtk.STOCK_CANCEL,gtk.RESPONSE_CANCEL,gtk.STOCK_OPEN,gtk.RESPONSE_OK)) - chooser.set_filename(self.profile) + #try: + # chooser = gtk.FileChooserDialog(title="Please select a profile file to load", + # action=gtk.FILE_CHOOSER_ACTION_OPEN, + # buttons=(gtk.STOCK_CANCEL,gtk.RESPONSE_CANCEL,gtk.STOCK_OPEN,gtk.RESPONSE_OK)) + # chooser.set_filename(self.profile) - response = chooser.run() - chooser.destroy() - if response == gtk.RESPONSE_OK: - self.load_profile(chooser.get_filename()) - elif response == gtk.RESPONSE_CANCEL: - print 'User cancelled loading profile' - except: - pass + # response = chooser.run() + # chooser.destroy() + # if response == gtk.RESPONSE_OK: + # self.load_profile(chooser.get_filename()) + # elif response == gtk.RESPONSE_CANCEL: + # print 'User cancelled loading profile' + #except: + # pass + self.load_profile() self.release_global_lock() #end def dia_load_profile @@ -347,6 +349,7 @@ class fpdb: def load_profile(self): """Loads profile from the provided path name.""" + self.config = Configuration.Config(file=options.config, dbname=options.dbname) self.settings = {} if (os.sep=="/"): self.settings['os']="linuxmac" @@ -383,10 +386,18 @@ class fpdb: response = diaDbVersionWarning.run() diaDbVersionWarning.destroy() + if self.status_bar == 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() + else: + self.status_bar.set_text("Status: Connected to %s database named %s on host %s" % (self.db.get_backend_name(),self.db.database, self.db.host)) + # Database connected to successfully, load queries to pass on to other classes self.querydict = FpdbSQLQueries.FpdbSQLQueries(self.db.get_backend_name()) - self.dbi = Database.Database(self.config) # dbi for db interface and to avoid clashes with db/database/etc - # can rename later if required + self.sql = SQL.Sql(type = self.settings['db-type'], db_server = self.settings['db-server']) + self.dbi = Database.Database(self.config, sql = self.sql) # dbi for db interface and to avoid clashes with db/database/etc + # can rename later if required self.db.db.rollback() #end def load_profile @@ -476,10 +487,9 @@ This program is licensed under the AGPL3, see docs"""+os.sep+"agpl-3.0.txt") #end def tabGraphViewer def __init__(self): - self.threads=[] - self.db=None - self.config = Configuration.Config(file=options.config, dbname=options.dbname) - self.load_profile() + self.threads = [] + self.db = None + self.status_bar = None self.window = gtk.Window(gtk.WINDOW_TOPLEVEL) self.window.connect("delete_event", self.delete_event) @@ -514,11 +524,8 @@ This program is licensed under the AGPL3, see docs"""+os.sep+"agpl-3.0.txt") self.tab_main_help(None, 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() - self.window.show() + self.load_profile() sys.stderr.write("fpdb starting ...") #end def __init__ From 84cc951045ee3e8981d7dc40d26d1346a250cf59 Mon Sep 17 00:00:00 2001 From: sqlcoder Date: Tue, 23 Jun 2009 22:05:22 +0100 Subject: [PATCH 21/57] comment out database creation wrongly included from my dev code --- pyfpdb/fpdb.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pyfpdb/fpdb.py b/pyfpdb/fpdb.py index 6c982002..a6d4cb3c 100755 --- a/pyfpdb/fpdb.py +++ b/pyfpdb/fpdb.py @@ -396,7 +396,7 @@ class fpdb: # Database connected to successfully, load queries to pass on to other classes self.querydict = FpdbSQLQueries.FpdbSQLQueries(self.db.get_backend_name()) self.sql = SQL.Sql(type = self.settings['db-type'], db_server = self.settings['db-server']) - self.dbi = Database.Database(self.config, sql = self.sql) # dbi for db interface and to avoid clashes with db/database/etc + #self.dbi = Database.Database(self.config, sql = self.sql) # dbi for db interface and to avoid clashes with db/database/etc # can rename later if required self.db.db.rollback() #end def load_profile From 9b50987d0cf05d9e8cbe0c5cc97d288770e882e0 Mon Sep 17 00:00:00 2001 From: sqlcoder Date: Tue, 23 Jun 2009 23:44:37 +0100 Subject: [PATCH 22/57] add sql param to Database constructor - aim is to have just one SQL instance passed around and to use Database for db connections and methods --- pyfpdb/Database.py | 9 +++++++-- pyfpdb/fpdb.py | 2 +- 2 files changed, 8 insertions(+), 3 deletions(-) diff --git a/pyfpdb/Database.py b/pyfpdb/Database.py index f652d9a7..392681eb 100755 --- a/pyfpdb/Database.py +++ b/pyfpdb/Database.py @@ -39,7 +39,8 @@ import SQL import Card class Database: - def __init__(self, c, db_name = None, game = None): # db_name and game not used any more + def __init__(self, c, db_name = None, game = None, sql = None): # db_name and game not used any more + print "creating Database instance, sql =", sql self.fdb = fpdb_db.fpdb_db() # sets self.fdb.db self.fdb.cursor and self.fdb.sql self.fdb.do_connect(c) self.connection = self.fdb.db @@ -48,7 +49,11 @@ class Database: self.import_options = c.get_import_parameters() self.type = db_params['db-type'] self.backend = db_params['db-backend'] - self.sql = SQL.Sql(type = self.type, db_server = db_params['db-server']) + # where possible avoid creating new SQL instance by using the global one passed in + if sql == None: + self.sql = SQL.Sql(type = self.type, db_server = db_params['db-server']) + else: + self.sql = sql self.connection.rollback() # To add to config: diff --git a/pyfpdb/fpdb.py b/pyfpdb/fpdb.py index a6d4cb3c..6c982002 100755 --- a/pyfpdb/fpdb.py +++ b/pyfpdb/fpdb.py @@ -396,7 +396,7 @@ class fpdb: # Database connected to successfully, load queries to pass on to other classes self.querydict = FpdbSQLQueries.FpdbSQLQueries(self.db.get_backend_name()) self.sql = SQL.Sql(type = self.settings['db-type'], db_server = self.settings['db-server']) - #self.dbi = Database.Database(self.config, sql = self.sql) # dbi for db interface and to avoid clashes with db/database/etc + self.dbi = Database.Database(self.config, sql = self.sql) # dbi for db interface and to avoid clashes with db/database/etc # can rename later if required self.db.db.rollback() #end def load_profile From 7f7ad2a13e0e342468909fae20c5545474b2e91a Mon Sep 17 00:00:00 2001 From: Ray Date: Thu, 25 Jun 2009 10:07:40 -0400 Subject: [PATCH 23/57] Further on Aux_Seats interface. Works. Not ready for prime time. --- pyfpdb/Mucked.py | 85 +++++++++++++++++++++++++++--------------------- 1 file changed, 48 insertions(+), 37 deletions(-) diff --git a/pyfpdb/Mucked.py b/pyfpdb/Mucked.py index eb1d7c86..4c8b2eb4 100755 --- a/pyfpdb/Mucked.py +++ b/pyfpdb/Mucked.py @@ -335,6 +335,7 @@ class Aux_Seats(Aux_Window): # placeholders that should be overridden--so we don't throw errors def create_contents(self): pass + def update_contents(self): pass def create(self): self.adj = self.hud.adj_seats(0, self.config) # move adj_seats to aux and get rid of it in Hud.py @@ -363,6 +364,11 @@ class Aux_Seats(Aux_Window): self.m_windows[i].show_all() self.m_windows[i].hide() + def update_gui(self, new_hand_id): + """Update the gui, LDO.""" + for i in self.m_windows.keys(): + self.update_contents(self.m_windows[i], i) + # Methods likely to be of use for any Seat_Window implementation def destroy(self): """Destroy all of the seat windows.""" @@ -377,6 +383,17 @@ class Aux_Seats(Aux_Window): w.hide() self.displayed = False + def save_layout(self, *args): + """Save new layout back to the aux element in the config file.""" + new_locs = {} +# print "adj =", self.adj + for (i, pos) in self.positions.iteritems(): + if i != 'common': + new_locs[self.adj[int(i)]] = (pos[0] - self.hud.table.x, pos[1] - self.hud.table.y) + else: + new_locs[i] = (pos[0] - self.hud.table.x, pos[1] - self.hud.table.y) + self.config.edit_aux_layout(self.params['name'], self.hud.max, locations = new_locs) + class Flop_Mucked(Aux_Seats): """Aux_Window class for displaying mucked cards for flop games.""" @@ -393,6 +410,33 @@ class Flop_Mucked(Aux_Seats): container.seen_cards = gtk.image_new_from_pixbuf(self.card_images[0]) container.eb.add(container.seen_cards) + def update_contents(self, container, i): + if not self.hud.cards.has_key(i): return + cards = self.hud.cards[i] + n_cards = self.has_cards(cards) + if n_cards > 1: + +# scratch is a working pixbuf, used to assemble the image + scratch = gtk.gdk.Pixbuf(gtk.gdk.COLORSPACE_RGB, True, 8, + int(self.params['card_wd'])*n_cards, + int(self.params['card_ht'])) + x = 0 # x coord where the next card starts in scratch + for card in cards: +# concatenate each card image to scratch + if card == None or card ==0: + break + self.card_images[card].copy_area(0, 0, + int(self.params['card_wd']), int(self.params['card_ht']), + scratch, x, 0) + x = x + int(self.params['card_wd']) + container.seen_cards.set_from_pixbuf(scratch) + container.resize(1,1) + container.show() + container.move(self.positions[i][0], self.positions[i][1]) # here is where I move back + self.displayed = True + if i != "common": + self.m_windows[i].eb.set_tooltip_text(self.hud.stat_dict[i]['screen_name']) + def update_gui(self, new_hand_id): """Prepare and show the mucked cards.""" if self.displayed: self.hide() @@ -403,33 +447,11 @@ class Flop_Mucked(Aux_Seats): n_cards = self.has_cards(cards) if n_cards > 0: n_sd = n_sd + 1 - if n_sd < 2: return + if n_sd < 2: + print "skipping, n_sd =", n_sd + return -# More than 1 player showed, so display the hole cards - for (i, cards) in self.hud.cards.iteritems(): - n_cards = self.has_cards(cards) - if n_cards > 0: -# scratch is a working pixbuf, used to assemble the image - scratch = gtk.gdk.Pixbuf(gtk.gdk.COLORSPACE_RGB, True, 8, - int(self.params['card_wd'])*n_cards, - int(self.params['card_ht'])) - x = 0 # x coord where the next card starts in scratch - for card in cards: -# concatenate each card image to scratch - if card == None or card ==0: - break - self.card_images[card].copy_area(0, 0, - int(self.params['card_wd']), int(self.params['card_ht']), - scratch, x, 0) - x = x + int(self.params['card_wd']) - self.m_windows[i].seen_cards.set_from_pixbuf(scratch) - self.m_windows[i].resize(1,1) - self.m_windows[i].show() - self.m_windows[i].move(self.positions[i][0], self.positions[i][1]) # here is where I move back - self.displayed = True - - for stats in self.hud.stat_dict.itervalues(): - self.m_windows[i].eb.set_tooltip_text(stats['screen_name']) + super(Flop_Mucked, self).update_gui(new_hand_id) if self.displayed and float(self.params['timeout']) > 0: self.timer_on = True @@ -478,14 +500,3 @@ class Flop_Mucked(Aux_Seats): self.m_windows[i].show() self.m_windows[i].move(self.positions[i][0], self.positions[i][1]) # here is where I move back self.displayed = True - - def save_layout(self, *args): - """Save new layout back to the aux element in the config file.""" - new_locs = {} -# print "adj =", self.adj - for (i, pos) in self.positions.iteritems(): - if i != 'common': - new_locs[self.adj[int(i)]] = (pos[0] - self.hud.table.x, pos[1] - self.hud.table.y) - else: - new_locs[i] = (pos[0] - self.hud.table.x, pos[1] - self.hud.table.y) - self.config.edit_aux_layout(self.params['name'], self.hud.max, locations = new_locs) From 9b4e47df9abf8a6293f9d2fc12b902307950b221 Mon Sep 17 00:00:00 2001 From: sqlcoder Date: Thu, 25 Jun 2009 23:10:37 +0100 Subject: [PATCH 24/57] comment out debug message --- pyfpdb/Tables.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pyfpdb/Tables.py b/pyfpdb/Tables.py index ead3beba..dcd145f4 100755 --- a/pyfpdb/Tables.py +++ b/pyfpdb/Tables.py @@ -231,7 +231,7 @@ def discover_nt_by_name(c, tablename): titles = {} win32gui.EnumWindows(win_enum_handler, titles) for hwnd in titles: - print "Tbales.py: tablename =", tablename, "title =", titles[hwnd] + #print "Tables.py: tablename =", tablename, "title =", titles[hwnd] try: # this can blow up in XP on some windows, eg firefox displaying http://docs.python.org/tutorial/classes.html if not tablename in titles[hwnd]: continue From a2db28ebf241ee077c7e89caa4daa084448dabc0 Mon Sep 17 00:00:00 2001 From: sqlcoder Date: Thu, 25 Jun 2009 23:14:32 +0100 Subject: [PATCH 25/57] create Database instance in import to pass into parser - will eventually replace fpdb_db --- pyfpdb/Database.py | 1 + pyfpdb/fpdb_import.py | 10 +++++++--- pyfpdb/fpdb_parse_logic.py | 9 ++++++--- 3 files changed, 14 insertions(+), 6 deletions(-) diff --git a/pyfpdb/Database.py b/pyfpdb/Database.py index 392681eb..2cade5de 100755 --- a/pyfpdb/Database.py +++ b/pyfpdb/Database.py @@ -49,6 +49,7 @@ class Database: 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'] # where possible avoid creating new SQL instance by using the global one passed in if sql == None: self.sql = SQL.Sql(type = self.type, db_server = db_params['db-server']) diff --git a/pyfpdb/fpdb_import.py b/pyfpdb/fpdb_import.py index 455c1e27..2468fecf 100644 --- a/pyfpdb/fpdb_import.py +++ b/pyfpdb/fpdb_import.py @@ -31,6 +31,7 @@ import re import fpdb_simple import fpdb_db +import Database import fpdb_parse_logic import Configuration @@ -57,7 +58,8 @@ class Importer: self.settings = settings self.caller = caller self.config = config - self.fdb = None + self.database = None # database will be the main db interface eventually + self.fdb = None # fdb may disappear or just hold the simple db connection self.cursor = None self.filelist = {} self.dirlist = {} @@ -75,6 +77,7 @@ class Importer: self.settings.setdefault("minPrint", 30) self.settings.setdefault("handCount", 0) + self.database = Database.Database(self.config) # includes .connection and .sql variables self.fdb = fpdb_db.fpdb_db() # sets self.fdb.db self.fdb.cursor and self.fdb.sql self.fdb.do_connect(self.config) self.fdb.db.rollback() @@ -392,8 +395,9 @@ class Importer: self.hand=hand try: - handsId = fpdb_parse_logic.mainParser(self.settings, self.fdb - , self.siteIds[site], category, hand, self.config) + handsId = fpdb_parse_logic.mainParser( self.settings, self.fdb + , self.siteIds[site], category, hand + , self.config, self.database ) self.fdb.db.commit() stored += 1 diff --git a/pyfpdb/fpdb_parse_logic.py b/pyfpdb/fpdb_parse_logic.py index eff8179f..bb361f63 100644 --- a/pyfpdb/fpdb_parse_logic.py +++ b/pyfpdb/fpdb_parse_logic.py @@ -21,10 +21,13 @@ import fpdb_simple import Database #parses a holdem hand -def mainParser(settings, fdb, siteID, category, hand, config): +def mainParser(settings, fdb, siteID, category, hand, config, db = None): backend = settings['db-backend'] - #This is redundant - hopefully fdb will be a Database object in an interation soon - db = Database.Database(config, 'fpdb', '') + if db == None: + #This is redundant - hopefully fdb will be a Database object in an iteration soon + db = Database.Database(c = config, sql = None) + else: + db = db category = fpdb_simple.recogniseCategory(hand[0]) base = "hold" if category == "holdem" or category == "omahahi" or category == "omahahilo" else "stud" From cb323d2d6323a508c53fb430e39786c2aefdbc32 Mon Sep 17 00:00:00 2001 From: sqlcoder Date: Sun, 28 Jun 2009 17:20:41 +0100 Subject: [PATCH 26/57] remove unused queries --- pyfpdb/FpdbSQLQueries.py | 167 --------------------------------------- pyfpdb/fpdb_db.py | 1 - 2 files changed, 168 deletions(-) diff --git a/pyfpdb/FpdbSQLQueries.py b/pyfpdb/FpdbSQLQueries.py index 598c0868..db2d7231 100644 --- a/pyfpdb/FpdbSQLQueries.py +++ b/pyfpdb/FpdbSQLQueries.py @@ -248,43 +248,6 @@ class FpdbSQLQueries: self.query['createHandsTable'] = """ """ - ################################ - # Create Gametypes - ################################ - - if(self.dbname == 'MySQL InnoDB'): - self.query['createBoardCardsTable'] = """CREATE TABLE BoardCards ( - id BIGINT UNSIGNED AUTO_INCREMENT NOT NULL, PRIMARY KEY (id), - handId BIGINT UNSIGNED NOT NULL, FOREIGN KEY (handId) REFERENCES Hands(id), - card1Value smallint NOT NULL, - card1Suit char(1) NOT NULL, - card2Value smallint NOT NULL, - card2Suit char(1) NOT NULL, - card3Value smallint NOT NULL, - card3Suit char(1) NOT NULL, - card4Value smallint NOT NULL, - card4Suit char(1) NOT NULL, - card5Value smallint NOT NULL, - card5Suit char(1) NOT NULL) - ENGINE=INNODB""" - elif(self.dbname == 'PostgreSQL'): - self.query['createBoardCardsTable'] = """CREATE TABLE BoardCards ( - id BIGSERIAL, PRIMARY KEY (id), - handId BIGINT, FOREIGN KEY (handId) REFERENCES Hands(id), - card1Value smallint, - card1Suit char(1), - card2Value smallint, - card2Suit char(1), - card3Value smallint, - card3Suit char(1), - card4Value smallint, - card4Suit char(1), - card5Value smallint, - card5Suit char(1))""" - elif(self.dbname == 'SQLite'): - self.query['createBoardCardsTable'] = """ """ - - ################################ # Create TourneyTypes ################################ @@ -1550,136 +1513,6 @@ class FpdbSQLQueries: elif(self.dbname == 'SQLite'): self.query['playerStatsByPosition'] = """ """ - if(self.dbname == 'MySQL InnoDB'): - self.query['playerStatsByPositionAndHoleCards'] = """ - SELECT - concat(upper(stats.limitType), ' ' - ,concat(upper(substring(stats.category,1,1)),substring(stats.category,2) ), ' ' - ,stats.name, ' $' - ,cast(trim(leading ' ' from - case when stats.bigBlind < 100 then format(stats.bigBlind/100.0,2) - else format(stats.bigBlind/100.0,0) - end ) as char) - ) AS Game - ,case when stats.PlPosition = -2 then 'BB' - when stats.PlPosition = -1 then 'SB' - when stats.PlPosition = 0 then 'Btn' - when stats.PlPosition = 1 then 'CO' - when stats.PlPosition = 2 then 'MP' - when stats.PlPosition = 5 then 'EP' - else '??' - end AS PlPosition - /*,stats.n*/,hprof2.n - /*,stats.vpip*/,0 - /*,stats.pfr*/,0 - /*,stats.saw_f*/,0 - /*,stats.sawsd*/,0 - /*,stats.wtsdwsf*/,0 - /*,stats.wmsd*/,0 - /*,stats.FlAFq*/,0 - /*,stats.TuAFq*/,0 - /*,stats.RvAFq*/,0 - /*,stats.PoFAFq*/,0 - /* if you have handsactions data the next 3 fields should give same answer as - following 3 commented out fields */ - /*,stats.Net - ,stats.BBper100 - ,stats.Profitperhand*/ - ,format(hprof2.sum_profit/100.0,2) AS Net - /*,format((hprof2.sum_profit/(stats.bigBlind+0.0)) / (stats.n/100.0),2)*/,0 - AS BBlPer100 - ,hprof2.profitperhand AS Profitperhand - ,format(hprof2.variance,2) AS Variance - FROM - (select /* stats from hudcache */ - gt.base - ,gt.category - ,upper(gt.limitType) as limitType - ,s.name - ,gt.bigBlind - ,hc.gametypeId - ,case when hc.position = 'B' then -2 - when hc.position = 'S' then -1 - when hc.position = 'D' then 0 - when hc.position = 'C' then 1 - when hc.position = 'M' then 2 - when hc.position = 'E' then 5 - else 9 - end as PlPosition - ,sum(HDs) AS n - ,format(100.0*sum(street0VPI)/sum(HDs),1) AS vpip - ,format(100.0*sum(street0Aggr)/sum(HDs),1) AS pfr - ,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 '-' - 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 - 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 - # use here ? - group by gt.base - ,gt.category - ,upper(gt.limitType) - ,s.name - ,gt.bigBlind - ,hc.gametypeId - ,PlPosition - ) stats - inner join - ( select # profit from handsplayers/handsactions - hprof.gameTypeId, - case when hprof.position = 'B' then -2 - when hprof.position = 'S' then -1 - when hprof.position in ('3','4') then 2 - when hprof.position in ('6','7') then 5 - else hprof.position - end as PlPosition, - sum(hprof.profit) as sum_profit, - avg(hprof.profit/100.0) as profitperhand, - variance(hprof.profit/100.0) as variance, - count(*) as n - from - (select hp.handId, h.gameTypeId, hp.position, hp.winnings, SUM(ha.amount) as costs - , hp.winnings - SUM(ha.amount) as profit - from HandsPlayers hp - inner join Hands h ON h.id = hp.handId - left join HandsActions ha ON ha.handsPlayerId = hp.id - where hp.playerId in - # use here ? - and hp.tourneysPlayersId IS NULL - and ((hp.card1Value = and hp.card2Value = ) or (hp.card1Value = and hp.card2Value = )) - group by hp.handId, h.gameTypeId, hp.position, hp.winnings - ) hprof - group by hprof.gameTypeId, PlPosition - ) hprof2 - on ( hprof2.gameTypeId = stats.gameTypeId - and hprof2.PlPosition = stats.PlPosition) - order by stats.category, stats.limittype, stats.bigBlind, cast(stats.PlPosition as signed) - """ if(self.dbname == 'MySQL InnoDB') or (self.dbname == 'PostgreSQL') or (self.dbname == 'SQLite'): self.query['getGames'] = """SELECT DISTINCT category from Gametypes""" diff --git a/pyfpdb/fpdb_db.py b/pyfpdb/fpdb_db.py index 29817af9..911618e1 100644 --- a/pyfpdb/fpdb_db.py +++ b/pyfpdb/fpdb_db.py @@ -243,7 +243,6 @@ class fpdb_db: self.cursor.execute(self.sql.query['createPlayersTable']) self.cursor.execute(self.sql.query['createAutoratesTable']) self.cursor.execute(self.sql.query['createHandsTable']) - self.cursor.execute(self.sql.query['createBoardCardsTable']) self.cursor.execute(self.sql.query['createTourneyTypesTable']) self.cursor.execute(self.sql.query['createTourneysTable']) self.cursor.execute(self.sql.query['createTourneysPlayersTable']) From dc7a3fb88ebd82f90a87c6e344474498749727d4 Mon Sep 17 00:00:00 2001 From: sqlcoder Date: Sun, 28 Jun 2009 18:56:18 +0100 Subject: [PATCH 27/57] finish removal of store_board_cards() --- pyfpdb/Database.py | 3 --- pyfpdb/fpdb_simple.py | 10 ---------- 2 files changed, 13 deletions(-) diff --git a/pyfpdb/Database.py b/pyfpdb/Database.py index 2cade5de..f59476b9 100755 --- a/pyfpdb/Database.py +++ b/pyfpdb/Database.py @@ -328,7 +328,6 @@ class Database: if 'updateHudCache' not in settings or settings['updateHudCache'] != 'drop': fpdb_simple.storeHudCache(self.backend, cursor, base, category, gametype_id, hand_start_time, player_ids, hudImportData) t5 = time() - fpdb_simple.store_board_cards(cursor, hands_id, board_values, board_suits) t6 = time() if self.saveActions: fpdb_simple.storeActions(cursor, hands_players_ids, action_types, allIns, action_amounts, actionNos) @@ -363,8 +362,6 @@ class Database: if 'updateHudCache' not in settings or settings['updateHudCache'] != 'drop': fpdb_simple.storeHudCache(self.backend, cursor, base, category, gametype_id, hand_start_time, player_ids, hudImportData) - fpdb_simple.store_board_cards(cursor, hands_id, board_values, board_suits) - if self.saveActions: fpdb_simple.storeActions(cursor, hands_players_ids, action_types, allIns, action_amounts, actionNos) return hands_id diff --git a/pyfpdb/fpdb_simple.py b/pyfpdb/fpdb_simple.py index 34f99e2f..3e862254 100644 --- a/pyfpdb/fpdb_simple.py +++ b/pyfpdb/fpdb_simple.py @@ -1136,16 +1136,6 @@ def storeActions(cursor, handsPlayersIds, actionTypes, allIns, actionAmounts, ac cursor.executemany("INSERT INTO HandsActions (handsPlayerId, street, actionNo, action, allIn, amount) VALUES (%s, %s, %s, %s, %s, %s)", inserts) #end def storeActions -def store_board_cards(cursor, hands_id, board_values, board_suits): -#stores into table board_cards - cursor.execute ("""INSERT INTO BoardCards (handId, card1Value, card1Suit, -card2Value, card2Suit, card3Value, card3Suit, card4Value, card4Suit, -card5Value, card5Suit) VALUES (%s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s)""", - (hands_id, board_values[0], board_suits[0], board_values[1], board_suits[1], - board_values[2], board_suits[2], board_values[3], board_suits[3], - board_values[4], board_suits[4])) -#end def store_board_cards - def storeHands(backend, conn, cursor, site_hand_no, gametype_id ,hand_start_time, names, tableName, maxSeats, hudCache, board_values, board_suits): From a3e6c2696faa9dde60316b3f091d723aa06dbd37 Mon Sep 17 00:00:00 2001 From: sqlcoder Date: Sun, 28 Jun 2009 19:19:32 +0100 Subject: [PATCH 28/57] use Database instead of fpdb_db --- pyfpdb/fpdb.py | 58 ++++++++++++++++++++++++++++---------------------- 1 file changed, 33 insertions(+), 25 deletions(-) diff --git a/pyfpdb/fpdb.py b/pyfpdb/fpdb.py index 6c982002..3f6b7fb6 100755 --- a/pyfpdb/fpdb.py +++ b/pyfpdb/fpdb.py @@ -32,7 +32,7 @@ import pygtk pygtk.require('2.0') import gtk -import fpdb_db + import fpdb_simple import GuiBulkImport import GuiPlayerStats @@ -206,22 +206,23 @@ class fpdb: try: dia_confirm = gtk.MessageDialog(parent=None, flags=0, type=gtk.MESSAGE_WARNING, buttons=(gtk.BUTTONS_YES_NO), message_format="Confirm deleting and recreating tables") - diastring = "Please confirm that you want to (re-)create the tables. If there already are tables in the database "+self.db.database+" on "+self.db.host+" they will be deleted." + diastring = "Please confirm that you want to (re-)create the tables. If there already are tables in the database " \ + +self.db.fdb.database+" on "+self.db.fdb.host+" they will be deleted." dia_confirm.format_secondary_text(diastring)#todo: make above string with bold for db, host and deleted response = dia_confirm.run() dia_confirm.destroy() if response == gtk.RESPONSE_YES: - if self.db.backend == self.fdb_lock.MYSQL_INNODB: + if self.db.fdb.backend == self.fdb_lock.fdb.MYSQL_INNODB: # mysql requires locks on all tables or none - easier to release this lock # than lock all the other tables # ToDo: lock all other tables so that lock doesn't have to be released self.release_global_lock() lock_released = True - self.db.recreate_tables() + self.db.fdb.recreate_tables() else: # for other dbs use same connection as holds global lock - self.fdb_lock.recreate_tables() + self.fdb_lock.fdb.recreate_tables() elif response == gtk.RESPONSE_NO: print 'User cancelled recreating tables' except: @@ -362,13 +363,18 @@ class fpdb: self.settings.update(self.config.get_import_parameters()) self.settings.update(self.config.get_default_paths()) - if self.db!=None: - self.db.disconnect() + if self.db != None and self.db.fdb != None: + self.db.fdb.disconnect() - self.db = fpdb_db.fpdb_db() - #print "end of fpdb.load_profile, databaseName:",self.settings['db-databaseName'] - self.db.do_connect(self.config) - if self.db.wrongDbVersion: + self.sql = SQL.Sql(type = self.settings['db-type'], db_server = self.settings['db-server']) + self.db = Database.Database(self.config, sql = self.sql) + + + + + + + if self.db.fdb.wrongDbVersion: diaDbVersionWarning = gtk.Dialog(title="Strong Warning - Invalid database version", parent=None, flags=0, buttons=(gtk.STOCK_OK,gtk.RESPONSE_OK)) label = gtk.Label("An invalid DB version or missing tables have been detected.") @@ -387,18 +393,19 @@ class fpdb: diaDbVersionWarning.destroy() if self.status_bar == None: - self.status_bar = gtk.Label("Status: Connected to %s database named %s on host %s"%(self.db.get_backend_name(),self.db.database, self.db.host)) + self.status_bar = gtk.Label("Status: Connected to %s database named %s on host %s"%(self.db.fdb.get_backend_name(),self.db.fdb.database, self.db.fdb.host)) self.main_vbox.pack_end(self.status_bar, False, True, 0) self.status_bar.show() else: - self.status_bar.set_text("Status: Connected to %s database named %s on host %s" % (self.db.get_backend_name(),self.db.database, self.db.host)) + self.status_bar.set_text("Status: Connected to %s database named %s on host %s" % (self.db.fdb.get_backend_name(),self.db.fdb.database, self.db.fdb.host)) # Database connected to successfully, load queries to pass on to other classes - self.querydict = FpdbSQLQueries.FpdbSQLQueries(self.db.get_backend_name()) - self.sql = SQL.Sql(type = self.settings['db-type'], db_server = self.settings['db-server']) - self.dbi = Database.Database(self.config, sql = self.sql) # dbi for db interface and to avoid clashes with db/database/etc - # can rename later if required - self.db.db.rollback() + self.querydict = FpdbSQLQueries.FpdbSQLQueries(self.db.fdb.get_backend_name()) + self.db.fdb.db.rollback() + + + + #end def load_profile def not_implemented(self, widget, data=None): @@ -407,21 +414,22 @@ class fpdb: def obtain_global_lock(self): print "\nTaking global lock ..." - self.fdb_lock = fpdb_db.fpdb_db() - self.fdb_lock.do_connect(self.config) - return self.fdb_lock.get_global_lock() + self.fdb_lock = Database.Database(self.config, sql = self.sql) + + self.fdb_lock.fdb.do_connect(self.config) + return self.fdb_lock.fdb.get_global_lock() #end def obtain_global_lock def quit(self, widget, data=None): print "Quitting normally" #check if current settings differ from profile, if so offer to save or abort - self.db.disconnect() + self.db.fdb.disconnect() gtk.main_quit() #end def quit_cliecked def release_global_lock(self): - self.fdb_lock.db.rollback() - self.fdb_lock.disconnect() + self.fdb_lock.fdb.db.rollback() + self.fdb_lock.fdb.disconnect() print "Global lock released." #end def release_global_lock @@ -471,7 +479,7 @@ This program is licensed under the AGPL3, see docs"""+os.sep+"agpl-3.0.txt") def tab_table_viewer(self, widget, data=None): """opens a table viewer tab""" #print "start of tab_table_viewer" - new_tv_thread=GuiTableViewer.GuiTableViewer(self.db, self.settings) + new_tv_thread=GuiTableViewer.GuiTableViewer(self.db.fdb, self.settings) self.threads.append(new_tv_thread) tv_tab=new_tv_thread.get_vbox() self.add_and_display_tab(tv_tab, "Table Viewer") From a8b8ff2f4d5542aa3fab36a923cb8e69f275058b Mon Sep 17 00:00:00 2001 From: Ray Date: Tue, 30 Jun 2009 11:43:47 -0400 Subject: [PATCH 29/57] More on Aux_Seats class. This seems to work OK. --- pyfpdb/Mucked.py | 21 +++++++++++++++------ 1 file changed, 15 insertions(+), 6 deletions(-) diff --git a/pyfpdb/Mucked.py b/pyfpdb/Mucked.py index 4c8b2eb4..c0715632 100755 --- a/pyfpdb/Mucked.py +++ b/pyfpdb/Mucked.py @@ -87,6 +87,13 @@ class Aux_Window(object): if c != None and c > 0: n = n + 1 return n + def get_id_from_seat(self, seat): + """Determine player id from seat number, given stat_dict.""" + for id, dict in self.hud.stat_dict.iteritems(): + if seat == dict['seat']: + return id + return None + class Stud_mucked(Aux_Window): def __init__(self, hud, config, params): @@ -356,13 +363,15 @@ class Aux_Seats(Aux_Window): self.m_windows[i].connect("configure_event", self.configure_event_cb, i) self.positions[i] = (int(x) + self.hud.table.x, int(y) + self.hud.table.y) self.m_windows[i].move(self.positions[i][0], self.positions[i][1]) - self.m_windows[i].set_opacity(float(self.params['opacity'])) + if self.params.has_key('opacity'): + self.m_windows[i].set_opacity(float(self.params['opacity'])) # the create_contents method is supplied by the subclass self.create_contents(self.m_windows[i], i) self.m_windows[i].show_all() - self.m_windows[i].hide() + if self.uses_timer: + self.m_windows[i].hide() def update_gui(self, new_hand_id): """Update the gui, LDO.""" @@ -394,6 +403,10 @@ class Aux_Seats(Aux_Window): new_locs[i] = (pos[0] - self.hud.table.x, pos[1] - self.hud.table.y) self.config.edit_aux_layout(self.params['name'], self.hud.max, locations = new_locs) + def configure_event_cb(self, widget, event, i, *args): + self.positions[i] = widget.get_position() +# self.rel_positions[i] = (self.positions[i][0] - self.hud.table.x, self.positions[i][1] - self.hud.table.y) + class Flop_Mucked(Aux_Seats): """Aux_Window class for displaying mucked cards for flop games.""" @@ -491,10 +504,6 @@ class Flop_Mucked(Aux_Seats): window = widget.get_parent() window.begin_move_drag(event.button, int(event.x_root), int(event.y_root), event.time) - def configure_event_cb(self, widget, event, i, *args): - self.positions[i] = widget.get_position() -# self.rel_positions[i] = (self.positions[i][0] - self.hud.table.x, self.positions[i][1] - self.hud.table.y) - def expose_all(self): for (i, cards) in self.hud.cards.iteritems(): self.m_windows[i].show() From 71d673f64f32c8ae1ef576fa5b6861d808eceee4 Mon Sep 17 00:00:00 2001 From: Ray Date: Tue, 30 Jun 2009 11:45:14 -0400 Subject: [PATCH 30/57] Added Hello_Seats to Hello.py. Demo of Aux_Seats class. --- pyfpdb/Hello.py | 28 +++++++++++++++++----------- 1 file changed, 17 insertions(+), 11 deletions(-) diff --git a/pyfpdb/Hello.py b/pyfpdb/Hello.py index 41262d6c..7f3f6442 100644 --- a/pyfpdb/Hello.py +++ b/pyfpdb/Hello.py @@ -34,10 +34,13 @@ import gobject # FreePokerTools modules from Mucked import Aux_Window +from Mucked import Seat_Window +from Mucked import Aux_Seats class Hello(Aux_Window): """A 'Hello World' Aux_Window demo.""" def create(self): + print "creating Hello" # This demo simply creates a label in a window. self.container = gtk.Window() self.container.add(gtk.Label("Hello World")) @@ -99,15 +102,18 @@ class Hello_plus(Aux_Window): # hands played that was updated in the "update_data()" function. self.label.set_text("Hello %s\nYou have played %d hands\n on %s." % (self.hero, self.hands_played, self.site)) -class Hello_Menu(Aux_Window): - """A 'Hello World' Aux_Window demo.""" - def create(self): -# This demo puts a menu item on the HUD mainwindow. - self.item = gtk.MenuItem('Print cards') - self.hud.menu.append(self.item) - self.item.connect("activate", self.print_cards) - self.item.show() +class Hello_Seats(Aux_Seats): + """A 'Hello World' Seat_Window demo.""" - def print_cards(self, *args): -# callback for the menu item - print "cards =", self.hud.cards + def create_contents(self, container, i): + container.label = gtk.Label("empty") + container.add(container.label) + container.show_all() + + def update_contents(self, container, i): + if i == "common": return + id = self.get_id_from_seat(i) + if id == None: + container.label.set_text("empty") + else: + container.label.set_text("player = %s" % self.hud.stat_dict[id]['screen_name']) From a3f233ca07e13bfa1c07ac8f7f44c7889792afae Mon Sep 17 00:00:00 2001 From: Ray Date: Tue, 30 Jun 2009 14:21:06 -0400 Subject: [PATCH 31/57] Comment out a DEBUG print. --- pyfpdb/Hand.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pyfpdb/Hand.py b/pyfpdb/Hand.py index 38c3609b..b9272031 100644 --- a/pyfpdb/Hand.py +++ b/pyfpdb/Hand.py @@ -202,7 +202,7 @@ If a player has None chips he won't be added.""" def setCommunityCards(self, street, cards): logging.debug("setCommunityCards %s %s" %(street, cards)) self.board[street] = [self.card(c) for c in cards] - print "DEBUG: self.board: %s" % self.board +# print "DEBUG: self.board: %s" % self.board def card(self,c): """upper case the ranks but not suits, 'atjqk' => 'ATJQK'""" From 04b9dd91268563e2569417a5252ababaf8376cd4 Mon Sep 17 00:00:00 2001 From: sqlcoder Date: Tue, 30 Jun 2009 21:58:59 +0100 Subject: [PATCH 32/57] use Players table for global lock because Database.init() tries to access Hands --- pyfpdb/fpdb_db.py | 17 +++++++++-------- 1 file changed, 9 insertions(+), 8 deletions(-) diff --git a/pyfpdb/fpdb_db.py b/pyfpdb/fpdb_db.py index 911618e1..f89b5d6d 100644 --- a/pyfpdb/fpdb_db.py +++ b/pyfpdb/fpdb_db.py @@ -567,17 +567,18 @@ class fpdb_db: print "analyze took", atime, "seconds" #end def analyzeDB - # Currently uses an exclusive lock on the Hands table as a global lock + # Currently uses an exclusive lock on the Players table as a global lock + # ( Changed because Hands is used in Database.init() ) # Return values are Unix style, 0 for success, positive integers for errors # 1 = generic error - # 2 = hands table does not exist (error message is suppressed) + # 2 = players table does not exist (error message is suppressed) def get_global_lock(self): if self.backend == self.MYSQL_INNODB: try: - self.cursor.execute( "lock tables Hands write" ) + self.cursor.execute( "lock tables Players write" ) except: - # Table 'fpdb.hands' doesn't exist - if str(sys.exc_value).find(".Hands' doesn't exist") >= 0: + # Table 'fpdb.players' doesn't exist + if str(sys.exc_value).find(".Players' doesn't exist") >= 0: return(2) print "Error! failed to obtain global lock. Close all programs accessing " \ + "database (including fpdb) and try again (%s)." \ @@ -585,11 +586,11 @@ class fpdb_db: return(1) elif self.backend == self.PGSQL: try: - self.cursor.execute( "lock table Hands in exclusive mode nowait" ) + self.cursor.execute( "lock table Players in exclusive mode nowait" ) #print "... after lock table, status =", self.cursor.statusmessage except: - # relation "hands" does not exist - if str(sys.exc_value).find('relation "hands" does not exist') >= 0: + # relation "players" does not exist + if str(sys.exc_value).find('relation "players" does not exist') >= 0: return(2) print "Error! failed to obtain global lock. Close all programs accessing " \ + "database (including fpdb) and try again (%s)." \ From cb1a4d2d0ab6500e11666cf92b4677b8f51953dc Mon Sep 17 00:00:00 2001 From: sqlcoder Date: Tue, 30 Jun 2009 22:00:55 +0100 Subject: [PATCH 33/57] add wrappers for fpdb_db methods (plan is to move the fpdb_db methods into Database) --- pyfpdb/Database.py | 17 ++++++++++++++++- 1 file changed, 16 insertions(+), 1 deletion(-) diff --git a/pyfpdb/Database.py b/pyfpdb/Database.py index f59476b9..cf80b3d3 100755 --- a/pyfpdb/Database.py +++ b/pyfpdb/Database.py @@ -40,7 +40,7 @@ import Card class Database: def __init__(self, c, db_name = None, game = None, sql = None): # db_name and game not used any more - print "creating Database instance, sql =", sql + print "\ncreating Database instance, sql =", sql self.fdb = fpdb_db.fpdb_db() # sets self.fdb.db self.fdb.cursor and self.fdb.sql self.fdb.do_connect(c) self.connection = self.fdb.db @@ -87,13 +87,28 @@ class Database: #row = cur.fetchone() self.saveActions = False if self.import_options['saveActions'] == False else True + def do_connect(self, c): + self.fdb.do_connect(c) def commit(self): self.fdb.db.commit() def close_connection(self): self.connection.close() + + def disconnect(self, due_to_error=False): + """Disconnects the DB (rolls back if param is true, otherwise commits""" + self.fdb.disconnect(due_to_error) + + def reconnect(self, due_to_error=False): + """Reconnects the DB""" + self.fdb.reconnect(due_to_error=False) + + def get_backend_name(self): + """Reconnects the DB""" + return self.fdb.get_backend_name() + def get_table_name(self, hand_id): c = self.connection.cursor() c.execute(self.sql.query['get_table_name'], (hand_id, )) From 56ef131bedb9dc06998250d11b2890a83b886a7c Mon Sep 17 00:00:00 2001 From: sqlcoder Date: Tue, 30 Jun 2009 22:18:15 +0100 Subject: [PATCH 34/57] use 1 or 2 Database methods instead of the underlying fpdb_db methods (more to do) --- pyfpdb/fpdb.py | 26 ++++++++------------------ 1 file changed, 8 insertions(+), 18 deletions(-) diff --git a/pyfpdb/fpdb.py b/pyfpdb/fpdb.py index 3f6b7fb6..cdb89894 100755 --- a/pyfpdb/fpdb.py +++ b/pyfpdb/fpdb.py @@ -364,16 +364,11 @@ class fpdb: self.settings.update(self.config.get_default_paths()) if self.db != None and self.db.fdb != None: - self.db.fdb.disconnect() + self.db.disconnect() self.sql = SQL.Sql(type = self.settings['db-type'], db_server = self.settings['db-server']) self.db = Database.Database(self.config, sql = self.sql) - - - - - if self.db.fdb.wrongDbVersion: diaDbVersionWarning = gtk.Dialog(title="Strong Warning - Invalid database version", parent=None, flags=0, buttons=(gtk.STOCK_OK,gtk.RESPONSE_OK)) @@ -393,19 +388,15 @@ class fpdb: diaDbVersionWarning.destroy() if self.status_bar == None: - self.status_bar = gtk.Label("Status: Connected to %s database named %s on host %s"%(self.db.fdb.get_backend_name(),self.db.fdb.database, self.db.fdb.host)) + self.status_bar = gtk.Label("Status: Connected to %s database named %s on host %s"%(self.db.get_backend_name(),self.db.fdb.database, self.db.fdb.host)) self.main_vbox.pack_end(self.status_bar, False, True, 0) self.status_bar.show() else: - self.status_bar.set_text("Status: Connected to %s database named %s on host %s" % (self.db.fdb.get_backend_name(),self.db.fdb.database, self.db.fdb.host)) + self.status_bar.set_text("Status: Connected to %s database named %s on host %s" % (self.db.get_backend_name(),self.db.fdb.database, self.db.fdb.host)) # Database connected to successfully, load queries to pass on to other classes - self.querydict = FpdbSQLQueries.FpdbSQLQueries(self.db.fdb.get_backend_name()) - self.db.fdb.db.rollback() - - - - + self.querydict = FpdbSQLQueries.FpdbSQLQueries(self.db.get_backend_name()) + self.db.connection.rollback() #end def load_profile def not_implemented(self, widget, data=None): @@ -415,22 +406,21 @@ class fpdb: def obtain_global_lock(self): print "\nTaking global lock ..." self.fdb_lock = Database.Database(self.config, sql = self.sql) - - self.fdb_lock.fdb.do_connect(self.config) + self.fdb_lock.do_connect(self.config) return self.fdb_lock.fdb.get_global_lock() #end def obtain_global_lock def quit(self, widget, data=None): print "Quitting normally" #check if current settings differ from profile, if so offer to save or abort - self.db.fdb.disconnect() + self.db.disconnect() gtk.main_quit() #end def quit_cliecked def release_global_lock(self): self.fdb_lock.fdb.db.rollback() self.fdb_lock.fdb.disconnect() - print "Global lock released." + print "Global lock released.\n" #end def release_global_lock def tab_abbreviations(self, widget, data=None): From 2cfe7f2ccc5ab27b567962de5c52926e8a463db8 Mon Sep 17 00:00:00 2001 From: Ray Date: Wed, 1 Jul 2009 08:29:37 -0400 Subject: [PATCH 35/57] Fix bug--get correct player id in Flop_Mucked tool tip. --- pyfpdb/Mucked.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/pyfpdb/Mucked.py b/pyfpdb/Mucked.py index c0715632..b3b134c5 100755 --- a/pyfpdb/Mucked.py +++ b/pyfpdb/Mucked.py @@ -448,7 +448,8 @@ class Flop_Mucked(Aux_Seats): container.move(self.positions[i][0], self.positions[i][1]) # here is where I move back self.displayed = True if i != "common": - self.m_windows[i].eb.set_tooltip_text(self.hud.stat_dict[i]['screen_name']) + id = self.get_id_from_seat(i) + self.m_windows[i].eb.set_tooltip_text(self.hud.stat_dict[id]['screen_name']) def update_gui(self, new_hand_id): """Prepare and show the mucked cards.""" @@ -458,7 +459,7 @@ class Flop_Mucked(Aux_Seats): n_sd = 0 for (i, cards) in self.hud.cards.iteritems(): n_cards = self.has_cards(cards) - if n_cards > 0: + if n_cards > 0 and i != 'common': n_sd = n_sd + 1 if n_sd < 2: print "skipping, n_sd =", n_sd From 4394c7beb38af9fbad8b82da97562eabab939b82 Mon Sep 17 00:00:00 2001 From: Ray Date: Wed, 1 Jul 2009 13:53:30 -0400 Subject: [PATCH 36/57] Fix to convert stud hands. --- pyfpdb/Hand.py | 35 ++++++++++++++++++++--------------- 1 file changed, 20 insertions(+), 15 deletions(-) diff --git a/pyfpdb/Hand.py b/pyfpdb/Hand.py index b9272031..a0c1537c 100644 --- a/pyfpdb/Hand.py +++ b/pyfpdb/Hand.py @@ -916,6 +916,11 @@ class StudHand(Hand): def __init__(self, hhc, sitename, gametype, handText, builtFrom = "HHC"): if gametype['base'] != 'stud': pass # or indeed don't pass and complain instead + + self.allStreets = ['ANTES','THIRD','FOURTH','FIFTH','SIXTH','SEVENTH'] + self.communityStreets = [] + self.actionStreets = ['ANTES','THIRD','FOURTH','FIFTH','SIXTH','SEVENTH'] + self.streetList = ['ANTES','THIRD','FOURTH','FIFTH','SIXTH','SEVENTH'] # a list of the observed street names in order self.holeStreets = ['ANTES','THIRD','FOURTH','FIFTH','SIXTH','SEVENTH'] Hand.__init__(self, sitename, gametype, handText) @@ -957,7 +962,7 @@ closed likewise, but known only to player logging.debug("addPlayerCards %s, o%s x%s" % (player, open, closed)) try: self.checkPlayerExists(player) - self.holecards[player][street] = (open, closed) + self.holecards[street][player] = (open, closed) # cards = set([self.card(c) for c in cards]) # self.holecards[player].update(cards) except FpdbParseError, e: @@ -1015,8 +1020,8 @@ Add a complete on [street] by [player] to [amountTo] dealt = 0 #~ print >>fh, _("*** 3RD STREET ***") for player in [x[1] for x in self.players if x[1] in players_who_post_antes]: - if 'THIRD' in self.holecards[player]: - (open, closed) = self.holecards[player]['THIRD'] + if self.holecards['THIRD'].has_key(player): + (open, closed) = self.holecards['THIRD'][player] dealt+=1 if dealt==1: print >>fh, _("*** 3RD STREET ***") @@ -1029,12 +1034,12 @@ Add a complete on [street] by [player] to [amountTo] dealt = 0 #~ print >>fh, _("*** 4TH STREET ***") for player in [x[1] for x in self.players if x[1] in players_who_post_antes]: - if 'FOURTH' in self.holecards[player]: + if player in self.holecards['FOURTH']: old = [] - (o,c) = self.holecards[player]['THIRD'] + (o,c) = self.holecards['THIRD'][player] if o:old.extend(o) if c:old.extend(c) - new = self.holecards[player]['FOURTH'][0] + new = self.holecards['FOURTH'][player][0] dealt+=1 if dealt==1: print >>fh, _("*** 4TH STREET ***") @@ -1046,13 +1051,13 @@ Add a complete on [street] by [player] to [amountTo] dealt = 0 #~ print >>fh, _("*** 5TH STREET ***") for player in [x[1] for x in self.players if x[1] in players_who_post_antes]: - if 'FIFTH' in self.holecards[player]: + if self.holecards['FIFTH'].has_key(player): old = [] for street in ('THIRD','FOURTH'): - (o,c) = self.holecards[player][street] + (o,c) = self.holecards[street][player] if o:old.extend(o) if c:old.extend(c) - new = self.holecards[player]['FIFTH'][0] + new = self.holecards['FIFTH'][player][0] dealt+=1 if dealt==1: print >>fh, _("*** 5TH STREET ***") @@ -1064,13 +1069,13 @@ Add a complete on [street] by [player] to [amountTo] dealt = 0 #~ print >>fh, _("*** 6TH STREET ***") for player in [x[1] for x in self.players if x[1] in players_who_post_antes]: - if 'SIXTH' in self.holecards[player]: + if self.holecards['SIXTH'].has_key(player): old = [] for street in ('THIRD','FOURTH','FIFTH'): - (o,c) = self.holecards[player][street] + (o,c) = self.holecards[street][player] if o:old.extend(o) if c:old.extend(c) - new = self.holecards[player]['SIXTH'][0] + new = self.holecards['SIXTH'][player][0] dealt += 1 if dealt == 1: print >>fh, _("*** 6TH STREET ***") @@ -1085,13 +1090,13 @@ Add a complete on [street] by [player] to [amountTo] # i.e. are all but one players folded; is there an allin showdown; and all that. print >>fh, _("*** 7TH STREET ***") for player in [x[1] for x in self.players if x[1] in players_who_post_antes]: - if 'SEVENTH' in self.holecards[player]: + if self.holecards['SEVENTH'].has_key(player): old = [] for street in ('THIRD','FOURTH','FIFTH','SIXTH'): - (o,c) = self.holecards[player][street] + (o,c) = self.holecards[street][player] if o:old.extend(o) if c:old.extend(c) - new = self.holecards[player]['SEVENTH'][0] + new = self.holecards['SEVENTH'][player][0] if new: print >>fh, _("Dealt to %s:%s%s") % (player, " [" + " ".join(old) + "] " if old else " ", "[" + " ".join(new) + "]" if new else "") for act in self.actions['SEVENTH']: From 97520bfee9705d936c48c9e183999db60dbb0900 Mon Sep 17 00:00:00 2001 From: Ray Date: Wed, 1 Jul 2009 13:55:12 -0400 Subject: [PATCH 37/57] Fix call to StoreHands for stud games. --- pyfpdb/Database.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/pyfpdb/Database.py b/pyfpdb/Database.py index 2cade5de..e9401d35 100755 --- a/pyfpdb/Database.py +++ b/pyfpdb/Database.py @@ -287,7 +287,8 @@ class Database: fpdb_simple.fillCardArrays(len(names), base, category, card_values, card_suits) hands_id = fpdb_simple.storeHands(self.backend, db, cursor, site_hand_no, gametype_id - ,hand_start_time, names, tableName, maxSeats, hudImportData) + ,hand_start_time, names, tableName, maxSeats, hudImportData + ,(None, None, None, None, None), (None, None, None, None, None)) #print "before calling store_hands_players_stud, antes:", antes hands_players_ids = fpdb_simple.store_hands_players_stud(self.backend, db, cursor, hands_id, player_ids From 3c2c328f5ae6aea2dc3b90b13f027c8f96ee648b Mon Sep 17 00:00:00 2001 From: Ray Date: Fri, 3 Jul 2009 13:23:30 -0400 Subject: [PATCH 38/57] Fix for PokerStars NewVPP tables. --- pyfpdb/Tables.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pyfpdb/Tables.py b/pyfpdb/Tables.py index dcd145f4..d4b879b2 100755 --- a/pyfpdb/Tables.py +++ b/pyfpdb/Tables.py @@ -369,7 +369,7 @@ def clean_title(name): for pattern in [' \(6 max\)', ' \(heads up\)', ' \(deep\)', ' \(deep hu\)', ' \(deep 6\)', ' \(2\)', ' \(edu\)', ' \(edu, 6 max\)', ' \(6\)', - ' \(speed\)', + ' \(speed\)', 'special', 'newVPP', ' no all-in', ' fast', ',', ' 50BB min', '50bb min', '\s+$']: name = re.sub(pattern, '', name) name = name.rstrip() From 9d7c370449f62dfef40b6c9f7978bec827fb1c3e Mon Sep 17 00:00:00 2001 From: Ray Date: Fri, 3 Jul 2009 18:59:50 -0400 Subject: [PATCH 39/57] Get mucked cards from Stars flop games. __str__ method for Hand. --- pyfpdb/Hand.py | 56 ++++++++++++++++++++++++++++++++++---- pyfpdb/PokerStarsToFpdb.py | 12 ++++++-- 2 files changed, 60 insertions(+), 8 deletions(-) diff --git a/pyfpdb/Hand.py b/pyfpdb/Hand.py index a0c1537c..fa472b03 100644 --- a/pyfpdb/Hand.py +++ b/pyfpdb/Hand.py @@ -26,6 +26,7 @@ import operator import time,datetime from copy import deepcopy from Exceptions import * +import pprint import DerivedStats import Card @@ -74,6 +75,7 @@ class Hand: self.folded = set() self.dealt = set() # 'dealt to' line to be printed self.shown = set() # cards were shown + self.mucked = set() # cards were mucked at showdown # self.action = [] # Things to do with money @@ -83,8 +85,49 @@ class Hand: self.rake = None def __str__(self): + vars = ( ("BB", self.bb), + ("SB", self.sb), + ("BUTTONPOS", self.buttonpos), + ("HAND NO.", self.handid), + ("SITE", self.sitename), + ("TABLE NAME", self.tablename), + ("HERO", self.hero), + ("MAXSEATS", self.maxseats), + ("LASTBET", self.lastBet), + ("ACTION STREETS", self.actionStreets), + ("STREETS", self.streets), + ("ALL STREETS", self.allStreets), + ("COMMUNITY STREETS", self.communityStreets), + ("HOLE STREETS", self.holeStreets), + ("COUNTED SEATS", self.counted_seats), + ("DEALT", self.dealt), + ("SHOWN", self.shown), + ("MUCKED", self.mucked), + ("TOTAL POT", self.totalpot), + ("TOTAL COLLECTED", self.totalcollected), + ("RAKE", self.rake), + ("START TIME", self.starttime), + ) + + structs = ( ("PLAYERS", self.players), + ("STACKS", self.stacks), + ("POSTED", self.posted), + ("POT", self.pot), + ("SEATING", self.seating), + ("GAMETYPE", self.gametype), + ("ACTION", self.actions), + ("COLLECTEES", self.collectees), + ("BETS", self.bets), + ("BOARD", self.board), + ("DISCARDS", self.discards), + ("HOLECARDS", self.holecards), + ) str = '' - str = str + "Hand Object for %s at %s" % (self.handid, self.sitename) + for (name, var) in vars: + str = str + "\n%s = " % name + pprint.pformat(var) + + for (name, struct) in structs: + str = str + "\n%s =\n" % name + pprint.pformat(struct, 4) return str def insert(self, db): @@ -494,12 +537,13 @@ class HoldemOmahaHand(Hand): pass - def addHoleCards(self, cards, player, shown=False, dealt=False): + def addHoleCards(self, cards, player, shown, mucked, dealt=False): """\ Assigns observed holecards to a player. cards list of card bigrams e.g. ['2h','Jc'] player (string) name of player shown whether they were revealed at showdown +mucked whether they were mucked at showdown dealt whether they were seen in a 'dealt to' line """ logging.debug("addHoleCards %s %s" % (cards, player)) @@ -516,23 +560,25 @@ dealt whether they were seen in a 'dealt to' line self.dealt.add(player) if shown: self.shown.add(player) + if mucked: + self.mucked.add(player) if player in self.holecards['PREFLOP']: self.holecards['PREFLOP'][player].update(cardset) else: self.holecards['PREFLOP'][player] = cardset - def addShownCards(self, cards, player, holeandboard=None): + def addShownCards(self, cards, player, holeandboard=None, shown=True, mucked=False): """\ For when a player shows cards for any reason (for showdown or out of choice). Card ranks will be uppercased """ logging.debug("addShownCards %s hole=%s all=%s" % (player, cards, holeandboard)) if cards is not None: - self.addHoleCards(cards,player,shown=True) + self.addHoleCards(cards,player,shown, mucked) elif holeandboard is not None: holeandboard = set([self.card(c) for c in holeandboard]) board = set([c for s in self.board.values() for c in s]) - self.addHoleCards(holeandboard.difference(board),player,shown=True) + self.addHoleCards(holeandboard.difference(board),player,shown, mucked) def writeHTMLHand(self, fh=sys.__stdout__): diff --git a/pyfpdb/PokerStarsToFpdb.py b/pyfpdb/PokerStarsToFpdb.py index 5350713c..154d2b9d 100755 --- a/pyfpdb/PokerStarsToFpdb.py +++ b/pyfpdb/PokerStarsToFpdb.py @@ -66,7 +66,7 @@ follow : whether to tail -f the input""" self.re_ShowdownAction = re.compile(r"^%s: shows \[(?P.*)\]" % player_re, re.MULTILINE) self.re_CollectPot = re.compile(r"Seat (?P[0-9]+): %s (\(button\) |\(small blind\) |\(big blind\) )?(collected|showed \[.*\] and won) \(\$(?P[.\d]+)\)(, mucked| with.*|)" % player_re, re.MULTILINE) self.re_sitsOut = re.compile("^%s sits out" % player_re, re.MULTILINE) - self.re_ShownCards = re.compile("^Seat (?P[0-9]+): %s \(.*\) showed \[(?P.*)\].*" % player_re, re.MULTILINE) + self.re_ShownCards = re.compile("^Seat (?P[0-9]+): %s \(.*\) (?Pshowed|mucked) \[(?P.*)\].*" % player_re, re.MULTILINE) def readSupportedGames(self): @@ -222,7 +222,7 @@ follow : whether to tail -f the input""" # Also works with Omaha hands. cards = m.group('NEWCARDS') cards = set(cards.split(' ')) - hand.addHoleCards(cards, m.group('PNAME')) + hand.addHoleCards(cards, m.group('PNAME'), shown=False, mucked=False) def readDrawCards(self, hand, street): logging.debug("readDrawCards") @@ -314,9 +314,15 @@ follow : whether to tail -f the input""" def readShownCards(self,hand): for m in self.re_ShownCards.finditer(hand.handText): if m.group('CARDS') is not None: + print "SHOWED", m.group('SHOWED') cards = m.group('CARDS') cards = set(cards.split(' ')) - hand.addShownCards(cards=cards, player=m.group('PNAME')) + + (shown, mucked) = (False, False) + if m.group('SHOWED') == "showed": shown = True + elif m.group('SHOWED') == "mucked": mucked = True + + hand.addShownCards(cards=cards, player=m.group('PNAME'), shown=shown, mucked=mucked) if __name__ == "__main__": parser = OptionParser() From 0636a290f7a24eeebee311f3687488cc65540de8 Mon Sep 17 00:00:00 2001 From: Ray Date: Fri, 3 Jul 2009 19:28:32 -0400 Subject: [PATCH 40/57] Get mixed game info and put it in gameType structure. --- pyfpdb/PokerStarsToFpdb.py | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/pyfpdb/PokerStarsToFpdb.py b/pyfpdb/PokerStarsToFpdb.py index 154d2b9d..8719a8c0 100755 --- a/pyfpdb/PokerStarsToFpdb.py +++ b/pyfpdb/PokerStarsToFpdb.py @@ -26,7 +26,7 @@ from HandHistoryConverter import * class PokerStars(HandHistoryConverter): # Static regexes - re_GameInfo = re.compile("PokerStars Game #(?P[0-9]+):\s+(HORSE)? \(?(?PHold\'em|Razz|7 Card Stud|7 Card Stud Hi/Lo|Omaha|Omaha Hi/Lo|Badugi) (?PNo Limit|Limit|Pot Limit),? \(?(?P\$|)?(?P[.0-9]+)/\$?(?P[.0-9]+)\) - (?P.*$)", re.MULTILINE) + re_GameInfo = re.compile("PokerStars Game #(?P[0-9]+):\s+(?PHORSE|8\-Game|HOSE)? \(?(?PHold\'em|Razz|7 Card Stud|7 Card Stud Hi/Lo|Omaha|Omaha Hi/Lo|Badugi) (?PNo Limit|Limit|Pot Limit),? \(?(?P\$|)?(?P[.0-9]+)/\$?(?P[.0-9]+)\) - (?P.*$)", re.MULTILINE) re_SplitHands = re.compile('\n\n+') re_TailSplitHands = re.compile('(\n\n\n+)') re_HandInfo = re.compile("^Table \'(?P[- a-zA-Z]+)\'(?P.+?$)?", re.MULTILINE) @@ -89,6 +89,7 @@ follow : whether to tail -f the input""" # translations from captured groups to our info strings limits = { 'No Limit':'nl', 'Pot Limit':'pl', 'Limit':'fl' } + mixes = { 'HORSE': 'horse', '8-Game': '8game', 'HOSE': 'hose'} games = { # base, category "Hold'em" : ('hold','holdem'), 'Omaha' : ('hold','omahahi'), @@ -109,6 +110,8 @@ follow : whether to tail -f the input""" info['bb'] = mg['BB'] if 'CURRENCY' in mg: info['currency'] = currencies[mg['CURRENCY']] + if 'MIXED' in mg: + info['mixedType'] = mixes[mg['MIXED']] # NB: SB, BB must be interpreted as blinds or bets depending on limit type. return info From 23a4ca34c8a6ecd54b9fba5617856fc0e0c90a1c Mon Sep 17 00:00:00 2001 From: Ray Date: Fri, 3 Jul 2009 20:41:08 -0400 Subject: [PATCH 41/57] Fix bug preventing some shown cards from being read. --- pyfpdb/PokerStarsToFpdb.py | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/pyfpdb/PokerStarsToFpdb.py b/pyfpdb/PokerStarsToFpdb.py index 8719a8c0..75609001 100755 --- a/pyfpdb/PokerStarsToFpdb.py +++ b/pyfpdb/PokerStarsToFpdb.py @@ -66,8 +66,7 @@ follow : whether to tail -f the input""" self.re_ShowdownAction = re.compile(r"^%s: shows \[(?P.*)\]" % player_re, re.MULTILINE) self.re_CollectPot = re.compile(r"Seat (?P[0-9]+): %s (\(button\) |\(small blind\) |\(big blind\) )?(collected|showed \[.*\] and won) \(\$(?P[.\d]+)\)(, mucked| with.*|)" % player_re, re.MULTILINE) self.re_sitsOut = re.compile("^%s sits out" % player_re, re.MULTILINE) - self.re_ShownCards = re.compile("^Seat (?P[0-9]+): %s \(.*\) (?Pshowed|mucked) \[(?P.*)\].*" % player_re, re.MULTILINE) - + self.re_ShownCards = re.compile("^Seat (?P[0-9]+): %s (\(.*\) )?(?Pshowed|mucked) \[(?P.*)\].*" % player_re, re.MULTILINE) def readSupportedGames(self): return [["ring", "hold", "nl"], @@ -317,7 +316,6 @@ follow : whether to tail -f the input""" def readShownCards(self,hand): for m in self.re_ShownCards.finditer(hand.handText): if m.group('CARDS') is not None: - print "SHOWED", m.group('SHOWED') cards = m.group('CARDS') cards = set(cards.split(' ')) From f323447313ddcc3efe8bdafbe775e0914787647c Mon Sep 17 00:00:00 2001 From: Ray Date: Sat, 4 Jul 2009 14:35:20 -0400 Subject: [PATCH 42/57] Get shown and mucked cards for stud games. --- pyfpdb/Hand.py | 61 ++++++++++++++++++++++++++++---------- pyfpdb/PokerStarsToFpdb.py | 2 +- 2 files changed, 47 insertions(+), 16 deletions(-) diff --git a/pyfpdb/Hand.py b/pyfpdb/Hand.py index fa472b03..237b609a 100644 --- a/pyfpdb/Hand.py +++ b/pyfpdb/Hand.py @@ -410,6 +410,20 @@ Add a raise on [street] by [player] to [amountTo] self.collectees[player] += Decimal(pot) + def addShownCards(self, cards, player, holeandboard=None, shown=True, mucked=False): + """\ +For when a player shows cards for any reason (for showdown or out of choice). +Card ranks will be uppercased +""" + logging.debug("addShownCards %s hole=%s all=%s" % (player, cards, holeandboard)) + if cards is not None: + self.addHoleCards(cards,player,shown, mucked) + elif holeandboard is not None: + holeandboard = set([self.card(c) for c in holeandboard]) + board = set([c for s in self.board.values() for c in s]) + self.addHoleCards(holeandboard.difference(board),player,shown, mucked) + + def totalPot(self): """If all bets and blinds have been added, totals up the total pot size""" @@ -567,20 +581,6 @@ dealt whether they were seen in a 'dealt to' line else: self.holecards['PREFLOP'][player] = cardset - def addShownCards(self, cards, player, holeandboard=None, shown=True, mucked=False): - """\ -For when a player shows cards for any reason (for showdown or out of choice). -Card ranks will be uppercased -""" - logging.debug("addShownCards %s hole=%s all=%s" % (player, cards, holeandboard)) - if cards is not None: - self.addHoleCards(cards,player,shown, mucked) - elif holeandboard is not None: - holeandboard = set([self.card(c) for c in holeandboard]) - board = set([c for s in self.board.values() for c in s]) - self.addHoleCards(holeandboard.difference(board),player,shown, mucked) - - def writeHTMLHand(self, fh=sys.__stdout__): from nevow import tags as T from nevow import flat @@ -991,7 +991,7 @@ class StudHand(Hand): hhc.readStudPlayerCards(self, street) hhc.readAction(self, street) hhc.readCollectPot(self) - #hhc.readShownCards(self) # not done yet + hhc.readShownCards(self) # not done yet self.totalPot() # finalise it (total the pot) hhc.getRake(self) elif builtFrom == "DB": @@ -1014,6 +1014,36 @@ closed likewise, but known only to player except FpdbParseError, e: print "[ERROR] Tried to add holecards for unknown player: %s" % (player,) + def addHoleCards(self, cards, player, shown, mucked, dealt=False): + """\ +Assigns observed holecards to a player. +cards list of card bigrams e.g. ['2h','Jc'] +player (string) name of player +shown whether they were revealed at showdown +mucked whether they were mucked at showdown +dealt whether they were seen in a 'dealt to' line +""" +# +# For stud games we just need to do the routine setting of shown/mucked/etc +# and then update the cards 'THIRD' and 'SEVENTH' + logging.debug("addHoleCards %s %s" % (cards, player)) + try: + self.checkPlayerExists(player) + except FpdbParseError, e: + print "[ERROR] Tried to add holecards for unknown player: %s" % (player,) + return + + if dealt: + self.dealt.add(player) + if shown: + self.shown.add(player) + if mucked: + self.mucked.add(player) + if len(cards) > 2: + self.holecards['THIRD'][player] = (cards[0:3], None) + if len(cards) > 6: + self.holecards['SEVENTH'][player] = (cards[6], None) + # TODO: def addComplete(self, player, amount): def addComplete(self, street, player, amountTo): # assert street=='THIRD' @@ -1045,6 +1075,7 @@ Add a complete on [street] by [player] to [amountTo] self.actions['THIRD'].append(act) self.lastBet['THIRD'] = Decimal(bringin) self.pot.addMoney(player, Decimal(bringin)) + def writeHand(self, fh=sys.__stdout__): # PokerStars format. diff --git a/pyfpdb/PokerStarsToFpdb.py b/pyfpdb/PokerStarsToFpdb.py index 75609001..2181b7cc 100755 --- a/pyfpdb/PokerStarsToFpdb.py +++ b/pyfpdb/PokerStarsToFpdb.py @@ -317,7 +317,7 @@ follow : whether to tail -f the input""" for m in self.re_ShownCards.finditer(hand.handText): if m.group('CARDS') is not None: cards = m.group('CARDS') - cards = set(cards.split(' ')) + cards = cards.split(' ') # needs to be a list, not a set--stud needs the order (shown, mucked) = (False, False) if m.group('SHOWED') == "showed": shown = True From a35b1a8b3c48924fc1141a4f39a9bed26b1b1caf Mon Sep 17 00:00:00 2001 From: Ray Date: Sat, 4 Jul 2009 15:19:46 -0400 Subject: [PATCH 43/57] Make WriteHand for stud report mucked hand. --- pyfpdb/Hand.py | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) diff --git a/pyfpdb/Hand.py b/pyfpdb/Hand.py index 237b609a..bf2b1ab2 100644 --- a/pyfpdb/Hand.py +++ b/pyfpdb/Hand.py @@ -1042,7 +1042,7 @@ dealt whether they were seen in a 'dealt to' line if len(cards) > 2: self.holecards['THIRD'][player] = (cards[0:3], None) if len(cards) > 6: - self.holecards['SEVENTH'][player] = (cards[6], None) + self.holecards['SEVENTH'][player] = ([cards[6]], None) # TODO: def addComplete(self, player, amount): def addComplete(self, street, player, amountTo): @@ -1212,11 +1212,13 @@ Add a complete on [street] by [player] to [amountTo] seatnum = player[0] name = player[1] if name in self.collectees and name in self.shown: - print >>fh, _("Seat %d: %s showed [%s] and won ($%s)" % (seatnum, name, " ".join(self.holecards[name]), self.collectees[name])) + print >>fh, _("Seat %d: %s showed [%s] and won ($%s)" % (seatnum, name, self.join_holecards(name), self.collectees[name])) elif name in self.collectees: print >>fh, _("Seat %d: %s collected ($%s)" % (seatnum, name, self.collectees[name])) elif name in self.shown: - print >>fh, _("Seat %d: %s showed [%s]" % (seatnum, name, " ".join(self.holecards[name]))) + print >>fh, _("Seat %d: %s showed [%s]" % (seatnum, name, self.join_holecards(name))) + elif name in self.mucked: + print >>fh, _("Seat %d: %s mucked [%s]" % (seatnum, name, self.join_holecards(name))) elif name in self.folded: print >>fh, _("Seat %d: %s folded" % (seatnum, name)) else: @@ -1225,6 +1227,12 @@ Add a complete on [street] by [player] to [amountTo] print >>fh, "\n\n" + def join_holecards(self, player): + holecards = [] + for street in self.holeStreets: + if self.holecards[street].has_key(player): + holecards = holecards + self.holecards[street][player][0] + return " ".join(holecards) class Pot(object): From c4cc6bd1aa066a91fec77c089327a5c6c8ec5140 Mon Sep 17 00:00:00 2001 From: Ray Date: Sat, 4 Jul 2009 15:28:20 -0400 Subject: [PATCH 44/57] Make WriteHand for holdem report mucked cards. --- pyfpdb/Hand.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/pyfpdb/Hand.py b/pyfpdb/Hand.py index bf2b1ab2..2a5c671d 100644 --- a/pyfpdb/Hand.py +++ b/pyfpdb/Hand.py @@ -772,6 +772,8 @@ dealt whether they were seen in a 'dealt to' line else: if name in self.shown: print >>fh, ("Seat %d: %s showed [%s] and lost with..." % (seatnum, name, " ".join(self.holecards['PREFLOP'][name]))) + elif name in self.mucked: + print >>fh, ("Seat %d: %s mucked [%s] " % (seatnum, name, " ".join(self.holecards['PREFLOP'][name]))) else: print >>fh, ("Seat %d: %s mucked" % (seatnum, name)) From 8f2350f86198fd8da88c22a9401855f1f4c18844 Mon Sep 17 00:00:00 2001 From: Ray Date: Sun, 5 Jul 2009 11:47:18 -0400 Subject: [PATCH 45/57] Set dealt flag when reading holdem hero cards. --- pyfpdb/PokerStarsToFpdb.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pyfpdb/PokerStarsToFpdb.py b/pyfpdb/PokerStarsToFpdb.py index 2181b7cc..6cb81081 100755 --- a/pyfpdb/PokerStarsToFpdb.py +++ b/pyfpdb/PokerStarsToFpdb.py @@ -224,7 +224,7 @@ follow : whether to tail -f the input""" # Also works with Omaha hands. cards = m.group('NEWCARDS') cards = set(cards.split(' ')) - hand.addHoleCards(cards, m.group('PNAME'), shown=False, mucked=False) + hand.addHoleCards(cards, m.group('PNAME'), shown=False, mucked=False, dealt=True) def readDrawCards(self, hand, street): logging.debug("readDrawCards") From 799aa41c1ed8c2571ffef3cf92caf7d1c90c3c02 Mon Sep 17 00:00:00 2001 From: Ray Date: Sun, 5 Jul 2009 23:44:53 -0400 Subject: [PATCH 46/57] Correct handling of open/closed stud hole cards. --- pyfpdb/Hand.py | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/pyfpdb/Hand.py b/pyfpdb/Hand.py index 2a5c671d..db1d1197 100644 --- a/pyfpdb/Hand.py +++ b/pyfpdb/Hand.py @@ -1041,10 +1041,16 @@ dealt whether they were seen in a 'dealt to' line self.shown.add(player) if mucked: self.mucked.add(player) - if len(cards) > 2: - self.holecards['THIRD'][player] = (cards[0:3], None) - if len(cards) > 6: - self.holecards['SEVENTH'][player] = ([cards[6]], None) + if player == self.hero: + if len(cards) > 2: + self.holecards['THIRD'][player] = ([cards[0:3]], []) + if len(cards) > 6: + self.holecards['SEVENTH'][player] = ([cards[6]], []) + else: + if len(cards) > 2: + self.holecards['THIRD'][player] = ([cards[0]], cards[1:3]) + if len(cards) > 6: + self.holecards['SEVENTH'][player] = ([], [cards[6]]) # TODO: def addComplete(self, player, amount): def addComplete(self, street, player, amountTo): From 4ae8b123ce1561a0bba727a9aec39ac3ec15e396 Mon Sep 17 00:00:00 2001 From: Ray Date: Mon, 6 Jul 2009 12:00:16 -0400 Subject: [PATCH 47/57] Fix game type for non-Mixed games. --- pyfpdb/PokerStarsToFpdb.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pyfpdb/PokerStarsToFpdb.py b/pyfpdb/PokerStarsToFpdb.py index 6cb81081..45306281 100755 --- a/pyfpdb/PokerStarsToFpdb.py +++ b/pyfpdb/PokerStarsToFpdb.py @@ -109,7 +109,7 @@ follow : whether to tail -f the input""" info['bb'] = mg['BB'] if 'CURRENCY' in mg: info['currency'] = currencies[mg['CURRENCY']] - if 'MIXED' in mg: + if 'MIXED' in mg and mg['MIXED'] != None: info['mixedType'] = mixes[mg['MIXED']] # NB: SB, BB must be interpreted as blinds or bets depending on limit type. From 21d227667966b844fcaff561133eebc3075f24d3 Mon Sep 17 00:00:00 2001 From: Ray Date: Mon, 6 Jul 2009 12:01:39 -0400 Subject: [PATCH 48/57] Get rid of intermediate hand obj print. --- pyfpdb/HandHistoryConverter.py | 1 + 1 file changed, 1 insertion(+) diff --git a/pyfpdb/HandHistoryConverter.py b/pyfpdb/HandHistoryConverter.py index f5c4c2a5..fc6567f0 100644 --- a/pyfpdb/HandHistoryConverter.py +++ b/pyfpdb/HandHistoryConverter.py @@ -238,6 +238,7 @@ which it expects to find at self.re_TailSplitHands -- see for e.g. Everleaf.py. logging.info("Unsupported game type: %s" % gametype) if hand: +# print hand hand.writeHand(self.out_fh) else: logging.info("Unsupported game type: %s" % gametype) From 56bd7b37baedba73f5c45ee611150c2be86ef116 Mon Sep 17 00:00:00 2001 From: Ray Date: Tue, 7 Jul 2009 13:48:43 -0400 Subject: [PATCH 49/57] Parse Stars tournaments for flop and stud games. Tournaments are not correctly written in writehand(). Nor are stud games. --- pyfpdb/Hand.py | 5 +++++ pyfpdb/PokerStarsToFpdb.py | 39 +++++++++++++++++++++++++++++++++----- 2 files changed, 39 insertions(+), 5 deletions(-) diff --git a/pyfpdb/Hand.py b/pyfpdb/Hand.py index db1d1197..d51424e6 100644 --- a/pyfpdb/Hand.py +++ b/pyfpdb/Hand.py @@ -1088,6 +1088,11 @@ Add a complete on [street] by [player] to [amountTo] def writeHand(self, fh=sys.__stdout__): # PokerStars format. # print >>fh, _("%s Game #%s: %s ($%s/$%s) - %s" %("PokerStars", self.handid, self.getGameTypeAsString(), self.sb, self.bb, time.strftime('%Y/%m/%d - %H:%M:%S (ET)', self.starttime))) + +# TODO: +# Hole cards are not currently correctly written. Currently the down cards for non-heros +# are shown in the "dealt to" lines. They should be hidden in those lines. I tried to fix +# but mind got boggled, will try again. print >>fh, _("%s Game #%s: %s ($%s/$%s) - %s" %("PokerStars", self.handid, self.getGameTypeAsString(), self.sb, self.bb, datetime.datetime.strftime(self.starttime,'%Y/%m/%d - %H:%M:%S ET'))) print >>fh, _("Table '%s' %d-max Seat #%s is the button" %(self.tablename, self.maxseats, self.buttonpos)) diff --git a/pyfpdb/PokerStarsToFpdb.py b/pyfpdb/PokerStarsToFpdb.py index 45306281..3c2c959c 100755 --- a/pyfpdb/PokerStarsToFpdb.py +++ b/pyfpdb/PokerStarsToFpdb.py @@ -26,7 +26,18 @@ from HandHistoryConverter import * class PokerStars(HandHistoryConverter): # Static regexes - re_GameInfo = re.compile("PokerStars Game #(?P[0-9]+):\s+(?PHORSE|8\-Game|HOSE)? \(?(?PHold\'em|Razz|7 Card Stud|7 Card Stud Hi/Lo|Omaha|Omaha Hi/Lo|Badugi) (?PNo Limit|Limit|Pot Limit),? \(?(?P\$|)?(?P[.0-9]+)/\$?(?P[.0-9]+)\) - (?P.*$)", re.MULTILINE) +# re_GameInfo = re.compile("PokerStars Game #(?P[0-9]+):\s+(?PHORSE|8\-Game|HOSE)? \(?(?PHold\'em|Razz|7 Card Stud|7 Card Stud Hi/Lo|Omaha|Omaha Hi/Lo|Badugi) (?PNo Limit|Limit|Pot Limit),? \(?(?P\$|)?(?P[.0-9]+)/\$?(?P[.0-9]+)\) - (?P.*$)", re.MULTILINE) + re_GameInfo = re.compile("""PokerStars\sGame\s\#(?P[0-9]+):\s+ + (Tournament\s\#(?P\d+),\s(?P[\$\+\d\.]+)\s)? + (?PHORSE|8\-Game|HOSE)?\s?\(? + (?PHold\'em|Razz|7\sCard Stud|7\sCard\sStud\sHi/Lo|Omaha|Omaha\sHi/Lo|Badugi)\s + (?PNo\sLimit|Limit|Pot\sLimit),?\s + (-\sLevel\s(?P[IVXLC]+)\s)?\(? + (?P\$|)? + (?P[.0-9]+)/\$? + (?P[.0-9]+)\)\s-\s + (?P.*$)""", + re.MULTILINE|re.VERBOSE) re_SplitHands = re.compile('\n\n+') re_TailSplitHands = re.compile('(\n\n\n+)') re_HandInfo = re.compile("^Table \'(?P
[- a-zA-Z]+)\'(?P.+?$)?", re.MULTILINE) @@ -62,7 +73,8 @@ follow : whether to tail -f the input""" self.re_BringIn = re.compile(r"^%s: brings[- ]in( low|) for \$?(?P[.0-9]+)" % player_re, re.MULTILINE) self.re_PostBoth = re.compile(r"^%s: posts small \& big blinds \[\$? (?P[.0-9]+)" % player_re, re.MULTILINE) self.re_HeroCards = re.compile(r"^Dealt to %s(?: \[(?P.+?)\])?( \[(?P.+?)\])" % player_re, re.MULTILINE) - self.re_Action = re.compile(r"^%s:(?P bets| checks| raises| calls| folds| discards| stands pat)( \$(?P[.\d]+))?( to \$(?P[.\d]+))?( (?P\d) cards?( \[(?P.+?)\])?)?" % player_re, re.MULTILINE) +# self.re_Action = re.compile(r"^%s:(?P bets| checks| raises| calls| folds| discards| stands pat)( \$(?P[.\d]+))?( to \$(?P[.\d]+))?( (?P\d) cards?( \[(?P.+?)\])?)?" % player_re, re.MULTILINE) + self.re_Action = re.compile(r"^%s:(?P bets| checks| raises| calls| folds| discards| stands pat)( \$?(?P[.\d]+))?( to \$?(?P[.\d]+))?( (?P\d) cards?( \[(?P.+?)\])?)?" % player_re, re.MULTILINE) self.re_ShowdownAction = re.compile(r"^%s: shows \[(?P.*)\]" % player_re, re.MULTILINE) self.re_CollectPot = re.compile(r"Seat (?P[0-9]+): %s (\(button\) |\(small blind\) |\(big blind\) )?(collected|showed \[.*\] and won) \(\$(?P[.\d]+)\)(, mucked| with.*|)" % player_re, re.MULTILINE) self.re_sitsOut = re.compile("^%s sits out" % player_re, re.MULTILINE) @@ -72,20 +84,26 @@ follow : whether to tail -f the input""" return [["ring", "hold", "nl"], ["ring", "hold", "pl"], ["ring", "hold", "fl"], + ["ring", "stud", "fl"], #["ring", "draw", "fl"], - ["ring", "omaha", "pl"] + + ["tour", "hold", "nl"], + ["tour", "hold", "pl"], + ["tour", "hold", "fl"], + + ["tour", "stud", "fl"], ] def determineGameType(self, handText): - info = {'type':'ring'} + info = {} m = self.re_GameInfo.search(handText) if not m: return None mg = m.groupdict() - + print "mg =", mg # translations from captured groups to our info strings limits = { 'No Limit':'nl', 'Pot Limit':'pl', 'Limit':'fl' } mixes = { 'HORSE': 'horse', '8-Game': '8game', 'HOSE': 'hose'} @@ -99,6 +117,10 @@ follow : whether to tail -f the input""" 'Badugi' : ('draw','badugi') } currencies = { u'€':'EUR', '$':'USD', '':'T$' } +# I don't think this is doing what we think. mg will always have all +# the expected keys, but the ones that didn't match in the regex will +# have a value of None. It is OK if it throws an exception when it +# runs across an unknown game or limit or whatever. if 'LIMIT' in mg: info['limitType'] = limits[mg['LIMIT']] if 'GAME' in mg: @@ -111,6 +133,13 @@ follow : whether to tail -f the input""" info['currency'] = currencies[mg['CURRENCY']] if 'MIXED' in mg and mg['MIXED'] != None: info['mixedType'] = mixes[mg['MIXED']] + info['tourNo'] = mg['TOURNO'] + if info['tourNo'] == None: + info['type'] = 'ring' + else: + info['type'] = 'tour' + info['buyin'] = mg['BUYIN'] + info['level'] = mg['LEVEL'] # NB: SB, BB must be interpreted as blinds or bets depending on limit type. return info From 4e952de82529b3e6ff8595998fbcee7e8e2c2672 Mon Sep 17 00:00:00 2001 From: Ray Date: Tue, 7 Jul 2009 14:15:36 -0400 Subject: [PATCH 50/57] Remove intermediate print. --- pyfpdb/PokerStarsToFpdb.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pyfpdb/PokerStarsToFpdb.py b/pyfpdb/PokerStarsToFpdb.py index 3c2c959c..580d5481 100755 --- a/pyfpdb/PokerStarsToFpdb.py +++ b/pyfpdb/PokerStarsToFpdb.py @@ -103,7 +103,7 @@ follow : whether to tail -f the input""" return None mg = m.groupdict() - print "mg =", mg +# print "mg =", mg # translations from captured groups to our info strings limits = { 'No Limit':'nl', 'Pot Limit':'pl', 'Limit':'fl' } mixes = { 'HORSE': 'horse', '8-Game': '8game', 'HOSE': 'hose'} From d8820ae1f7a5dbf5b963144b42d1dcfd60a20e8a Mon Sep 17 00:00:00 2001 From: Ray Date: Sat, 11 Jul 2009 13:44:32 -0400 Subject: [PATCH 51/57] Allow parsing of tournaments, draw and play money. Sorry about the massive commit. There are still numerous bugs parsing non-holdem hands and writehand() is broken for all but holdem cash games. --- pyfpdb/Hand.py | 76 ++++++++++++++++++++++++++--------- pyfpdb/PokerStarsToFpdb.py | 81 ++++++++++++++++++++++++-------------- 2 files changed, 108 insertions(+), 49 deletions(-) diff --git a/pyfpdb/Hand.py b/pyfpdb/Hand.py index d51424e6..cc1dfd5a 100644 --- a/pyfpdb/Hand.py +++ b/pyfpdb/Hand.py @@ -45,6 +45,9 @@ class Hand: self.maxseats = 10 self.counted_seats = 0 self.buttonpos = 0 + self.tourNo = None + self.buyin = None + self.level = None self.seating = [] self.players = [] self.posted = [] @@ -56,17 +59,19 @@ class Hand: self.actions = {} # [['mct','bets','$10'],['mika','folds'],['carlg','raises','$20']] self.board = {} # dict from street names to community cards self.holecards = {} + self.discards = {} for street in self.allStreets: self.streets[street] = "" # portions of the handText, filled by markStreets() + self.actions[street] = [] + for street in self.actionStreets: self.bets[street] = {} self.lastBet[street] = 0 - self.actions[street] = [] self.board[street] = [] + for street in self.holeStreets: self.holecards[street] = {} # dict from player names to holecards - + self.discards[street] = {} # dict from player names to dicts by street ... of tuples ... of discarded holecards # Collections indexed by player names # self.holecards = {} # dict from player names to dicts by street ... of tuples ... of holecards - self.discards = {} # dict from player names to dicts by street ... of tuples ... of discarded holecards self.stacks = {} self.collected = [] #list of ? self.collectees = {} # dict from player names to amounts collected (?) @@ -93,6 +98,9 @@ class Hand: ("TABLE NAME", self.tablename), ("HERO", self.hero), ("MAXSEATS", self.maxseats), + ("TOURNAMENT NO", self.tourNo), + ("BUYIN", self.buyin), + ("LEVEL", self.level), ("LASTBET", self.lastBet), ("ACTION STREETS", self.actionStreets), ("STREETS", self.streets), @@ -221,10 +229,10 @@ If a player has None chips he won't be added.""" self.players.append([seat, name, chips]) self.stacks[name] = Decimal(chips) self.pot.addPlayer(name) - for street in self.allStreets: + for street in self.actionStreets: self.bets[street][name] = [] #self.holecards[name] = {} # dict from street names. - self.discards[name] = {} # dict from street names. + #self.discards[name] = {} # dict from street names. def addStreets(self, match): @@ -784,8 +792,10 @@ class DrawHand(Hand): if gametype['base'] != 'draw': pass # or indeed don't pass and complain instead self.streetList = ['BLINDSANTES', 'DEAL', 'DRAWONE', 'DRAWTWO', 'DRAWTHREE'] + self.allStreets = ['BLINDSANTES', 'DEAL', 'DRAWONE', 'DRAWTWO', 'DRAWTHREE'] self.holeStreets = ['DEAL', 'DRAWONE', 'DRAWTWO', 'DRAWTHREE'] self.actionStreets = ['PREDEAL', 'DEAL', 'DRAWONE', 'DRAWTWO', 'DRAWTHREE'] + self.communityStreets = [] Hand.__init__(self, sitename, gametype, handText) self.sb = gametype['sb'] self.bb = gametype['bb'] @@ -849,18 +859,19 @@ player (string) name of player self.checkPlayerExists(player) # if shown and len(cardset) > 0: # self.shown.add(player) - self.holecards[player][street] = (newcards,oldcards) + self.holecards[street][player] = (newcards,oldcards) except FpdbParseError, e: print "[ERROR] Tried to add holecards for unknown player: %s" % (player,) def discardDrawHoleCards(self, cards, player, street): logging.debug("discardDrawHoleCards '%s' '%s' '%s'" % (cards, player, street)) - self.discards[player][street] = set([cards]) + self.discards[street][player] = set([cards]) def addDiscard(self, street, player, num, cards): self.checkPlayerExists(player) + print "street, player, num, cards =", street, player, num, cards if cards: act = (player, 'discards', num, cards) self.discardDrawHoleCards(cards, player, street) @@ -869,12 +880,12 @@ player (string) name of player self.actions[street].append(act) - def addShownCards(self, cards, player, holeandboard=None): - """\ -For when a player shows cards for any reason (for showdown or out of choice). -Card ranks will be uppercased -""" - logging.debug("addShownCards %s hole=%s all=%s" % (player, cards, holeandboard)) +# def addShownCards(self, cards, player, holeandboard=None, shown=False, mucked=False): +# """\ +#For when a player shows cards for any reason (for showdown or out of choice). +#Card ranks will be uppercased +#""" +# logging.debug("addShownCards %s hole=%s all=%s" % (player, cards, holeandboard)) # if cards is not None: # self.shown.add(player) # self.addHoleCards(cards,player) @@ -884,6 +895,33 @@ Card ranks will be uppercased # self.addHoleCards(holeandboard.difference(board),player,shown=True) + def addHoleCards(self, cards, player, shown, mucked, dealt=False): + """\ +Assigns observed holecards to a player. +cards list of card bigrams e.g. ['2h','Jc'] +player (string) name of player +shown whether they were revealed at showdown +mucked whether they were mucked at showdown +dealt whether they were seen in a 'dealt to' line +""" +# I think this only gets called for shown cards. + logging.debug("addHoleCards %s %s" % (cards, player)) + try: + self.checkPlayerExists(player) + except FpdbParseError, e: + print "[ERROR] Tried to add holecards for unknown player: %s" % (player,) + return + + if dealt: + self.dealt.add(player) + if shown: + self.shown.add(player) + if mucked: + self.mucked.add(player) + if player != self.hero: #skip hero, we know his cards + print "player, cards =", player, cards + self.holecards[self.holeStreets[-1]][player] = (cards, set([])) + def writeHand(self, fh=sys.__stdout__): # PokerStars format. print >>fh, _("%s Game #%s: %s ($%s/$%s) - %s" %("PokerStars", self.handid, self.getGameTypeAsString(), self.sb, self.bb, time.strftime('%Y/%m/%d %H:%M:%S ET', self.starttime))) @@ -913,8 +951,8 @@ Card ranks will be uppercased for act in self.actions['DRAWONE']: print >>fh, self.actionString(act) if act[0] == self.hero and act[1] == 'discards': - (nc,oc) = self.holecards[act[0]]['DRAWONE'] - dc = self.discards[act[0]]['DRAWONE'] + (nc,oc) = self.holecards['DRAWONE'][act[0]] + dc = self.discards['DRAWONE'][act[0]] kc = oc - dc print >>fh, _("Dealt to %s [%s] [%s]" % (act[0], " ".join(kc), " ".join(nc))) @@ -923,8 +961,8 @@ Card ranks will be uppercased for act in self.actions['DRAWTWO']: print >>fh, self.actionString(act) if act[0] == self.hero and act[1] == 'discards': - (nc,oc) = self.holecards[act[0]]['DRAWTWO'] - dc = self.discards[act[0]]['DRAWTWO'] + (nc,oc) = self.holecards['DRAWTWO'][act[0]] + dc = self.discards['DRAWTWO'][act[0]] kc = oc - dc print >>fh, _("Dealt to %s [%s] [%s]" % (act[0], " ".join(kc), " ".join(nc))) @@ -933,8 +971,8 @@ Card ranks will be uppercased for act in self.actions['DRAWTHREE']: print >>fh, self.actionString(act) if act[0] == self.hero and act[1] == 'discards': - (nc,oc) = self.holecards[act[0]]['DRAWTHREE'] - dc = self.discards[act[0]]['DRAWTHREE'] + (nc,oc) = self.holecards['DRAWTHREE'][act[0]] + dc = self.discards['DRAWTHREE'][act[0]] kc = oc - dc print >>fh, _("Dealt to %s [%s] [%s]" % (act[0], " ".join(kc), " ".join(nc))) diff --git a/pyfpdb/PokerStarsToFpdb.py b/pyfpdb/PokerStarsToFpdb.py index 580d5481..80c16d07 100755 --- a/pyfpdb/PokerStarsToFpdb.py +++ b/pyfpdb/PokerStarsToFpdb.py @@ -30,7 +30,7 @@ class PokerStars(HandHistoryConverter): re_GameInfo = re.compile("""PokerStars\sGame\s\#(?P[0-9]+):\s+ (Tournament\s\#(?P\d+),\s(?P[\$\+\d\.]+)\s)? (?PHORSE|8\-Game|HOSE)?\s?\(? - (?PHold\'em|Razz|7\sCard Stud|7\sCard\sStud\sHi/Lo|Omaha|Omaha\sHi/Lo|Badugi)\s + (?PHold\'em|Razz|7\sCard Stud|7\sCard\sStud\sHi/Lo|Omaha|Omaha\sHi/Lo|Badugi|Triple\sDraw\s2\-7\sLowball)\s (?PNo\sLimit|Limit|Pot\sLimit),?\s (-\sLevel\s(?P[IVXLC]+)\s)?\(? (?P\$|)? @@ -40,7 +40,11 @@ class PokerStars(HandHistoryConverter): re.MULTILINE|re.VERBOSE) re_SplitHands = re.compile('\n\n+') re_TailSplitHands = re.compile('(\n\n\n+)') - re_HandInfo = re.compile("^Table \'(?P
[- a-zA-Z]+)\'(?P.+?$)?", re.MULTILINE) + re_HandInfo = re.compile("""^Table\s\'(?P
[-\ a-zA-Z\d]+)\'\s + ((?P\d+)-max\s)? + (?P\(Play\sMoney\)\s)? + (Seat\s\#(?P
[ a-zA-Z]+) - \$?(?P[.0-9]+)/\$?(?P[.0-9]+) - (?P.*) - (?P
[0-9]+):(?P[0-9]+) ET - (?P[0-9]+)/(?P[0-9]+)/(?P[0-9]+)Table (?P
[ a-zA-Z]+)\nSeat (?P