Merge branch 'master' into good

This commit is contained in:
Mika Bostrom 2009-12-16 09:25:29 +02:00
commit 8abdc6597d
11 changed files with 396 additions and 208 deletions

View File

@ -187,6 +187,7 @@ class Database:
def __init__(self, c, sql = None): def __init__(self, c, sql = None):
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.fdb = fpdb_db.fpdb_db() # sets self.fdb.db self.fdb.cursor and self.fdb.sql self.fdb = fpdb_db.fpdb_db() # sets self.fdb.db self.fdb.cursor and self.fdb.sql
self.do_connect(c) self.do_connect(c)
@ -237,7 +238,12 @@ class Database:
self.hud_style = style self.hud_style = style
def do_connect(self, c): def do_connect(self, c):
self.fdb.do_connect(c) try:
self.fdb.do_connect(c)
except:
# error during connect
self.__connected = False
raise
self.connection = self.fdb.db self.connection = self.fdb.db
self.wrongDbVersion = self.fdb.wrongDbVersion self.wrongDbVersion = self.fdb.wrongDbVersion
@ -247,6 +253,7 @@ class Database:
self.db_server = db_params['db-server'] self.db_server = db_params['db-server']
self.database = db_params['db-databaseName'] self.database = db_params['db-databaseName']
self.host = db_params['db-host'] self.host = db_params['db-host']
self.__connected = True
def commit(self): def commit(self):
self.fdb.db.commit() self.fdb.db.commit()
@ -254,6 +261,9 @@ class Database:
def rollback(self): def rollback(self):
self.fdb.db.rollback() self.fdb.db.rollback()
def connected(self):
return self.__connected
def get_cursor(self): def get_cursor(self):
return self.connection.cursor() return self.connection.cursor()
@ -1608,103 +1618,43 @@ class Database:
pdata[p]['street2Bets'], pdata[p]['street2Bets'],
pdata[p]['street3Bets'], pdata[p]['street3Bets'],
pdata[p]['street4Bets'], pdata[p]['street4Bets'],
pdata[p]['position'],
pdata[p]['tourneyTypeId'],
pdata[p]['startCards'],
pdata[p]['street0_3BChance'],
pdata[p]['street0_3BDone'],
pdata[p]['otherRaisedStreet1'],
pdata[p]['otherRaisedStreet2'],
pdata[p]['otherRaisedStreet3'],
pdata[p]['otherRaisedStreet4'],
pdata[p]['foldToOtherRaisedStreet1'],
pdata[p]['foldToOtherRaisedStreet2'],
pdata[p]['foldToOtherRaisedStreet3'],
pdata[p]['foldToOtherRaisedStreet4'],
pdata[p]['stealAttemptChance'],
pdata[p]['stealAttempted'],
pdata[p]['foldBbToStealChance'],
pdata[p]['foldedBbToSteal'],
pdata[p]['foldSbToStealChance'],
pdata[p]['foldedSbToSteal'],
pdata[p]['foldToStreet1CBChance'],
pdata[p]['foldToStreet1CBDone'],
pdata[p]['foldToStreet2CBChance'],
pdata[p]['foldToStreet2CBDone'],
pdata[p]['foldToStreet3CBChance'],
pdata[p]['foldToStreet3CBDone'],
pdata[p]['foldToStreet4CBChance'],
pdata[p]['foldToStreet4CBDone'],
pdata[p]['street1CheckCallRaiseChance'],
pdata[p]['street1CheckCallRaiseDone'],
pdata[p]['street2CheckCallRaiseChance'],
pdata[p]['street2CheckCallRaiseDone'],
pdata[p]['street3CheckCallRaiseChance'],
pdata[p]['street3CheckCallRaiseDone'],
pdata[p]['street4CheckCallRaiseChance']
) ) ) )
q = """INSERT INTO HandsPlayers ( q = self.sql.query['store_hands_players']
handId,
playerId,
startCash,
seatNo,
card1,
card2,
card3,
card4,
card5,
card6,
card7,
winnings,
rake,
totalProfit,
street0VPI,
street1Seen,
street2Seen,
street3Seen,
street4Seen,
sawShowdown,
wonAtSD,
street0Aggr,
street1Aggr,
street2Aggr,
street3Aggr,
street4Aggr,
street1CBChance,
street2CBChance,
street3CBChance,
street4CBChance,
street1CBDone,
street2CBDone,
street3CBDone,
street4CBDone,
wonWhenSeenStreet1,
street0Calls,
street1Calls,
street2Calls,
street3Calls,
street4Calls,
street0Bets,
street1Bets,
street2Bets,
street3Bets,
street4Bets
)
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
)"""
# position,
# tourneyTypeId,
# startCards,
# street0_3BChance,
# street0_3BDone,
# otherRaisedStreet1,
# otherRaisedStreet2,
# otherRaisedStreet3,
# otherRaisedStreet4,
# foldToOtherRaisedStreet1,
# foldToOtherRaisedStreet2,
# foldToOtherRaisedStreet3,
# foldToOtherRaisedStreet4,
# stealAttemptChance,
# stealAttempted,
# foldBbToStealChance,
# foldedBbToSteal,
# foldSbToStealChance,
# foldedSbToSteal,
# foldToStreet1CBChance,
# foldToStreet1CBDone,
# foldToStreet2CBChance,
# foldToStreet2CBDone,
# foldToStreet3CBChance,
# foldToStreet3CBDone,
# foldToStreet4CBChance,
# foldToStreet4CBDone,
# street1CheckCallRaiseChance,
# street1CheckCallRaiseDone,
# street2CheckCallRaiseChance,
# street2CheckCallRaiseDone,
# street3CheckCallRaiseChance,
# street3CheckCallRaiseDone,
# street4CheckCallRaiseChance,
# street4CheckCallRaiseDone,
q = q.replace('%s', self.sql.query['placeholder']) q = q.replace('%s', self.sql.query['placeholder'])
#print "DEBUG: inserts: %s" %inserts #print "DEBUG: inserts: %s" %inserts

