Merge branch 'master' of git://git.assembla.com/fpdboz.git
This commit is contained in:
commit
2dd5536d98
|
@ -56,36 +56,36 @@ def get_exec_path():
|
||||||
if hasattr(sys, "frozen"): # compiled by py2exe
|
if hasattr(sys, "frozen"): # compiled by py2exe
|
||||||
return os.path.dirname(sys.executable)
|
return os.path.dirname(sys.executable)
|
||||||
else:
|
else:
|
||||||
pathname = os.path.dirname(sys.argv[0])
|
return sys.path[0]
|
||||||
return os.path.abspath(pathname)
|
|
||||||
|
|
||||||
def get_config(file_name, fallback = True):
|
def get_config(file_name, fallback = True):
|
||||||
"""Looks in cwd and in self.default_config_path for a config file."""
|
"""Looks in exec dir and in self.default_config_path for a config file."""
|
||||||
config_path = os.path.join(get_exec_path(), file_name)
|
config_path = os.path.join(DIR_SELF, file_name) # look in exec dir
|
||||||
# print "config_path=", config_path
|
if os.path.exists(config_path) and os.path.isfile(config_path):
|
||||||
if os.path.exists(config_path): # there is a file in the cwd
|
return config_path # there is a file in the exec dir so we use it
|
||||||
return config_path # so we use it
|
else:
|
||||||
else: # no file in the cwd, look where it should be in the first place
|
config_path = os.path.join(DIR_CONFIG, file_name) # look in config dir
|
||||||
config_path = os.path.join(get_default_config_path(), file_name)
|
if os.path.exists(config_path) and os.path.isfile(config_path):
|
||||||
# print "config path 2=", config_path
|
|
||||||
if os.path.exists(config_path):
|
|
||||||
return config_path
|
return config_path
|
||||||
|
|
||||||
# No file found
|
# No file found
|
||||||
if not fallback:
|
if not fallback:
|
||||||
return False
|
return False
|
||||||
|
|
||||||
# OK, fall back to the .example file, should be in the start dir
|
# OK, fall back to the .example file, should be in the exec dir
|
||||||
if os.path.exists(file_name + ".example"):
|
if os.path.exists(os.path.join(DIR_SELF, file_name + ".example")):
|
||||||
try:
|
try:
|
||||||
shutil.copyfile(file_name + ".example", file_name)
|
shutil.copyfile(os.path.join(DIR_SELF, file_name + ".example"), os.path.join(DIR_CONFIG, file_name))
|
||||||
print "No %s found, using %s.example.\n" % (file_name, file_name)
|
print "No %s found, using %s.example.\n" % (file_name, file_name)
|
||||||
print "A %s file has been created. You will probably have to edit it." % file_name
|
print "A %s file has been created. You will probably have to edit it." % os.path.join(DIR_CONFIG, file_name)
|
||||||
sys.stderr.write("No %s found, using %s.example.\n" % (file_name, file_name) )
|
log.error("No %s found, using %s.example.\n" % (file_name, file_name) )
|
||||||
except:
|
except:
|
||||||
print "No %s found, cannot fall back. Exiting.\n" % file_name
|
print "No %s found, cannot fall back. Exiting.\n" % file_name
|
||||||
sys.stderr.write("No %s found, cannot fall back. Exiting.\n" % file_name)
|
|
||||||
sys.exit()
|
sys.exit()
|
||||||
|
else:
|
||||||
|
print "No %s found, cannot fall back. Exiting.\n" % file_name
|
||||||
|
sys.stderr.write("No %s found, cannot fall back. Exiting.\n" % file_name)
|
||||||
|
sys.exit()
|
||||||
return file_name
|
return file_name
|
||||||
|
|
||||||
def get_logger(file_name, config = "config", fallback = False):
|
def get_logger(file_name, config = "config", fallback = False):
|
||||||
|
@ -94,18 +94,26 @@ def get_logger(file_name, config = "config", fallback = False):
|
||||||
try:
|
try:
|
||||||
logging.config.fileConfig(conf)
|
logging.config.fileConfig(conf)
|
||||||
log = logging.getLogger(config)
|
log = logging.getLogger(config)
|
||||||
log.debug("%s logger initialised" % config)
|
|
||||||
return log
|
return log
|
||||||
except:
|
except:
|
||||||
pass
|
pass
|
||||||
|
|
||||||
log = logging.basicConfig()
|
log = logging.basicConfig()
|
||||||
log = logging.getLogger()
|
log = logging.getLogger()
|
||||||
log.debug("config logger initialised")
|
log.error("basicConfig logger initialised")
|
||||||
return log
|
return log
|
||||||
|
|
||||||
# find a logging.conf file and set up logging
|
def check_dir(path, create = True):
|
||||||
log = get_logger("logging.conf")
|
"""Check if a dir exists, optionally creates if not."""
|
||||||
|
if os.path.exists(path):
|
||||||
|
if os.path.isdir(path):
|
||||||
|
return path
|
||||||
|
else:
|
||||||
|
return False
|
||||||
|
if create:
|
||||||
|
print "creating directory %s" % path
|
||||||
|
else:
|
||||||
|
return False
|
||||||
|
|
||||||
########################################################################
|
########################################################################
|
||||||
# application wide consts
|
# application wide consts
|
||||||
|
@ -113,19 +121,31 @@ log = get_logger("logging.conf")
|
||||||
APPLICATION_NAME_SHORT = 'fpdb'
|
APPLICATION_NAME_SHORT = 'fpdb'
|
||||||
APPLICATION_VERSION = 'xx.xx.xx'
|
APPLICATION_VERSION = 'xx.xx.xx'
|
||||||
|
|
||||||
DIR_SELF = os.path.dirname(get_exec_path())
|
DIR_SELF = get_exec_path()
|
||||||
#TODO: imo no good idea to place 'database' in parent dir
|
DIR_CONFIG = check_dir(get_default_config_path())
|
||||||
DIR_DATABASES = os.path.join(os.path.dirname(DIR_SELF), 'database')
|
DIR_DATABASE = check_dir(os.path.join(DIR_CONFIG, 'database'))
|
||||||
|
DIR_LOG = check_dir(os.path.join(DIR_CONFIG, 'log'))
|
||||||
|
|
||||||
DATABASE_TYPE_POSTGRESQL = 'postgresql'
|
DATABASE_TYPE_POSTGRESQL = 'postgresql'
|
||||||
DATABASE_TYPE_SQLITE = 'sqlite'
|
DATABASE_TYPE_SQLITE = 'sqlite'
|
||||||
DATABASE_TYPE_MYSQL = 'mysql'
|
DATABASE_TYPE_MYSQL = 'mysql'
|
||||||
|
#TODO: should this be a tuple or a dict
|
||||||
DATABASE_TYPES = (
|
DATABASE_TYPES = (
|
||||||
DATABASE_TYPE_POSTGRESQL,
|
DATABASE_TYPE_POSTGRESQL,
|
||||||
DATABASE_TYPE_SQLITE,
|
DATABASE_TYPE_SQLITE,
|
||||||
DATABASE_TYPE_MYSQL,
|
DATABASE_TYPE_MYSQL,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
# find a logging.conf file and set up logging
|
||||||
|
log = get_logger("logging.conf", config = "config")
|
||||||
|
log.debug("config logger initialised")
|
||||||
|
|
||||||
|
# and then log our consts
|
||||||
|
log.info("DIR SELF = %s" % DIR_SELF)
|
||||||
|
log.info("DIR CONFIG = %s" % DIR_CONFIG)
|
||||||
|
log.info("DIR DATABASE = %s" % DIR_DATABASE)
|
||||||
|
log.info("DIR LOG = %s" % DIR_LOG)
|
||||||
|
NEWIMPORT = True
|
||||||
LOCALE_ENCODING = locale.getdefaultlocale()[1]
|
LOCALE_ENCODING = locale.getdefaultlocale()[1]
|
||||||
|
|
||||||
########################################################################
|
########################################################################
|
||||||
|
@ -408,11 +428,10 @@ class Config:
|
||||||
if file is not None: # config file path passed in
|
if file is not None: # config file path passed in
|
||||||
file = os.path.expanduser(file)
|
file = os.path.expanduser(file)
|
||||||
if not os.path.exists(file):
|
if not os.path.exists(file):
|
||||||
print "Configuration file %s not found. Using defaults." % (file)
|
log.error("Specified configuration file %s not found. Using defaults." % (file))
|
||||||
sys.stderr.write("Configuration file %s not found. Using defaults." % (file))
|
|
||||||
file = None
|
file = None
|
||||||
|
|
||||||
if file is None: file = get_config("HUD_config.xml")
|
if file is None: file = get_config("HUD_config.xml", True)
|
||||||
|
|
||||||
# Parse even if there was no real config file found and we are using the example
|
# Parse even if there was no real config file found and we are using the example
|
||||||
# If using the example, we'll edit it later
|
# If using the example, we'll edit it later
|
||||||
|
@ -429,6 +448,8 @@ class Config:
|
||||||
|
|
||||||
self.doc = doc
|
self.doc = doc
|
||||||
self.file = file
|
self.file = file
|
||||||
|
self.dir = os.path.dirname(self.file)
|
||||||
|
self.dir_databases = os.path.join(self.dir, 'database')
|
||||||
self.supported_sites = {}
|
self.supported_sites = {}
|
||||||
self.supported_games = {}
|
self.supported_games = {}
|
||||||
self.supported_databases = {} # databaseName --> Database instance
|
self.supported_databases = {} # databaseName --> Database instance
|
||||||
|
|
|
@ -38,11 +38,31 @@ from decimal import Decimal
|
||||||
import string
|
import string
|
||||||
import re
|
import re
|
||||||
import Queue
|
import Queue
|
||||||
|
import codecs
|
||||||
|
import logging
|
||||||
|
import math
|
||||||
|
|
||||||
|
|
||||||
# pyGTK modules
|
# pyGTK modules
|
||||||
|
|
||||||
|
|
||||||
|
# Other library modules
|
||||||
|
try:
|
||||||
|
import sqlalchemy.pool as pool
|
||||||
|
use_pool = True
|
||||||
|
except ImportError:
|
||||||
|
logging.info("Not using sqlalchemy connection pool.")
|
||||||
|
use_pool = False
|
||||||
|
|
||||||
|
try:
|
||||||
|
from numpy import var
|
||||||
|
use_numpy = True
|
||||||
|
except ImportError:
|
||||||
|
logging.info("Not using numpy to define variance in sqlite.")
|
||||||
|
use_numpy = False
|
||||||
|
|
||||||
|
|
||||||
# FreePokerTools modules
|
# FreePokerTools modules
|
||||||
import fpdb_db
|
|
||||||
import Configuration
|
import Configuration
|
||||||
import SQL
|
import SQL
|
||||||
import Card
|
import Card
|
||||||
|
@ -50,7 +70,29 @@ import Tourney
|
||||||
import Charset
|
import Charset
|
||||||
from Exceptions import *
|
from Exceptions import *
|
||||||
|
|
||||||
log = Configuration.get_logger("logging.conf")
|
log = Configuration.get_logger("logging.conf", config = "db")
|
||||||
|
log.debug("db logger initialized.")
|
||||||
|
encoder = codecs.lookup('utf-8')
|
||||||
|
|
||||||
|
DB_VERSION = 119
|
||||||
|
|
||||||
|
|
||||||
|
# Variance created as sqlite has a bunch of undefined aggregate functions.
|
||||||
|
|
||||||
|
class VARIANCE:
|
||||||
|
def __init__(self):
|
||||||
|
self.store = []
|
||||||
|
|
||||||
|
def step(self, value):
|
||||||
|
self.store.append(value)
|
||||||
|
|
||||||
|
def finalize(self):
|
||||||
|
return float(var(self.store))
|
||||||
|
|
||||||
|
class sqlitemath:
|
||||||
|
def mod(self, a, b):
|
||||||
|
return a%b
|
||||||
|
|
||||||
|
|
||||||
class Database:
|
class Database:
|
||||||
|
|
||||||
|
@ -188,15 +230,14 @@ class Database:
|
||||||
log.info("Creating Database instance, sql = %s" % sql)
|
log.info("Creating Database instance, sql = %s" % sql)
|
||||||
self.config = c
|
self.config = c
|
||||||
self.__connected = False
|
self.__connected = False
|
||||||
self.fdb = fpdb_db.fpdb_db() # sets self.fdb.db self.fdb.cursor and self.fdb.sql
|
self.settings = {}
|
||||||
self.do_connect(c)
|
self.settings['os'] = "linuxmac" if os.name != "nt" else "windows"
|
||||||
|
db_params = c.get_db_parameters()
|
||||||
if self.backend == self.PGSQL:
|
self.import_options = c.get_import_parameters()
|
||||||
from psycopg2.extensions import ISOLATION_LEVEL_AUTOCOMMIT, ISOLATION_LEVEL_READ_COMMITTED, ISOLATION_LEVEL_SERIALIZABLE
|
self.backend = db_params['db-backend']
|
||||||
#ISOLATION_LEVEL_AUTOCOMMIT = 0
|
self.db_server = db_params['db-server']
|
||||||
#ISOLATION_LEVEL_READ_COMMITTED = 1
|
self.database = db_params['db-databaseName']
|
||||||
#ISOLATION_LEVEL_SERIALIZABLE = 2
|
self.host = db_params['db-host']
|
||||||
|
|
||||||
|
|
||||||
# where possible avoid creating new SQL instance by using the global one passed in
|
# where possible avoid creating new SQL instance by using the global one passed in
|
||||||
if sql is None:
|
if sql is None:
|
||||||
|
@ -204,6 +245,15 @@ class Database:
|
||||||
else:
|
else:
|
||||||
self.sql = sql
|
self.sql = sql
|
||||||
|
|
||||||
|
# connect to db
|
||||||
|
self.do_connect(c)
|
||||||
|
print "connection =", self.connection
|
||||||
|
if self.backend == self.PGSQL:
|
||||||
|
from psycopg2.extensions import ISOLATION_LEVEL_AUTOCOMMIT, ISOLATION_LEVEL_READ_COMMITTED, ISOLATION_LEVEL_SERIALIZABLE
|
||||||
|
#ISOLATION_LEVEL_AUTOCOMMIT = 0
|
||||||
|
#ISOLATION_LEVEL_READ_COMMITTED = 1
|
||||||
|
#ISOLATION_LEVEL_SERIALIZABLE = 2
|
||||||
|
|
||||||
if self.backend == self.SQLITE and self.database == ':memory:' and self.wrongDbVersion:
|
if self.backend == self.SQLITE and self.database == ':memory:' and self.wrongDbVersion:
|
||||||
log.info("sqlite/:memory: - creating")
|
log.info("sqlite/:memory: - creating")
|
||||||
self.recreate_tables()
|
self.recreate_tables()
|
||||||
|
@ -226,8 +276,6 @@ class Database:
|
||||||
self.h_date_ndays_ago = 'd000000' # date N days ago ('d' + YYMMDD) for hero
|
self.h_date_ndays_ago = 'd000000' # date N days ago ('d' + YYMMDD) for hero
|
||||||
self.date_nhands_ago = {} # dates N hands ago per player - not used yet
|
self.date_nhands_ago = {} # dates N hands ago per player - not used yet
|
||||||
|
|
||||||
self.cursor = self.fdb.cursor
|
|
||||||
|
|
||||||
self.saveActions = False if self.import_options['saveActions'] == False else True
|
self.saveActions = False if self.import_options['saveActions'] == False else True
|
||||||
|
|
||||||
self.connection.rollback() # make sure any locks taken so far are released
|
self.connection.rollback() # make sure any locks taken so far are released
|
||||||
|
@ -238,14 +286,20 @@ class Database:
|
||||||
self.hud_style = style
|
self.hud_style = style
|
||||||
|
|
||||||
def do_connect(self, c):
|
def do_connect(self, c):
|
||||||
|
if c is None:
|
||||||
|
raise FpdbError('Configuration not defined')
|
||||||
|
|
||||||
|
db = c.get_db_parameters()
|
||||||
try:
|
try:
|
||||||
self.fdb.do_connect(c)
|
self.connect(backend=db['db-backend'],
|
||||||
|
host=db['db-host'],
|
||||||
|
database=db['db-databaseName'],
|
||||||
|
user=db['db-user'],
|
||||||
|
password=db['db-password'])
|
||||||
except:
|
except:
|
||||||
# error during connect
|
# error during connect
|
||||||
self.__connected = False
|
self.__connected = False
|
||||||
raise
|
raise
|
||||||
self.connection = self.fdb.db
|
|
||||||
self.wrongDbVersion = self.fdb.wrongDbVersion
|
|
||||||
|
|
||||||
db_params = c.get_db_parameters()
|
db_params = c.get_db_parameters()
|
||||||
self.import_options = c.get_import_parameters()
|
self.import_options = c.get_import_parameters()
|
||||||
|
@ -255,11 +309,137 @@ class Database:
|
||||||
self.host = db_params['db-host']
|
self.host = db_params['db-host']
|
||||||
self.__connected = True
|
self.__connected = True
|
||||||
|
|
||||||
|
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
|
||||||
|
self.connection = None
|
||||||
|
self.cursor = None
|
||||||
|
|
||||||
|
if backend == Database.MYSQL_INNODB:
|
||||||
|
import MySQLdb
|
||||||
|
if use_pool:
|
||||||
|
MySQLdb = pool.manage(MySQLdb, pool_size=5)
|
||||||
|
try:
|
||||||
|
self.connection = MySQLdb.connect(host=host, user=user, passwd=password, db=database, use_unicode=True)
|
||||||
|
#TODO: Add port option
|
||||||
|
except MySQLdb.Error, ex:
|
||||||
|
if ex.args[0] == 1045:
|
||||||
|
raise FpdbMySQLAccessDenied(ex.args[0], ex.args[1])
|
||||||
|
elif ex.args[0] == 2002 or ex.args[0] == 2003: # 2002 is no unix socket, 2003 is no tcp socket
|
||||||
|
raise FpdbMySQLNoDatabase(ex.args[0], ex.args[1])
|
||||||
|
else:
|
||||||
|
print "*** WARNING UNKNOWN MYSQL ERROR", ex
|
||||||
|
elif backend == Database.PGSQL:
|
||||||
|
import psycopg2
|
||||||
|
import psycopg2.extensions
|
||||||
|
if use_pool:
|
||||||
|
psycopg2 = pool.manage(psycopg2, pool_size=5)
|
||||||
|
psycopg2.extensions.register_type(psycopg2.extensions.UNICODE)
|
||||||
|
# If DB connection is made over TCP, then the variables
|
||||||
|
# host, user and password are required
|
||||||
|
# For local domain-socket connections, only DB name is
|
||||||
|
# needed, and everything else is in fact undefined and/or
|
||||||
|
# flat out wrong
|
||||||
|
# sqlcoder: This database only connect failed in my windows setup??
|
||||||
|
# Modifed it to try the 4 parameter style if the first connect fails - does this work everywhere?
|
||||||
|
connected = False
|
||||||
|
if self.host == "localhost" or self.host == "127.0.0.1":
|
||||||
|
try:
|
||||||
|
self.connection = psycopg2.connect(database = database)
|
||||||
|
connected = True
|
||||||
|
except:
|
||||||
|
# direct connection failed so try user/pass/... version
|
||||||
|
pass
|
||||||
|
if not connected:
|
||||||
|
try:
|
||||||
|
self.connection = psycopg2.connect(host = host,
|
||||||
|
user = user,
|
||||||
|
password = password,
|
||||||
|
database = database)
|
||||||
|
except Exception, ex:
|
||||||
|
if 'Connection refused' in ex.args[0]:
|
||||||
|
# meaning eg. db not running
|
||||||
|
raise FpdbPostgresqlNoDatabase(errmsg = ex.args[0])
|
||||||
|
elif 'password authentication' in ex.args[0]:
|
||||||
|
raise FpdbPostgresqlAccessDenied(errmsg = ex.args[0])
|
||||||
|
else:
|
||||||
|
msg = ex.args[0]
|
||||||
|
print msg
|
||||||
|
raise FpdbError(msg)
|
||||||
|
elif backend == Database.SQLITE:
|
||||||
|
logging.info("Connecting to SQLite: %(database)s" % {'database':database})
|
||||||
|
import sqlite3
|
||||||
|
if use_pool:
|
||||||
|
sqlite3 = pool.manage(sqlite3, pool_size=1)
|
||||||
|
else:
|
||||||
|
logging.warning("SQLite won't work well without 'sqlalchemy' installed.")
|
||||||
|
|
||||||
|
if database != ":memory:":
|
||||||
|
if not os.path.isdir(self.config.dir_databases):
|
||||||
|
print "Creating directory: '%s'" % (self.config.dir_databases)
|
||||||
|
logging.info("Creating directory: '%s'" % (self.config.dir_databases))
|
||||||
|
os.mkdir(self.config.dir_databases)
|
||||||
|
database = os.path.join(self.config.dir_databases, database)
|
||||||
|
logging.info(" sqlite db: " + database)
|
||||||
|
self.connection = sqlite3.connect(database, detect_types=sqlite3.PARSE_DECLTYPES )
|
||||||
|
sqlite3.register_converter("bool", lambda x: bool(int(x)))
|
||||||
|
sqlite3.register_adapter(bool, lambda x: "1" if x else "0")
|
||||||
|
self.connection.create_function("floor", 1, math.floor)
|
||||||
|
tmp = sqlitemath()
|
||||||
|
self.connection.create_function("mod", 2, tmp.mod)
|
||||||
|
if use_numpy:
|
||||||
|
self.connection.create_aggregate("variance", 1, VARIANCE)
|
||||||
|
else:
|
||||||
|
logging.warning("Some database functions will not work without NumPy support")
|
||||||
|
else:
|
||||||
|
raise FpdbError("unrecognised database backend:"+backend)
|
||||||
|
|
||||||
|
self.cursor = self.connection.cursor()
|
||||||
|
self.cursor.execute(self.sql.query['set tx level'])
|
||||||
|
self.check_version(database=database, create=True)
|
||||||
|
|
||||||
|
|
||||||
|
def check_version(self, database, create):
|
||||||
|
self.wrongDbVersion = False
|
||||||
|
try:
|
||||||
|
self.cursor.execute("SELECT * FROM Settings")
|
||||||
|
settings = self.cursor.fetchone()
|
||||||
|
if settings[0] != DB_VERSION:
|
||||||
|
logging.error("outdated or too new database version (%s) - please recreate tables"
|
||||||
|
% (settings[0]))
|
||||||
|
self.wrongDbVersion = True
|
||||||
|
except:# _mysql_exceptions.ProgrammingError:
|
||||||
|
if database != ":memory:":
|
||||||
|
if create:
|
||||||
|
print "Failed to read settings table - recreating tables"
|
||||||
|
log.info("failed to read settings table - recreating tables")
|
||||||
|
self.recreate_tables()
|
||||||
|
self.check_version(database=database, create=False)
|
||||||
|
if not self.wrongDbVersion:
|
||||||
|
msg = "Edit your screen_name and hand history path in the supported_sites "\
|
||||||
|
+"section of the \nPreferences window (Main menu) before trying to import hands"
|
||||||
|
print "\n%s" % msg
|
||||||
|
log.warning(msg)
|
||||||
|
else:
|
||||||
|
print "Failed to read settings table - please recreate tables"
|
||||||
|
log.info("failed to read settings table - please recreate tables")
|
||||||
|
self.wrongDbVersion = True
|
||||||
|
else:
|
||||||
|
self.wrongDbVersion = True
|
||||||
|
#end def connect
|
||||||
|
|
||||||
def commit(self):
|
def commit(self):
|
||||||
self.fdb.db.commit()
|
self.connection.commit()
|
||||||
|
|
||||||
def rollback(self):
|
def rollback(self):
|
||||||
self.fdb.db.rollback()
|
self.connection.rollback()
|
||||||
|
|
||||||
def connected(self):
|
def connected(self):
|
||||||
return self.__connected
|
return self.__connected
|
||||||
|
@ -272,11 +452,18 @@ class Database:
|
||||||
|
|
||||||
def disconnect(self, due_to_error=False):
|
def disconnect(self, due_to_error=False):
|
||||||
"""Disconnects the DB (rolls back if param is true, otherwise commits"""
|
"""Disconnects the DB (rolls back if param is true, otherwise commits"""
|
||||||
self.fdb.disconnect(due_to_error)
|
if due_to_error:
|
||||||
|
self.connection.rollback()
|
||||||
|
else:
|
||||||
|
self.connection.commit()
|
||||||
|
self.cursor.close()
|
||||||
|
self.connection.close()
|
||||||
|
|
||||||
def reconnect(self, due_to_error=False):
|
def reconnect(self, due_to_error=False):
|
||||||
"""Reconnects the DB"""
|
"""Reconnects the DB"""
|
||||||
self.fdb.reconnect(due_to_error=False)
|
#print "started reconnect"
|
||||||
|
self.disconnect(due_to_error)
|
||||||
|
self.connect(self.backend, self.host, self.database, self.user, self.password)
|
||||||
|
|
||||||
def get_backend_name(self):
|
def get_backend_name(self):
|
||||||
"""Returns the name of the currently used backend"""
|
"""Returns the name of the currently used backend"""
|
||||||
|
@ -289,6 +476,9 @@ class Database:
|
||||||
else:
|
else:
|
||||||
raise FpdbError("invalid backend")
|
raise FpdbError("invalid backend")
|
||||||
|
|
||||||
|
def get_db_info(self):
|
||||||
|
return (self.host, self.database, self.user, self.password)
|
||||||
|
|
||||||
def get_table_name(self, hand_id):
|
def get_table_name(self, hand_id):
|
||||||
c = self.connection.cursor()
|
c = self.connection.cursor()
|
||||||
c.execute(self.sql.query['get_table_name'], (hand_id, ))
|
c.execute(self.sql.query['get_table_name'], (hand_id, ))
|
||||||
|
@ -844,6 +1034,7 @@ class Database:
|
||||||
self.create_tables()
|
self.create_tables()
|
||||||
self.createAllIndexes()
|
self.createAllIndexes()
|
||||||
self.commit()
|
self.commit()
|
||||||
|
print "Finished recreating tables"
|
||||||
log.info("Finished recreating tables")
|
log.info("Finished recreating tables")
|
||||||
#end def recreate_tables
|
#end def recreate_tables
|
||||||
|
|
||||||
|
@ -1109,7 +1300,7 @@ class Database:
|
||||||
|
|
||||||
def fillDefaultData(self):
|
def fillDefaultData(self):
|
||||||
c = self.get_cursor()
|
c = self.get_cursor()
|
||||||
c.execute("INSERT INTO Settings (version) VALUES (118);")
|
c.execute("INSERT INTO Settings (version) VALUES (%s);" % (DB_VERSION))
|
||||||
c.execute("INSERT INTO Sites (name,currency) VALUES ('Full Tilt Poker', 'USD')")
|
c.execute("INSERT INTO Sites (name,currency) VALUES ('Full Tilt Poker', 'USD')")
|
||||||
c.execute("INSERT INTO Sites (name,currency) VALUES ('PokerStars', 'USD')")
|
c.execute("INSERT INTO Sites (name,currency) VALUES ('PokerStars', 'USD')")
|
||||||
c.execute("INSERT INTO Sites (name,currency) VALUES ('Everleaf', 'USD')")
|
c.execute("INSERT INTO Sites (name,currency) VALUES ('Everleaf', 'USD')")
|
||||||
|
@ -1265,7 +1456,7 @@ class Database:
|
||||||
try:
|
try:
|
||||||
self.get_cursor().execute(self.sql.query['lockForInsert'])
|
self.get_cursor().execute(self.sql.query['lockForInsert'])
|
||||||
except:
|
except:
|
||||||
print "Error during fdb.lock_for_insert:", str(sys.exc_value)
|
print "Error during lock_for_insert:", str(sys.exc_value)
|
||||||
#end def lock_for_insert
|
#end def lock_for_insert
|
||||||
|
|
||||||
###########################
|
###########################
|
||||||
|
@ -1284,6 +1475,7 @@ class Database:
|
||||||
p['tableName'],
|
p['tableName'],
|
||||||
p['gameTypeId'],
|
p['gameTypeId'],
|
||||||
p['siteHandNo'],
|
p['siteHandNo'],
|
||||||
|
0, # tourneyId: 0 means not a tourney hand
|
||||||
p['handStart'],
|
p['handStart'],
|
||||||
datetime.today(), #importtime
|
datetime.today(), #importtime
|
||||||
p['seats'],
|
p['seats'],
|
||||||
|
|
|
@ -27,8 +27,8 @@ import gobject
|
||||||
#import pokereval
|
#import pokereval
|
||||||
|
|
||||||
import Configuration
|
import Configuration
|
||||||
import fpdb_db
|
import Database
|
||||||
import FpdbSQLQueries
|
import SQL
|
||||||
import Charset
|
import Charset
|
||||||
|
|
||||||
class Filters(threading.Thread):
|
class Filters(threading.Thread):
|
||||||
|
@ -800,10 +800,10 @@ def main(argv=None):
|
||||||
config = Configuration.Config()
|
config = Configuration.Config()
|
||||||
db = None
|
db = None
|
||||||
|
|
||||||
db = fpdb_db.fpdb_db()
|
db = Database.Database()
|
||||||
db.do_connect(config)
|
db.do_connect(config)
|
||||||
|
|
||||||
qdict = FpdbSQLQueries.FpdbSQLQueries(db.get_backend_name())
|
qdict = SQL.SQL(db.get_backend_name())
|
||||||
|
|
||||||
i = Filters(db, config, qdict)
|
i = Filters(db, config, qdict)
|
||||||
main_window = gtk.Window()
|
main_window = gtk.Window()
|
||||||
|
|
|
@ -18,12 +18,10 @@
|
||||||
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||||
########################################################################
|
########################################################################
|
||||||
|
|
||||||
import sys
|
|
||||||
import logging
|
import logging
|
||||||
from HandHistoryConverter import *
|
from HandHistoryConverter import *
|
||||||
|
|
||||||
# Fulltilt HH Format converter
|
# Fulltilt HH Format converter
|
||||||
# TODO: cat tourno and table to make table name for tournaments
|
|
||||||
|
|
||||||
class Fulltilt(HandHistoryConverter):
|
class Fulltilt(HandHistoryConverter):
|
||||||
|
|
||||||
|
@ -67,8 +65,8 @@ class Fulltilt(HandHistoryConverter):
|
||||||
(\s\((?P<TURBO>Turbo)\))?)|(?P<UNREADABLE_INFO>.+))
|
(\s\((?P<TURBO>Turbo)\))?)|(?P<UNREADABLE_INFO>.+))
|
||||||
''', re.VERBOSE)
|
''', re.VERBOSE)
|
||||||
re_Button = re.compile('^The button is in seat #(?P<BUTTON>\d+)', re.MULTILINE)
|
re_Button = re.compile('^The button is in seat #(?P<BUTTON>\d+)', re.MULTILINE)
|
||||||
re_PlayerInfo = re.compile('Seat (?P<SEAT>[0-9]+): (?P<PNAME>.*) \(\$(?P<CASH>[,.0-9]+)\)$', re.MULTILINE)
|
re_PlayerInfo = re.compile('Seat (?P<SEAT>[0-9]+): (?P<PNAME>.*) (?! collected )?\(\$(?P<CASH>[,.0-9]+)\)$', re.MULTILINE)
|
||||||
re_TourneyPlayerInfo = re.compile('Seat (?P<SEAT>[0-9]+): (?P<PNAME>.*) \(\$?(?P<CASH>[,.0-9]+)\)(, is sitting out)?$', re.MULTILINE)
|
re_TourneyPlayerInfo = re.compile('Seat (?P<SEAT>[0-9]+): (?P<PNAME>.*) (?! collected )?\(\$?(?P<CASH>[,.0-9]+)\)(, is sitting out)?$', re.MULTILINE)
|
||||||
re_Board = re.compile(r"\[(?P<CARDS>.+)\]")
|
re_Board = re.compile(r"\[(?P<CARDS>.+)\]")
|
||||||
|
|
||||||
#static regex for tourney purpose
|
#static regex for tourney purpose
|
||||||
|
@ -114,6 +112,7 @@ class Fulltilt(HandHistoryConverter):
|
||||||
# These regexes are for FTP only
|
# These regexes are for FTP only
|
||||||
re_Mixed = re.compile(r'\s\-\s(?P<MIXED>HA|HORSE|HOSE)\s\-\s', re.VERBOSE)
|
re_Mixed = re.compile(r'\s\-\s(?P<MIXED>HA|HORSE|HOSE)\s\-\s', re.VERBOSE)
|
||||||
re_Max = re.compile("(?P<MAX>\d+)( max)?", re.MULTILINE)
|
re_Max = re.compile("(?P<MAX>\d+)( max)?", re.MULTILINE)
|
||||||
|
re_Collected = re.compile(" collected")
|
||||||
# NB: if we ever match "Full Tilt Poker" we should also match "FullTiltPoker", which PT Stud erroneously exports.
|
# NB: if we ever match "Full Tilt Poker" we should also match "FullTiltPoker", which PT Stud erroneously exports.
|
||||||
|
|
||||||
|
|
||||||
|
@ -191,7 +190,6 @@ class Fulltilt(HandHistoryConverter):
|
||||||
if mg['TOURNO'] is None: info['type'] = "ring"
|
if mg['TOURNO'] is None: info['type'] = "ring"
|
||||||
else: info['type'] = "tour"
|
else: info['type'] = "tour"
|
||||||
# NB: SB, BB must be interpreted as blinds or bets depending on limit type.
|
# NB: SB, BB must be interpreted as blinds or bets depending on limit type.
|
||||||
# if info['type'] == "tour": return None # importer is screwed on tournies, pass on those hands so we don't interrupt other autoimporting
|
|
||||||
return info
|
return info
|
||||||
|
|
||||||
def readHandInfo(self, hand):
|
def readHandInfo(self, hand):
|
||||||
|
@ -258,7 +256,6 @@ class Fulltilt(HandHistoryConverter):
|
||||||
#TODO: Need some date functions to convert to different timezones (Date::Manip for perl rocked for this)
|
#TODO: Need some date functions to convert to different timezones (Date::Manip for perl rocked for this)
|
||||||
#hand.starttime = "%d/%02d/%02d %d:%02d:%02d ET" %(int(m.group('YEAR')), int(m.group('MON')), int(m.group('DAY')),
|
#hand.starttime = "%d/%02d/%02d %d:%02d:%02d ET" %(int(m.group('YEAR')), int(m.group('MON')), int(m.group('DAY')),
|
||||||
##int(m.group('HR')), int(m.group('MIN')), int(m.group('SEC')))
|
##int(m.group('HR')), int(m.group('MIN')), int(m.group('SEC')))
|
||||||
#FIXME: hand.buttonpos = int(m.group('BUTTON'))
|
|
||||||
|
|
||||||
def readPlayerStacks(self, hand):
|
def readPlayerStacks(self, hand):
|
||||||
if hand.gametype['type'] == "ring" :
|
if hand.gametype['type'] == "ring" :
|
||||||
|
@ -266,7 +263,6 @@ class Fulltilt(HandHistoryConverter):
|
||||||
else: #if hand.gametype['type'] == "tour"
|
else: #if hand.gametype['type'] == "tour"
|
||||||
m = self.re_TourneyPlayerInfo.finditer(hand.handText)
|
m = self.re_TourneyPlayerInfo.finditer(hand.handText)
|
||||||
|
|
||||||
players = []
|
|
||||||
for a in m:
|
for a in m:
|
||||||
hand.addPlayer(int(a.group('SEAT')), a.group('PNAME'), a.group('CASH'))
|
hand.addPlayer(int(a.group('SEAT')), a.group('PNAME'), a.group('CASH'))
|
||||||
|
|
||||||
|
@ -422,7 +418,6 @@ class Fulltilt(HandHistoryConverter):
|
||||||
hand.mixed = self.mixes[m.groupdict()['MIXED']]
|
hand.mixed = self.mixes[m.groupdict()['MIXED']]
|
||||||
|
|
||||||
def readSummaryInfo(self, summaryInfoList):
|
def readSummaryInfo(self, summaryInfoList):
|
||||||
starttime = time.time()
|
|
||||||
self.status = True
|
self.status = True
|
||||||
|
|
||||||
m = re.search("Tournament Summary", summaryInfoList[0])
|
m = re.search("Tournament Summary", summaryInfoList[0])
|
||||||
|
@ -542,14 +537,14 @@ class Fulltilt(HandHistoryConverter):
|
||||||
tourney.buyin = 100*Decimal(re.sub(u',', u'', "%s" % mg['BUYIN']))
|
tourney.buyin = 100*Decimal(re.sub(u',', u'', "%s" % mg['BUYIN']))
|
||||||
else :
|
else :
|
||||||
if 100*Decimal(re.sub(u',', u'', "%s" % mg['BUYIN'])) != tourney.buyin:
|
if 100*Decimal(re.sub(u',', u'', "%s" % mg['BUYIN'])) != tourney.buyin:
|
||||||
log.error( "Conflict between buyins read in topline (%s) and in BuyIn field (%s)" % (touney.buyin, 100*Decimal(re.sub(u',', u'', "%s" % mg['BUYIN']))) )
|
log.error( "Conflict between buyins read in topline (%s) and in BuyIn field (%s)" % (tourney.buyin, 100*Decimal(re.sub(u',', u'', "%s" % mg['BUYIN']))) )
|
||||||
tourney.subTourneyBuyin = 100*Decimal(re.sub(u',', u'', "%s" % mg['BUYIN']))
|
tourney.subTourneyBuyin = 100*Decimal(re.sub(u',', u'', "%s" % mg['BUYIN']))
|
||||||
if mg['FEE'] is not None:
|
if mg['FEE'] is not None:
|
||||||
if tourney.fee is None:
|
if tourney.fee is None:
|
||||||
tourney.fee = 100*Decimal(re.sub(u',', u'', "%s" % mg['FEE']))
|
tourney.fee = 100*Decimal(re.sub(u',', u'', "%s" % mg['FEE']))
|
||||||
else :
|
else :
|
||||||
if 100*Decimal(re.sub(u',', u'', "%s" % mg['FEE'])) != tourney.fee:
|
if 100*Decimal(re.sub(u',', u'', "%s" % mg['FEE'])) != tourney.fee:
|
||||||
log.error( "Conflict between fees read in topline (%s) and in BuyIn field (%s)" % (touney.fee, 100*Decimal(re.sub(u',', u'', "%s" % mg['FEE']))) )
|
log.error( "Conflict between fees read in topline (%s) and in BuyIn field (%s)" % (tourney.fee, 100*Decimal(re.sub(u',', u'', "%s" % mg['FEE']))) )
|
||||||
tourney.subTourneyFee = 100*Decimal(re.sub(u',', u'', "%s" % mg['FEE']))
|
tourney.subTourneyFee = 100*Decimal(re.sub(u',', u'', "%s" % mg['FEE']))
|
||||||
|
|
||||||
if tourney.buyin is None:
|
if tourney.buyin is None:
|
||||||
|
|
|
@ -300,7 +300,6 @@ if __name__== "__main__":
|
||||||
(options, argv) = parser.parse_args()
|
(options, argv) = parser.parse_args()
|
||||||
|
|
||||||
config = Configuration.Config()
|
config = Configuration.Config()
|
||||||
# db = fpdb_db.fpdb_db()
|
|
||||||
|
|
||||||
settings = {}
|
settings = {}
|
||||||
settings['minPrint'] = options.minPrint
|
settings['minPrint'] = options.minPrint
|
||||||
|
|
|
@ -27,7 +27,6 @@ from time import time, strftime
|
||||||
import Card
|
import Card
|
||||||
import fpdb_import
|
import fpdb_import
|
||||||
import Database
|
import Database
|
||||||
import fpdb_db
|
|
||||||
import Filters
|
import Filters
|
||||||
import Charset
|
import Charset
|
||||||
|
|
||||||
|
|
|
@ -588,8 +588,8 @@ Left-Drag to Move"
|
||||||
</hhcs>
|
</hhcs>
|
||||||
|
|
||||||
<supported_databases>
|
<supported_databases>
|
||||||
<database db_name="fpdb" db_server="mysql" db_ip="localhost" db_user="fpdb" db_pass="YOUR MYSQL PASSWORD"></database>
|
<!-- <database db_name="fpdb" db_server="mysql" db_ip="localhost" db_user="fpdb" db_pass="YOUR MYSQL PASSWORD"></database> -->
|
||||||
<!-- <database db_ip="localhost" db_name="fpdb" db_pass="fpdb" db_server="sqlite" db_user="fpdb"/> -->
|
<database db_ip="localhost" db_server="sqlite" db_name="fpdb.db3" db_user="fpdb" db_pass="fpdb"/>
|
||||||
</supported_databases>
|
</supported_databases>
|
||||||
|
|
||||||
</FreePokerToolsConfig>
|
</FreePokerToolsConfig>
|
||||||
|
|
|
@ -36,9 +36,7 @@ import traceback
|
||||||
(options, argv) = Options.fpdb_options()
|
(options, argv) = Options.fpdb_options()
|
||||||
|
|
||||||
if not options.errorsToConsole:
|
if not options.errorsToConsole:
|
||||||
print "Note: error output is being diverted to fpdb-error-log.txt and HUD-error.txt. Any major error will be reported there _only_."
|
print "Note: error output is being logged. Any major error will be reported there _only_."
|
||||||
errorFile = open('HUD-error.txt', 'w', 0)
|
|
||||||
sys.stderr = errorFile
|
|
||||||
|
|
||||||
import thread
|
import thread
|
||||||
import time
|
import time
|
||||||
|
@ -52,6 +50,13 @@ import gobject
|
||||||
|
|
||||||
# FreePokerTools modules
|
# FreePokerTools modules
|
||||||
import Configuration
|
import Configuration
|
||||||
|
|
||||||
|
print "start logging"
|
||||||
|
log = Configuration.get_logger("logging.conf", config = 'hud')
|
||||||
|
log.debug("%s logger initialized." % "dud")
|
||||||
|
print "logging started"
|
||||||
|
|
||||||
|
|
||||||
import Database
|
import Database
|
||||||
from HandHistoryConverter import getTableTitleRe
|
from HandHistoryConverter import getTableTitleRe
|
||||||
# get the correct module for the current os
|
# get the correct module for the current os
|
||||||
|
@ -72,6 +77,7 @@ class HUD_main(object):
|
||||||
|
|
||||||
def __init__(self, db_name = 'fpdb'):
|
def __init__(self, db_name = 'fpdb'):
|
||||||
self.db_name = db_name
|
self.db_name = db_name
|
||||||
|
self.log = log
|
||||||
self.config = Configuration.Config(file=options.config, dbname=options.dbname)
|
self.config = Configuration.Config(file=options.config, dbname=options.dbname)
|
||||||
self.hud_dict = {}
|
self.hud_dict = {}
|
||||||
self.hud_params = self.config.get_hud_ui_parameters()
|
self.hud_params = self.config.get_hud_ui_parameters()
|
||||||
|
@ -91,6 +97,7 @@ class HUD_main(object):
|
||||||
self.main_window.show_all()
|
self.main_window.show_all()
|
||||||
|
|
||||||
def destroy(self, *args): # call back for terminating the main eventloop
|
def destroy(self, *args): # call back for terminating the main eventloop
|
||||||
|
self.log.info("Terminating normally.")
|
||||||
gtk.main_quit()
|
gtk.main_quit()
|
||||||
|
|
||||||
def kill_hud(self, event, table):
|
def kill_hud(self, event, table):
|
||||||
|
@ -198,6 +205,7 @@ class HUD_main(object):
|
||||||
t0 = time.time()
|
t0 = time.time()
|
||||||
t1 = t2 = t3 = t4 = t5 = t6 = t0
|
t1 = t2 = t3 = t4 = t5 = t6 = t0
|
||||||
new_hand_id = string.rstrip(new_hand_id)
|
new_hand_id = string.rstrip(new_hand_id)
|
||||||
|
self.log.debug("Received hand no %s" % new_hand_id)
|
||||||
if new_hand_id == "": # blank line means quit
|
if new_hand_id == "": # blank line means quit
|
||||||
self.destroy()
|
self.destroy()
|
||||||
break # this thread is not always killed immediately with gtk.main_quit()
|
break # this thread is not always killed immediately with gtk.main_quit()
|
||||||
|
@ -207,9 +215,8 @@ class HUD_main(object):
|
||||||
try:
|
try:
|
||||||
(table_name, max, poker_game, type, site_id, site_name, num_seats, tour_number, tab_number) = \
|
(table_name, max, poker_game, type, site_id, site_name, num_seats, tour_number, tab_number) = \
|
||||||
self.db_connection.get_table_info(new_hand_id)
|
self.db_connection.get_table_info(new_hand_id)
|
||||||
except Exception, err: # TODO: we need to make this a much less generic Exception lulz
|
except Exception, err:
|
||||||
print "db error: skipping %s" % new_hand_id
|
self.log.error("db error: skipping %s" % new_hand_id)
|
||||||
sys.stderr.write("Database error: could not find hand %s.\n" % new_hand_id)
|
|
||||||
continue
|
continue
|
||||||
t1 = time.time()
|
t1 = time.time()
|
||||||
|
|
||||||
|
@ -267,7 +274,8 @@ class HUD_main(object):
|
||||||
# If no client window is found on the screen, complain and continue
|
# If no client window is found on the screen, complain and continue
|
||||||
if type == "tour":
|
if type == "tour":
|
||||||
table_name = "%s %s" % (tour_number, tab_number)
|
table_name = "%s %s" % (tour_number, tab_number)
|
||||||
sys.stderr.write("HUD create: table name "+table_name+" not found, skipping.\n")
|
# sys.stderr.write("HUD create: table name "+table_name+" not found, skipping.\n")
|
||||||
|
self.log.error("HUD create: table name %s not found, skipping." % table_name)
|
||||||
else:
|
else:
|
||||||
tablewindow.max = max
|
tablewindow.max = max
|
||||||
tablewindow.site = site_name
|
tablewindow.site = site_name
|
||||||
|
@ -284,8 +292,8 @@ class HUD_main(object):
|
||||||
|
|
||||||
if __name__== "__main__":
|
if __name__== "__main__":
|
||||||
|
|
||||||
sys.stderr.write("HUD_main starting\n")
|
log.info("HUD_main starting")
|
||||||
sys.stderr.write("Using db name = %s\n" % (options.dbname))
|
log.info("Using db name = %s" % (options.dbname))
|
||||||
|
|
||||||
# start the HUD_main object
|
# start the HUD_main object
|
||||||
hm = HUD_main(db_name = options.dbname)
|
hm = HUD_main(db_name = options.dbname)
|
||||||
|
|
|
@ -205,7 +205,7 @@ dealt whether they were seen in a 'dealt to' line
|
||||||
def insert(self, db):
|
def insert(self, db):
|
||||||
""" Function to insert Hand into database
|
""" Function to insert Hand into database
|
||||||
Should not commit, and do minimal selects. Callers may want to cache commits
|
Should not commit, and do minimal selects. Callers may want to cache commits
|
||||||
db: a connected fpdb_db object"""
|
db: a connected Database object"""
|
||||||
|
|
||||||
|
|
||||||
self.stats.getStats(self)
|
self.stats.getStats(self)
|
||||||
|
@ -396,7 +396,7 @@ Add a raise on [street] by [player] to [amountTo]
|
||||||
Bc = reduce(operator.add, self.bets[street][player], 0)
|
Bc = reduce(operator.add, self.bets[street][player], 0)
|
||||||
Rt = Decimal(amountTo)
|
Rt = Decimal(amountTo)
|
||||||
C = Bp - Bc
|
C = Bp - Bc
|
||||||
Rb = Rt - C
|
Rb = Rt - C - Bc
|
||||||
self._addRaise(street, player, C, Rb, Rt)
|
self._addRaise(street, player, C, Rb, Rt)
|
||||||
|
|
||||||
def _addRaise(self, street, player, C, Rb, Rt):
|
def _addRaise(self, street, player, C, Rb, Rt):
|
||||||
|
|
|
@ -26,29 +26,21 @@ from HandHistoryConverter import *
|
||||||
|
|
||||||
# PartyPoker HH Format
|
# PartyPoker HH Format
|
||||||
|
|
||||||
class PartyPokerParseError(FpdbParseError):
|
class FpdbParseError(FpdbParseError):
|
||||||
"Usage: raise PartyPokerParseError(<msg>[, hh=<hh>][, hid=<hid>])"
|
"Usage: raise FpdbParseError(<msg>[, hh=<hh>][, hid=<hid>])"
|
||||||
|
|
||||||
def __init__(self, msg='', hh=None, hid=None):
|
def __init__(self, msg='', hh=None, hid=None):
|
||||||
if hh is not None:
|
return super(FpdbParseError, self).__init__(msg, hid=hid)
|
||||||
msg += "\n\nHand history attached below:\n" + self.wrapHh(hh)
|
|
||||||
return super(PartyPokerParseError, self).__init__(msg, hid=hid)
|
|
||||||
|
|
||||||
def wrapHh(self, hh):
|
def wrapHh(self, hh):
|
||||||
return ("%(DELIMETER)s\n%(HH)s\n%(DELIMETER)s") % \
|
return ("%(DELIMETER)s\n%(HH)s\n%(DELIMETER)s") % \
|
||||||
{'DELIMETER': '#'*50, 'HH': hh}
|
{'DELIMETER': '#'*50, 'HH': hh}
|
||||||
|
|
||||||
class PartyPoker(HandHistoryConverter):
|
class PartyPoker(HandHistoryConverter):
|
||||||
|
|
||||||
############################################################
|
|
||||||
# Class Variables
|
|
||||||
|
|
||||||
sitename = "PartyPoker"
|
sitename = "PartyPoker"
|
||||||
codepage = "cp1252"
|
codepage = "cp1252"
|
||||||
siteId = 9 # TODO: automate; it's a class variable so shouldn't hit DB too often
|
siteId = 9
|
||||||
filetype = "text" # "text" or "xml". I propose we subclass HHC to HHC_Text and HHC_XML.
|
filetype = "text"
|
||||||
|
|
||||||
|
|
||||||
sym = {'USD': "\$", }
|
sym = {'USD': "\$", }
|
||||||
|
|
||||||
# Static regexes
|
# Static regexes
|
||||||
|
@ -92,9 +84,9 @@ class PartyPoker(HandHistoryConverter):
|
||||||
\((?P<PLAY>Real|Play)\s+Money\)\s+ # FIXME: check if play money is correct
|
\((?P<PLAY>Real|Play)\s+Money\)\s+ # FIXME: check if play money is correct
|
||||||
Seat\s+(?P<BUTTON>\d+)\sis\sthe\sbutton
|
Seat\s+(?P<BUTTON>\d+)\sis\sthe\sbutton
|
||||||
""",
|
""",
|
||||||
re.MULTILINE|re.VERBOSE)
|
re.VERBOSE|re.MULTILINE)
|
||||||
|
|
||||||
# re_TotalPlayers = re.compile("^Total\s+number\s+of\s+players\s*:\s*(?P<MAXSEATS>\d+)", re.MULTILINE)
|
re_CountedSeats = re.compile("^Total\s+number\s+of\s+players\s*:\s*(?P<COUNTED_SEATS>\d+)", re.MULTILINE)
|
||||||
re_SplitHands = re.compile('\x00+')
|
re_SplitHands = re.compile('\x00+')
|
||||||
re_TailSplitHands = re.compile('(\x00+)')
|
re_TailSplitHands = re.compile('(\x00+)')
|
||||||
lineSplitter = '\n'
|
lineSplitter = '\n'
|
||||||
|
@ -131,16 +123,12 @@ class PartyPoker(HandHistoryConverter):
|
||||||
'CUR': hand.gametype['currency'] if hand.gametype['currency']!='T$' else ''}
|
'CUR': hand.gametype['currency'] if hand.gametype['currency']!='T$' else ''}
|
||||||
for key in ('CUR_SYM', 'CUR'):
|
for key in ('CUR_SYM', 'CUR'):
|
||||||
subst[key] = re.escape(subst[key])
|
subst[key] = re.escape(subst[key])
|
||||||
log.debug("player_re: '%s'" % subst['PLYR'])
|
|
||||||
log.debug("CUR_SYM: '%s'" % subst['CUR_SYM'])
|
|
||||||
log.debug("CUR: '%s'" % subst['CUR'])
|
|
||||||
self.re_PostSB = re.compile(
|
self.re_PostSB = re.compile(
|
||||||
r"^%(PLYR)s posts small blind \[%(CUR_SYM)s(?P<SB>[.,0-9]+) ?%(CUR)s\]\." % subst,
|
r"^%(PLYR)s posts small blind \[%(CUR_SYM)s(?P<SB>[.,0-9]+) ?%(CUR)s\]\." % subst,
|
||||||
re.MULTILINE)
|
re.MULTILINE)
|
||||||
self.re_PostBB = re.compile(
|
self.re_PostBB = re.compile(
|
||||||
r"^%(PLYR)s posts big blind \[%(CUR_SYM)s(?P<BB>[.,0-9]+) ?%(CUR)s\]\." % subst,
|
r"^%(PLYR)s posts big blind \[%(CUR_SYM)s(?P<BB>[.,0-9]+) ?%(CUR)s\]\." % subst,
|
||||||
re.MULTILINE)
|
re.MULTILINE)
|
||||||
# NOTE: comma is used as a fraction part delimeter in re below
|
|
||||||
self.re_PostDead = re.compile(
|
self.re_PostDead = re.compile(
|
||||||
r"^%(PLYR)s posts big blind \+ dead \[(?P<BBNDEAD>[.,0-9]+) ?%(CUR_SYM)s\]\." % subst,
|
r"^%(PLYR)s posts big blind \+ dead \[(?P<BBNDEAD>[.,0-9]+) ?%(CUR_SYM)s\]\." % subst,
|
||||||
re.MULTILINE)
|
re.MULTILINE)
|
||||||
|
@ -195,8 +183,6 @@ class PartyPoker(HandHistoryConverter):
|
||||||
gametype dict is:
|
gametype dict is:
|
||||||
{'limitType': xxx, 'base': xxx, 'category': xxx}"""
|
{'limitType': xxx, 'base': xxx, 'category': xxx}"""
|
||||||
|
|
||||||
log.debug(PartyPokerParseError().wrapHh( handText ))
|
|
||||||
|
|
||||||
info = {}
|
info = {}
|
||||||
m = self._getGameType(handText)
|
m = self._getGameType(handText)
|
||||||
if m is None:
|
if m is None:
|
||||||
|
@ -213,22 +199,16 @@ class PartyPoker(HandHistoryConverter):
|
||||||
|
|
||||||
for expectedField in ['LIMIT', 'GAME']:
|
for expectedField in ['LIMIT', 'GAME']:
|
||||||
if mg[expectedField] is None:
|
if mg[expectedField] is None:
|
||||||
raise PartyPokerParseError(
|
raise FpdbParseError( "Cannot fetch field '%s'" % expectedField)
|
||||||
"Cannot fetch field '%s'" % expectedField,
|
|
||||||
hh = handText)
|
|
||||||
try:
|
try:
|
||||||
info['limitType'] = limits[mg['LIMIT'].strip()]
|
info['limitType'] = limits[mg['LIMIT'].strip()]
|
||||||
except:
|
except:
|
||||||
raise PartyPokerParseError(
|
raise FpdbParseError("Unknown limit '%s'" % mg['LIMIT'])
|
||||||
"Unknown limit '%s'" % mg['LIMIT'],
|
|
||||||
hh = handText)
|
|
||||||
|
|
||||||
try:
|
try:
|
||||||
(info['base'], info['category']) = games[mg['GAME']]
|
(info['base'], info['category']) = games[mg['GAME']]
|
||||||
except:
|
except:
|
||||||
raise PartyPokerParseError(
|
raise FpdbParseError("Unknown game type '%s'" % mg['GAME'])
|
||||||
"Unknown game type '%s'" % mg['GAME'],
|
|
||||||
hh = handText)
|
|
||||||
|
|
||||||
if 'TOURNO' in mg:
|
if 'TOURNO' in mg:
|
||||||
info['type'] = 'tour'
|
info['type'] = 'tour'
|
||||||
|
@ -251,23 +231,21 @@ class PartyPoker(HandHistoryConverter):
|
||||||
try:
|
try:
|
||||||
info.update(self.re_Hid.search(hand.handText).groupdict())
|
info.update(self.re_Hid.search(hand.handText).groupdict())
|
||||||
except:
|
except:
|
||||||
raise PartyPokerParseError("Cannot read HID for current hand", hh=hand.handText)
|
raise FpdbParseError("Cannot read HID for current hand")
|
||||||
|
|
||||||
try:
|
try:
|
||||||
info.update(self.re_HandInfo.search(hand.handText,re.DOTALL).groupdict())
|
info.update(self.re_HandInfo.search(hand.handText,re.DOTALL).groupdict())
|
||||||
except:
|
except:
|
||||||
raise PartyPokerParseError("Cannot read Handinfo for current hand",
|
raise FpdbParseError("Cannot read Handinfo for current hand", hid = info['HID'])
|
||||||
hh=hand.handText, hid = info['HID'])
|
|
||||||
|
|
||||||
try:
|
try:
|
||||||
info.update(self._getGameType(hand.handText).groupdict())
|
info.update(self._getGameType(hand.handText).groupdict())
|
||||||
except:
|
except:
|
||||||
raise PartyPokerParseError("Cannot read GameType for current hand",
|
raise FpdbParseError("Cannot read GameType for current hand", hid = info['HID'])
|
||||||
hh=hand.handText, hid = info['HID'])
|
|
||||||
|
|
||||||
|
|
||||||
# m = self.re_TotalPlayers.search(hand.handText)
|
m = self.re_CountedSeats.search(hand.handText)
|
||||||
# if m: info.update(m.groupdict())
|
if m: info.update(m.groupdict())
|
||||||
|
|
||||||
|
|
||||||
# FIXME: it's dirty hack
|
# FIXME: it's dirty hack
|
||||||
|
@ -294,6 +272,7 @@ class PartyPoker(HandHistoryConverter):
|
||||||
if key == 'DATETIME':
|
if key == 'DATETIME':
|
||||||
#Saturday, July 25, 07:53:52 EDT 2009
|
#Saturday, July 25, 07:53:52 EDT 2009
|
||||||
#Thursday, July 30, 21:40:41 MSKS 2009
|
#Thursday, July 30, 21:40:41 MSKS 2009
|
||||||
|
#Sunday, October 25, 13:39:07 MSK 2009
|
||||||
m2 = re.search("\w+, (?P<M>\w+) (?P<D>\d+), (?P<H>\d+):(?P<MIN>\d+):(?P<S>\d+) (?P<TZ>[A-Z]+) (?P<Y>\d+)", info[key])
|
m2 = re.search("\w+, (?P<M>\w+) (?P<D>\d+), (?P<H>\d+):(?P<MIN>\d+):(?P<S>\d+) (?P<TZ>[A-Z]+) (?P<Y>\d+)", info[key])
|
||||||
# we cant use '%B' due to locale problems
|
# we cant use '%B' due to locale problems
|
||||||
months = ['January', 'February', 'March', 'April','May', 'June',
|
months = ['January', 'February', 'March', 'April','May', 'June',
|
||||||
|
@ -317,6 +296,10 @@ class PartyPoker(HandHistoryConverter):
|
||||||
hand.buttonpos = info[key]
|
hand.buttonpos = info[key]
|
||||||
if key == 'TOURNO':
|
if key == 'TOURNO':
|
||||||
hand.tourNo = info[key]
|
hand.tourNo = info[key]
|
||||||
|
if key == 'TABLE_ID_WRAPPER':
|
||||||
|
if info[key] == '#':
|
||||||
|
# FIXME: there is no such property in Hand class
|
||||||
|
self.isSNG = True
|
||||||
if key == 'BUYIN':
|
if key == 'BUYIN':
|
||||||
# FIXME: it's dirty hack T_T
|
# FIXME: it's dirty hack T_T
|
||||||
# code below assumes that tournament rake is equal to zero
|
# code below assumes that tournament rake is equal to zero
|
||||||
|
@ -328,7 +311,7 @@ class PartyPoker(HandHistoryConverter):
|
||||||
if key == 'LEVEL':
|
if key == 'LEVEL':
|
||||||
hand.level = info[key]
|
hand.level = info[key]
|
||||||
if key == 'PLAY' and info['PLAY'] != 'Real':
|
if key == 'PLAY' and info['PLAY'] != 'Real':
|
||||||
# if realy there's no play money hh on party
|
# if realy party doesn's save play money hh
|
||||||
hand.gametype['currency'] = 'play'
|
hand.gametype['currency'] = 'play'
|
||||||
|
|
||||||
def readButton(self, hand):
|
def readButton(self, hand):
|
||||||
|
@ -413,8 +396,6 @@ class PartyPoker(HandHistoryConverter):
|
||||||
blind = smartMin(hand.bb, playersMap[bigBlindSeat][1])
|
blind = smartMin(hand.bb, playersMap[bigBlindSeat][1])
|
||||||
hand.addBlind(playersMap[bigBlindSeat][0], 'big blind', blind)
|
hand.addBlind(playersMap[bigBlindSeat][0], 'big blind', blind)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
def readHeroCards(self, hand):
|
def readHeroCards(self, hand):
|
||||||
# we need to grab hero's cards
|
# we need to grab hero's cards
|
||||||
for street in ('PREFLOP',):
|
for street in ('PREFLOP',):
|
||||||
|
@ -425,7 +406,6 @@ class PartyPoker(HandHistoryConverter):
|
||||||
newcards = renderCards(found.group('NEWCARDS'))
|
newcards = renderCards(found.group('NEWCARDS'))
|
||||||
hand.addHoleCards(street, hand.hero, closed=newcards, shown=False, mucked=False, dealt=True)
|
hand.addHoleCards(street, hand.hero, closed=newcards, shown=False, mucked=False, dealt=True)
|
||||||
|
|
||||||
|
|
||||||
def readAction(self, hand, street):
|
def readAction(self, hand, street):
|
||||||
m = self.re_Action.finditer(hand.streets[street])
|
m = self.re_Action.finditer(hand.streets[street])
|
||||||
for action in m:
|
for action in m:
|
||||||
|
@ -460,10 +440,9 @@ class PartyPoker(HandHistoryConverter):
|
||||||
elif actionType == 'checks':
|
elif actionType == 'checks':
|
||||||
hand.addCheck( street, playerName )
|
hand.addCheck( street, playerName )
|
||||||
else:
|
else:
|
||||||
raise PartyPokerParseError(
|
raise FpdbParseError(
|
||||||
"Unimplemented readAction: '%s' '%s'" % (playerName,actionType,),
|
"Unimplemented readAction: '%s' '%s'" % (playerName,actionType,),
|
||||||
hid = hand.hid, hh = hand.handText )
|
hid = hand.hid, )
|
||||||
|
|
||||||
|
|
||||||
def readShowdownActions(self, hand):
|
def readShowdownActions(self, hand):
|
||||||
# all action in readShownCards
|
# all action in readShownCards
|
||||||
|
@ -482,6 +461,17 @@ class PartyPoker(HandHistoryConverter):
|
||||||
|
|
||||||
hand.addShownCards(cards=cards, player=m.group('PNAME'), shown=True, mucked=mucked)
|
hand.addShownCards(cards=cards, player=m.group('PNAME'), shown=True, mucked=mucked)
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def getTableTitleRe(type, table_name=None, tournament = None, table_number=None):
|
||||||
|
"Returns string to search in windows titles"
|
||||||
|
if type=="tour":
|
||||||
|
print 'party', 'getTableTitleRe', "%s.+Table\s#%s" % (table_name, table_number)
|
||||||
|
return "%s.+Table\s#%s" % (table_name, table_number)
|
||||||
|
else:
|
||||||
|
print 'party', 'getTableTitleRe', table_number
|
||||||
|
return table_name
|
||||||
|
|
||||||
|
|
||||||
def ringBlinds(ringLimit):
|
def ringBlinds(ringLimit):
|
||||||
"Returns blinds for current limit in cash games"
|
"Returns blinds for current limit in cash games"
|
||||||
ringLimit = float(clearMoneyString(ringLimit))
|
ringLimit = float(clearMoneyString(ringLimit))
|
||||||
|
|
|
@ -237,7 +237,6 @@ class PokerStars(HandHistoryConverter):
|
||||||
def readPlayerStacks(self, hand):
|
def readPlayerStacks(self, hand):
|
||||||
log.debug("readPlayerStacks")
|
log.debug("readPlayerStacks")
|
||||||
m = self.re_PlayerInfo.finditer(hand.handText)
|
m = self.re_PlayerInfo.finditer(hand.handText)
|
||||||
players = []
|
|
||||||
for a in m:
|
for a in m:
|
||||||
hand.addPlayer(int(a.group('SEAT')), a.group('PNAME'), a.group('CASH'))
|
hand.addPlayer(int(a.group('SEAT')), a.group('PNAME'), a.group('CASH'))
|
||||||
|
|
||||||
|
|
|
@ -58,6 +58,27 @@ class Sql:
|
||||||
self.query['drop_table'] = """DROP TABLE IF EXISTS """
|
self.query['drop_table'] = """DROP TABLE IF EXISTS """
|
||||||
|
|
||||||
|
|
||||||
|
##################################################################
|
||||||
|
# Set transaction isolation level
|
||||||
|
##################################################################
|
||||||
|
|
||||||
|
if db_server == 'mysql' or db_server == 'postgresql':
|
||||||
|
self.query['set tx level'] = """SET SESSION TRANSACTION
|
||||||
|
ISOLATION LEVEL READ COMMITTED"""
|
||||||
|
elif db_server == 'sqlite':
|
||||||
|
self.query['set tx level'] = """ """
|
||||||
|
|
||||||
|
|
||||||
|
################################
|
||||||
|
# Select basic info
|
||||||
|
################################
|
||||||
|
|
||||||
|
self.query['getSiteId'] = """SELECT id from Sites where name = %s"""
|
||||||
|
|
||||||
|
self.query['getGames'] = """SELECT DISTINCT category from Gametypes"""
|
||||||
|
|
||||||
|
self.query['getLimits'] = """SELECT DISTINCT bigBlind from Gametypes ORDER by bigBlind DESC"""
|
||||||
|
|
||||||
################################
|
################################
|
||||||
# Create Settings
|
# Create Settings
|
||||||
################################
|
################################
|
||||||
|
@ -214,6 +235,7 @@ class Sql:
|
||||||
id BIGINT UNSIGNED AUTO_INCREMENT NOT NULL, PRIMARY KEY (id),
|
id BIGINT UNSIGNED AUTO_INCREMENT NOT NULL, PRIMARY KEY (id),
|
||||||
tableName VARCHAR(22) NOT NULL,
|
tableName VARCHAR(22) NOT NULL,
|
||||||
siteHandNo BIGINT NOT NULL,
|
siteHandNo BIGINT NOT NULL,
|
||||||
|
tourneyId INT UNSIGNED NOT NULL,
|
||||||
gametypeId SMALLINT UNSIGNED NOT NULL, FOREIGN KEY (gametypeId) REFERENCES Gametypes(id),
|
gametypeId SMALLINT UNSIGNED NOT NULL, FOREIGN KEY (gametypeId) REFERENCES Gametypes(id),
|
||||||
handStart DATETIME NOT NULL,
|
handStart DATETIME NOT NULL,
|
||||||
importTime DATETIME NOT NULL,
|
importTime DATETIME NOT NULL,
|
||||||
|
@ -249,6 +271,7 @@ class Sql:
|
||||||
id BIGSERIAL, PRIMARY KEY (id),
|
id BIGSERIAL, PRIMARY KEY (id),
|
||||||
tableName VARCHAR(22) NOT NULL,
|
tableName VARCHAR(22) NOT NULL,
|
||||||
siteHandNo BIGINT NOT NULL,
|
siteHandNo BIGINT NOT NULL,
|
||||||
|
tourneyId INT NOT NULL,
|
||||||
gametypeId INT NOT NULL, FOREIGN KEY (gametypeId) REFERENCES Gametypes(id),
|
gametypeId INT NOT NULL, FOREIGN KEY (gametypeId) REFERENCES Gametypes(id),
|
||||||
handStart timestamp without time zone NOT NULL,
|
handStart timestamp without time zone NOT NULL,
|
||||||
importTime timestamp without time zone NOT NULL,
|
importTime timestamp without time zone NOT NULL,
|
||||||
|
@ -283,6 +306,7 @@ class Sql:
|
||||||
id INTEGER PRIMARY KEY,
|
id INTEGER PRIMARY KEY,
|
||||||
tableName TEXT(22) NOT NULL,
|
tableName TEXT(22) NOT NULL,
|
||||||
siteHandNo INT NOT NULL,
|
siteHandNo INT NOT NULL,
|
||||||
|
tourneyId INT NOT NULL,
|
||||||
gametypeId INT NOT NULL,
|
gametypeId INT NOT NULL,
|
||||||
handStart REAL NOT NULL,
|
handStart REAL NOT NULL,
|
||||||
importTime REAL NOT NULL,
|
importTime REAL NOT NULL,
|
||||||
|
@ -3437,6 +3461,7 @@ class Sql:
|
||||||
tablename,
|
tablename,
|
||||||
gametypeid,
|
gametypeid,
|
||||||
sitehandno,
|
sitehandno,
|
||||||
|
tourneyId,
|
||||||
handstart,
|
handstart,
|
||||||
importtime,
|
importtime,
|
||||||
seats,
|
seats,
|
||||||
|
@ -3467,7 +3492,7 @@ class Sql:
|
||||||
VALUES
|
VALUES
|
||||||
(%s, %s, %s, %s, %s, %s, %s, %s, %s, %s,
|
(%s, %s, %s, %s, %s, %s, %s, %s, %s, %s,
|
||||||
%s, %s, %s, %s, %s, %s, %s, %s, %s, %s,
|
%s, %s, %s, %s, %s, %s, %s, %s, %s, %s,
|
||||||
%s, %s, %s, %s, %s, %s, %s, %s, %s)"""
|
%s, %s, %s, %s, %s, %s, %s, %s, %s, %s)"""
|
||||||
|
|
||||||
|
|
||||||
self.query['store_hands_players'] = """INSERT INTO HandsPlayers (
|
self.query['store_hands_players'] = """INSERT INTO HandsPlayers (
|
||||||
|
|
|
@ -185,7 +185,7 @@ class Tourney(object):
|
||||||
def old_insert_from_Hand(self, db):
|
def old_insert_from_Hand(self, db):
|
||||||
""" Function to insert Hand into database
|
""" Function to insert Hand into database
|
||||||
Should not commit, and do minimal selects. Callers may want to cache commits
|
Should not commit, and do minimal selects. Callers may want to cache commits
|
||||||
db: a connected fpdb_db object"""
|
db: a connected Database object"""
|
||||||
# TODO:
|
# TODO:
|
||||||
# Players - base playerid and siteid tuple
|
# Players - base playerid and siteid tuple
|
||||||
sqlids = db.getSqlPlayerIDs([p[1] for p in self.players], self.siteId)
|
sqlids = db.getSqlPlayerIDs([p[1] for p in self.players], self.siteId)
|
||||||
|
|
|
@ -112,7 +112,6 @@ import GuiGraphViewer
|
||||||
import GuiSessionViewer
|
import GuiSessionViewer
|
||||||
import SQL
|
import SQL
|
||||||
import Database
|
import Database
|
||||||
import FpdbSQLQueries
|
|
||||||
import Configuration
|
import Configuration
|
||||||
import Exceptions
|
import Exceptions
|
||||||
|
|
||||||
|
|
|
@ -16,207 +16,6 @@
|
||||||
#In the "official" distribution you can find the license in
|
#In the "official" distribution you can find the license in
|
||||||
#agpl-3.0.txt in the docs folder of the package.
|
#agpl-3.0.txt in the docs folder of the package.
|
||||||
|
|
||||||
import os
|
|
||||||
import re
|
|
||||||
import sys
|
|
||||||
import logging
|
|
||||||
import math
|
|
||||||
from time import time, strftime
|
|
||||||
from Exceptions import *
|
|
||||||
|
|
||||||
try:
|
|
||||||
import sqlalchemy.pool as pool
|
|
||||||
use_pool = True
|
|
||||||
except ImportError:
|
|
||||||
logging.info("Not using sqlalchemy connection pool.")
|
|
||||||
use_pool = False
|
|
||||||
|
|
||||||
try:
|
|
||||||
from numpy import var
|
|
||||||
use_numpy = True
|
|
||||||
except ImportError:
|
|
||||||
logging.info("Not using numpy to define variance in sqlite.")
|
|
||||||
use_numpy = False
|
|
||||||
|
|
||||||
import FpdbSQLQueries
|
|
||||||
import Configuration
|
|
||||||
|
|
||||||
# Variance created as sqlite has a bunch of undefined aggregate functions.
|
|
||||||
|
|
||||||
class VARIANCE:
|
|
||||||
def __init__(self):
|
|
||||||
self.store = []
|
|
||||||
|
|
||||||
def step(self, value):
|
|
||||||
self.store.append(value)
|
|
||||||
|
|
||||||
def finalize(self):
|
|
||||||
return float(var(self.store))
|
|
||||||
|
|
||||||
class sqlitemath:
|
|
||||||
def mod(self, a, b):
|
|
||||||
return a%b
|
|
||||||
|
|
||||||
class fpdb_db:
|
|
||||||
MYSQL_INNODB = 2
|
|
||||||
PGSQL = 3
|
|
||||||
SQLITE = 4
|
|
||||||
|
|
||||||
def __init__(self):
|
|
||||||
"""Simple constructor, doesnt really do anything"""
|
|
||||||
self.db = None
|
|
||||||
self.cursor = None
|
|
||||||
self.sql = {}
|
|
||||||
#end def __init__
|
|
||||||
|
|
||||||
def do_connect(self, config=None):
|
|
||||||
"""Connects a database using information in config"""
|
|
||||||
if config is None:
|
|
||||||
raise FpdbError('Configuration not defined')
|
|
||||||
|
|
||||||
self.settings = {}
|
|
||||||
self.settings['os'] = "linuxmac" if os.name != "nt" else "windows"
|
|
||||||
|
|
||||||
db = config.get_db_parameters()
|
|
||||||
self.connect(backend=db['db-backend'],
|
|
||||||
host=db['db-host'],
|
|
||||||
database=db['db-databaseName'],
|
|
||||||
user=db['db-user'],
|
|
||||||
password=db['db-password'])
|
|
||||||
#end def do_connect
|
|
||||||
|
|
||||||
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 == fpdb_db.MYSQL_INNODB:
|
|
||||||
import MySQLdb
|
|
||||||
if use_pool:
|
|
||||||
MySQLdb = pool.manage(MySQLdb, pool_size=5)
|
|
||||||
try:
|
|
||||||
self.db = MySQLdb.connect(host=host, user=user, passwd=password, db=database, use_unicode=True)
|
|
||||||
#TODO: Add port option
|
|
||||||
except MySQLdb.Error, ex:
|
|
||||||
if ex.args[0] == 1045:
|
|
||||||
raise FpdbMySQLAccessDenied(ex.args[0], ex.args[1])
|
|
||||||
elif ex.args[0] == 2002 or ex.args[0] == 2003: # 2002 is no unix socket, 2003 is no tcp socket
|
|
||||||
raise FpdbMySQLNoDatabase(ex.args[0], ex.args[1])
|
|
||||||
else:
|
|
||||||
print "*** WARNING UNKNOWN MYSQL ERROR", ex
|
|
||||||
elif backend == fpdb_db.PGSQL:
|
|
||||||
import psycopg2
|
|
||||||
import psycopg2.extensions
|
|
||||||
if use_pool:
|
|
||||||
psycopg2 = pool.manage(psycopg2, pool_size=5)
|
|
||||||
psycopg2.extensions.register_type(psycopg2.extensions.UNICODE)
|
|
||||||
# If DB connection is made over TCP, then the variables
|
|
||||||
# host, user and password are required
|
|
||||||
# For local domain-socket connections, only DB name is
|
|
||||||
# needed, and everything else is in fact undefined and/or
|
|
||||||
# flat out wrong
|
|
||||||
# sqlcoder: This database only connect failed in my windows setup??
|
|
||||||
# Modifed it to try the 4 parameter style if the first connect fails - does this work everywhere?
|
|
||||||
connected = False
|
|
||||||
if self.host == "localhost" or self.host == "127.0.0.1":
|
|
||||||
try:
|
|
||||||
self.db = psycopg2.connect(database = database)
|
|
||||||
connected = True
|
|
||||||
except:
|
|
||||||
# direct connection failed so try user/pass/... version
|
|
||||||
pass
|
|
||||||
if not connected:
|
|
||||||
try:
|
|
||||||
self.db = psycopg2.connect(host = host,
|
|
||||||
user = user,
|
|
||||||
password = password,
|
|
||||||
database = database)
|
|
||||||
except Exception, ex:
|
|
||||||
if 'Connection refused' in ex.args[0]:
|
|
||||||
# meaning eg. db not running
|
|
||||||
raise FpdbPostgresqlNoDatabase(errmsg = ex.args[0])
|
|
||||||
elif 'password authentication' in ex.args[0]:
|
|
||||||
raise FpdbPostgresqlAccessDenied(errmsg = ex.args[0])
|
|
||||||
else:
|
|
||||||
msg = ex.args[0]
|
|
||||||
print msg
|
|
||||||
raise FpdbError(msg)
|
|
||||||
elif backend == fpdb_db.SQLITE:
|
|
||||||
logging.info("Connecting to SQLite:%(database)s" % {'database':database})
|
|
||||||
import sqlite3
|
|
||||||
if use_pool:
|
|
||||||
sqlite3 = pool.manage(sqlite3, pool_size=1)
|
|
||||||
else:
|
|
||||||
logging.warning("SQLite won't work well without 'sqlalchemy' installed.")
|
|
||||||
|
|
||||||
if not os.path.isdir(Configuration.DIR_DATABASES) and not database == ":memory:":
|
|
||||||
print "Creating directory: '%s'" % (Configuration.DIR_DATABASES)
|
|
||||||
os.mkdir(Configuration.DIR_DATABASES)
|
|
||||||
database = os.path.join(Configuration.DIR_DATABASES, database)
|
|
||||||
self.db = sqlite3.connect(database, detect_types=sqlite3.PARSE_DECLTYPES )
|
|
||||||
sqlite3.register_converter("bool", lambda x: bool(int(x)))
|
|
||||||
sqlite3.register_adapter(bool, lambda x: "1" if x else "0")
|
|
||||||
self.db.create_function("floor", 1, math.floor)
|
|
||||||
tmp = sqlitemath()
|
|
||||||
self.db.create_function("mod", 2, tmp.mod)
|
|
||||||
if use_numpy:
|
|
||||||
self.db.create_aggregate("variance", 1, VARIANCE)
|
|
||||||
else:
|
|
||||||
logging.warning("Some database functions will not work without NumPy support")
|
|
||||||
else:
|
|
||||||
raise FpdbError("unrecognised database backend:"+backend)
|
|
||||||
|
|
||||||
self.cursor = self.db.cursor()
|
|
||||||
# Set up query dictionary as early in the connection process as we can.
|
|
||||||
self.sql = FpdbSQLQueries.FpdbSQLQueries(self.get_backend_name())
|
|
||||||
self.cursor.execute(self.sql.query['set tx level'])
|
|
||||||
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:
|
|
||||||
if database != ":memory:": 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 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"
|
|
||||||
elif self.backend==4:
|
|
||||||
return "SQLite"
|
|
||||||
else:
|
|
||||||
raise 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
|
|
||||||
|
|
||||||
#end class fpdb_db
|
#end class fpdb_db
|
||||||
|
|
|
@ -35,7 +35,6 @@ import gtk
|
||||||
|
|
||||||
# fpdb/FreePokerTools modules
|
# fpdb/FreePokerTools modules
|
||||||
|
|
||||||
import fpdb_db
|
|
||||||
import Database
|
import Database
|
||||||
import Configuration
|
import Configuration
|
||||||
import Exceptions
|
import Exceptions
|
||||||
|
|
0
pyfpdb/test_PokerStars.py
Normal file → Executable file
0
pyfpdb/test_PokerStars.py
Normal file → Executable file
34
run_fpdb.py
Executable file
34
run_fpdb.py
Executable file
|
@ -0,0 +1,34 @@
|
||||||
|
#!/usr/bin/python
|
||||||
|
|
||||||
|
#Copyright 2008 Carl Gherardi
|
||||||
|
#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
|
||||||
|
|
||||||
|
# sys.path[0] holds the directory run_fpdb.py is in
|
||||||
|
sys.path[0] = sys.path[0]+os.sep+"pyfpdb"
|
||||||
|
os.chdir(sys.path[0])
|
||||||
|
#print "sys.path[0] =", sys.path[0], "cwd =", os.getcwd()
|
||||||
|
|
||||||
|
|
||||||
|
import fpdb
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
me = fpdb.fpdb()
|
||||||
|
me.main()
|
||||||
|
exit()
|
Loading…
Reference in New Issue
Block a user