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

This commit is contained in:
Ray 2008-10-14 13:00:18 -04:00
commit 81f5450a17
10 changed files with 312 additions and 126 deletions

65
pyfpdb/CliFpdb.py Executable file
View File

@ -0,0 +1,65 @@
#!/usr/bin/python
#Copyright 2008 Steffen Jobbagy-Felso
#This program is free software: you can redistribute it and/or modify
#it under the terms of the GNU Affero General Public License as published by
#the Free Software Foundation, version 3 of the License.
#
#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 Affero General Public License
#along with this program. If not, see <http://www.gnu.org/licenses/>.
#In the "official" distribution you can find the license in
#agpl-3.0.txt in the docs folder of the package.
import os
import sys
import fpdb_simple
from optparse import OptionParser
try:
import MySQLdb
except:
diaSQLLibMissing = gtk.Dialog(title="Fatal Error - SQL interface library missing", parent=None, flags=0, buttons=(gtk.STOCK_QUIT,gtk.RESPONSE_OK))
print "Please note that the CLI importer only works with MySQL, if you use PostgreSQL this error is expected."
import fpdb_import
import fpdb_db
if __name__ == "__main__":
#process CLI parameters
parser = OptionParser()
parser.add_option("-c", "--handCount", default="0", type="int",
help="Number of hands to import (default 0 means unlimited)")
parser.add_option("-d", "--database", default="fpdb", help="The MySQL database to use (default fpdb)")
parser.add_option("-e", "--errorFile", default="failed.txt",
help="File to store failed hands into. (default: failed.txt) Not implemented.")
parser.add_option("-f", "--inputFile", "--file", "--inputfile", default="stdin",
help="The file you want to import (remember to use quotes if necessary)")
parser.add_option("-m", "--minPrint", "--status", default="50", type="int",
help="How often to print a one-line status report (0 means never, default is 50)")
parser.add_option("-p", "--password", help="The password for the MySQL user")
parser.add_option("-q", "--quiet", action="store_true",
help="If this is passed it doesn't print a total at the end nor the opening line. Note that this purposely does NOT change --minPrint")
parser.add_option("-s", "--server", default="localhost",
help="Hostname/IP of the MySQL server (default localhost)")
parser.add_option("-u", "--user", default="fpdb", help="The MySQL username (default fpdb)")
parser.add_option("-x", "--failOnError", action="store_true",
help="If this option is passed it quits when it encounters any error")
(options, sys.argv) = parser.parse_args()
settings={'imp-callFpdbHud':False, 'db-backend':2}
settings['db-host']=options.server
settings['db-user']=options.user
settings['db-password']=options.password
settings['db-databaseName']=options.database
settings['handCount']=options.handCount
importer = fpdb_import.Importer(options, settings)
importer.addImportFile(options.inputFile)
importer.runImport()

View File

@ -50,16 +50,7 @@ class GuiAutoImport (threading.Thread):
def do_import(self): def do_import(self):
"""Callback for timer to do an import iteration.""" """Callback for timer to do an import iteration."""
for file in os.listdir(self.path): self.importer.runUpdated()
if os.path.isdir(file):
print "AutoImport is not recursive - please select the final directory in which the history files are"
else:
self.inputFile = os.path.join(self.path, file)
stat_info = os.stat(self.inputFile)
if not self.import_files.has_key(self.inputFile) or stat_info.st_mtime > self.import_files[self.inputFile]:
self.importer.import_file_dict(self, self.settings)
self.import_files[self.inputFile] = stat_info.st_mtime
print "GuiAutoImport.import_dir done" print "GuiAutoImport.import_dir done"
return True return True
@ -96,17 +87,8 @@ class GuiAutoImport (threading.Thread):
# self.pipe_to_hud = os.popen(command, 'w') # self.pipe_to_hud = os.popen(command, 'w')
self.path=self.pathTBuffer.get_text(self.pathTBuffer.get_start_iter(), self.pathTBuffer.get_end_iter()) self.path=self.pathTBuffer.get_text(self.pathTBuffer.get_start_iter(), self.pathTBuffer.get_end_iter())
# Iniitally populate the self.import_files dict, which keeps mtimes for the files watched # Add directory to importer object and set the initial mtime reference.
self.importer.addImportDirectory(self.path, True)
self.import_files = {}
for file in os.listdir(self.path):
if os.path.isdir(file):
pass # skip subdirs for now
else:
inputFile = os.path.join(self.path, file)
stat_info = os.stat(inputFile)
self.import_files[inputFile] = stat_info.st_mtime
self.do_import() self.do_import()
interval=int(self.intervalTBuffer.get_text(self.intervalTBuffer.get_start_iter(), self.intervalTBuffer.get_end_iter())) interval=int(self.intervalTBuffer.get_text(self.intervalTBuffer.get_start_iter(), self.intervalTBuffer.get_end_iter()))
@ -121,17 +103,18 @@ class GuiAutoImport (threading.Thread):
def __init__(self, settings, debug=True): def __init__(self, settings, debug=True):
"""Constructor for GuiAutoImport""" """Constructor for GuiAutoImport"""
self.settings=settings self.settings=settings
self.importer = fpdb_import.Importer() self.importer = fpdb_import.Importer(self,self.settings)
self.importer.setCallHud(True) self.importer.setCallHud(True)
self.importer.setMinPrint(30)
self.importer.setQuiet(False)
self.importer.setFailOnError(False)
self.importer.setHandCount(0)
self.importer.setWatchTime()
self.server=settings['db-host'] self.server=settings['db-host']
self.user=settings['db-user'] self.user=settings['db-user']
self.password=settings['db-password'] self.password=settings['db-password']
self.database=settings['db-databaseName'] self.database=settings['db-databaseName']
self.quiet=False
self.failOnError=False
self.minPrint=30
self.handCount=0
self.mainVBox=gtk.VBox(False,1) self.mainVBox=gtk.VBox(False,1)
self.mainVBox.show() self.mainVBox.show()