View File

@ -53,6 +53,27 @@ class DerivedStats():
self.handsplayers[player[1]]['street%dCBChance' %i] = False self.handsplayers[player[1]]['street%dCBChance' %i] = False
self.handsplayers[player[1]]['street%dCBDone' %i] = False self.handsplayers[player[1]]['street%dCBDone' %i] = False
#FIXME - Everything below this point is incomplete.
self.handsplayers[player[1]]['position'] = 2
self.handsplayers[player[1]]['tourneyTypeId'] = 1
self.handsplayers[player[1]]['startCards'] = 0
self.handsplayers[player[1]]['street0_3BChance'] = False
self.handsplayers[player[1]]['street0_3BDone'] = False
self.handsplayers[player[1]]['stealAttemptChance'] = False
self.handsplayers[player[1]]['stealAttempted'] = False
self.handsplayers[player[1]]['foldBbToStealChance'] = False
self.handsplayers[player[1]]['foldBbToStealChance'] = False
self.handsplayers[player[1]]['foldSbToStealChance'] = False
self.handsplayers[player[1]]['foldedSbToSteal'] = False
self.handsplayers[player[1]]['foldedBbToSteal'] = False
for i in range(1,5):
self.handsplayers[player[1]]['otherRaisedStreet%d' %i] = False
self.handsplayers[player[1]]['foldToOtherRaisedStreet%d' %i] = False
self.handsplayers[player[1]]['foldToStreet%dCBChance' %i] = False
self.handsplayers[player[1]]['foldToStreet%dCBDone' %i] = False
self.handsplayers[player[1]]['street%dCheckCallRaiseChance' %i] = False
self.handsplayers[player[1]]['street%dCheckCallRaiseDone' %i] = False
self.assembleHands(self.hand) self.assembleHands(self.hand)
self.assembleHandsPlayers(self.hand) self.assembleHandsPlayers(self.hand)
@ -149,6 +170,7 @@ class DerivedStats():
for i, card in enumerate(hcs[:7], 1): for i, card in enumerate(hcs[:7], 1):
self.handsplayers[player[1]]['card%s' % i] = Card.encodeCard(card) self.handsplayers[player[1]]['card%s' % i] = Card.encodeCard(card)
# position, # position,
#Stud 3rd street card test #Stud 3rd street card test
# denny501: brings in for $0.02 # denny501: brings in for $0.02
@ -159,16 +181,6 @@ class DerivedStats():
# u.pressure: folds (Seat 1) # u.pressure: folds (Seat 1)
# 123smoothie: calls $0.02 # 123smoothie: calls $0.02
# gashpor: calls $0.02 # gashpor: calls $0.02
# tourneyTypeId,
# startCards,
# street0_3BChance,street0_3BDone,
# otherRaisedStreet1-4
# foldToOtherRaisedStreet1-4
# stealAttemptChance,stealAttempted,
# foldBbToStealChance,foldedBbToSteal,
# foldSbToStealChance,foldedSbToSteal,
# foldToStreet1-4CBChance, foldToStreet1-4CBDone,
# street1-4CheckCallRaiseChance, street1-4CheckCallRaiseDone,
# Additional stats # Additional stats
# 3betSB, 3betBB # 3betSB, 3betBB

View File

@ -34,5 +34,19 @@ class FpdbMySQLNoDatabase(FpdbDatabaseError):
def __str__(self): def __str__(self):
return repr(self.value +" " + self.errmsg) return repr(self.value +" " + self.errmsg)
class FpdbPostgresqlAccessDenied(FpdbDatabaseError):
def __init__(self, value='', errmsg=''):
self.value = value
self.errmsg = errmsg
def __str__(self):
return repr(self.value +" " + self.errmsg)
class FpdbPostgresqlNoDatabase(FpdbDatabaseError):
def __init__(self, value='', errmsg=''):
self.value = value
self.errmsg = errmsg
def __str__(self):
return repr(self.value +" " + self.errmsg)
class DuplicateError(FpdbError): class DuplicateError(FpdbError):
pass pass

View File

