diff --git a/pyfpdb/FpdbSQLQueries.py b/pyfpdb/FpdbSQLQueries.py index 11826018..c56e6de3 100644 --- a/pyfpdb/FpdbSQLQueries.py +++ b/pyfpdb/FpdbSQLQueries.py @@ -577,7 +577,7 @@ class FpdbSQLQueries: self.query['addTourneyIndex'] = """ALTER TABLE Tourneys ADD INDEX siteTourneyNo(siteTourneyNo)""" elif(self.dbname == 'PostgreSQL'): # FIXME: This query has a different syntax - self.query['addTourneyIndex'] = """ALTER TABLE Tourneys ADD INDEX siteTourneyNo(siteTourneyNo)""" + self.query['addTourneyIndex'] = """CREATE INDEX siteTourneyNo ON Tourneys (siteTourneyNo)""" elif(self.dbname == 'SQLite'): self.query['addHandsIndex'] = """ """ @@ -585,7 +585,7 @@ class FpdbSQLQueries: self.query['addHandsIndex'] = """ALTER TABLE Hands ADD INDEX siteHandNo(siteHandNo)""" elif(self.dbname == 'PostgreSQL'): # FIXME: This query has a different syntax - self.query['addHandsIndex'] = """ALTER TABLE Hands ADD INDEX siteHandNo(siteHandNo)""" + self.query['addHandsIndex'] = """CREATE INDEX siteHandNo ON Hands (siteHandNo)""" elif(self.dbname == 'SQLite'): self.query['addHandsIndex'] = """ """ @@ -593,9 +593,9 @@ class FpdbSQLQueries: self.query['addPlayersIndex'] = """ALTER TABLE Players ADD INDEX name(name)""" elif(self.dbname == 'PostgreSQL'): # FIXME: This query has a different syntax - self.query['addHandsIndex'] = """ALTER TABLE Hands ADD INDEX siteHandNo(siteHandNo)""" + self.query['addPlayersIndex'] = """CREATE INDEX name ON Players (name)""" elif(self.dbname == 'SQLite'): - self.query['addHandsIndex'] = """ """ + self.query['addPlayersIndex'] = """ """ ################################ # Queries used in GuiGraphViewer diff --git a/pyfpdb/fpdb.py b/pyfpdb/fpdb.py index 8206b2b9..7c442ef0 100755 --- a/pyfpdb/fpdb.py +++ b/pyfpdb/fpdb.py @@ -118,12 +118,12 @@ class fpdb: def dia_create_del_database(self, widget, data): print "todo: implement dia_create_del_database" - obtain_global_lock() + self.obtain_global_lock() #end def dia_create_del_database def dia_create_del_user(self, widget, data): print "todo: implement dia_create_del_user" - obtain_global_lock() + self.obtain_global_lock() #end def dia_create_del_user def dia_database_stats(self, widget, data): @@ -133,17 +133,17 @@ class fpdb: def dia_delete_db_parts(self, widget, data): print "todo: implement dia_delete_db_parts" - obtain_global_lock() + self.obtain_global_lock() #end def dia_delete_db_parts def dia_edit_profile(self, widget=None, data=None, create_default=False, path=None): print "todo: implement dia_edit_profile" - obtain_global_lock() + self.obtain_global_lock() #end def dia_edit_profile def dia_export_db(self, widget, data): print "todo: implement dia_export_db" - obtain_global_lock() + self.obtain_global_lock() #end def dia_export_db def dia_get_db_root_credentials(self): @@ -168,7 +168,7 @@ class fpdb: def dia_import_db(self, widget, data): print "todo: implement dia_import_db" - obtain_global_lock() + self.obtain_global_lock() #end def dia_import_db def dia_licensing(self, widget, data): @@ -264,7 +264,11 @@ 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.connect(self.settings['db-backend'], + self.settings['db-host'], + self.settings['db-databaseName'], + self.settings['db-user'], + self.settings['db-password']) if self.db.wrongDbVersion: diaDbVersionWarning = gtk.Dialog(title="Strong Warning - Invalid database version", parent=None, flags=0, buttons=(gtk.STOCK_OK,gtk.RESPONSE_OK)) diff --git a/pyfpdb/fpdb_db.py b/pyfpdb/fpdb_db.py index 8165211c..2663224e 100755 --- a/pyfpdb/fpdb_db.py +++ b/pyfpdb/fpdb_db.py @@ -21,156 +21,170 @@ import fpdb_simple import FpdbSQLQueries class fpdb_db: - def __init__(self): - """Simple constructor, doesnt really do anything""" - self.db=None - self.cursor=None - self.sql = {} - self.MYSQL_INNODB=2 - self.PGSQL=3 - self.SQLITE=4 - #end def __init__ - - def connect(self, backend, host, database, user, password): - """Connects a database with the given parameters""" - self.backend=backend - self.host=host - self.database=database - self.user=user - self.password=password - if backend==self.MYSQL_INNODB: - import MySQLdb - self.db=MySQLdb.connect(host = host, user = user, passwd = password, db = database) - elif backend==self.PGSQL: - import psycopg2 - self.db = psycopg2.connect(host = host, user = user, password = password, database = database) - else: - raise fpdb_simple.FpdbError("unrecognised database backend:"+backend) - self.cursor=self.db.cursor() - self.cursor.execute('SET SESSION TRANSACTION ISOLATION LEVEL READ COMMITTED') - # Set up query dictionary as early in the connection process as we can. - self.sql = FpdbSQLQueries.FpdbSQLQueries(self.get_backend_name()) - self.wrongDbVersion=False - try: - self.cursor.execute("SELECT * FROM Settings") - settings=self.cursor.fetchone() - if settings[0]!=118: - print "outdated or too new database version - please recreate tables" - self.wrongDbVersion=True - except:# _mysql_exceptions.ProgrammingError: - print "failed to read settings table - please recreate tables" - self.wrongDbVersion=True - #end def connect + def __init__(self): + """Simple constructor, doesnt really do anything""" + self.db=None + self.cursor=None + self.sql = {} + self.MYSQL_INNODB=2 + self.PGSQL=3 + self.SQLITE=4 + #end def __init__ + + def connect(self, backend=None, host=None, database=None, + user=None, password=None): + """Connects a database with the given parameters""" + if backend is None: + raise FpdbError('Database backend not defined') + self.backend=backend + self.host=host + self.user=user + self.password=password + self.database=database + if backend==self.MYSQL_INNODB: + import MySQLdb + self.db=MySQLdb.connect(host = host, user = user, passwd = password, db = database) + elif backend==self.PGSQL: + import psycopg2 + # If DB connection is made over TCP, then the variables + # host, user and password are required + if self.host or self.user: + self.db = psycopg2.connect(host = host, + user = user, + password = password, + database = database) + # For local domain-socket connections, only DB name is + # needed, and everything else is in fact undefined and/or + # flat out wrong + else: + self.db = psycopg2.connect(database = database) + else: + raise fpdb_simple.FpdbError("unrecognised database backend:"+backend) + self.cursor=self.db.cursor() + self.cursor.execute('SET SESSION TRANSACTION ISOLATION LEVEL READ COMMITTED') + # Set up query dictionary as early in the connection process as we can. + self.sql = FpdbSQLQueries.FpdbSQLQueries(self.get_backend_name()) + self.wrongDbVersion=False + try: + self.cursor.execute("SELECT * FROM Settings") + settings=self.cursor.fetchone() + if settings[0]!=118: + print "outdated or too new database version - please recreate tables" + self.wrongDbVersion=True + except:# _mysql_exceptions.ProgrammingError: + print "failed to read settings table - please recreate tables" + self.wrongDbVersion=True + #end def connect - def disconnect(self, due_to_error=False): - """Disconnects the DB""" - if due_to_error: - self.db.rollback() - else: - self.db.commit() - self.cursor.close() - self.db.close() - #end def disconnect - - def reconnect(self, due_to_error=False): - """Reconnects the DB""" - #print "started fpdb_db.reconnect" - self.disconnect(due_to_error) - self.connect(self.backend, self.host, self.database, self.user, self.password) + def disconnect(self, due_to_error=False): + """Disconnects the DB""" + if due_to_error: + self.db.rollback() + else: + self.db.commit() + self.cursor.close() + self.db.close() + #end def disconnect + + def reconnect(self, due_to_error=False): + """Reconnects the DB""" + #print "started fpdb_db.reconnect" + self.disconnect(due_to_error) + self.connect(self.backend, self.host, self.database, self.user, self.password) - def create_tables(self): - #todo: should detect and fail gracefully if tables already exist. - self.cursor.execute(self.sql.query['createSettingsTable']) - self.cursor.execute(self.sql.query['createSitesTable']) - self.cursor.execute(self.sql.query['createGametypesTable']) - 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']) - self.cursor.execute(self.sql.query['createHandsPlayersTable']) - self.cursor.execute(self.sql.query['createHandsActionsTable']) - self.cursor.execute(self.sql.query['createHudCacheTable']) - self.cursor.execute(self.sql.query['addTourneyIndex']) - self.cursor.execute(self.sql.query['addHandsIndex']) - self.cursor.execute(self.sql.query['addPlayersIndex']) - self.fillDefaultData() - self.db.commit() + def create_tables(self): + #todo: should detect and fail gracefully if tables already exist. + self.cursor.execute(self.sql.query['createSettingsTable']) + self.cursor.execute(self.sql.query['createSitesTable']) + self.cursor.execute(self.sql.query['createGametypesTable']) + 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']) + self.cursor.execute(self.sql.query['createHandsPlayersTable']) + self.cursor.execute(self.sql.query['createHandsActionsTable']) + self.cursor.execute(self.sql.query['createHudCacheTable']) + self.cursor.execute(self.sql.query['addTourneyIndex']) + self.cursor.execute(self.sql.query['addHandsIndex']) + self.cursor.execute(self.sql.query['addPlayersIndex']) + self.fillDefaultData() + self.db.commit() #end def disconnect - - def drop_tables(self): - """Drops the fpdb tables from the current db""" + + def drop_tables(self): + """Drops the fpdb tables from the current db""" - if(self.get_backend_name() == 'MySQL InnoDB'): - #Databases with FOREIGN KEY support need this switched of before you can drop tables - self.drop_referencial_integrity() + if(self.get_backend_name() == 'MySQL InnoDB'): + #Databases with FOREIGN KEY support need this switched of before you can drop tables + self.drop_referencial_integrity() - # Query the DB to see what tables exist - self.cursor.execute(self.sql.query['list_tables']) - for table in self.cursor: - self.cursor.execute(self.sql.query['drop_table'] + table[0]) - elif(self.get_backend_name() == 'PostgreSQL'): - self.db.commit()# I have no idea why this makes the query work--REB 07OCT2008 - self.cursor.execute(self.sql.query['list_tables']) - tables = self.cursor.fetchall() - for table in tables: - self.cursor.execute(self.sql.query['drop_table'] + table[0] + ' cascade') - elif(self.get_backend_name() == 'SQLite'): - #todo: sqlite version here - print "Empty function here" + # Query the DB to see what tables exist + self.cursor.execute(self.sql.query['list_tables']) + for table in self.cursor: + self.cursor.execute(self.sql.query['drop_table'] + table[0]) + elif(self.get_backend_name() == 'PostgreSQL'): + self.db.commit()# I have no idea why this makes the query work--REB 07OCT2008 + self.cursor.execute(self.sql.query['list_tables']) + tables = self.cursor.fetchall() + for table in tables: + self.cursor.execute(self.sql.query['drop_table'] + table[0] + ' cascade') + elif(self.get_backend_name() == 'SQLite'): + #todo: sqlite version here + print "Empty function here" - self.db.commit() - #end def drop_tables + self.db.commit() + #end def drop_tables - def drop_referencial_integrity(self): - """Update all tables to remove foreign keys""" + def drop_referencial_integrity(self): + """Update all tables to remove foreign keys""" - self.cursor.execute(self.sql.query['list_tables']) - result = self.cursor.fetchall() + self.cursor.execute(self.sql.query['list_tables']) + result = self.cursor.fetchall() - for i in range(len(result)): - self.cursor.execute("SHOW CREATE TABLE " + result[i][0]) - inner = self.cursor.fetchall() + for i in range(len(result)): + self.cursor.execute("SHOW CREATE TABLE " + result[i][0]) + inner = self.cursor.fetchall() - for j in range(len(inner)): - # result[i][0] - Table name - # result[i][1] - CREATE TABLE parameters - #Searching for CONSTRAINT `tablename_ibfk_1` - for m in re.finditer('(ibfk_[0-9]+)', inner[j][1]): - key = "`" + inner[j][0] + "_" + m.group() + "`" - self.cursor.execute("ALTER TABLE " + inner[j][0] + " DROP FOREIGN KEY " + key) + for j in range(len(inner)): + # result[i][0] - Table name + # result[i][1] - CREATE TABLE parameters + #Searching for CONSTRAINT `tablename_ibfk_1` + for m in re.finditer('(ibfk_[0-9]+)', inner[j][1]): + key = "`" + inner[j][0] + "_" + m.group() + "`" + self.cursor.execute("ALTER TABLE " + inner[j][0] + " DROP FOREIGN KEY " + key) self.db.commit() #end drop_referencial_inegrity - - def get_backend_name(self): - """Returns the name of the currently used backend""" - if self.backend==2: - return "MySQL InnoDB" - elif self.backend==3: - return "PostgreSQL" - else: - raise fpdb_simple.FpdbError("invalid backend") - #end def get_backend_name - - def get_db_info(self): - return (self.host, self.database, self.user, self.password) - #end def get_db_info - - def fillDefaultData(self): - self.cursor.execute("INSERT INTO Settings VALUES (118);") - self.cursor.execute("INSERT INTO Sites VALUES (DEFAULT, 'Full Tilt Poker', 'USD');") - self.cursor.execute("INSERT INTO Sites VALUES (DEFAULT, 'PokerStars', 'USD');") - self.cursor.execute("INSERT INTO TourneyTypes VALUES (DEFAULT, 1, 0, 0, 0, False);") - #end def fillDefaultData - - def recreate_tables(self): - """(Re-)creates the tables of the current DB""" - - self.drop_tables() - self.create_tables() - self.db.commit() - print "Finished recreating tables" - #end def recreate_tables + + def get_backend_name(self): + """Returns the name of the currently used backend""" + if self.backend==2: + return "MySQL InnoDB" + elif self.backend==3: + return "PostgreSQL" + else: + raise fpdb_simple.FpdbError("invalid backend") + #end def get_backend_name + + def get_db_info(self): + return (self.host, self.database, self.user, self.password) + #end def get_db_info + + def fillDefaultData(self): + self.cursor.execute("INSERT INTO Settings VALUES (118);") + self.cursor.execute("INSERT INTO Sites VALUES (DEFAULT, 'Full Tilt Poker', 'USD');") + self.cursor.execute("INSERT INTO Sites VALUES (DEFAULT, 'PokerStars', 'USD');") + self.cursor.execute("INSERT INTO TourneyTypes VALUES (DEFAULT, 1, 0, 0, 0, False);") + #end def fillDefaultData + + def recreate_tables(self): + """(Re-)creates the tables of the current DB""" + + self.drop_tables() + self.create_tables() + self.db.commit() + print "Finished recreating tables" + #end def recreate_tables #end class fpdb_db diff --git a/pyfpdb/fpdb_import.py b/pyfpdb/fpdb_import.py index 0ff8179c..fd2a321f 100755 --- a/pyfpdb/fpdb_import.py +++ b/pyfpdb/fpdb_import.py @@ -20,16 +20,16 @@ import sys try: - import MySQLdb - mysqlLibFound=True + import MySQLdb + mysqlLibFound=True except: - pass - + pass + try: - import psycopg2 - pgsqlLibFound=True + import psycopg2 + pgsqlLibFound=True except: - pass + pass import traceback import math @@ -42,274 +42,281 @@ from time import time class Importer: - def __init__(self, caller, settings, config): - """Constructor""" - self.settings=settings - self.caller=caller - self.config = config - self.db = None - self.cursor = None - self.filelist = {} - self.dirlist = {} - self.monitor = False - self.updated = {} #Time last import was run {file:mtime} - self.lines = None - self.faobs = None #File as one big string - self.pos_in_file = {} # dict to remember how far we have read in the file - #Set defaults - self.callHud = self.config.get_import_parameters().get("callFpdbHud") - if not self.settings.has_key('minPrint'): - self.settings['minPrint'] = 30 - self.dbConnect() + def __init__(self, caller, settings, config): + """Constructor""" + self.settings=settings + self.caller=caller + self.config = config + self.db = None + self.cursor = None + self.filelist = {} + self.dirlist = {} + self.monitor = False + self.updated = {} #Time last import was run {file:mtime} + self.lines = None + self.faobs = None #File as one big string + self.pos_in_file = {} # dict to remember how far we have read in the file + #Set defaults + self.callHud = self.config.get_import_parameters().get("callFpdbHud") + if not self.settings.has_key('minPrint'): + self.settings['minPrint'] = 30 + self.dbConnect() - def dbConnect(self): - #connect to DB - if self.settings['db-backend'] == 2: - 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") - self.db = MySQLdb.connect(self.settings['db-host'], self.settings['db-user'], - self.settings['db-password'], self.settings['db-databaseName']) - elif self.settings['db-backend'] == 3: - 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") - print self.settings - self.db = psycopg2.connect(host = self.settings['db-host'], - user = self.settings['db-user'], - password = self.settings['db-password'], - database = self.settings['db-databaseName']) - elif self.settings['db-backend'] == 4: - pass - else: - pass - self.cursor = self.db.cursor() + # XXX: Why is this here, when fpdb_db.connect() already does the + # same? + def dbConnect(self): + #connect to DB + if self.settings['db-backend'] == 2: + 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") + self.db = MySQLdb.connect(self.settings['db-host'], self.settings['db-user'], + self.settings['db-password'], self.settings['db-databaseName']) + elif self.settings['db-backend'] == 3: + 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") + print self.settings + if not self.settings.has_key('db-host') or \ + not self.settings.has_key('db-user'): + self.db = psycopg2.connect(host = self.settings['db-host'], + user = self.settings['db-user'], + password = self.settings['db-password'], + database = self.settings['db-databaseName']) + else: + dbname = self.settings['db-databaseName'] + self.db = psycopg2.connect(database = dbname) + elif self.settings['db-backend'] == 4: + pass + else: + pass + self.cursor = self.db.cursor() - #Set functions - def setCallHud(self, value): - self.callHud = value + #Set functions + def setCallHud(self, value): + self.callHud = value - def setMinPrint(self, value): - self.settings['minPrint'] = int(value) + def setMinPrint(self, value): + self.settings['minPrint'] = int(value) - def setHandCount(self, value): - self.settings['handCount'] = int(value) + def setHandCount(self, value): + self.settings['handCount'] = int(value) - def setQuiet(self, value): - self.settings['quiet'] = value + def setQuiet(self, value): + self.settings['quiet'] = value - def setFailOnError(self, value): - self.settings['failOnError'] = value + def setFailOnError(self, value): + self.settings['failOnError'] = value -# def setWatchTime(self): -# self.updated = time() +# def setWatchTime(self): +# self.updated = time() - def clearFileList(self): - self.filelist = {} + def clearFileList(self): + self.filelist = {} - #Add an individual file to filelist - def addImportFile(self, filename, site = "default", filter = "passthrough"): - #TODO: test it is a valid file - self.filelist[filename] = [site] + [filter] + #Add an individual file to filelist + def addImportFile(self, filename, site = "default", filter = "passthrough"): + #TODO: test it is a valid file + self.filelist[filename] = [site] + [filter] - #Add a directory of files to filelist - #Only one import directory per site supported. - #dirlist is a hash of lists: - #dirlist{ 'PokerStars' => ["/path/to/import/", "filtername"] } - def addImportDirectory(self,dir,monitor = False, site = "default", filter = "passthrough"): - if os.path.isdir(dir): - if monitor == True: - self.monitor = True - self.dirlist[site] = [dir] + [filter] + #Add a directory of files to filelist + #Only one import directory per site supported. + #dirlist is a hash of lists: + #dirlist{ 'PokerStars' => ["/path/to/import/", "filtername"] } + def addImportDirectory(self,dir,monitor = False, site = "default", filter = "passthrough"): + if os.path.isdir(dir): + if monitor == True: + self.monitor = True + self.dirlist[site] = [dir] + [filter] - for file in os.listdir(dir): - self.addImportFile(os.path.join(dir, file), site, filter) - else: - print "Warning: Attempted to add: '" + str(dir) + "' as an import directory" + for file in os.listdir(dir): + self.addImportFile(os.path.join(dir, file), site, filter) + else: + print "Warning: Attempted to add: '" + str(dir) + "' as an import directory" - #Run full import on filelist - def runImport(self): - for file in self.filelist: - self.import_file_dict(file, self.filelist[file][0], self.filelist[file][1]) + #Run full import on filelist + def runImport(self): + for file in self.filelist: + self.import_file_dict(file, self.filelist[file][0], self.filelist[file][1]) - #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 site in self.dirlist: - self.addImportDirectory(self.dirlist[site][0], False, site, self.dirlist[site][1]) + #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 site in self.dirlist: + self.addImportDirectory(self.dirlist[site][0], False, site, self.dirlist[site][1]) - for file in self.filelist: - stat_info = os.stat(file) - try: - lastupdate = self.updated[file] - if stat_info.st_mtime > lastupdate: - self.import_file_dict(file, self.filelist[file][0], self.filelist[file][1]) - self.updated[file] = time() - except: - self.updated[file] = time() - # This codepath only runs first time the file is found, if modified in the last - # minute run an immediate import. - if (time() - stat_info.st_mtime) < 60: - self.import_file_dict(file, self.filelist[file][0], self.filelist[file][1]) + for file in self.filelist: + stat_info = os.stat(file) + try: + lastupdate = self.updated[file] + if stat_info.st_mtime > lastupdate: + self.import_file_dict(file, self.filelist[file][0], self.filelist[file][1]) + self.updated[file] = time() + except: + self.updated[file] = time() + # This codepath only runs first time the file is found, if modified in the last + # minute run an immediate import. + if (time() - stat_info.st_mtime) < 60: + self.import_file_dict(file, self.filelist[file][0], self.filelist[file][1]) - # This is now an internal function that should not be called directly. - def import_file_dict(self, file, site, filter): - if(filter == "passthrough"): - self.import_fpdb_file(file, site) - else: - #Load filter, and run filtered file though main importer - self.import_fpdb_file(file, site) + # This is now an internal function that should not be called directly. + def import_file_dict(self, file, site, filter): + if(filter == "passthrough"): + self.import_fpdb_file(file, site) + else: + #Load filter, and run filtered file though main importer + self.import_fpdb_file(file, site) - def import_fpdb_file(self, file, site): - starttime = time() - last_read_hand=0 - loc = 0 - if (file=="stdin"): - inputFile=sys.stdin - else: - inputFile=open(file, "rU") - try: loc = self.pos_in_file[file] - except: pass + def import_fpdb_file(self, file, site): + starttime = time() + last_read_hand=0 + loc = 0 + if (file=="stdin"): + inputFile=sys.stdin + else: + inputFile=open(file, "rU") + try: loc = self.pos_in_file[file] + except: pass - # Read input file into class and close file - inputFile.seek(loc) - self.lines=fpdb_simple.removeTrailingEOL(inputFile.readlines()) - self.pos_in_file[file] = inputFile.tell() - inputFile.close() + # Read input file into class and close file + inputFile.seek(loc) + self.lines=fpdb_simple.removeTrailingEOL(inputFile.readlines()) + self.pos_in_file[file] = inputFile.tell() + inputFile.close() - try: # sometimes we seem to be getting an empty self.lines, in which case, we just want to return. - firstline = self.lines[0] - except: -# print "import_fpdb_file", file, site, self.lines, "\n" - return + try: # sometimes we seem to be getting an empty self.lines, in which case, we just want to return. + firstline = self.lines[0] + except: +# print "import_fpdb_file", file, site, self.lines, "\n" + return - if firstline.find("Tournament Summary")!=-1: - print "TODO: implement importing tournament summaries" - #self.faobs = readfile(inputFile) - #self.parseTourneyHistory() - return 0 - - site=fpdb_simple.recogniseSite(firstline) - category=fpdb_simple.recogniseCategory(firstline) + if firstline.find("Tournament Summary")!=-1: + print "TODO: implement importing tournament summaries" + #self.faobs = readfile(inputFile) + #self.parseTourneyHistory() + return 0 + + site=fpdb_simple.recogniseSite(firstline) + category=fpdb_simple.recogniseCategory(firstline) - startpos=0 - stored=0 #counter - duplicates=0 #counter - partial=0 #counter - errors=0 #counter + startpos=0 + stored=0 #counter + duplicates=0 #counter + partial=0 #counter + errors=0 #counter - for i in range (len(self.lines)): #main loop, iterates through the lines of a file and calls the appropriate parser method - if (len(self.lines[i])<2): - endpos=i - hand=self.lines[startpos:endpos] - - if (len(hand[0])<2): - hand=hand[1:] - - cancelled=False - damaged=False - if (site=="ftp"): - for i in range (len(hand)): - if (hand[i].endswith(" has been canceled")): #this is their typo. this is a typo, right? - cancelled=True - - seat1=hand[i].find("Seat ") #todo: make this recover by skipping this line - if (seat1!=-1): - if (hand[i].find("Seat ", seat1+3)!=-1): - damaged=True - - if (len(hand)<3): - pass - #todo: the above 2 lines are kind of a dirty hack, the mentioned circumstances should be handled elsewhere but that doesnt work with DOS/Win EOL. actually this doesnt work. - elif (hand[0].endswith(" (partial)")): #partial hand - do nothing - partial+=1 - elif (hand[1].find("Seat")==-1 and hand[2].find("Seat")==-1 and hand[3].find("Seat")==-1):#todo: should this be or instead of and? - partial+=1 - elif (cancelled or damaged): - partial+=1 - else: #normal processing - isTourney=fpdb_simple.isTourney(hand[0]) - if not isTourney: - fpdb_simple.filterAnteBlindFold(site,hand) - hand=fpdb_simple.filterCrap(site, hand, isTourney) - self.hand=hand - - try: - handsId=fpdb_parse_logic.mainParser(self.db, self.cursor, site, category, hand) - self.db.commit() - - stored+=1 - self.db.commit() - if self.callHud: - #print "call to HUD here. handsId:",handsId - #pipe the Hands.id out to the HUD - self.caller.pipe_to_hud.stdin.write("%s" % (handsId) + os.linesep) - except fpdb_simple.DuplicateError: - duplicates+=1 - except (ValueError), fe: - errors+=1 - self.printEmailErrorMessage(errors, file, hand) - - if (self.settings['failOnError']): - self.db.commit() #dont remove this, in case hand processing was cancelled. - raise - except (fpdb_simple.FpdbError), fe: - errors+=1 - self.printEmailErrorMessage(errors, file, hand) + for i in range (len(self.lines)): #main loop, iterates through the lines of a file and calls the appropriate parser method + if (len(self.lines[i])<2): + endpos=i + hand=self.lines[startpos:endpos] + + if (len(hand[0])<2): + hand=hand[1:] + + cancelled=False + damaged=False + if (site=="ftp"): + for i in range (len(hand)): + if (hand[i].endswith(" has been canceled")): #this is their typo. this is a typo, right? + cancelled=True + + seat1=hand[i].find("Seat ") #todo: make this recover by skipping this line + if (seat1!=-1): + if (hand[i].find("Seat ", seat1+3)!=-1): + damaged=True + + if (len(hand)<3): + pass + #todo: the above 2 lines are kind of a dirty hack, the mentioned circumstances should be handled elsewhere but that doesnt work with DOS/Win EOL. actually this doesnt work. + elif (hand[0].endswith(" (partial)")): #partial hand - do nothing + partial+=1 + elif (hand[1].find("Seat")==-1 and hand[2].find("Seat")==-1 and hand[3].find("Seat")==-1):#todo: should this be or instead of and? + partial+=1 + elif (cancelled or damaged): + partial+=1 + else: #normal processing + isTourney=fpdb_simple.isTourney(hand[0]) + if not isTourney: + fpdb_simple.filterAnteBlindFold(site,hand) + hand=fpdb_simple.filterCrap(site, hand, isTourney) + self.hand=hand + + try: + handsId=fpdb_parse_logic.mainParser(self.db, self.cursor, site, category, hand) + self.db.commit() + + stored+=1 + self.db.commit() + if self.callHud: + #print "call to HUD here. handsId:",handsId + #pipe the Hands.id out to the HUD + self.caller.pipe_to_hud.stdin.write("%s" % (handsId) + os.linesep) + except fpdb_simple.DuplicateError: + duplicates+=1 + except (ValueError), fe: + errors+=1 + self.printEmailErrorMessage(errors, file, hand) + + if (self.settings['failOnError']): + self.db.commit() #dont remove this, in case hand processing was cancelled. + raise + except (fpdb_simple.FpdbError), fe: + errors+=1 + self.printEmailErrorMessage(errors, file, hand) - #fe.printStackTrace() #todo: get stacktrace - self.db.rollback() - - if (self.settings['failOnError']): - self.db.commit() #dont remove this, in case hand processing was cancelled. - raise - if (self.settings['minPrint']!=0): - if ((stored+duplicates+partial+errors)%self.settings['minPrint']==0): - print "stored:", stored, "duplicates:", duplicates, "partial:", partial, "errors:", errors - - if (self.settings['handCount']!=0): - if ((stored+duplicates+partial+errors)>=self.settings['handCount']): - if (not self.settings['quiet']): - 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) - sys.exit(0) - startpos=endpos - print "Total stored:", stored, "duplicates:", duplicates, "partial:", partial, "errors:", errors, " time:", (time() - starttime) - - if stored==0: - if duplicates>0: - for line_no in range(len(self.lines)): - if self.lines[line_no].find("Game #")!=-1: - final_game_line=self.lines[line_no] - handsId=fpdb_simple.parseSiteHandNo(final_game_line) - else: - print "failed to read a single hand from file:", inputFile - handsId=0 - #todo: this will cause return of an unstored hand number if the last hand was error or partial - self.db.commit() - self.handsId=handsId - return handsId + #fe.printStackTrace() #todo: get stacktrace + self.db.rollback() + + if (self.settings['failOnError']): + self.db.commit() #dont remove this, in case hand processing was cancelled. + raise + if (self.settings['minPrint']!=0): + if ((stored+duplicates+partial+errors)%self.settings['minPrint']==0): + print "stored:", stored, "duplicates:", duplicates, "partial:", partial, "errors:", errors + + if (self.settings['handCount']!=0): + if ((stored+duplicates+partial+errors)>=self.settings['handCount']): + if (not self.settings['quiet']): + 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) + sys.exit(0) + startpos=endpos + print "Total stored:", stored, "duplicates:", duplicates, "partial:", partial, "errors:", errors, " time:", (time() - starttime) + + if stored==0: + if duplicates>0: + for line_no in range(len(self.lines)): + if self.lines[line_no].find("Game #")!=-1: + final_game_line=self.lines[line_no] + handsId=fpdb_simple.parseSiteHandNo(final_game_line) + else: + print "failed to read a single hand from file:", inputFile + handsId=0 + #todo: this will cause return of an unstored hand number if the last hand was error or partial + self.db.commit() + self.handsId=handsId + return handsId #end def import_file_dict - def parseTourneyHistory(self): - print "Tourney history parser stub" - #Find tournament boundaries. - #print self.foabs - + def parseTourneyHistory(self): + print "Tourney history parser stub" + #Find tournament boundaries. + #print self.foabs + - def printEmailErrorMessage(self, errors, filename, line): - traceback.print_exc(file=sys.stderr) - print "Error No.",errors,", please send the hand causing this to steffen@sycamoretest.info so I can fix it." - print "Filename:", filename - print "Here is the first line so you can identify it. Please mention that the error was a ValueError:" - print self.hand[0] - print "Hand logged to hand-errors.txt" - logfile = open('hand-errors.txt', 'a') - for s in self.hand: - logfile.write(str(s) + "\n") - logfile.write("\n") - logfile.close() + def printEmailErrorMessage(self, errors, filename, line): + traceback.print_exc(file=sys.stderr) + print "Error No.",errors,", please send the hand causing this to steffen@sycamoretest.info so I can fix it." + print "Filename:", filename + print "Here is the first line so you can identify it. Please mention that the error was a ValueError:" + print self.hand[0] + print "Hand logged to hand-errors.txt" + logfile = open('hand-errors.txt', 'a') + for s in self.hand: + logfile.write(str(s) + "\n") + logfile.write("\n") + logfile.close() if __name__ == "__main__": - print "CLI for fpdb_import is now available as CliFpdb.py" + print "CLI for fpdb_import is now available as CliFpdb.py"