View File

@ -27,12 +27,8 @@ class GuiBulkImport (threading.Thread):
def import_dir(self): def import_dir(self):
"""imports a directory, non-recursive. todo: move this to fpdb_import so CLI can use it""" """imports a directory, non-recursive. todo: move this to fpdb_import so CLI can use it"""
self.path=self.inputFile self.path=self.inputFile
for file in os.listdir(self.path): self.importer.addImportDirectory(self.path)
if os.path.isdir(file): self.importer.runImport()
print "BulkImport is not recursive - please select the final directory in which the history files are"
else:
self.inputFile=self.path+os.sep+file
self.importer.import_file_dict(self, self.settings)
print "GuiBulkImport.import_dir done" print "GuiBulkImport.import_dir done"
def load_clicked(self, widget, data=None): def load_clicked(self, widget, data=None):
@ -40,36 +36,36 @@ class GuiBulkImport (threading.Thread):
self.handCount=self.hand_count_tbuffer.get_text(self.hand_count_tbuffer.get_start_iter(), self.hand_count_tbuffer.get_end_iter()) self.handCount=self.hand_count_tbuffer.get_text(self.hand_count_tbuffer.get_start_iter(), self.hand_count_tbuffer.get_end_iter())
if (self.handCount=="unlimited" or self.handCount=="Unlimited"): if (self.handCount=="unlimited" or self.handCount=="Unlimited"):
self.handCount=0 self.importer.setHandCount(0)
else: else:
self.handCount=int(self.handCount) self.importer.setHandCount(int(self.handCount))
self.errorFile="failed.txt" self.errorFile="failed.txt"
self.minPrint=self.min_print_tbuffer.get_text(self.min_print_tbuffer.get_start_iter(), self.min_print_tbuffer.get_end_iter()) self.minPrint=self.min_print_tbuffer.get_text(self.min_print_tbuffer.get_start_iter(), self.min_print_tbuffer.get_end_iter())
if (self.minPrint=="never" or self.minPrint=="Never"): if (self.minPrint=="never" or self.minPrint=="Never"):
self.minPrint=0 self.importer.setMinPrint(0)
else: else:
self.minPrint=int(self.minPrint) self.importer.setMinPrint=int(self.minPrint)
self.quiet=self.info_tbuffer.get_text(self.info_tbuffer.get_start_iter(), self.info_tbuffer.get_end_iter()) self.quiet=self.info_tbuffer.get_text(self.info_tbuffer.get_start_iter(), self.info_tbuffer.get_end_iter())
if (self.quiet=="yes"): if (self.quiet=="yes"):
self.quiet=False self.importer.setQuiet(False)
else: else:
self.quiet=True self.importer.setQuiet(True)
self.failOnError=self.fail_error_tbuffer.get_text(self.fail_error_tbuffer.get_start_iter(), self.fail_error_tbuffer.get_end_iter()) self.failOnError=self.fail_error_tbuffer.get_text(self.fail_error_tbuffer.get_start_iter(), self.fail_error_tbuffer.get_end_iter())
if (self.failOnError=="no"): if (self.failOnError=="no"):
self.failOnError=False self.importer.setFailOnError(False)
else: else:
self.failOnError=True self.importer.setFailOnError(True)
self.server, self.database, self.user, self.password=self.db.get_db_info()
if os.path.isdir(self.inputFile): if os.path.isdir(self.inputFile):
self.import_dir() self.import_dir()
else: else:
self.importer.import_file_dict(self, self.settings) self.importer.addImportFile(self.inputFile)
self.importer.runImport()
self.importer.clearFileList()
def get_vbox(self): def get_vbox(self):
"""returns the vbox of this thread""" """returns the vbox of this thread"""
@ -83,7 +79,7 @@ class GuiBulkImport (threading.Thread):
def __init__(self, db, settings): def __init__(self, db, settings):
self.db=db self.db=db
self.settings=settings self.settings=settings
self.importer = fpdb_import.Importer() self.importer = fpdb_import.Importer(self,self.settings)
self.vbox=gtk.VBox(False,1) self.vbox=gtk.VBox(False,1)
self.vbox.show() self.vbox.show()