@ -17,7 +17,8 @@
#agpl-3.0.txt in the docs folder of the package. #agpl-3.0.txt in the docs folder of the package.
import mmap import os
import Queue
import pygtk import pygtk
pygtk.require('2.0') pygtk.require('2.0')
@ -29,18 +30,27 @@ import Configuration
log = Configuration.get_logger("logging.conf", "logview") log = Configuration.get_logger("logging.conf", "logview")
MAX_LINES = 100000 MAX_LINES = 100000 # max lines to display in window
EST_CHARS_PER_LINE = 150 # used to guesstimate number of lines in log file
logfile = 'logging.out' # name of logfile
class GuiLogView: class GuiLogView:
def __init__(self, config, mainwin, vbox): def __init__(self, config, mainwin, closeq):
self.config = config self.config = config
self.main_window = mainwin self.main_window = mainwin
self.vbox = vbox self.closeq = closeq
self.dia = gtk.Dialog(title="Log Messages"
,parent=None
,flags=gtk.DIALOG_DESTROY_WITH_PARENT
,buttons=(gtk.STOCK_CLOSE,gtk.RESPONSE_OK))
self.dia.set_modal(False)
self.vbox = self.dia.vbox
gtk.Widget.set_size_request(self.vbox, 700, 400); gtk.Widget.set_size_request(self.vbox, 700, 400);
self.liststore = gtk.ListStore(str, str, str, str, gobject.TYPE_BOOLEAN) # date, module, level, text self.liststore = gtk.ListStore(str, str, str, str, gobject.TYPE_BOOLEAN) # date, module, level, text
# this is how to add a filter: # this is how to add a filter:
# #
# # Creation of the filter, from the model # # Creation of the filter, from the model
@ -49,7 +59,6 @@ class GuiLogView:
# #
# # The TreeView gets the filter as model # # The TreeView gets the filter as model
# self.listview = gtk.TreeView(filter) # self.listview = gtk.TreeView(filter)
self.listview = gtk.TreeView(model=self.liststore) self.listview = gtk.TreeView(model=self.liststore)
self.listview.set_grid_lines(gtk.TREE_VIEW_GRID_LINES_NONE) self.listview.set_grid_lines(gtk.TREE_VIEW_GRID_LINES_NONE)
self.listcols = [] self.listcols = []
@ -67,6 +76,7 @@ class GuiLogView:
self.listview.show() self.listview.show()
scrolledwindow.show() scrolledwindow.show()
self.vbox.show() self.vbox.show()
self.dia.set_focus(self.listview)
col = self.addColumn("Date/Time", 0) col = self.addColumn("Date/Time", 0)
col = self.addColumn("Module", 1) col = self.addColumn("Module", 1)
@ -75,6 +85,17 @@ class GuiLogView:
self.loadLog() self.loadLog()
self.vbox.show_all() self.vbox.show_all()
self.dia.show()
self.dia.connect('response', self.dialog_response_cb)
def dialog_response_cb(self, dialog, response_id):
# this is called whether close button is pressed or window is closed
self.closeq.put(self.__class__)
dialog.destroy()
def get_dialog(self):
return self.dia
def addColumn(self, title, n): def addColumn(self, title, n):
col = gtk.TreeViewColumn(title) col = gtk.TreeViewColumn(title)
@ -92,39 +113,28 @@ class GuiLogView:
def loadLog(self): def loadLog(self):
#self.configStore = gtk.TreeStore(gobject.TYPE_PYOBJECT, gobject.TYPE_STRING, gobject.TYPE_STRING)
#self.configView = gtk.TreeView(self.configStore)
#self.configView.set_enable_tree_lines(True)
self.liststore.clear() self.liststore.clear()
self.listcols = [] self.listcols = []
# count number of lines in file # guesstimate number of lines in file
f = open('logging.out', "r+") if os.path.exists(logfile):
buf = mmap.mmap(f.fileno(), 0) stat_info = os.stat(logfile)
readline = buf.readline lines = stat_info.st_size / EST_CHARS_PER_LINE
lines = 0 print "logview: size =", stat_info.st_size, "lines =", lines
while readline():
lines += 1
f.close()
startline = 0 # set startline to line number to start display from
if lines > MAX_LINES: startline = 0
# only display from startline if log file is large if lines > MAX_LINES:
startline = lines - MAX_LINES # only display from startline if log file is large
startline = lines - MAX_LINES
f = open('logging.out', "r+") l = 0
buf = mmap.mmap(f.fileno(), 0) for line in open(logfile):
readline = buf.readline # eg line:
l = 0 # 2009-12-02 15:23:21,716 - config DEBUG config logger initialised
line = readline() l = l + 1
while line: if l > startline and len(line) > 49:
# eg line: iter = self.liststore.append( (line[0:23], line[26:32], line[39:46], line[48:].strip(), True) )
# 2009-12-02 15:23:21,716 - config DEBUG config logger initialised
l = l + 1
if l > startline and len(line) > 49:
iter = self.liststore.append( (line[0:23], line[26:32], line[39:46], line[48:].strip(), True) )
line = readline()
f.close()
def sortCols(self, col, n): def sortCols(self, col, n):
try: try:

View File

@ -91,10 +91,15 @@ class GuiPrefs:
#iter = self.configStore.append( parent, [node.nodeValue, None] ) #iter = self.configStore.append( parent, [node.nodeValue, None] )
iter = None iter = None
if node.nodeType != node.TEXT_NODE and node.nodeType != node.COMMENT_NODE: if node.nodeType != node.TEXT_NODE and node.nodeType != node.COMMENT_NODE:
name = ""
iter = self.configStore.append( parent, [node, setting, value] ) iter = self.configStore.append( parent, [node, setting, value] )
if node.hasAttributes(): if node.hasAttributes():
for i in xrange(node.attributes.length): for i in xrange(node.attributes.length):
self.configStore.append( iter, [node, node.attributes.item(i).localName, node.attributes.item(i).value] ) self.configStore.append( iter, [node, node.attributes.item(i).localName, node.attributes.item(i).value] )
if node.attributes.item(i).localName in ('site_name', 'game_name', 'stat_name', 'name', 'db_server', 'site'):
name = " " + node.attributes.item(i).value
if name != "":
self.configStore.set_value(iter, 1, setting+name)
if node.hasChildNodes(): if node.hasChildNodes():
for elem in node.childNodes: for elem in node.childNodes:
self.addTreeRows(iter, elem) self.addTreeRows(iter, elem)
@ -156,7 +161,7 @@ if __name__=="__main__":
gtk.DIALOG_MODAL | gtk.DIALOG_DESTROY_WITH_PARENT, gtk.DIALOG_MODAL | gtk.DIALOG_DESTROY_WITH_PARENT,
(gtk.STOCK_CANCEL, gtk.RESPONSE_REJECT, (gtk.STOCK_CANCEL, gtk.RESPONSE_REJECT,
gtk.STOCK_SAVE, gtk.RESPONSE_ACCEPT)) gtk.STOCK_SAVE, gtk.RESPONSE_ACCEPT))
dia.set_default_size(500, 500) dia.set_default_size(700, 500)
prefs = GuiPrefs(config, win, dia.vbox) prefs = GuiPrefs(config, win, dia.vbox)
response = dia.run() response = dia.run()
if response == gtk.RESPONSE_ACCEPT: if response == gtk.RESPONSE_ACCEPT:

