From bbb21b4b4d1580cd9565e9d2adf7569cbb57b541 Mon Sep 17 00:00:00 2001 From: Eratosthenes Date: Thu, 26 Aug 2010 22:52:16 -0400 Subject: [PATCH 1/5] FulltiltToFpdb: Throw exception when HandInfo reg ex doesn't match. --- pyfpdb/FulltiltToFpdb.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/pyfpdb/FulltiltToFpdb.py b/pyfpdb/FulltiltToFpdb.py index 4b5fbcfd..b235ed4d 100755 --- a/pyfpdb/FulltiltToFpdb.py +++ b/pyfpdb/FulltiltToFpdb.py @@ -208,8 +208,7 @@ class Fulltilt(HandHistoryConverter): if m is None: logging.info("Didn't match re_HandInfo") logging.info(hand.handText) - # Should this throw an exception? - CG - return None + raise FpdbParseError("No match in readHandInfo.") hand.handid = m.group('HID') hand.tablename = m.group('TABLE') From f5db60f23baf21e83da1c3df455a2452f68c75d3 Mon Sep 17 00:00:00 2001 From: Eratosthenes Date: Thu, 26 Aug 2010 22:47:30 -0400 Subject: [PATCH 2/5] Get rid of obsolete import of obsolete Tables.py. --- pyfpdb/Hud.py | 24 ------------------------ 1 file changed, 24 deletions(-) diff --git a/pyfpdb/Hud.py b/pyfpdb/Hud.py index c394108c..99b65c00 100644 --- a/pyfpdb/Hud.py +++ b/pyfpdb/Hud.py @@ -55,7 +55,6 @@ else: def _(string): return string # FreePokerTools modules -import Tables # needed for testing only import Configuration import Stats import Mucked @@ -941,26 +940,3 @@ class Popup_window: # window.present() -if __name__== "__main__": - main_window = gtk.Window() - main_window.connect("destroy", destroy) - label = gtk.Label(_('Fake main window, blah blah, blah\nblah, blah')) - main_window.add(label) - main_window.show_all() - - c = Configuration.Config() - #tables = Tables.discover(c) - t = Tables.discover_table_by_name(c, "Corona") - if t is None: - print _("Table not found.") - db = Database.Database(c, 'fpdb', 'holdem') - - stat_dict = db.get_stats_from_hand(1) - -# for t in tables: - win = Hud(None, t, 10, 'holdem', c, db) # parent, table, max, poker_game, config, db_connection - win.create(1, c, stat_dict, None) # hand, config, stat_dict, cards): -# t.get_details() - win.update(8300, c) # self, hand, config): - - gtk.main() From 6b978b8290c0f69a47f9976a9318a93379c99fbd Mon Sep 17 00:00:00 2001 From: Eratosthenes Date: Thu, 26 Aug 2010 22:48:06 -0400 Subject: [PATCH 3/5] Remove obsolete and unused Tables.py. --- pyfpdb/Tables.py | 449 ----------------------------------------------- 1 file changed, 449 deletions(-) delete mode 100755 pyfpdb/Tables.py diff --git a/pyfpdb/Tables.py b/pyfpdb/Tables.py deleted file mode 100755 index 3ffc7d1a..00000000 --- a/pyfpdb/Tables.py +++ /dev/null @@ -1,449 +0,0 @@ -#!/usr/bin/env python -# -*- coding: utf-8 -*- -"""Discover_Tables.py - -Inspects the currently open windows and finds those of interest to us--that is -poker table windows from supported sites. Returns a list -of Table_Window objects representing the windows found. -""" -# Copyright 2008-2010, Ray E. Barker - -# This program is free software; you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation; either version 2 of the License, or -# (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program; if not, write to the Free Software -# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - -######################################################################## - -# Standard Library modules -import os -import sys -import re - -import locale -lang=locale.getdefaultlocale()[0][0:2] -if lang=="en": - def _(string): return string -else: - import gettext - try: - trans = gettext.translation("fpdb", localedir="locale", languages=[lang]) - trans.install() - except IOError: - def _(string): return string - -# Win32 modules -if os.name == 'nt': - import win32gui - import win32process - import win32api - import win32con - import win32security - -# FreePokerTools modules -import Configuration - -# Each TableWindow object must have the following attributes correctly populated: -# tw.name = the table name from the title bar, which must to match the table name -# from the corresponding hand history. -# tw.site = the site name, e.g. PokerStars, FullTilt. This must match the site -# name specified in the config file. -# tw.number = This is the system id number for the client table window in the -# format that the system presents it. This is Xid in Xwindows and -# hwnd in Microsoft Windows. -# tw.title = The full title from the window title bar. -# tw.width, tw.height = The width and height of the window in pixels. This is -# the internal width and height, not including the title bar and -# window borders. -# tw.x, tw.y = The x, y (horizontal, vertical) location of the window relative -# to the top left of the display screen. This also does not include the -# title bar and window borders. To put it another way, this is the -# screen location of (0, 0) in the working window. - -class Table_Window: - def __init__(self, info = {}): - if 'number' in info: self.number = info['number'] - if 'exe' in info: self.exe = info['exe'] - if 'width' in info: self.width = info['width'] - if 'height' in info: self.height = info['height'] - if 'x' in info: self.x = info['x'] - if 'y' in info: self.y = info['y'] - if 'site' in info: self.site = info['site'] - if 'title' in info: self.title = info['title'] - if 'name' in info: self.name = info['name'] - self.gdkhandle = None - - def __str__(self): -# __str__ method for testing - temp = 'TableWindow object\n' - temp = temp + " name = %s\n site = %s\n number = %s\n title = %s\n" % (self.name, self.site, self.number, self.title) -# temp = temp + " game = %s\n structure = %s\n max = %s\n" % (self.game, self.structure, self.max) - temp = temp + " width = %d\n height = %d\n x = %d\n y = %d\n" % (self.width, self.height, self.x, self.y) - if getattr(self, 'tournament', 0): - temp = temp + " tournament = %d\n table = %d" % (self.tournament, self.table) - return temp - -############################################################################ -# Top-level discovery routines--these are the modules interface -def discover(c): - """Dispatch routine for finding all potential poker client windows.""" - if os.name == 'posix': - tables = discover_posix(c) - elif os.name == 'nt': - tables = discover_nt(c) - elif os.name == 'mac': - tables = discover_mac(c) - else: - tables = {} - return tables - -def discover_table_by_name(c, tablename): - """Dispatch routine for finding poker client windows with the given name.""" - if os.name == 'posix': - info = discover_posix_by_name(c, tablename) - elif os.name == 'nt': - info = discover_nt_by_name(c, tablename) - elif os.name == 'mac': - info = discover_mac_by_name(c, tablename) - else: - return None - if info is None: - return None - return Table_Window(info) - -def discover_tournament_table(c, tour_number, tab_number): - """Dispatch routine for finding poker clients with tour and table number.""" - if os.name == 'posix': - info = discover_posix_tournament(c, tour_number, tab_number) - elif os.name == 'nt': - info = discover_nt_tournament(c, tour_number, tab_number) - elif os.name == 'mac': - info = discover_mac_tournament(c, tour_number, tab_number) - else: - return None - if info: - return Table_Window(info) - return None - -############################################################################# -# Posix (= XWindows) specific routines -def discover_posix(c): - """Poker client table window finder for posix/Linux = XWindows.""" - tables = {} - for listing in os.popen('xwininfo -root -tree').readlines(): -# xwininfo -root -tree -id 0xnnnnn gets the info on a single window - for s in c.get_supported_sites(): - params = c.get_site_parameters(s) - -# TODO: We need to make a list of phrases, shared between the WIndows and Unix code!!!!!! - if re.search(params['table_finder'], listing): - if 'Lobby' in listing: continue - if 'Instant Hand History' in listing: continue -# if '\"Full Tilt Poker\"' in listing: continue - if 'History for table:' in listing: continue - if 'has no name' in listing: continue - info = decode_xwininfo(c, listing) - if info['site'] is None: continue - if info['title'] == info['exe']: continue -# this appears to be a poker client, so make a table object for it - tw = Table_Window(info) - eval("%s(tw)" % params['decoder']) - tables[tw.name] = tw - return tables - -def discover_posix_by_name(c, tablename): - """Find an XWindows poker client of the given name.""" - for listing in os.popen('xwininfo -root -tree').readlines(): - if tablename in listing: - if 'History for table:' in listing: continue - info = decode_xwininfo(c, listing) - if not info['name'] == tablename: continue - return info - return None - -def discover_posix_tournament(c, t_number, s_number): - """Finds the X window for a client, given tournament and table nos.""" - search_string = "%s.+Table.+%s" % (t_number, s_number) - for listing in os.popen('xwininfo -root -tree').readlines(): - if re.search(search_string, listing): - return decode_xwininfo(c, listing) - return None - -def decode_xwininfo(c, info_string): - """Gets window parameters from xwinifo string--XWindows.""" - info = {} - mo = re.match('\s+([\dxabcdef]+) (.+):\s\(\"([a-zA-Z.]+)\".+ (\d+)x(\d+)\+\d+\+\d+ \+(\d+)\+(\d+)', info_string) - if not mo: - return None - else: - info['number'] = int( mo.group(1), 0) - info['exe'] = mo.group(3) - info['width'] = int( mo.group(4) ) - info['height'] = int( mo.group(5) ) - info['x'] = int( mo.group(6) ) - info['y'] = int( mo.group(7) ) - info['site'] = get_site_from_exe(c, info['exe']) - info['title'] = re.sub('\"', '', mo.group(2)) - title_bits = re.split(' - ', info['title']) - info['name'] = clean_title(title_bits[0]) - return info - -############################################################################## -# NT (= Windows) specific routines -def discover_nt(c): - """ Poker client table window finder for Windows.""" -# -# I cannot figure out how to get the inside dimensions of the poker table -# windows. So I just assume all borders are 3 thick and all title bars -# are 29 high. No doubt this will be off when used with certain themes. -# - b_width = 3 - tb_height = 29 - titles = {} - tables = {} - win32gui.EnumWindows(win_enum_handler, titles) - for hwnd in titles: - if 'Logged In as' in titles[hwnd] and not 'Lobby' in titles[hwnd]: - if 'Full Tilt Poker' in titles[hwnd]: - continue - tw = Table_Window() - tw.number = hwnd - (x, y, width, height) = win32gui.GetWindowRect(hwnd) - tw.title = titles[hwnd] - tw.width = int( width ) - 2*b_width - tw.height = int( height ) - b_width - tb_height - tw.x = int( x ) + b_width - tw.y = int( y ) + tb_height - -# TODO: Isn't the site being determined by the EXE name it belongs to? is this section of code even useful? cleaning it anyway - if 'Logged In as' in titles[hwnd]: - tw.site = "PokerStars" - elif 'Logged In As' in titles[hwnd]: - tw.site = "Full Tilt" - else: - tw.site = "Unknown" - sys.stderr.write(_("Found unknown table = %s") % tw.title) - if tw.site != "Unknown": - eval("%s(tw)" % c.supported_sites[tw.site].decoder) - else: - tw.name = "Unknown" - tables[len(tables)] = tw - return tables - -def discover_nt_by_name(c, tablename): - """Finds poker client window with the given table name.""" - titles = {} - win32gui.EnumWindows(win_enum_handler, titles) - - for hwnd in titles: - #print "Tables.py: tablename =", tablename, "title =", titles[hwnd] - try: - # maybe it's better to make global titles[hwnd] decoding? - # this can blow up in XP on some windows, eg firefox displaying http://docs.python.org/tutorial/classes.html - if not tablename.lower() in titles[hwnd].decode(Configuration.LOCALE_ENCODING).lower(): - continue - except: - continue - if 'History for table:' in titles[hwnd]: continue # Everleaf Network HH viewer window - if 'HUD:' in titles[hwnd]: continue # FPDB HUD window - if 'Chat:' in titles[hwnd]: continue # Some sites (FTP? PS? Others?) have seperable or seperately constructed chat windows - if ' - Table ' in titles[hwnd]: continue # Absolute table Chat window.. sigh. TODO: Can we tell what site we're trying to discover for somehow in here, so i can limit this check just to AP searches? - temp = decode_windows(c, titles[hwnd], hwnd) - print _("attach to window"), temp - return temp - return None - -def discover_nt_tournament(c, tour_number, tab_number): - """Finds the Windows window handle for the given tournament/table.""" - search_string = "%s.+%s" % (tour_number, tab_number) - - titles ={} - win32gui.EnumWindows(win_enum_handler, titles) - for hwnd in titles: - # Some sites (FTP? PS? Others?) have seperable or seperately constructed chat windows - if 'Chat:' in titles[hwnd]: continue - # Everleaf Network HH viewer window - if 'History for table:' in titles[hwnd]: continue - # FPDB HUD window - if 'HUD:' in titles[hwnd]: continue - - if re.search(search_string, titles[hwnd]): - return decode_windows(c, titles[hwnd], hwnd) - return None - -def get_nt_exe(hwnd): - """Finds the name of the executable that the given window handle belongs to.""" - - # Request privileges to enable "debug process", so we can later use - # PROCESS_VM_READ, retardedly required to GetModuleFileNameEx() - priv_flags = win32security.TOKEN_ADJUST_PRIVILEGES | win32security.TOKEN_QUERY - hToken = win32security.OpenProcessToken (win32api.GetCurrentProcess(), - priv_flags) - # enable "debug process" - privilege_id = win32security.LookupPrivilegeValue(None, - win32security.SE_DEBUG_NAME) - old_privs = win32security.AdjustTokenPrivileges(hToken, 0, - [(privilege_id, - win32security.SE_PRIVILEGE_ENABLED)]) - - # Open the process, and query it's filename - processid = win32process.GetWindowThreadProcessId(hwnd) - pshandle = win32api.OpenProcess(win32con.PROCESS_QUERY_INFORMATION | - win32con.PROCESS_VM_READ, False, - processid[1]) - try: - exename = win32process.GetModuleFileNameEx(pshandle, 0) - except pywintypes.error: - # insert code to call GetProcessImageName if we can find it.. - # returning None from here will hopefully break all following code - exename = None - finally: - # clean up - win32api.CloseHandle(pshandle) - win32api.CloseHandle(hToken) - - return exename - -def decode_windows(c, title, hwnd): - """Gets window parameters from the window title and handle--Windows.""" - -# I cannot figure out how to get the inside dimensions of the poker table -# windows. So I just assume all borders are 3 thick and all title bars -# are 29 high. No doubt this will be off when used with certain themes. - b_width = 3 - tb_height = 29 - - info = {} - info['number'] = hwnd - info['title'] = re.sub('\"', '', title) - (x, y, width, height) = win32gui.GetWindowRect(hwnd) - - info['x'] = int(x) + b_width - info['y'] = int( y ) + tb_height - info['width'] = int( width ) - 2*b_width - info['height'] = int( height ) - b_width - tb_height - info['exe'] = get_nt_exe(hwnd) - print "get_nt_exe returned ", info['exe'] - # TODO: 'width' here is all sorts of screwed up. - - title_bits = re.split(' - ', info['title']) - info['name'] = title_bits[0] - info['site'] = get_site_from_exe(c, info['exe']) - - return info - -def win_enum_handler(hwnd, titles): - str = win32gui.GetWindowText(hwnd) - if str != "": - titles[hwnd] = win32gui.GetWindowText(hwnd) - -################################################################### -# Utility routines used by all the discoverers. -def get_site_from_exe(c, exe): - """Look up the site from config, given the exe.""" - for s in c.get_supported_sites(): - params = c.get_site_parameters(s) - if re.search(params['table_finder'], 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. -# This is needed only when using the HUD with a backend less integrated. - title_bits = re.split(' - ', tw.title) - name = title_bits[0] - mo = re.search('Tournament (\d+) Table (\d+)', name) - if mo: - tw.tournament = int( mo.group(1) ) - tw.table = int( mo.group(2) ) - tw.name = name - else: - tw.tournament = None - tw.name = clean_title(name) - mo = re.search('(Razz|Stud H/L|Stud|Omaha H/L|Omaha|Hold\'em|5-Card Draw|Triple Draw 2-7 Lowball|Badugi)', tw.title) - - tw.game = mo.group(1).lower() - tw.game = re.sub('\'', '', tw.game) - tw.game = re.sub('h/l', 'hi/lo', tw.game) - - mo = re.search('(No Limit|Pot Limit)', tw.title) - if mo: - tw.structure = mo.group(1).lower() - else: - tw.structure = 'limit' - - tw.max = None - if tw.game in ('razz', 'stud', 'stud hi/lo'): - tw.max = 8 - elif tw.game in ('5-card draw', 'triple draw 2-7 lowball'): - tw.max = 6 - elif tw.game == 'holdem': - pass - elif tw.game in ('omaha', 'omaha hi/lo'): - pass - -def fulltilt_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. -# This is needed only when using the HUD with a backend less integrated. - title_bits = re.split(' - ', tw.title) - name = title_bits[0] - tw.tournament = None - tw.name = clean_title(name) - -def clean_title(name): - """Clean the little info strings from the table name.""" -# these strings could go in a config file - for pattern in [' \(6 max\)', ' \(heads up\)', ' \(deep\)', - ' \(deep hu\)', ' \(deep 6\)', '\(6 max, deep\)', ' \(2\)', - ' \(edu\)', ' \(edu, 6 max\)', ' \(6\)', - ' \(speed\)', 'special', 'newVPP', - ' no all-in', ' fast', ',', ' 50BB min', '50bb min', '\s+$']: - name = re.sub(pattern, '', name) - name = name.rstrip() - return name - -########################################################################### -# Mac specific routines....all stubs for now -def discover_mac_tournament(c, tour_number, tab_number): - """Mac users need help.""" - return None - -def discover_mac(c): - """Poker client table window finder for Macintosh.""" - tables = {} - return tables - -def discover_mac_by_name(c, tablename): - """Oh, the humanity.""" - # again, i have no mac to test this on, sorry -eric - return None - -########################################################################### -# Main function used for testing -if __name__=="__main__": - c = Configuration.Config() - - print discover_table_by_name(c, "Torino") -# print discover_tournament_table(c, "118942908", "3") - - tables = discover(c) - for t in tables.keys(): - print tables[t] - - print _("press enter to continue") - sys.stdin.readline() From de9c0d9ba6ce52524cbde3015a316e22dff5a3e7 Mon Sep 17 00:00:00 2001 From: Worros Date: Fri, 27 Aug 2010 14:44:19 +0800 Subject: [PATCH 4/5] Stars: Minor refactor to readHandInfo Make the readHandInfo function throw an exception if either of the regexes used fails to match --- pyfpdb/PokerStarsToFpdb.py | 17 +++++++++-------- 1 file changed, 9 insertions(+), 8 deletions(-) diff --git a/pyfpdb/PokerStarsToFpdb.py b/pyfpdb/PokerStarsToFpdb.py index 39347f73..4fbe9dfd 100644 --- a/pyfpdb/PokerStarsToFpdb.py +++ b/pyfpdb/PokerStarsToFpdb.py @@ -224,14 +224,15 @@ class PokerStars(HandHistoryConverter): def readHandInfo(self, hand): info = {} - m = self.re_HandInfo.search(hand.handText,re.DOTALL) - if m: - info.update(m.groupdict()) - else: - pass # throw an exception here, eh? - m = self.re_GameInfo.search(hand.handText) - if m: - info.update(m.groupdict()) + m = self.re_HandInfo.search(hand.handText,re.DOTALL) + m2 = self.re_GameInfo.search(hand.handText) + if m is None or m2 is None: + logging.info("Didn't match re_HandInfo") + logging.info(hand.handText) + raise FpdbParseError("No match in readHandInfo.") + + info.update(m.groupdict()) + info.update(m2.groupdict()) log.debug("readHandInfo: %s" % info) for key in info: From 3eb4f057bc445f93c64e217c3374cd4e844ff0af Mon Sep 17 00:00:00 2001 From: Worros Date: Sat, 28 Aug 2010 16:43:05 +0800 Subject: [PATCH 5/5] THP: Add 'support' for other sites --- pyfpdb/TestHandsPlayers.py | 23 ++++++++++++++++++----- 1 file changed, 18 insertions(+), 5 deletions(-) diff --git a/pyfpdb/TestHandsPlayers.py b/pyfpdb/TestHandsPlayers.py index 5da4d672..ae521f71 100644 --- a/pyfpdb/TestHandsPlayers.py +++ b/pyfpdb/TestHandsPlayers.py @@ -12,7 +12,8 @@ import fpdb_import class FpdbError: - def __init__(self): + def __init__(self, sitename): + self.site = sitename self.errorcount = 0 self.histogram = {} @@ -28,6 +29,7 @@ class FpdbError: self.errorcount += 1 def print_histogram(self): + print "%s:" % self.site for f in self.histogram: idx = f.find('regression') print "(%3d) : %s" %(self.histogram[f], f[idx:]) @@ -103,14 +105,25 @@ def main(argv=None): importer.setCallHud(False) importer.setFakeCacheHHC(True) - errors = FpdbError() + PokerStarsErrors = FpdbError('PokerStars') + FTPErrors = FpdbError('Full Tilt Poker') + PartyPokerErrors = FpdbError('Party Poker') + BetfairErrors = FpdbError('Betfair') - walk_testfiles("regression-test-files/cash/Stars/", compare, importer, errors) + walk_testfiles("regression-test-files/cash/Stars/", compare, importer, PokerStarsErrors) + walk_testfiles("regression-test-files/cash/FTP/", compare, importer, FTPErrors) + walk_testfiles("regression-test-files/cash/PartyPoker/", compare, importer, PartyPokerErrors) + walk_testfiles("regression-test-files/cash/Betfair/", compare, importer, BetfairErrors) + + totalerrors = PokerStarsErrors.errorcount + FTPErrors.errorcount + PartyPokerErrors.errorcount + BetfairErrors.errorcount print "---------------------" - print "Total Errors: %d" % errors.errorcount + print "Total Errors: %d" % totalerrors print "---------------------" - errors.print_histogram() + PokerStarsErrors.print_histogram() + FTPErrors.print_histogram() + PartyPokerErrors.print_histogram() + BetfairErrors.print_histogram() if __name__ == '__main__': sys.exit(main())