View File

@ -51,8 +51,10 @@ class GuiGraphViewer (threading.Thread):
if site=="PS": if site=="PS":
site=2 site=2
sitename="PokerStars: "
elif site=="FTP": elif site=="FTP":
site=1 site=1
sitename="Full Tilt: "
else: else:
print "invalid text in site selection in graph, defaulting to PS" print "invalid text in site selection in graph, defaulting to PS"
site=2 site=2
@ -69,7 +71,9 @@ class GuiGraphViewer (threading.Thread):
self.ax.set_xlabel("Hands", fontsize = 12) self.ax.set_xlabel("Hands", fontsize = 12)
self.ax.set_ylabel("$", fontsize = 12) self.ax.set_ylabel("$", fontsize = 12)
self.ax.grid(color='g', linestyle=':', linewidth=0.2) self.ax.grid(color='g', linestyle=':', linewidth=0.2)
self.ax.annotate ("All Hands, Site %s", (61,25), xytext =(0.1, 0.9) , textcoords ="axes fraction" ,) text = "All Hands, " + sitename + str(name)
self.ax.annotate (text, (61,25), xytext =(0.1, 0.9) , textcoords ="axes fraction" ,)
#Get graph data from DB #Get graph data from DB
line = self.getRingProfitGraph(name, site) line = self.getRingProfitGraph(name, site)

View File

@ -251,13 +251,13 @@ class GuiTableViewer (threading.Thread):
self.user=self.db.user self.user=self.db.user
self.password=self.db.password self.password=self.db.password
self.quiet=False self.importer = fpdb_import.Importer(self, self.settings)
self.failOnError=False self.importer.setMinPrint(0)
self.minPrint=0 self.importer.setQuiet(False)
self.handCount=0 self.importer.setFailOnError(False)
self.importer = fpdb_import.Importer() self.importer.setHandCount(0)
self.last_read_hand_id=importer.import_file_dict(self, self.settings) self.last_read_hand_id=self.importer.import_file_dict()
#end def table_viewer.import_clicked #end def table_viewer.import_clicked
def all_clicked(self, widget, data): def all_clicked(self, widget, data):

View File