View File

@ -55,6 +55,8 @@ class Hand(object):
self.handText = handText self.handText = handText
self.handid = 0 self.handid = 0
self.dbid_hands = 0 self.dbid_hands = 0
self.dbid_pids = None
self.dbid_gt = 0
self.tablename = "" self.tablename = ""
self.hero = "" self.hero = ""
self.maxseats = None self.maxseats = None
@ -189,22 +191,21 @@ dealt whether they were seen in a 'dealt to' line
self.holecards[street][player] = [open, closed] self.holecards[street][player] = [open, closed]
def prepInsert(self, db): def prepInsert(self, db):
pass #####
# Players, Gametypes, TourneyTypes are all shared functions that are needed for additional tables
# These functions are intended for prep insert eventually
#####
# Players - base playerid and siteid tuple
self.dbid_pids = db.getSqlPlayerIDs([p[1] for p in self.players], self.siteId)
#Gametypes
self.dbid_gt = db.getGameTypeId(self.siteId, self.gametype)
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 fpdb_db object"""
#####
# Players, Gametypes, TourneyTypes are all shared functions that are needed for additional tables
# These functions are intended for prep insert eventually
#####
# Players - base playerid and siteid tuple
sqlids = db.getSqlPlayerIDs([p[1] for p in self.players], self.siteId)
#Gametypes
gtid = db.getGameTypeId(self.siteId, self.gametype)
self.stats.getStats(self) self.stats.getStats(self)
@ -213,14 +214,14 @@ db: a connected fpdb_db object"""
##### #####
hh = self.stats.getHands() hh = self.stats.getHands()
if not db.isDuplicate(gtid, hh['siteHandNo']): if not db.isDuplicate(self.dbid_gt, hh['siteHandNo']):
# Hands - Summary information of hand indexed by handId - gameinfo # Hands - Summary information of hand indexed by handId - gameinfo
hh['gameTypeId'] = gtid hh['gameTypeId'] = self.dbid_gt
# seats TINYINT NOT NULL, # seats TINYINT NOT NULL,
hh['seats'] = len(sqlids) hh['seats'] = len(self.dbid_pids)
self.dbid_hands = db.storeHand(hh) self.dbid_hands = db.storeHand(hh)
db.storeHandsPlayers(self.dbid_hands, sqlids, self.stats.getHandsPlayers()) db.storeHandsPlayers(self.dbid_hands, self.dbid_pids, self.stats.getHandsPlayers())
# HandsActions - all actions for all players for all streets - self.actions # HandsActions - all actions for all players for all streets - self.actions
# HudCache data can be generated from HandsActions (HandsPlayers?) # HudCache data can be generated from HandsActions (HandsPlayers?)
# Tourneys ? # Tourneys ?

View File