@ -25,51 +25,62 @@ import os
import sys import sys
import fpdb_db import fpdb_db
import fpdb_import
import FpdbSQLQueries import FpdbSQLQueries
import unittest import unittest
class TestSequenceFunctions(unittest.TestCase): class TestSequenceFunctions(unittest.TestCase):
def setUp(self): def setUp(self):
"""Configure MySQL settings/database and establish connection""" """Configure MySQL settings/database and establish connection"""
self.mysql_settings={ 'db-host':"localhost", 'db-backend':2, 'db-databaseName':"fpdbtest", 'db-user':"fpdb", 'db-password':"fpdb"} self.mysql_settings={ 'db-host':"localhost",
self.mysql_db = fpdb_db.fpdb_db() 'db-backend':2,
self.mysql_db.connect(self.mysql_settings['db-backend'], self.mysql_settings['db-host'], 'db-databaseName':"fpdbtest",
self.mysql_settings['db-databaseName'], self.mysql_settings['db-user'], 'db-user':"fpdb",
self.mysql_settings['db-password']) 'db-password':"fpdb"}
self.mysqldict = FpdbSQLQueries.FpdbSQLQueries('MySQL InnoDB') self.mysql_db = fpdb_db.fpdb_db()
self.mysql_db.connect(self.mysql_settings['db-backend'], self.mysql_settings['db-host'],
self.mysql_settings['db-databaseName'], self.mysql_settings['db-user'],
self.mysql_settings['db-password'])
self.mysqldict = FpdbSQLQueries.FpdbSQLQueries('MySQL InnoDB')
self.mysqlimporter = fpdb_import.Importer(self, self.mysql_settings)
"""Configure Postgres settings/database and establish connection""" # """Configure Postgres settings/database and establish connection"""
self.pg_settings={ 'db-host':"localhost", 'db-backend':3, 'db-databaseName':"fpdbtest", 'db-user':"fpdb", 'db-password':"fpdb"} # self.pg_settings={ 'db-host':"localhost", 'db-backend':3, 'db-databaseName':"fpdbtest", 'db-user':"fpdb", 'db-password':"fpdb"}
self.pg_db = fpdb_db.fpdb_db() # self.pg_db = fpdb_db.fpdb_db()
self.pg_db.connect(self.pg_settings['db-backend'], self.pg_settings['db-host'], # self.pg_db.connect(self.pg_settings['db-backend'], self.pg_settings['db-host'],
self.pg_settings['db-databaseName'], self.pg_settings['db-user'], # self.pg_settings['db-databaseName'], self.pg_settings['db-user'],
self.pg_settings['db-password']) # self.pg_settings['db-password'])
self.pgdict = FpdbSQLQueries.FpdbSQLQueries('PostgreSQL') # self.pgdict = FpdbSQLQueries.FpdbSQLQueries('PostgreSQL')
def testDatabaseConnection(self): def testDatabaseConnection(self):
"""Test all supported DBs""" """Test all supported DBs"""
self.result = self.mysql_db.cursor.execute(self.mysqldict.query['list_tables']) self.result = self.mysql_db.cursor.execute(self.mysqldict.query['list_tables'])
self.failUnless(self.result==13, "Number of tables in database incorrect. Expected 13 got " + str(self.result))
print self.pgdict.query['list_tables']
self.result = self.pg_db.cursor.execute(self.pgdict.query['list_tables'])
self.failUnless(self.result==13, "Number of tables in database incorrect. Expected 13 got " + str(self.result)) self.failUnless(self.result==13, "Number of tables in database incorrect. Expected 13 got " + str(self.result))
# self.result = self.pg_db.cursor.execute(self.pgdict.query['list_tables'])
# self.failUnless(self.result==13, "Number of tables in database incorrect. Expected 13 got " + str(self.result))
def testMySQLRecreateTables(self): def testMySQLRecreateTables(self):
"""Test droping then recreating fpdb table schema""" """Test droping then recreating fpdb table schema"""
self.mysql_db.recreate_tables() self.mysql_db.recreate_tables()
self.result = self.mysql_db.cursor.execute("SHOW TABLES") self.result = self.mysql_db.cursor.execute("SHOW TABLES")
self.failUnless(self.result==13, "Number of tables in database incorrect. Expected 13 got " + str(self.result)) self.failUnless(self.result==13, "Number of tables in database incorrect. Expected 13 got " + str(self.result))
def testPostgresSQLRecreateTables(self): def testImportHandHistoryFiles(self):
"""Test droping then recreating fpdb table schema""" """Test import of single HH file"""
self.pg_db.recreate_tables() self.mysqlimporter.addImportFile("regression-test-files/hand-histories/ps-lhe-ring-3hands.txt")
self.result = self.pg_db.cursor.execute(self.pgdict.query['list_tables']) self.mysqlimporter.runImport()
self.failUnless(self.result==13, "Number of tables in database incorrect. Expected 13 got " + str(self.result)) self.mysqlimporter.addImportDirectory("regression-test-files/hand-histories")
self.mysqlimporter.runImport()
# def testPostgresSQLRecreateTables(self):
# """Test droping then recreating fpdb table schema"""
# self.pg_db.recreate_tables()
# self.result = self.pg_db.cursor.execute(self.pgdict.query['list_tables'])
# self.failUnless(self.result==13, "Number of tables in database incorrect. Expected 13 got " + str(self.result))
if __name__ == '__main__': if __name__ == '__main__':
unittest.main() unittest.main()

View File

@ -355,7 +355,8 @@ class fpdb:
#end def not_implemented #end def not_implemented
def obtain_global_lock(self): def obtain_global_lock(self):
print "todo: implement obtain_global_lock (users: pls ignore this)" #print "todo: implement obtain_global_lock (users: pls ignore this)"
pass
#end def obtain_global_lock #end def obtain_global_lock
def quit(self, widget, data): def quit(self, widget, data):
@ -425,7 +426,7 @@ This program is licensed under the AGPL3, see docs"""+os.sep+"agpl-3.0.txt")
self.window = gtk.Window(gtk.WINDOW_TOPLEVEL) self.window = gtk.Window(gtk.WINDOW_TOPLEVEL)
self.window.connect("delete_event", self.delete_event) self.window.connect("delete_event", self.delete_event)
self.window.connect("destroy", self.destroy) self.window.connect("destroy", self.destroy)
self.window.set_title("Free Poker DB - version: alpha6+, p124 or higher") self.window.set_title("Free Poker DB - version: alpha6+, p131 or higher")
self.window.set_border_width(1) self.window.set_border_width(1)
self.window.set_size_request(1020,400) self.window.set_size_request(1020,400)
self.window.set_resizable(True) self.window.set_resizable(True)

View File

@ -36,67 +36,136 @@ import os
import datetime import datetime
import fpdb_simple import fpdb_simple
import fpdb_parse_logic import fpdb_parse_logic
from optparse import OptionParser
from time import time from time import time
class Importer: class Importer:
def __init__(self): def __init__(self, caller, settings):
"""Constructor""" """Constructor"""
self.settings={'imp-callFpdbHud':False} self.settings=settings
self.caller=caller
self.db = None self.db = None
self.cursor = None self.cursor = None
self.options = None self.filelist = []
self.dirlist = []
self.monitor = False
self.updated = 0 #Time last import was run, used as mtime reference
self.callHud = False self.callHud = False
self.lines = None self.lines = None
self.pos_in_file = {} # dict to remember how far we have read in the file self.pos_in_file = {} # dict to remember how far we have read in the file
#Set defaults
if not self.settings.has_key('imp-callFpdbHud'):
self.settings['imp-callFpdbHud'] = False
if not self.settings.has_key('minPrint'):
self.settings['minPrint'] = 30
self.dbConnect()
def dbConnect(self, options, settings): def dbConnect(self):
#connect to DB #connect to DB
if settings['db-backend'] == 2: if self.settings['db-backend'] == 2:
if not mysqlLibFound: if not mysqlLibFound:
raise fpdb_simple.FpdbError("interface library MySQLdb not found but MySQL selected as backend - please install the library or change the config file") raise fpdb_simple.FpdbError("interface library MySQLdb not found but MySQL selected as backend - please install the library or change the config file")
self.db = MySQLdb.connect(host = options.server, user = options.user, self.db = MySQLdb.connect(self.settings['db-host'], self.settings['db-user'],
passwd = options.password, db = options.database) self.settings['db-password'], self.settings['db-databaseName'])
elif settings['db-backend'] == 3: elif self.settings['db-backend'] == 3:
if not pgsqlLibFound: if not pgsqlLibFound:
raise fpdb_simple.FpdbError("interface library psycopg2 not found but PostgreSQL selected as backend - please install the library or change the config file") raise fpdb_simple.FpdbError("interface library psycopg2 not found but PostgreSQL selected as backend - please install the library or change the config file")
self.db = psycopg2.connect(host = options.server, user = options.user, self.db = psycopg2.connect(self.settings['db-host'], self.settings['db-user'],
password = options.password, database = options.database) self.settings['db-password'], self.settings['db-databaseName'])
elif settings['db-backend'] == 4: elif self.settings['db-backend'] == 4:
pass pass
else: else:
pass pass
self.cursor = self.db.cursor() self.cursor = self.db.cursor()
#Set functions
def setCallHud(self, value): def setCallHud(self, value):
self.callHud = value self.callHud = value
def import_file_dict(self, options, settings): def setMinPrint(self, value):
self.settings['minPrint'] = int(value)
def setHandCount(self, value):
self.settings['handCount'] = int(value)
def setQuiet(self, value):
self.settings['quiet'] = value
def setFailOnError(self, value):
self.settings['failOnError'] = value
def setWatchTime(self):
self.updated = time()
def clearFileList(self):
self.filelist = []
#Add an individual file to filelist
def addImportFile(self, filename):
#todo: test it is a valid file
self.filelist = self.filelist + [filename]
#Remove duplicates
self.filelist = list(set(self.filelist))
#Add a directory of files to filelist
def addImportDirectory(self,dir,monitor = False):
#todo: test it is a valid directory
if monitor == True:
self.monitor = True
self.dirlist = self.dirlist + [dir]
for file in os.listdir(dir):
if os.path.isdir(file):
print "BulkImport is not recursive - please select the final directory in which the history files are"
else:
self.filelist = self.filelist + [os.path.join(dir, file)]
#Remove duplicates
self.filelist = list(set(self.filelist))
#Run full import on filelist
def runImport(self):
for file in self.filelist:
self.import_file_dict(file)
#Run import on updated files, then store latest update time.
def runUpdated(self):
#Check for new files in directory
#todo: make efficient - always checks for new file, should be able to use mtime of directory
# ^^ May not work on windows
for dir in self.dirlist:
for file in os.listdir(dir):
self.filelist = self.filelist + [dir+os.sep+file]
self.filelist = list(set(self.filelist))
for file in self.filelist:
stat_info = os.stat(file)
if stat_info.st_mtime > self.updated:
self.import_file_dict(file)
self.updated = time()
# This is now an internal function that should not be called directly.
def import_file_dict(self, file):
starttime = time() starttime = time()
last_read_hand=0 last_read_hand=0
loc = 0 loc = 0
if (options.inputFile=="stdin"): if (file=="stdin"):
inputFile=sys.stdin inputFile=sys.stdin
else: else:
inputFile=open(options.inputFile, "rU") inputFile=open(file, "rU")
try: loc = self.pos_in_file[options.inputFile] try: loc = self.pos_in_file[file]
except: pass except: pass
self.dbConnect(options,settings)
# Read input file into class and close file # Read input file into class and close file
inputFile.seek(loc) inputFile.seek(loc)
self.lines=fpdb_simple.removeTrailingEOL(inputFile.readlines()) self.lines=fpdb_simple.removeTrailingEOL(inputFile.readlines())
self.pos_in_file[options.inputFile] = inputFile.tell() self.pos_in_file[file] = inputFile.tell()
inputFile.close() inputFile.close()
firstline = self.lines[0] firstline = self.lines[0]
if firstline.find("Tournament Summary")!=-1: if firstline.find("Tournament Summary")!=-1:
print "TODO: implement importing tournament summaries" print "TODO: implement importing tournament summaries"
self.cursor.close()
self.db.close()
return 0 return 0
site=fpdb_simple.recogniseSite(firstline) site=fpdb_simple.recogniseSite(firstline)
@ -142,6 +211,7 @@ class Importer:
if not isTourney: if not isTourney:
fpdb_simple.filterAnteBlindFold(site,hand) fpdb_simple.filterAnteBlindFold(site,hand)
hand=fpdb_simple.filterCrap(site, hand, isTourney) hand=fpdb_simple.filterCrap(site, hand, isTourney)
self.hand=hand
try: try:
handsId=fpdb_parse_logic.mainParser(self.db, self.cursor, site, category, hand) handsId=fpdb_parse_logic.mainParser(self.db, self.cursor, site, category, hand)
@ -150,41 +220,36 @@ class Importer:
stored+=1 stored+=1
self.db.commit() self.db.commit()
# if settings['imp-callFpdbHud'] and self.callHud and os.sep=='/': # if settings['imp-callFpdbHud'] and self.callHud and os.sep=='/':
if settings['imp-callFpdbHud'] and self.callHud: if self.settings['imp-callFpdbHud'] and self.callHud:
#print "call to HUD here. handsId:",handsId #print "call to HUD here. handsId:",handsId
#pipe the Hands.id out to the HUD #pipe the Hands.id out to the HUD
# options.pipe_to_hud.write("%s" % (handsId) + os.linesep) self.caller.pipe_to_hud.stdin.write("%s" % (handsId) + os.linesep)
options.pipe_to_hud.stdin.write("%s" % (handsId) + os.linesep)
except fpdb_simple.DuplicateError: except fpdb_simple.DuplicateError:
duplicates+=1 duplicates+=1
except (ValueError), fe: except (ValueError), fe:
errors+=1 errors+=1
self.printEmailErrorMessage(errors, options.inputFile, hand[0]) self.printEmailErrorMessage(errors, file, hand[0])
if (options.failOnError): if (self.settings['failOnError']):
self.db.commit() #dont remove this, in case hand processing was cancelled this ties up any open ends. self.db.commit() #dont remove this, in case hand processing was cancelled.
self.cursor.close()
self.db.close()
raise raise
except (fpdb_simple.FpdbError), fe: except (fpdb_simple.FpdbError), fe:
errors+=1 errors+=1
self.printEmailErrorMessage(errors, options.inputFile, hand[0]) self.printEmailErrorMessage(errors, file, hand[0])
#fe.printStackTrace() #todo: get stacktrace #fe.printStackTrace() #todo: get stacktrace
self.db.rollback() self.db.rollback()
if (options.failOnError): if (self.settings['failOnError']):
self.db.commit() #dont remove this, in case hand processing was cancelled this ties up any open ends. self.db.commit() #dont remove this, in case hand processing was cancelled.
self.cursor.close()
self.db.close()
raise raise
if (options.minPrint!=0): if (self.settings['minPrint']!=0):
if ((stored+duplicates+partial+errors)%options.minPrint==0): if ((stored+duplicates+partial+errors)%self.settings['minPrint']==0):
print "stored:", stored, "duplicates:", duplicates, "partial:", partial, "errors:", errors print "stored:", stored, "duplicates:", duplicates, "partial:", partial, "errors:", errors
if (options.handCount!=0): if (self.settings['handCount']!=0):
if ((stored+duplicates+partial+errors)>=options.handCount): if ((stored+duplicates+partial+errors)>=self.settings['handCount']):
if (not options.quiet): if (not self.settings['quiet']):
print "quitting due to reaching the amount of hands to be imported" print "quitting due to reaching the amount of hands to be imported"
print "Total stored:", stored, "duplicates:", duplicates, "partial/damaged:", partial, "errors:", errors, " time:", (time() - starttime) print "Total stored:", stored, "duplicates:", duplicates, "partial/damaged:", partial, "errors:", errors, " time:", (time() - starttime)
sys.exit(0) sys.exit(0)
@ -202,16 +267,14 @@ class Importer:
handsId=0 handsId=0
#todo: this will cause return of an unstored hand number if the last hand was error or partial #todo: this will cause return of an unstored hand number if the last hand was error or partial
self.db.commit() self.db.commit()
self.cursor.close()
self.db.close()
return handsId return handsId
#end def import_file_dict #end def import_file_dict
def printEmailErrorMessage(self, errors, filename, line): def printEmailErrorMessage(self, errors, filename, line):
print "Error No.",errors,", please send the hand causing this to steffen@sycamoretest.info so I can fix it." print "Error No.",errors,", please send the hand causing this to steffen@sycamoretest.info so I can fix it."
print "Filename:",options.inputFile print "Filename:", filename
print "Here is the first line so you can identify it. Please mention that the error was a ValueError:" print "Here is the first line so you can identify it. Please mention that the error was a ValueError:"
print hand[0] print self.hand[0]
if __name__ == "__main__": if __name__ == "__main__":

View File

@ -65,3 +65,66 @@ Seat 8: willowdale showed [3s 4d 5s 4s Ad 5h 2c] and won ($1.02) with HI: a stra
PokerStars Game #20711747191: Razz Limit ($1/$2) - 2008/09/26 14:36:50 ET
Table 'Siwa III' 8-max
Seat 2: dainmat ($63.15 in chips)
Seat 3: fnJ's ($30.75 in chips)
Seat 4: ambythegreat ($24.90 in chips)
Seat 5: jt studd ($39.90 in chips)
Seat 6: KyleHruby ($11.55 in chips)
Seat 7: nutOmatic ($71.30 in chips)
dainmat: posts the ante $0.10
fnJ's: posts the ante $0.10
ambythegreat: posts the ante $0.10
jt studd: posts the ante $0.10
KyleHruby: posts the ante $0.10
nutOmatic: posts the ante $0.10
*** 3rd STREET ***
Dealt to dainmat [Ts]
Dealt to fnJ's [3s]
Dealt to ambythegreat [5h]
Dealt to jt studd [Ad]
Dealt to KyleHruby [As]
Dealt to nutOmatic [6d Kd Th]
dainmat: brings in for $0.50
fnJ's: calls $0.50
ambythegreat: raises $0.50 to $1
garnishgut joins the table at seat #1
jt studd: folds
KyleHruby: folds
nutOmatic: folds
dainmat: folds
fnJ's: calls $0.50
*** 4th STREET ***
Dealt to fnJ's [3s] [6h]
Dealt to ambythegreat [5h] [4c]
ambythegreat: bets $1
fnJ's: calls $1
*** 5th STREET ***
Dealt to fnJ's [3s 6h] [2h]
Dealt to ambythegreat [5h 4c] [Kh]
fnJ's: bets $2
ambythegreat: calls $2
*** 6th STREET ***
Dealt to fnJ's [3s 6h 2h] [2c]
Dealt to ambythegreat [5h 4c Kh] [5s]
fnJ's: bets $2
ambythegreat: calls $2
*** RIVER ***
fnJ's: bets $2
ambythegreat: calls $2
*** SHOW DOWN ***
fnJ's: shows [9d 5c 3s 6h 2h 2c 4h] (Lo: 6,5,4,3,2)
ambythegreat: mucks hand
fnJ's collected $16.35 from pot
*** SUMMARY ***
Total pot $17.10 | Rake $0.75
Seat 2: dainmat folded on the 3rd Street
Seat 3: fnJ's showed [9d 5c 3s 6h 2h 2c 4h] and won ($16.35) with Lo: 6,5,4,3,2
Seat 4: ambythegreat mucked [6s 7h 5h 4c Kh 5s Jc]
Seat 5: jt studd folded on the 3rd Street (didn't bet)
Seat 6: KyleHruby folded on the 3rd Street (didn't bet)
Seat 7: nutOmatic folded on the 3rd Street (didn't bet)

View File

@ -18,8 +18,8 @@
echo "Please note for this to work you need to work on an empty database, otherwise some info (the id fields) will be off" echo "Please note for this to work you need to work on an empty database, otherwise some info (the id fields) will be off"
rm *.found.txt rm *.found.txt
../pyfpdb/fpdb_import.py -p$1 --file=ps-lhe-ring-3hands.txt -x ../pyfpdb/CliFpdb.py -p$1 --file=ps-lhe-ring-3hands.txt -x
../pyfpdb/fpdb_import.py -p$1 --file=ps-lhe-ring-3hands.txt -x ../pyfpdb/CliFpdb.py -p$1 --file=ps-lhe-ring-3hands.txt -x
echo "it should've reported first that it stored 3, then that it had 3 duplicates" echo "it should've reported first that it stored 3, then that it had 3 duplicates"
@ -31,12 +31,12 @@ echo "it should've reported first that it stored 3, then that it had 3 duplicate
./PrintPlayerHudData.py -p$1 -nPlayer_5 -oB > ps-flags-B-1hands.found.txt && colordiff ps-flags-B-1hands.found.txt ps-flags-B-1hands.expected.txt ./PrintPlayerHudData.py -p$1 -nPlayer_5 -oB > ps-flags-B-1hands.found.txt && colordiff ps-flags-B-1hands.found.txt ps-flags-B-1hands.expected.txt
../pyfpdb/fpdb_import.py -p$1 --file=ps-lhe-ring-call-3B-preflop-cb-no2b.txt -x ../pyfpdb/CliFpdb.py -p$1 --file=ps-lhe-ring-call-3B-preflop-cb-no2b.txt -x
echo "it should've now reported another successful store of 1 hand" echo "it should've now reported another successful store of 1 hand"
./PrintPlayerHudData.py -p$1 -nplayer3 -oE -e10 -b50 > ps-flags-CBflop.found.txt && colordiff ps-flags-CBflop.found.txt ps-flags-CBflop.expected.txt ./PrintPlayerHudData.py -p$1 -nplayer3 -oE -e10 -b50 > ps-flags-CBflop.found.txt && colordiff ps-flags-CBflop.found.txt ps-flags-CBflop.expected.txt
../pyfpdb/fpdb_import.py -p$1 --file=ps-studhilo-ring-showdown.txt -x ../pyfpdb/CliFpdb.py -p$1 --file=ps-studhilo-ring-showdown.txt -x
echo "it should've now reported another successful store of 1 hand" echo "it should've now reported another successful store of 1 hand"
./PrintHand.py -p$1 --hand=15043388146 > ps.15043388146.found.txt && colordiff ps.15043388146.found.txt ps.15043388146.expected.txt ./PrintHand.py -p$1 --hand=15043388146 > ps.15043388146.found.txt && colordiff ps.15043388146.found.txt ps.15043388146.expected.txt
./PrintPlayerHudData.py -p$1 -nbr1an -o0 -e6 -b20 -cstudhilo> ps-flags-studhilo.found.txt && colordiff ps-flags-studhilo.found.txt ps-flags-studhilo.expected.txt ./PrintPlayerHudData.py -p$1 -nbr1an -o0 -e6 -b20 -cstudhilo> ps-flags-studhilo.found.txt && colordiff ps-flags-studhilo.found.txt ps-flags-studhilo.expected.txt