@ -3327,8 +3327,105 @@ class Sql:
%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 (
handId,
playerId,
startCash,
seatNo,
card1,
card2,
card3,
card4,
card5,
card6,
card7,
winnings,
rake,
totalProfit,
street0VPI,
street1Seen,
street2Seen,
street3Seen,
street4Seen,
sawShowdown,
wonAtSD,
street0Aggr,
street1Aggr,
street2Aggr,
street3Aggr,
street4Aggr,
street1CBChance,
street2CBChance,
street3CBChance,
street4CBChance,
street1CBDone,
street2CBDone,
street3CBDone,
street4CBDone,
wonWhenSeenStreet1,
street0Calls,
street1Calls,
street2Calls,
street3Calls,
street4Calls,
street0Bets,
street1Bets,
street2Bets,
street3Bets,
street4Bets,
position,
tourneyTypeId,
startCards,
street0_3BChance,
street0_3BDone,
otherRaisedStreet1,
otherRaisedStreet2,
otherRaisedStreet3,
otherRaisedStreet4,
foldToOtherRaisedStreet1,
foldToOtherRaisedStreet2,
foldToOtherRaisedStreet3,
foldToOtherRaisedStreet4,
stealAttemptChance,
stealAttempted,
foldBbToStealChance,
foldedBbToSteal,
foldSbToStealChance,
foldedSbToSteal,
foldToStreet1CBChance,
foldToStreet1CBDone,
foldToStreet2CBChance,
foldToStreet2CBDone,
foldToStreet3CBChance,
foldToStreet3CBDone,
foldToStreet4CBChance,
foldToStreet4CBDone,
street1CheckCallRaiseChance,
street1CheckCallRaiseDone,
street2CheckCallRaiseChance,
street2CheckCallRaiseDone,
street3CheckCallRaiseChance,
street3CheckCallRaiseDone,
street4CheckCallRaiseChance
)
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,
%s, %s, %s, %s, %s,
%s, %s, %s, %s, %s,
%s, %s, %s, %s, %s,
%s, %s, %s, %s, %s
)"""
if db_server == 'mysql': if db_server == 'mysql':
self.query['placeholder'] = u'%s' self.query['placeholder'] = u'%s'

View File

@ -18,6 +18,7 @@
import os import os
import sys import sys
import re import re
import Queue
# if path is set to use an old version of python look for a new one: # if path is set to use an old version of python look for a new one:
# (does this work in linux?) # (does this work in linux?)
@ -73,6 +74,7 @@ try:
import pygtk import pygtk
pygtk.require('2.0') pygtk.require('2.0')
import gtk import gtk
import pango
except: except:
print "Unable to load PYGTK modules required for GUI. Please install PyCairo, PyGObject, and PyGTK from www.pygtk.org." print "Unable to load PYGTK modules required for GUI. Please install PyCairo, PyGObject, and PyGTK from www.pygtk.org."
raw_input("Press ENTER to continue.") raw_input("Press ENTER to continue.")
@ -80,6 +82,24 @@ except:
import interlocks import interlocks
# these imports not required in this module, imported here to report version in About dialog
try:
import matplotlib
matplotlib_version = matplotlib.__version__
except:
matplotlib_version = 'not found'
try:
import numpy
numpy_version = numpy.__version__
except:
numpy_version = 'not found'
try:
import sqlite3
sqlite3_version = sqlite3.version
sqlite_version = sqlite3.sqlite_version
except:
sqlite3_version = 'not found'
sqlite_version = 'not found'
import GuiPrefs import GuiPrefs
import GuiLogView import GuiLogView
@ -112,12 +132,12 @@ class fpdb:
def add_tab(self, new_page, new_tab_name): def add_tab(self, new_page, new_tab_name):
"""adds a tab, namely creates the button and displays it and appends all the relevant arrays""" """adds a tab, namely creates the button and displays it and appends all the relevant arrays"""
for name in self.nb_tabs: #todo: check this is valid for name in self.nb_tab_names: #todo: check this is valid
if name == new_tab_name: if name == new_tab_name:
return # if tab already exists, just go to it return # if tab already exists, just go to it
used_before = False used_before = False
for i, name in enumerate(self.tab_names): #todo: check this is valid for i, name in enumerate(self.tab_names):
if name == new_tab_name: if name == new_tab_name:
used_before = True used_before = True
event_box = self.tabs[i] event_box = self.tabs[i]
@ -133,13 +153,13 @@ class fpdb:
#self.nb.append_page(new_page, gtk.Label(new_tab_name)) #self.nb.append_page(new_page, gtk.Label(new_tab_name))
self.nb.append_page(page, event_box) self.nb.append_page(page, event_box)
self.nb_tabs.append(new_tab_name) self.nb_tab_names.append(new_tab_name)
page.show() page.show()
def display_tab(self, new_tab_name): def display_tab(self, new_tab_name):
"""displays the indicated tab""" """displays the indicated tab"""
tab_no = -1 tab_no = -1
for i, name in enumerate(self.nb_tabs): for i, name in enumerate(self.nb_tab_names):
if new_tab_name == name: if new_tab_name == name:
tab_no = i tab_no = i
break break
@ -190,13 +210,13 @@ class fpdb:
(nb, text) = data (nb, text) = data
page = -1 page = -1
#print "\n remove_tab: start", text #print "\n remove_tab: start", text
for i, tab in enumerate(self.nb_tabs): for i, tab in enumerate(self.nb_tab_names):
if text == tab: if text == tab:
page = i page = i
#print " page =", page #print " page =", page
if page >= 0 and page < self.nb.get_n_pages(): if page >= 0 and page < self.nb.get_n_pages():
#print " removing page", page #print " removing page", page
del self.nb_tabs[page] del self.nb_tab_names[page]
nb.remove_page(page) nb.remove_page(page)
# Need to refresh the widget -- # Need to refresh the widget --
# This forces the widget to redraw itself. # This forces the widget to redraw itself.
@ -220,8 +240,39 @@ class fpdb:
dia.set_authors(['Steffen', 'Eratosthenes', 's0rrow', dia.set_authors(['Steffen', 'Eratosthenes', 's0rrow',
'EricBlade', '_mt', 'sqlcoder', 'Bostik', 'and others']) 'EricBlade', '_mt', 'sqlcoder', 'Bostik', 'and others'])
dia.set_program_name("Free Poker Database (FPDB)") dia.set_program_name("Free Poker Database (FPDB)")
db_version = ""
#if self.db is not None:
# db_version = self.db.get_version()
nums = [ ('Operating System', os.name)
, ('Python', sys.version[0:3])
, ('GTK+', '.'.join([str(x) for x in gtk.gtk_version]))
, ('PyGTK', '.'.join([str(x) for x in gtk.pygtk_version]))
, ('matplotlib', matplotlib_version)
, ('numpy', numpy_version)
, ('sqlite3', sqlite3_version)
, ('sqlite', sqlite_version)
, ('database', self.settings['db-server'] + db_version)
]
versions = gtk.TextBuffer()
w = 20 # width used for module names and version numbers
versions.set_text( '\n'.join( [x[0].rjust(w)+' '+ x[1].ljust(w) for x in nums] ) )
view = gtk.TextView(versions)
view.set_editable(False)
view.set_justification(gtk.JUSTIFY_CENTER)
view.modify_font(pango.FontDescription('monospace 10'))
view.show()
dia.vbox.pack_end(view, True, True, 2)
l = gtk.Label('Version Information:')
l.set_alignment(0.5, 0.5)
l.show()
dia.vbox.pack_end(l, True, True, 2)
dia.run() dia.run()
dia.destroy() dia.destroy()
log.debug("Threads: ")
for t in self.threads:
log.debug("........." + str(t.__class__))
def dia_preferences(self, widget, data=None): def dia_preferences(self, widget, data=None):
dia = gtk.Dialog("Preferences", dia = gtk.Dialog("Preferences",
@ -229,12 +280,20 @@ class fpdb:
gtk.DIALOG_MODAL | gtk.DIALOG_DESTROY_WITH_PARENT, gtk.DIALOG_MODAL | gtk.DIALOG_DESTROY_WITH_PARENT,
(gtk.STOCK_CANCEL, gtk.RESPONSE_REJECT, (gtk.STOCK_CANCEL, gtk.RESPONSE_REJECT,
gtk.STOCK_SAVE, gtk.RESPONSE_ACCEPT)) gtk.STOCK_SAVE, gtk.RESPONSE_ACCEPT))
dia.set_default_size(500, 500) dia.set_default_size(700, 500)
prefs = GuiPrefs.GuiPrefs(self.config, self.window, dia.vbox) prefs = GuiPrefs.GuiPrefs(self.config, self.window, dia.vbox)
response = dia.run() response = dia.run()
if response == gtk.RESPONSE_ACCEPT: if response == gtk.RESPONSE_ACCEPT:
# save updated config # save updated config
self.config.save() self.config.save()
if len(self.nb_tab_names) == 1:
# only main tab open, reload profile
self.load_profile()
else:
self.warning_box("Updated preferences have not been loaded because "
+ "windows are open. Re-start fpdb to load them.")
dia.destroy() dia.destroy()
def dia_create_del_database(self, widget, data=None): def dia_create_del_database(self, widget, data=None):
@ -430,28 +489,52 @@ class fpdb:
self.release_global_lock() self.release_global_lock()
def dia_logs(self, widget, data=None): def dia_logs(self, widget, data=None):
lock_set = False """opens the log viewer window"""
if self.obtain_global_lock():
lock_set = True
dia = gtk.Dialog(title="Log Messages" #lock_set = False
,parent=None #if self.obtain_global_lock():
,flags=0 # lock_set = True
,buttons=(gtk.STOCK_CLOSE,gtk.RESPONSE_OK))
logviewer = GuiLogView.GuiLogView(self.config, self.window, dia.vbox)
response = dia.run()
if response == gtk.RESPONSE_ACCEPT:
pass
dia.destroy()
if lock_set: # remove members from self.threads if close messages received
self.release_global_lock() self.process_close_messages()
viewer = None
for i, t in enumerate(self.threads):
if str(t.__class__) == 'GuiLogView.GuiLogView':
viewer = t
break
if viewer is None:
#print "creating new log viewer"
new_thread = GuiLogView.GuiLogView(self.config, self.window, self.closeq)
self.threads.append(new_thread)
else:
#print "showing existing log viewer"
viewer.get_dialog().present()
#if lock_set:
# self.release_global_lock()
def addLogText(self, text): def addLogText(self, text):
end_iter = self.logbuffer.get_end_iter() end_iter = self.logbuffer.get_end_iter()
self.logbuffer.insert(end_iter, text) self.logbuffer.insert(end_iter, text)
self.logview.scroll_to_mark(self.logbuffer.get_insert(), 0) self.logview.scroll_to_mark(self.logbuffer.get_insert(), 0)
def process_close_messages(self):
# check for close messages
try:
while True:
name = self.closeq.get(False)
for i, t in enumerate(self.threads):
if str(t.__class__) == str(name):
# thread has ended so remove from list:
del self.threads[i]
break
except Queue.Empty:
# no close messages on queue, do nothing
pass
def __calendar_dialog(self, widget, entry): def __calendar_dialog(self, widget, entry):
self.dia_confirm.set_modal(False) self.dia_confirm.set_modal(False)
d = gtk.Window(gtk.WINDOW_TOPLEVEL) d = gtk.Window(gtk.WINDOW_TOPLEVEL)
@ -572,7 +655,7 @@ class fpdb:
('LoadProf', None, '_Load Profile (broken)', '<control>L', 'Load your profile', self.dia_load_profile), ('LoadProf', None, '_Load Profile (broken)', '<control>L', 'Load your profile', self.dia_load_profile),
('EditProf', None, '_Edit Profile (todo)', '<control>E', 'Edit your profile', self.dia_edit_profile), ('EditProf', None, '_Edit Profile (todo)', '<control>E', 'Edit your profile', self.dia_edit_profile),
('SaveProf', None, '_Save Profile (todo)', '<control>S', 'Save your profile', self.dia_save_profile), ('SaveProf', None, '_Save Profile (todo)', '<control>S', 'Save your profile', self.dia_save_profile),
('Preferences', None, '_Preferences', None, 'Edit your preferences', self.dia_preferences), ('Preferences', None, 'Pre_ferences', '<control>F', 'Edit your preferences', self.dia_preferences),
('import', None, '_Import'), ('import', None, '_Import'),
('sethharchive', None, '_Set HandHistory Archive Directory', None, 'Set HandHistory Archive Directory', self.select_hhArchiveBase), ('sethharchive', None, '_Set HandHistory Archive Directory', None, 'Set HandHistory Archive Directory', self.select_hhArchiveBase),
('bulkimp', None, '_Bulk Import', '<control>B', 'Bulk Import', self.tab_bulk_import), ('bulkimp', None, '_Bulk Import', '<control>B', 'Bulk Import', self.tab_bulk_import),
@ -626,19 +709,26 @@ class fpdb:
self.settings.update(self.config.get_import_parameters()) self.settings.update(self.config.get_import_parameters())
self.settings.update(self.config.get_default_paths()) self.settings.update(self.config.get_default_paths())
if self.db is not None and self.db.fdb is not None: if self.db is not None and self.db.connected:
self.db.disconnect() self.db.disconnect()
self.sql = SQL.Sql(db_server = self.settings['db-server']) self.sql = SQL.Sql(db_server = self.settings['db-server'])
err_msg = None
try: try:
self.db = Database.Database(self.config, sql = self.sql) self.db = Database.Database(self.config, sql = self.sql)
except Exceptions.FpdbMySQLAccessDenied: except Exceptions.FpdbMySQLAccessDenied:
self.warning_box("MySQL Server reports: Access denied. Are your permissions set correctly?") err_msg = "MySQL Server reports: Access denied. Are your permissions set correctly?"
exit()
except Exceptions.FpdbMySQLNoDatabase: except Exceptions.FpdbMySQLNoDatabase:
msg = "MySQL client reports: 2002 or 2003 error. Unable to connect - Please check that the MySQL service has been started" err_msg = "MySQL client reports: 2002 or 2003 error. Unable to connect - " \
self.warning_box(msg) + "Please check that the MySQL service has been started"
exit except Exceptions.FpdbPostgresqlAccessDenied:
err_msg = "Postgres Server reports: Access denied. Are your permissions set correctly?"
except Exceptions.FpdbPostgresqlNoDatabase:
err_msg = "Postgres client reports: Unable to connect - " \
+ "Please check that the Postgres service has been started"
if err_msg is not None:
self.db = None
self.warning_box(err_msg)
# except FpdbMySQLFailedError: # except FpdbMySQLFailedError:
# self.warning_box("Unable to connect to MySQL! Is the MySQL server running?!", "FPDB ERROR") # self.warning_box("Unable to connect to MySQL! Is the MySQL server running?!", "FPDB ERROR")
@ -656,7 +746,7 @@ class fpdb:
# print "*** Error: " + err[2] + "(" + str(err[1]) + "): " + str(sys.exc_info()[1]) # print "*** Error: " + err[2] + "(" + str(err[1]) + "): " + str(sys.exc_info()[1])
# sys.stderr.write("Failed to connect to %s database with username %s." % (self.settings['db-server'], self.settings['db-user'])) # sys.stderr.write("Failed to connect to %s database with username %s." % (self.settings['db-server'], self.settings['db-user']))
if self.db.wrongDbVersion: if self.db is not None and self.db.wrongDbVersion:
diaDbVersionWarning = gtk.Dialog(title="Strong Warning - Invalid database version", parent=None, flags=0, buttons=(gtk.STOCK_OK,gtk.RESPONSE_OK)) diaDbVersionWarning = gtk.Dialog(title="Strong Warning - Invalid database version", parent=None, flags=0, buttons=(gtk.STOCK_OK,gtk.RESPONSE_OK))
label = gtk.Label("An invalid DB version or missing tables have been detected.") label = gtk.Label("An invalid DB version or missing tables have been detected.")
@ -675,14 +765,15 @@ class fpdb:
diaDbVersionWarning.destroy() diaDbVersionWarning.destroy()
if self.status_bar is None: if self.status_bar is None:
self.status_bar = gtk.Label("Status: Connected to %s database named %s on host %s"%(self.db.get_backend_name(),self.db.database, self.db.host)) self.status_bar = gtk.Label("")
self.main_vbox.pack_end(self.status_bar, False, True, 0) self.main_vbox.pack_end(self.status_bar, False, True, 0)
self.status_bar.show() self.status_bar.show()
else:
self.status_bar.set_text("Status: Connected to %s database named %s on host %s" % (self.db.get_backend_name(),self.db.database, self.db.host))
# Database connected to successfully, load queries to pass on to other classes if self.db is not None and self.db.connected:
self.db.rollback() self.status_bar.set_text("Status: Connected to %s database named %s on host %s"
% (self.db.get_backend_name(),self.db.database, self.db.host))
# rollback to make sure any locks are cleared:
self.db.rollback()
self.validate_config() self.validate_config()
@ -703,7 +794,8 @@ class fpdb:
# TODO: can we get some / all of the stuff done in this function to execute on any kind of abort? # TODO: can we get some / all of the stuff done in this function to execute on any kind of abort?
print "Quitting normally" print "Quitting normally"
# TODO: check if current settings differ from profile, if so offer to save or abort # TODO: check if current settings differ from profile, if so offer to save or abort
self.db.disconnect() if self.db is not None and self.db.connected:
self.db.disconnect()
self.statusIcon.set_visible(False) self.statusIcon.set_visible(False)
gtk.main_quit() gtk.main_quit()
@ -770,7 +862,6 @@ This program is licensed under the AGPL3, see docs"""+os.sep+"agpl-3.0.txt")
self.add_and_display_tab(gv_tab, "Graphs") self.add_and_display_tab(gv_tab, "Graphs")
def __init__(self): def __init__(self):
self.threads = []
# no more than 1 process can this lock at a time: # no more than 1 process can this lock at a time:
self.lock = interlocks.InterProcessLock(name="fpdb_global_lock") self.lock = interlocks.InterProcessLock(name="fpdb_global_lock")
self.db = None self.db = None
@ -794,14 +885,17 @@ This program is licensed under the AGPL3, see docs"""+os.sep+"agpl-3.0.txt")
menubar.show() menubar.show()
#done menubar #done menubar
self.threads = [] # objects used by tabs - no need for threads, gtk handles it
self.closeq = Queue.Queue(20) # used to signal ending of a thread (only logviewer for now)
self.nb = gtk.Notebook() self.nb = gtk.Notebook()
self.nb.set_show_tabs(True) self.nb.set_show_tabs(True)
self.nb.show() self.nb.show()
self.main_vbox.pack_start(self.nb, True, True, 0) self.main_vbox.pack_start(self.nb, True, True, 0)
self.pages=[] self.tabs=[] # the event_boxes forming the actual tabs
self.tabs=[] self.tab_names=[] # names of tabs used since program started, not removed if tab is closed
self.tab_names=[] self.pages=[] # the contents of the page, not removed if tab is closed
self.nb_tabs=[] self.nb_tab_names=[] # list of tab names currently displayed in notebook
self.tab_main_help(None, None) self.tab_main_help(None, None)

View File

@ -129,18 +129,22 @@ class fpdb_db:
self.db = psycopg2.connect(database = database) self.db = psycopg2.connect(database = database)
connected = True connected = True
except: except:
# direct connection failed so try user/pass/... version
pass pass
#msg = "PostgreSQL direct connection to database (%s) failed, trying with user ..." % (database,)
#print msg
#raise FpdbError(msg)
if not connected: if not connected:
try: try:
self.db = psycopg2.connect(host = host, self.db = psycopg2.connect(host = host,
user = user, user = user,
password = password, password = password,
database = database) database = database)
except: except Exception, ex:
msg = "PostgreSQL connection to database (%s) user (%s) failed. Are you sure the DB is running?" % (database, user) 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 print msg
raise FpdbError(msg) raise FpdbError(msg)
elif backend == fpdb_db.SQLITE: elif backend == fpdb_db.SQLITE:
@ -154,7 +158,7 @@ class fpdb_db:
if not os.path.isdir(Configuration.DIR_DATABASES) and not database == ":memory:": if not os.path.isdir(Configuration.DIR_DATABASES) and not database == ":memory:":
print "Creating directory: '%s'" % (Configuration.DIR_DATABASES) print "Creating directory: '%s'" % (Configuration.DIR_DATABASES)
os.mkdir(Configuration.DIR_DATABASES) os.mkdir(Configuration.DIR_DATABASES)
database = os.path.join(Configuration.DIR_DATABASE, database) database = os.path.join(Configuration.DIR_DATABASES, database)
self.db = sqlite3.connect(database, detect_types=sqlite3.PARSE_DECLTYPES ) self.db = sqlite3.connect(database, detect_types=sqlite3.PARSE_DECLTYPES )
sqlite3.register_converter("bool", lambda x: bool(int(x))) sqlite3.register_converter("bool", lambda x: bool(int(x)))
sqlite3.register_adapter(bool, lambda x: "1" if x else "0") sqlite3.register_adapter(bool, lambda x: "1" if x else "0")
@ -167,6 +171,7 @@ class fpdb_db:
logging.warning("Some database functions will not work without NumPy support") logging.warning("Some database functions will not work without NumPy support")
else: else:
raise FpdbError("unrecognised database backend:"+backend) raise FpdbError("unrecognised database backend:"+backend)
self.cursor = self.db.cursor() self.cursor = self.db.cursor()
# Set up query dictionary as early in the connection process as we can. # Set up query dictionary as early in the connection process as we can.
self.sql = FpdbSQLQueries.FpdbSQLQueries(self.get_backend_name()) self.sql = FpdbSQLQueries.FpdbSQLQueries(self.get_backend_name())

View File

@ -435,12 +435,12 @@ class Importer:
for hand in handlist: for hand in handlist:
#try, except duplicates here? #try, except duplicates here?
#hand.prepInsert() hand.prepInsert(self.database)
hand.insert(self.database) hand.insert(self.database)
if self.callHud and hand.dbid_hands != 0: if self.callHud and hand.dbid_hands != 0:
#print "DEBUG: call to HUD: handsId: %s" % hand.dbid_hands #print "DEBUG: call to HUD: handsId: %s" % hand.dbid_hands
#pipe the Hands.id out to the HUD #pipe the Hands.id out to the HUD
# print "fpdb_import: sending hand to hud", handsId, "pipe =", self.caller.pipe_to_hud print "fpdb_import: sending hand to hud", hand.dbid_hands, "pipe =", self.caller.pipe_to_hud
self.caller.pipe_to_hud.stdin.write("%s" % (hand.dbid_hands) + os.linesep) self.caller.pipe_to_hud.stdin.write("%s" % (hand.dbid_hands) + os.linesep)
errors = getattr(hhc, 'numErrors') errors = getattr(hhc, 'numErrors')

View File

@ -1247,13 +1247,13 @@ sure to also change the following storage method and table_viewer.prepare_data i
if not isAllIn: if not isAllIn:
isAllIn = any(i for i in allIns[1][player]) isAllIn = any(i for i in allIns[1][player])
elif len(action_types[2][player]) > 0: if isAllIn or len(action_types[2][player]) > 0:
if all(actiontype != "fold" for actiontype in action_types[1][player]): if all(actiontype != "fold" for actiontype in action_types[1][player]):
myStreet2Seen = True myStreet2Seen = True
if not isAllIn: if not isAllIn:
isAllAin = any(i for i in allIns[2][player]) isAllAin = any(i for i in allIns[2][player])
elif len(action_types[3][player]) > 0: if isAllIn or len(action_types[3][player]) > 0:
if all(actiontype != "fold" for actiontype in action_types[2][player]): if all(actiontype != "fold" for actiontype in action_types[2][player]):
myStreet3Seen = True myStreet3Seen = True
@ -1264,7 +1264,7 @@ sure to also change the following storage method and table_viewer.prepare_data i
#print "in else" #print "in else"
if not isAllIn: if not isAllIn:
isAllIn = any(i for i in allIns[3][player]) isAllIn = any(i for i in allIns[3][player])
elif len(action_types[4][player]) > 0: if isAllIn or len(action_types[4][player]) > 0:
#print "in if" #print "in if"
myStreet4Seen = True myStreet4Seen = True