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

This commit is contained in:
grindi 2009-12-17 15:54:35 +03:00
commit 28345009e1
32 changed files with 2078 additions and 508 deletions

11
Makefile Normal file
View File

@ -0,0 +1,11 @@
# Variable definitions
VERSION = 0.12
DATE = $(shell date +%Y%m%d)
all:
@echo "Usage:"
@echo " make snapshot - Tags the repository with $(VERSION)-$(DATE) and creates a tarball from that"
snapshot:
git tag $(VERSION)-$(DATE)
git archive --prefix=fpdb-$(VERSION)-$(DATE)/ $(VERSION)-$(DATE) | gzip -9 > ../fpdb-$(VERSION)-$(DATE).tar.gz

37
pyfpdb/Anonymise.py Normal file
View File

@ -0,0 +1,37 @@
import os
import re
import codecs
import Options
import HandHistoryConverter
(options, argv) = Options.fpdb_options()
filter = options.hhc
filter_name = filter.replace("ToFpdb", "")
mod = __import__(filter)
obj = getattr(mod, filter_name, None)
hhc = obj(autostart=False)
if os.path.exists(options.infile):
in_fh = codecs.open(options.infile, 'r', "utf8")
filecontents = in_fh.read()
in_fh.close()
else:
print "Could not find file %s" % options.infile
exit(1)
m = hhc.re_PlayerInfo.finditer(filecontents)
players = []
for a in m:
players = players + [a.group('PNAME')]
uniq = set(players)
for i, name in enumerate(uniq, 1):
filecontents = filecontents.replace(name, 'Player%d' %i)
print filecontents

166
pyfpdb/Database.py Executable file → Normal file
View File

@ -59,6 +59,7 @@ class Database:
SQLITE = 4 SQLITE = 4
hero_hudstart_def = '1999-12-31' # default for length of Hero's stats in HUD hero_hudstart_def = '1999-12-31' # default for length of Hero's stats in HUD
villain_hudstart_def = '1999-12-31' # default for length of Villain's stats in HUD
# Data Structures for index and foreign key creation # Data Structures for index and foreign key creation
# drop_code is an int with possible values: 0 - don't drop for bulk import # drop_code is an int with possible values: 0 - don't drop for bulk import
@ -186,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)
@ -236,7 +238,12 @@ class Database:
self.hud_style = style self.hud_style = style
def do_connect(self, c): def do_connect(self, c):
try:
self.fdb.do_connect(c) 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
@ -246,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()
@ -253,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()
@ -473,8 +484,9 @@ class Database:
else: else:
h_seats_min, h_seats_max = 0, 10 h_seats_min, h_seats_max = 0, 10
print "bad h_seats_style value:", h_seats_style print "bad h_seats_style value:", h_seats_style
print "opp seats style", seats_style, "hero seats style", h_seats_style log.info("opp seats style %s %d %d hero seats style %s %d %d"
print "opp seats:", seats_min, seats_max, " hero seats:", h_seats_min, h_seats_max % (seats_style, seats_min, seats_max
,h_seats_style, h_seats_min, h_seats_max) )
if hud_style == 'S' or h_hud_style == 'S': if hud_style == 'S' or h_hud_style == 'S':
self.get_stats_from_hand_session(hand, stat_dict, hero_id self.get_stats_from_hand_session(hand, stat_dict, hero_id
@ -1324,7 +1336,7 @@ class Database:
self.dropAllForeignKeys() self.dropAllForeignKeys()
self.createAllForeignKeys() self.createAllForeignKeys()
def rebuild_hudcache(self, start=None): def rebuild_hudcache(self, h_start=None, v_start=None):
"""clears hudcache and rebuilds from the individual handsplayers records""" """clears hudcache and rebuilds from the individual handsplayers records"""
try: try:
@ -1344,13 +1356,17 @@ class Database:
if p_id: if p_id:
self.hero_ids[site_id] = int(p_id) self.hero_ids[site_id] = int(p_id)
if start is None: if h_start is None:
start = self.hero_hudstart_def h_start = self.hero_hudstart_def
if v_start is None:
v_start = self.villain_hudstart_def
if self.hero_ids == {}: if self.hero_ids == {}:
where = "" where = ""
else: else:
where = "where hp.playerId not in " + str(tuple(self.hero_ids.values())) \ where = "where ( hp.playerId not in " + str(tuple(self.hero_ids.values())) \
+ " or h.handStart > '" + start + "'" + " and h.handStart > '" + v_start + "')" \
+ " or ( hp.playerId in " + str(tuple(self.hero_ids.values())) \
+ " and h.handStart > '" + h_start + "')"
rebuild_sql = self.sql.query['rebuildHudCache'].replace('<where_clause>', where) rebuild_sql = self.sql.query['rebuildHudCache'].replace('<where_clause>', where)
self.get_cursor().execute(self.sql.query['clearHudCache']) self.get_cursor().execute(self.sql.query['clearHudCache'])
@ -1602,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
@ -1911,8 +1867,10 @@ class Database:
,(name, site_id)) ,(name, site_id))
#Get last id might be faster here. #Get last id might be faster here.
#c.execute ("SELECT id FROM Players WHERE name=%s", (name,)) #c.execute ("SELECT id FROM Players WHERE name=%s", (name,))
tmp = [self.get_last_insert_id(c)] result = self.get_last_insert_id(c)
return tmp[0] else:
result = tmp[1]
return result
def insertGameTypes(self, row): def insertGameTypes(self, row):
c = self.get_cursor() c = self.get_cursor()

View File

@ -17,6 +17,7 @@
#fpdb modules #fpdb modules
import Card import Card
from decimal import Decimal
DEBUG = False DEBUG = False
@ -43,9 +44,9 @@ class DerivedStats():
self.handsplayers[player[1]]['totalProfit'] = 0 self.handsplayers[player[1]]['totalProfit'] = 0
self.handsplayers[player[1]]['street4Seen'] = False self.handsplayers[player[1]]['street4Seen'] = False
self.handsplayers[player[1]]['street4Aggr'] = False self.handsplayers[player[1]]['street4Aggr'] = False
self.handsplayers[player[1]]['wonWhenSeenStreet1'] = False self.handsplayers[player[1]]['wonWhenSeenStreet1'] = 0.0
self.handsplayers[player[1]]['sawShowdown'] = False self.handsplayers[player[1]]['sawShowdown'] = False
self.handsplayers[player[1]]['wonAtSD'] = False self.handsplayers[player[1]]['wonAtSD'] = 0.0
for i in range(5): for i in range(5):
self.handsplayers[player[1]]['street%dCalls' % i] = 0 self.handsplayers[player[1]]['street%dCalls' % i] = 0
self.handsplayers[player[1]]['street%dBets' % i] = 0 self.handsplayers[player[1]]['street%dBets' % i] = 0
@ -53,6 +54,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)
@ -114,7 +136,7 @@ class DerivedStats():
#hand.players = [[seat, name, chips],[seat, name, chips]] #hand.players = [[seat, name, chips],[seat, name, chips]]
for player in hand.players: for player in hand.players:
self.handsplayers[player[1]]['seatNo'] = player[0] self.handsplayers[player[1]]['seatNo'] = player[0]
self.handsplayers[player[1]]['startCash'] = player[2] self.handsplayers[player[1]]['startCash'] = int(100 * Decimal(player[2]))
for i, street in enumerate(hand.actionStreets[2:]): for i, street in enumerate(hand.actionStreets[2:]):
self.seen(self.hand, i+1) self.seen(self.hand, i+1)
@ -134,9 +156,9 @@ class DerivedStats():
# Should be fine for split-pots, but won't be accurate for multi-way pots # Should be fine for split-pots, but won't be accurate for multi-way pots
self.handsplayers[player]['rake'] = int(100* hand.rake)/len(hand.collectees) self.handsplayers[player]['rake'] = int(100* hand.rake)/len(hand.collectees)
if self.handsplayers[player]['street1Seen'] == True: if self.handsplayers[player]['street1Seen'] == True:
self.handsplayers[player]['wonWhenSeenStreet1'] = True self.handsplayers[player]['wonWhenSeenStreet1'] = 1.0
if self.handsplayers[player]['sawShowdown'] == True: if self.handsplayers[player]['sawShowdown'] == True:
self.handsplayers[player]['wonAtSD'] = True self.handsplayers[player]['wonAtSD'] = 1.0
for player in hand.pot.committed: for player in hand.pot.committed:
self.handsplayers[player]['totalProfit'] = int(self.handsplayers[player]['winnings'] - (100*hand.pot.committed[player])) self.handsplayers[player]['totalProfit'] = int(self.handsplayers[player]['winnings'] - (100*hand.pot.committed[player]))
@ -149,6 +171,33 @@ 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,
#Stud 3rd street card test
# denny501: brings in for $0.02
# s0rrow: calls $0.02
# TomSludge: folds
# Soroka69: calls $0.02
# rdiezchang: calls $0.02 (Seat 8)
# u.pressure: folds (Seat 1)
# 123smoothie: calls $0.02
# gashpor: calls $0.02
# Additional stats
# 3betSB, 3betBB
# Squeeze, Ratchet?
def getPosition(hand, seat):
"""Returns position value like 'B', 'S', 0, 1, ..."""
# Flop/Draw games with blinds
# Need a better system???
# -2 BB - B (all)
# -1 SB - S (all)
# 0 Button
# 1 Cutoff
# 2 Hijack
def assembleHudCache(self, hand): def assembleHudCache(self, hand):
pass pass
@ -195,6 +244,7 @@ class DerivedStats():
pas = set.union(self.pfba(actions) - self.pfba(actions, l=('folds',)), alliners) pas = set.union(self.pfba(actions) - self.pfba(actions, l=('folds',)), alliners)
self.hands['playersAtShowdown'] = len(pas) self.hands['playersAtShowdown'] = len(pas)
if self.hands['playersAtShowdown'] > 1:
for player in pas: for player in pas:
self.handsplayers[player]['sawShowdown'] = True self.handsplayers[player]['sawShowdown'] = True

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

@ -479,7 +479,8 @@ class Filters(threading.Thread):
self.cursor.execute(self.sql.query['getLimits2']) self.cursor.execute(self.sql.query['getLimits2'])
# selects limitType, bigBlind # selects limitType, bigBlind
result = self.db.cursor.fetchall() result = self.db.cursor.fetchall()
fl, nl = False, False found = {'nl':False, 'fl':False, 'ring':False, 'tour':False}
if len(result) >= 1: if len(result) >= 1:
hbox = gtk.HBox(True, 0) hbox = gtk.HBox(True, 0)
vbox1.pack_start(hbox, False, False, 0) vbox1.pack_start(hbox, False, False, 0)
@ -487,7 +488,6 @@ class Filters(threading.Thread):
hbox.pack_start(vbox2, False, False, 0) hbox.pack_start(vbox2, False, False, 0)
vbox3 = gtk.VBox(False, 0) vbox3 = gtk.VBox(False, 0)
hbox.pack_start(vbox3, False, False, 0) hbox.pack_start(vbox3, False, False, 0)
found = {'nl':False, 'fl':False, 'ring':False, 'tour':False}
for i, line in enumerate(result): for i, line in enumerate(result):
if "UseType" in self.display: if "UseType" in self.display:
if line[0] != self.display["UseType"]: if line[0] != self.display["UseType"]:

View File

@ -326,6 +326,8 @@ def main(argv=None):
help="How often to print a one-line status report (0 (default) means never)") help="How often to print a one-line status report (0 (default) means never)")
parser.add_option("-u", "--usage", action="store_true", dest="usage", default=False, parser.add_option("-u", "--usage", action="store_true", dest="usage", default=False,
help="Print some useful one liners") help="Print some useful one liners")
parser.add_option("-s", "--starsarchive", action="store_true", dest="starsArchive", default=False,
help="Do the required conversion for Stars Archive format (ie. as provided by support")
(options, argv) = parser.parse_args(args = argv) (options, argv) = parser.parse_args(args = argv)
if options.usage == True: if options.usage == True:
@ -369,6 +371,8 @@ def main(argv=None):
importer.setThreads(-1) importer.setThreads(-1)
importer.addBulkImportImportFileOrDir(os.path.expanduser(options.filename), site=options.filtername) importer.addBulkImportImportFileOrDir(os.path.expanduser(options.filename), site=options.filtername)
importer.setCallHud(False) importer.setCallHud(False)
if options.starsArchive:
importer.setStarsArchive(True)
(stored, dups, partial, errs, ttime) = importer.runImport() (stored, dups, partial, errs, ttime) = importer.runImport()
importer.clearFileList() importer.clearFileList()
print 'GuiBulkImport done: Stored: %d \tDuplicates: %d \tPartial: %d \tErrors: %d in %s seconds - %.0f/sec'\ print 'GuiBulkImport done: Stored: %d \tDuplicates: %d \tPartial: %d \tErrors: %d in %s seconds - %.0f/sec'\

View File

@ -31,6 +31,7 @@ try:
from matplotlib.figure import Figure from matplotlib.figure import Figure
from matplotlib.backends.backend_gtk import FigureCanvasGTK as FigureCanvas from matplotlib.backends.backend_gtk import FigureCanvasGTK as FigureCanvas
from matplotlib.backends.backend_gtkagg import NavigationToolbar2GTKAgg as NavigationToolbar from matplotlib.backends.backend_gtkagg import NavigationToolbar2GTKAgg as NavigationToolbar
from matplotlib.font_manager import FontProperties
from numpy import arange, cumsum from numpy import arange, cumsum
from pylab import * from pylab import *
except ImportError, inst: except ImportError, inst:
@ -170,7 +171,7 @@ class GuiGraphViewer (threading.Thread):
#Get graph data from DB #Get graph data from DB
starttime = time() starttime = time()
line = self.getRingProfitGraph(playerids, sitenos, limits) (green, blue, red) = self.getRingProfitGraph(playerids, sitenos, limits)
print "Graph generated in: %s" %(time() - starttime) print "Graph generated in: %s" %(time() - starttime)
self.ax.set_title("Profit graph for ring games") self.ax.set_title("Profit graph for ring games")
@ -179,22 +180,27 @@ class GuiGraphViewer (threading.Thread):
self.ax.set_xlabel("Hands", fontsize = 12) self.ax.set_xlabel("Hands", fontsize = 12)
self.ax.set_ylabel("$", fontsize = 12) self.ax.set_ylabel("$", fontsize = 12)
self.ax.grid(color='g', linestyle=':', linewidth=0.2) self.ax.grid(color='g', linestyle=':', linewidth=0.2)
if line == None or line == []: if green == None or green == []:
#TODO: Do something useful like alert user #TODO: Do something useful like alert user
print "No hands returned by graph query" print "No hands returned by graph query"
else: else:
# text = "All Hands, " + sitename + str(name) + "\nProfit: $" + str(line[-1]) + "\nTotal Hands: " + str(len(line)) #text = "Profit: $%.2f\nTotal Hands: %d" %(green[-1], len(green))
text = "All Hands, " + "\nProfit: $" + str(line[-1]) + "\nTotal Hands: " + str(len(line)) #self.ax.annotate(text,
# xy=(10, -10),
self.ax.annotate(text, # xycoords='axes points',
xy=(10, -10), # horizontalalignment='left', verticalalignment='top',
xycoords='axes points', # fontsize=10)
horizontalalignment='left', verticalalignment='top',
fontsize=10)
#Draw plot #Draw plot
self.ax.plot(line,) self.ax.plot(green, color='green', label='Hands: %d\nProfit: $%.2f' %(len(green), green[-1]))
self.ax.plot(blue, color='blue', label='Showdown: $%.2f' %(blue[-1]))
self.ax.plot(red, color='red', label='Non-showdown: $%.2f' %(red[-1]))
if sys.version[0:3] == '2.5':
self.ax.legend(loc='best', shadow=True, prop=FontProperties(size='smaller'))
else:
self.ax.legend(loc='best', fancybox=True, shadow=True, prop=FontProperties(size='smaller'))
self.graphBox.add(self.canvas) self.graphBox.add(self.canvas)
self.canvas.show() self.canvas.show()
@ -270,9 +276,13 @@ class GuiGraphViewer (threading.Thread):
if winnings == (): if winnings == ():
return None return None
y = map(lambda x:float(x[1]), winnings) green = map(lambda x:float(x[1]), winnings)
line = cumsum(y) blue = map(lambda x: float(x[1]) if x[2] == True else 0.0, winnings)
return line/100 red = map(lambda x: float(x[1]) if x[2] == False else 0.0, winnings)
greenline = cumsum(green)
blueline = cumsum(blue)
redline = cumsum(red)
return (greenline/100, blueline/100, redline/100)
#end of def getRingProfitGraph #end of def getRingProfitGraph
def exportGraph (self, widget, data): def exportGraph (self, widget, data):

185
pyfpdb/GuiLogView.py Executable file
View File

@ -0,0 +1,185 @@
#!/usr/bin/python
# -*- coding: utf-8 -*-
#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 Queue
import pygtk
pygtk.require('2.0')
import gtk
import gobject
import pango
import Configuration
log = Configuration.get_logger("logging.conf", "logview")
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:
def __init__(self, config, mainwin, closeq):
self.config = config
self.main_window = mainwin
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);
self.liststore = gtk.ListStore(str, str, str, str, gobject.TYPE_BOOLEAN) # date, module, level, text
# this is how to add a filter:
#
# # Creation of the filter, from the model
# filter = self.liststore.filter_new()
# filter.set_visible_column(1)
#
# # The TreeView gets the filter as model
# self.listview = gtk.TreeView(filter)
self.listview = gtk.TreeView(model=self.liststore)
self.listview.set_grid_lines(gtk.TREE_VIEW_GRID_LINES_NONE)
self.listcols = []
scrolledwindow = gtk.ScrolledWindow()
scrolledwindow.set_policy(gtk.POLICY_AUTOMATIC, gtk.POLICY_AUTOMATIC)
scrolledwindow.add(self.listview)
self.vbox.pack_start(scrolledwindow, expand=True, fill=True, padding=0)
refreshbutton = gtk.Button("Refresh")
refreshbutton.connect("clicked", self.refresh, None)
self.vbox.pack_start(refreshbutton, False, False, 3)
refreshbutton.show()
self.listview.show()
scrolledwindow.show()
self.vbox.show()
self.dia.set_focus(self.listview)
col = self.addColumn("Date/Time", 0)
col = self.addColumn("Module", 1)
col = self.addColumn("Level", 2)
col = self.addColumn("Text", 3)
self.loadLog()
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):
col = gtk.TreeViewColumn(title)
self.listview.append_column(col)
cRender = gtk.CellRendererText()
cRender.set_property("wrap-mode", pango.WRAP_WORD_CHAR)
col.pack_start(cRender, True)
col.add_attribute(cRender, 'text', n)
col.set_max_width(1000)
col.set_spacing(0) # no effect
self.listcols.append(col)
col.set_clickable(True)
col.connect("clicked", self.sortCols, n)
return(col)
def loadLog(self):
self.liststore.clear()
self.listcols = []
# guesstimate number of lines in file
if os.path.exists(logfile):
stat_info = os.stat(logfile)
lines = stat_info.st_size / EST_CHARS_PER_LINE
print "logview: size =", stat_info.st_size, "lines =", lines
# set startline to line number to start display from
startline = 0
if lines > MAX_LINES:
# only display from startline if log file is large
startline = lines - MAX_LINES
l = 0
for line in open(logfile):
# eg line:
# 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) )
def sortCols(self, col, n):
try:
if not col.get_sort_indicator() or col.get_sort_order() == gtk.SORT_ASCENDING:
col.set_sort_order(gtk.SORT_DESCENDING)
else:
col.set_sort_order(gtk.SORT_ASCENDING)
self.liststore.set_sort_column_id(n, col.get_sort_order())
#self.liststore.set_sort_func(n, self.sortnums, (n,grid))
for i in xrange(len(self.listcols)):
self.listcols[i].set_sort_indicator(False)
self.listcols[n].set_sort_indicator(True)
# use this listcols[col].set_sort_indicator(True)
# to turn indicator off for other cols
except:
err = traceback.extract_tb(sys.exc_info()[2])
print "***sortCols error: " + str(sys.exc_info()[1])
print "\n".join( [e[0]+':'+str(e[1])+" "+e[2] for e in err] )
def refresh(self, widget, data):
self.loadLog()
if __name__=="__main__":
config = Configuration.Config()
win = gtk.Window(gtk.WINDOW_TOPLEVEL)
win.set_title("Test Log Viewer")
win.set_border_width(1)
win.set_default_size(600, 500)
win.set_resizable(True)
dia = gtk.Dialog("Log Viewer",
win,
gtk.DIALOG_MODAL | gtk.DIALOG_DESTROY_WITH_PARENT,
(gtk.STOCK_CLOSE, gtk.RESPONSE_OK))
dia.set_default_size(500, 500)
log = GuiLogView(config, win, dia.vbox)
response = dia.run()
if response == gtk.RESPONSE_ACCEPT:
pass
dia.destroy()

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

@ -574,7 +574,7 @@ Left-Drag to Move"
</hhcs> </hhcs>
<supported_databases> <supported_databases>
<database db_ip="localhost" db_name=":memory:" db_pass="fpdb" db_server="sqlite" db_user="fpdb"/> <database db_ip="localhost" db_name="fpdb" db_pass="fpdb" db_server="sqlite" db_user="fpdb"/>
</supported_databases> </supported_databases>
</FreePokerToolsConfig> </FreePokerToolsConfig>

View File

@ -387,6 +387,18 @@ Left-Drag to Move"
<location seat="8" x="0" y="181"> </location> <location seat="8" x="0" y="181"> </location>
<location seat="9" x="70" y="53"> </location> <location seat="9" x="70" y="53"> </location>
</layout> </layout>
<layout fav_seat="6" height="547" max="10" width="794">
<location seat="1" x="698" y="69"> </location>
<location seat="2" x="716" y="243"> </location>
<location seat="3" x="699" y="301"> </location>
<location seat="4" x="456" y="391"> </location>
<location seat="5" x="338" y="369"> </location>
<location seat="6" x="98" y="363"> </location>
<location seat="7" x="15" y="242"> </location>
<location seat="8" x="11" y="55"> </location>
<location seat="9" x="341" y="30"> </location>
<location seat="10" x="562" y="8"> </location>
</layout>
</site> </site>

View File

@ -63,6 +63,9 @@ elif os.name == 'nt':
import Hud import Hud
log = Configuration.get_logger("logging.conf")
class HUD_main(object): class HUD_main(object):
"""A main() object to own both the read_stdin thread and the gui.""" """A main() object to own both the read_stdin thread and the gui."""
# This class mainly provides state for controlling the multiple HUDs. # This class mainly provides state for controlling the multiple HUDs.
@ -159,10 +162,10 @@ class HUD_main(object):
# function idle_func() to be run by the gui thread, at its leisure. # function idle_func() to be run by the gui thread, at its leisure.
def idle_func(): def idle_func():
gtk.gdk.threads_enter() gtk.gdk.threads_enter()
try:
self.hud_dict[table_name].update(new_hand_id, config) self.hud_dict[table_name].update(new_hand_id, config)
# The HUD could get destroyed in the above call ^^, which leaves us with a KeyError here vv # The HUD could get destroyed in the above call ^^, which leaves us with a KeyError here vv
# if we ever get an error we need to expect ^^ then we need to handle it vv - Eric # if we ever get an error we need to expect ^^ then we need to handle it vv - Eric
try:
[aw.update_gui(new_hand_id) for aw in self.hud_dict[table_name].aux_windows] [aw.update_gui(new_hand_id) for aw in self.hud_dict[table_name].aux_windows]
except KeyError: except KeyError:
pass pass
@ -192,6 +195,8 @@ class HUD_main(object):
while 1: # wait for a new hand number on stdin while 1: # wait for a new hand number on stdin
new_hand_id = sys.stdin.readline() new_hand_id = sys.stdin.readline()
t0 = time.time()
t1 = t2 = t3 = t4 = t5 = t6 = t0
new_hand_id = string.rstrip(new_hand_id) new_hand_id = string.rstrip(new_hand_id)
if new_hand_id == "": # blank line means quit if new_hand_id == "": # blank line means quit
self.destroy() self.destroy()
@ -206,6 +211,7 @@ class HUD_main(object):
print "db error: skipping %s" % new_hand_id print "db error: skipping %s" % new_hand_id
sys.stderr.write("Database error: could not find hand %s.\n" % new_hand_id) sys.stderr.write("Database error: could not find hand %s.\n" % new_hand_id)
continue continue
t1 = time.time()
if type == "tour": # hand is from a tournament if type == "tour": # hand is from a tournament
temp_key = tour_number temp_key = tour_number
@ -215,6 +221,12 @@ class HUD_main(object):
# Update an existing HUD # Update an existing HUD
if temp_key in self.hud_dict: if temp_key in self.hud_dict:
# get stats using hud's specific params and get cards # get stats using hud's specific params and get cards
self.db_connection.init_hud_stat_vars( self.hud_dict[temp_key].hud_params['hud_days']
, self.hud_dict[temp_key].hud_params['h_hud_days'])
t2 = time.time()
stat_dict = self.db_connection.get_stats_from_hand(new_hand_id, type, self.hud_dict[temp_key].hud_params
,self.hero_ids[site_id], num_seats)
t3 = time.time()
try: try:
self.db_connection.init_hud_stat_vars( self.hud_dict[temp_key].hud_params['hud_days'] self.db_connection.init_hud_stat_vars( self.hud_dict[temp_key].hud_params['hud_days']
, self.hud_dict[temp_key].hud_params['h_hud_days']) , self.hud_dict[temp_key].hud_params['h_hud_days'])
@ -238,8 +250,10 @@ class HUD_main(object):
else: else:
# get stats using default params--also get cards # get stats using default params--also get cards
self.db_connection.init_hud_stat_vars( self.hud_params['hud_days'], self.hud_params['h_hud_days'] ) self.db_connection.init_hud_stat_vars( self.hud_params['hud_days'], self.hud_params['h_hud_days'] )
t4 = time.time()
stat_dict = self.db_connection.get_stats_from_hand(new_hand_id, type, self.hud_params stat_dict = self.db_connection.get_stats_from_hand(new_hand_id, type, self.hud_params
,self.hero_ids[site_id], num_seats) ,self.hero_ids[site_id], num_seats)
t5 = time.time()
cards = self.db_connection.get_cards(new_hand_id) cards = self.db_connection.get_cards(new_hand_id)
comm_cards = self.db_connection.get_common_cards(new_hand_id) comm_cards = self.db_connection.get_common_cards(new_hand_id)
if comm_cards != {}: # stud! if comm_cards != {}: # stud!
@ -263,6 +277,9 @@ class HUD_main(object):
else: else:
sys.stderr.write('Table "%s" no longer exists\n' % table_name) sys.stderr.write('Table "%s" no longer exists\n' % table_name)
t6 = time.time()
log.info("HUD_main.read_stdin: hand read in %4.3f seconds (%4.3f,%4.3f,%4.3f,%4.3f,%4.3f,%4.3f)"
% (t6-t0,t1-t0,t2-t0,t3-t0,t4-t0,t5-t0,t6-t0))
self.db_connection.connection.rollback() self.db_connection.connection.rollback()
if __name__== "__main__": if __name__== "__main__":

View File

@ -54,6 +54,10 @@ class Hand(object):
self.starttime = 0 self.starttime = 0
self.handText = handText self.handText = handText
self.handid = 0 self.handid = 0
self.cancelled = False
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
@ -188,22 +192,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)
@ -212,14 +215,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)
handid = db.storeHand(hh) self.dbid_hands = db.storeHand(hh)
db.storeHandsPlayers(handid, 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 ?
@ -261,6 +264,9 @@ If a player has None chips he won't be added."""
log.debug("markStreets:\n"+ str(self.streets)) log.debug("markStreets:\n"+ str(self.streets))
else: else:
log.error("markstreets didn't match") log.error("markstreets didn't match")
log.error(" - Assuming hand cancelled")
self.cancelled = True
raise FpdbParseError
def checkPlayerExists(self,player): def checkPlayerExists(self,player):
if player not in [p[1] for p in self.players]: if player not in [p[1] for p in self.players]:
@ -611,6 +617,8 @@ class HoldemOmahaHand(Hand):
hhc.readPlayerStacks(self) hhc.readPlayerStacks(self)
hhc.compilePlayerRegexs(self) hhc.compilePlayerRegexs(self)
hhc.markStreets(self) hhc.markStreets(self)
if self.cancelled:
return
hhc.readBlinds(self) hhc.readBlinds(self)
hhc.readAntes(self) hhc.readAntes(self)
hhc.readButton(self) hhc.readButton(self)

View File

@ -57,7 +57,7 @@ class HandHistoryConverter():
codepage = "cp1252" codepage = "cp1252"
def __init__(self, in_path = '-', out_path = '-', follow=False, index=0, autostart=True): def __init__(self, in_path = '-', out_path = '-', follow=False, index=0, autostart=True, starsArchive=False):
"""\ """\
in_path (default '-' = sys.stdin) in_path (default '-' = sys.stdin)
out_path (default '-' = sys.stdout) out_path (default '-' = sys.stdout)
@ -66,11 +66,14 @@ follow : whether to tail -f the input"""
log.info("HandHistory init - %s subclass, in_path '%s'; out_path '%s'" % (self.sitename, in_path, out_path) ) log.info("HandHistory init - %s subclass, in_path '%s'; out_path '%s'" % (self.sitename, in_path, out_path) )
self.index = 0 self.index = 0
self.starsArchive = starsArchive
self.in_path = in_path self.in_path = in_path
self.out_path = out_path self.out_path = out_path
self.processedHands = [] self.processedHands = []
self.numHands = 0
self.numErrors = 0
# Tourney object used to store TourneyInfo when called to deal with a Summary file # Tourney object used to store TourneyInfo when called to deal with a Summary file
self.tourney = None self.tourney = None
@ -135,17 +138,17 @@ Otherwise, finish at EOF.
return return
try: try:
numHands = 0 self.numHands = 0
numErrors = 0 self.numErrors = 0
if self.follow: if self.follow:
#TODO: See how summary files can be handled on the fly (here they should be rejected as before) #TODO: See how summary files can be handled on the fly (here they should be rejected as before)
log.info("Tailing '%s'" % self.in_path) log.info("Tailing '%s'" % self.in_path)
for handText in self.tailHands(): for handText in self.tailHands():
try: try:
self.processHand(handText) self.processHand(handText)
numHands += 1 self.numHands += 1
except FpdbParseError, e: except FpdbParseError, e:
numErrors += 1 self.numErrors += 1
log.warning("Failed to convert hand %s" % e.hid) log.warning("Failed to convert hand %s" % e.hid)
log.warning("Exception msg: '%s'" % str(e)) log.warning("Exception msg: '%s'" % str(e))
log.debug(handText) log.debug(handText)
@ -160,13 +163,13 @@ Otherwise, finish at EOF.
try: try:
self.processedHands.append(self.processHand(handText)) self.processedHands.append(self.processHand(handText))
except FpdbParseError, e: except FpdbParseError, e:
numErrors += 1 self.numErrors += 1
log.warning("Failed to convert hand %s" % e.hid) log.warning("Failed to convert hand %s" % e.hid)
log.warning("Exception msg: '%s'" % str(e)) log.warning("Exception msg: '%s'" % str(e))
log.debug(handText) log.debug(handText)
numHands = len(handsList) self.numHands = len(handsList)
endtime = time.time() endtime = time.time()
log.info("Read %d hands (%d failed) in %.3f seconds" % (numHands, numErrors, endtime - starttime)) log.info("Read %d hands (%d failed) in %.3f seconds" % (self.numHands, self.numErrors, endtime - starttime))
else: else:
self.parsedObjectType = "Summary" self.parsedObjectType = "Summary"
summaryParsingStatus = self.readSummaryInfo(handsList) summaryParsingStatus = self.readSummaryInfo(handsList)
@ -252,6 +255,11 @@ which it expects to find at self.re_TailSplitHands -- see for e.g. Everleaf.py.
self.readFile() self.readFile()
self.obs = self.obs.strip() self.obs = self.obs.strip()
self.obs = self.obs.replace('\r\n', '\n') self.obs = self.obs.replace('\r\n', '\n')
if self.starsArchive == True:
log.debug("Converting starsArchive format to readable")
m = re.compile('^Hand #\d+', re.MULTILINE)
self.obs = m.sub('', self.obs)
if self.obs is None or self.obs == "": if self.obs is None or self.obs == "":
log.info("Read no hands.") log.info("Read no hands.")
return [] return []

View File

@ -358,7 +358,7 @@ class Hud:
def change_max_seats(self, widget): def change_max_seats(self, widget):
if self.max != widget.ms: if self.max != widget.ms:
print 'change_max_seats', widget.ms #print 'change_max_seats', widget.ms
self.max = widget.ms self.max = widget.ms
try: try:
self.kill() self.kill()
@ -678,7 +678,7 @@ class Stat_Window:
return True return True
def kill_popup(self, popup): def kill_popup(self, popup):
print "remove popup", popup #print "remove popup", popup
self.popups.remove(popup) self.popups.remove(popup)
popup.window.destroy() popup.window.destroy()

View File

@ -36,8 +36,11 @@ def fpdb_options():
action="store_true", action="store_true",
help="Indicates program was restarted with a different path (only allowed once).") help="Indicates program was restarted with a different path (only allowed once).")
parser.add_option("-i", "--infile", parser.add_option("-i", "--infile",
dest="config", default=None, dest="infile", default="Slartibartfast",
help="Input file") help="Input file")
parser.add_option("-k", "--konverter",
dest="hhc", default="PokerStarsToFpdb",
help="Module name for Hand History Converter")
(options, argv) = parser.parse_args() (options, argv) = parser.parse_args()
return (options, argv) return (options, argv)

View File

@ -1317,6 +1317,7 @@ class Sql:
1.25 would be a config value so user could change it) 1.25 would be a config value so user could change it)
*/ */
GROUP BY hc.PlayerId, hp.seatNo, p.name GROUP BY hc.PlayerId, hp.seatNo, p.name
ORDER BY hc.PlayerId, hp.seatNo, p.name
""" """
# same as above except stats are aggregated for all blind/limit levels # same as above except stats are aggregated for all blind/limit levels
@ -1418,6 +1419,7 @@ class Sql:
) )
) )
GROUP BY hc.PlayerId, p.name GROUP BY hc.PlayerId, p.name
ORDER BY hc.PlayerId, p.name
""" """
# NOTES on above cursor: # NOTES on above cursor:
# - Do NOT include %s inside query in a comment - the db api thinks # - Do NOT include %s inside query in a comment - the db api thinks
@ -2561,7 +2563,7 @@ class Sql:
# self.query['playerStatsByPosition'] = """ """ # self.query['playerStatsByPosition'] = """ """
self.query['getRingProfitAllHandsPlayerIdSite'] = """ self.query['getRingProfitAllHandsPlayerIdSite'] = """
SELECT hp.handId, hp.totalProfit SELECT hp.handId, hp.totalProfit, hp.sawShowdown
FROM HandsPlayers hp FROM HandsPlayers hp
INNER JOIN Players pl ON (pl.id = hp.playerId) INNER JOIN Players pl ON (pl.id = hp.playerId)
INNER JOIN Hands h ON (h.id = hp.handId) INNER JOIN Hands h ON (h.id = hp.handId)
@ -2572,7 +2574,7 @@ class Sql:
AND h.handStart < '<enddate_test>' AND h.handStart < '<enddate_test>'
<limit_test> <limit_test>
AND hp.tourneysPlayersId IS NULL AND hp.tourneysPlayersId IS NULL
GROUP BY h.handStart, hp.handId, hp.totalProfit GROUP BY h.handStart, hp.handId, hp.sawShowdown, hp.totalProfit
ORDER BY h.handStart""" ORDER BY h.handStart"""
#################################### ####################################
@ -2787,8 +2789,6 @@ class Sql:
,hp.tourneyTypeId ,hp.tourneyTypeId
,date_format(h.handStart, 'd%y%m%d') ,date_format(h.handStart, 'd%y%m%d')
""" """
#>>>>>>> 28ca49d592c8e706ad6ee58dd26655bcc33fc5fb:pyfpdb/SQL.py
#"""
elif db_server == 'postgresql': elif db_server == 'postgresql':
self.query['rebuildHudCache'] = """ self.query['rebuildHudCache'] = """
INSERT INTO HudCache INSERT INTO HudCache
@ -3325,8 +3325,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?)
@ -37,14 +38,20 @@ if os.name == 'nt' and sys.version[0:3] not in ('2.5', '2.6') and '-r' not in sy
os.execvpe('python.exe', ('python.exe', 'fpdb.py', '-r'), os.environ) # first arg is ignored (name of program being run) os.execvpe('python.exe', ('python.exe', 'fpdb.py', '-r'), os.environ) # first arg is ignored (name of program being run)
else: else:
print "\npython 2.5 not found, please install python 2.5 or 2.6 for fpdb\n" print "\npython 2.5 not found, please install python 2.5 or 2.6 for fpdb\n"
exit raw_input("Press ENTER to continue.")
exit()
else: else:
pass pass
#print "debug - not changing path" #print "debug - not changing path"
if os.name == 'nt': if os.name == 'nt':
try:
import win32api import win32api
import win32con import win32con
except ImportError:
print "We appear to be running in Windows, but the Windows Python Extensions are not loading. Please install the PYWIN32 package from http://sourceforge.net/projects/pywin32/"
raw_input("Press ENTER to continue.")
exit()
print "Python " + sys.version[0:3] + '...\n' print "Python " + sys.version[0:3] + '...\n'
@ -60,16 +67,42 @@ if not options.errorsToConsole:
errorFile = open('fpdb-error-log.txt', 'w', 0) errorFile = open('fpdb-error-log.txt', 'w', 0)
sys.stderr = errorFile sys.stderr = errorFile
import logging #import logging
import logging, logging.config
try:
import pygtk import pygtk
pygtk.require('2.0') pygtk.require('2.0')
import gtk import gtk
import pango
except:
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.")
exit()
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 GuiBulkImport import GuiBulkImport
import GuiPlayerStats import GuiPlayerStats
import GuiPositionalStats import GuiPositionalStats
@ -85,6 +118,8 @@ import Exceptions
VERSION = "0.12" VERSION = "0.12"
log = Configuration.get_logger("logging.conf", "fpdb")
class fpdb: class fpdb:
def tab_clicked(self, widget, tab_name): def tab_clicked(self, widget, tab_name):
"""called when a tab button is clicked to activate that tab""" """called when a tab button is clicked to activate that tab"""
@ -97,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]
@ -118,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
@ -175,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.
@ -196,16 +231,48 @@ class fpdb:
def dia_about(self, widget, data=None): def dia_about(self, widget, data=None):
#self.warning_box("About FPDB:\n\nFPDB was originally created by a guy named Steffen, sometime in 2008, \nand is mostly worked on these days by people named Eratosthenes, s0rrow, _mt, EricBlade, sqlcoder, and other strange people.\n\n", "ABOUT FPDB") #self.warning_box("About FPDB:\n\nFPDB was originally created by a guy named Steffen, sometime in 2008, \nand is mostly worked on these days by people named Eratosthenes, s0rrow, _mt, EricBlade, sqlcoder, and other strange people.\n\n", "ABOUT FPDB")
dia = gtk.AboutDialog() dia = gtk.AboutDialog()
dia.set_name("FPDB") dia.set_name("Free Poker Database (FPDB)")
dia.set_version(VERSION) dia.set_version(VERSION)
dia.set_copyright("2008-2009, Steffen, Eratosthenes, s0rrow, EricBlade, _mt, sqlcoder, and others") dia.set_copyright("2008-2010, Steffen, Eratosthenes, s0rrow, EricBlade, _mt, sqlcoder, Bostik, and others")
dia.set_comments("GTK AboutDialog comments here") dia.set_comments("GTK AboutDialog comments here")
dia.set_license("GPL v3") dia.set_license("GPL v3")
dia.set_website("http://fpdb.sourceforge.net/") dia.set_website("http://fpdb.sourceforge.net/")
dia.set_authors("Steffen, Eratosthenes, s0rrow, EricBlade, _mt, and others") dia.set_authors(['Steffen', 'Eratosthenes', 's0rrow',
dia.set_program_name("FPDB") 'EricBlade', '_mt', 'sqlcoder', 'Bostik', 'and others'])
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",
@ -213,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):
@ -334,27 +409,48 @@ class fpdb:
diastring = "Please confirm that you want to re-create the HUD cache." diastring = "Please confirm that you want to re-create the HUD cache."
self.dia_confirm.format_secondary_text(diastring) self.dia_confirm.format_secondary_text(diastring)
hb = gtk.HBox(True, 1) hb1 = gtk.HBox(True, 1)
self.h_start_date = gtk.Entry(max=12)
self.h_start_date.set_text( self.db.get_hero_hudcache_start() )
lbl = gtk.Label(" Hero's cache starts: ")
btn = gtk.Button()
btn.set_image(gtk.image_new_from_stock(gtk.STOCK_INDEX, gtk.ICON_SIZE_BUTTON))
btn.connect('clicked', self.__calendar_dialog, self.h_start_date)
hb1.pack_start(lbl, expand=True, padding=3)
hb1.pack_start(self.h_start_date, expand=True, padding=2)
hb1.pack_start(btn, expand=False, padding=3)
self.dia_confirm.vbox.add(hb1)
hb1.show_all()
hb2 = gtk.HBox(True, 1)
self.start_date = gtk.Entry(max=12) self.start_date = gtk.Entry(max=12)
self.start_date.set_text( self.db.get_hero_hudcache_start() ) self.start_date.set_text( self.db.get_hero_hudcache_start() )
lbl = gtk.Label(" Hero's cache starts: ") lbl = gtk.Label(" Villains' cache starts: ")
btn = gtk.Button() btn = gtk.Button()
btn.set_image(gtk.image_new_from_stock(gtk.STOCK_INDEX, gtk.ICON_SIZE_BUTTON)) btn.set_image(gtk.image_new_from_stock(gtk.STOCK_INDEX, gtk.ICON_SIZE_BUTTON))
btn.connect('clicked', self.__calendar_dialog, self.start_date) btn.connect('clicked', self.__calendar_dialog, self.start_date)
hb.pack_start(lbl, expand=True, padding=3) hb2.pack_start(lbl, expand=True, padding=3)
hb.pack_start(self.start_date, expand=True, padding=2) hb2.pack_start(self.start_date, expand=True, padding=2)
hb.pack_start(btn, expand=False, padding=3) hb2.pack_start(btn, expand=False, padding=3)
self.dia_confirm.vbox.add(hb) self.dia_confirm.vbox.add(hb2)
hb.show_all() hb2.show_all()
response = self.dia_confirm.run() response = self.dia_confirm.run()
self.dia_confirm.destroy()
if response == gtk.RESPONSE_YES: if response == gtk.RESPONSE_YES:
self.db.rebuild_hudcache( self.start_date.get_text() ) lbl = gtk.Label(" Rebuilding HUD Cache ... ")
self.dia_confirm.vbox.add(lbl)
lbl.show()
while gtk.events_pending():
gtk.main_iteration_do(False)
self.db.rebuild_hudcache( self.h_start_date.get_text(), self.start_date.get_text() )
elif response == gtk.RESPONSE_NO: elif response == gtk.RESPONSE_NO:
print 'User cancelled rebuilding hud cache' print 'User cancelled rebuilding hud cache'
self.dia_confirm.destroy()
self.release_global_lock() self.release_global_lock()
def dia_rebuild_indexes(self, widget, data=None): def dia_rebuild_indexes(self, widget, data=None):
@ -368,16 +464,77 @@ class fpdb:
self.dia_confirm.format_secondary_text(diastring) self.dia_confirm.format_secondary_text(diastring)
response = self.dia_confirm.run() response = self.dia_confirm.run()
self.dia_confirm.destroy()
if response == gtk.RESPONSE_YES: if response == gtk.RESPONSE_YES:
lbl = gtk.Label(" Rebuilding Indexes ... ")
self.dia_confirm.vbox.add(lbl)
lbl.show()
while gtk.events_pending():
gtk.main_iteration_do(False)
self.db.rebuild_indexes() self.db.rebuild_indexes()
lbl.set_text(" Cleaning Database ... ")
while gtk.events_pending():
gtk.main_iteration_do(False)
self.db.vacuumDB() self.db.vacuumDB()
lbl.set_text(" Analyzing Database ... ")
while gtk.events_pending():
gtk.main_iteration_do(False)
self.db.analyzeDB() self.db.analyzeDB()
elif response == gtk.RESPONSE_NO: elif response == gtk.RESPONSE_NO:
print 'User cancelled rebuilding db indexes' print 'User cancelled rebuilding db indexes'
self.dia_confirm.destroy()
self.release_global_lock() self.release_global_lock()
def dia_logs(self, widget, data=None):
"""opens the log viewer window"""
#lock_set = False
#if self.obtain_global_lock():
# lock_set = True
# remove members from self.threads if close messages received
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):
end_iter = self.logbuffer.get_end_iter()
self.logbuffer.insert(end_iter, text)
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)
@ -397,10 +554,13 @@ class fpdb:
d.show_all() d.show_all()
def __get_dates(self): def __get_dates(self):
t1 = self.start_date.get_text() t1 = self.h_start_date.get_text()
if t1 == '': if t1 == '':
t1 = '1970-01-01' t1 = '1970-01-01'
return (t1) t2 = self.start_date.get_text()
if t2 == '':
t2 = '1970-01-01'
return (t1, t2)
def __get_date(self, widget, calendar, entry, win): def __get_date(self, widget, calendar, entry, win):
# year and day are correct, month is 0..11 # year and day are correct, month is 0..11
@ -477,6 +637,7 @@ class fpdb:
</menu> </menu>
<menu action="help"> <menu action="help">
<menuitem action="Abbrev"/> <menuitem action="Abbrev"/>
<menuitem action="Logs"/>
<separator/> <separator/>
<menuitem action="About"/> <menuitem action="About"/>
<menuitem action="License"/> <menuitem action="License"/>
@ -494,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),
@ -518,6 +679,7 @@ class fpdb:
('stats', None, '_Statistics (todo)', None, 'View Database Statistics', self.dia_database_stats), ('stats', None, '_Statistics (todo)', None, 'View Database Statistics', self.dia_database_stats),
('help', None, '_Help'), ('help', None, '_Help'),
('Abbrev', None, '_Abbrevations (todo)', None, 'List of Abbrevations', self.tab_abbreviations), ('Abbrev', None, '_Abbrevations (todo)', None, 'List of Abbrevations', self.tab_abbreviations),
('Logs', None, '_Log Messages', None, 'Log and Debug Messages', self.dia_logs),
('About', None, 'A_bout', None, 'About the program', self.dia_about), ('About', None, 'A_bout', None, 'About the program', self.dia_about),
('License', None, '_License and Copying (todo)', None, 'License and Copying', self.dia_licensing), ('License', None, '_License and Copying (todo)', None, 'License and Copying', self.dia_licensing),
]) ])
@ -547,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 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")
@ -577,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.")
@ -596,13 +765,14 @@ 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.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.db.rollback()
self.validate_config() self.validate_config()
@ -624,6 +794,7 @@ 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
if self.db is not None and self.db.connected:
self.db.disconnect() self.db.disconnect()
self.statusIcon.set_visible(False) self.statusIcon.set_visible(False)
gtk.main_quit() gtk.main_quit()
@ -691,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
@ -715,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)
@ -752,7 +925,6 @@ This program is licensed under the AGPL3, see docs"""+os.sep+"agpl-3.0.txt")
sys.stderr.write("fpdb starting ...") sys.stderr.write("fpdb starting ...")
def window_state_event_cb(self, window, event): def window_state_event_cb(self, window, event):
print "window_state_event", event
if event.changed_mask & gtk.gdk.WINDOW_STATE_ICONIFIED: if event.changed_mask & gtk.gdk.WINDOW_STATE_ICONIFIED:
# -20 = GWL_EXSTYLE can't find it in the pywin32 libs # -20 = GWL_EXSTYLE can't find it in the pywin32 libs
#bits = win32api.GetWindowLong(self.window.window.handle, -20) #bits = win32api.GetWindowLong(self.window.window.handle, -20)
@ -835,6 +1007,7 @@ This program is licensed under the AGPL3, see docs"""+os.sep+"agpl-3.0.txt")
gtk.main() gtk.main()
return 0 return 0
if __name__ == "__main__": if __name__ == "__main__":
me = fpdb() me = fpdb()
me.main() me.main()

View File

@ -106,7 +106,7 @@ class fpdb_db:
except MySQLdb.Error, ex: except MySQLdb.Error, ex:
if ex.args[0] == 1045: if ex.args[0] == 1045:
raise FpdbMySQLAccessDenied(ex.args[0], ex.args[1]) raise FpdbMySQLAccessDenied(ex.args[0], ex.args[1])
elif ex.args[0] == 2002: 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]) raise FpdbMySQLNoDatabase(ex.args[0], ex.args[1])
else: else:
print "*** WARNING UNKNOWN MYSQL ERROR", ex print "*** WARNING UNKNOWN MYSQL ERROR", ex
@ -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

@ -21,7 +21,7 @@
import os # todo: remove this once import_dir is in fpdb_import import os # todo: remove this once import_dir is in fpdb_import
import sys import sys
from time import time, strftime, sleep from time import time, strftime, sleep, clock
import traceback import traceback
import math import math
import datetime import datetime
@ -91,6 +91,7 @@ class Importer:
self.settings.setdefault("writeQMaxWait", 10) # not used self.settings.setdefault("writeQMaxWait", 10) # not used
self.settings.setdefault("dropIndexes", "don't drop") self.settings.setdefault("dropIndexes", "don't drop")
self.settings.setdefault("dropHudCache", "don't drop") self.settings.setdefault("dropHudCache", "don't drop")
self.settings.setdefault("starsArchive", False)
self.writeq = None self.writeq = None
self.database = Database.Database(self.config, sql = self.sql) self.database = Database.Database(self.config, sql = self.sql)
@ -101,6 +102,8 @@ class Importer:
self.NEWIMPORT = Configuration.NEWIMPORT self.NEWIMPORT = Configuration.NEWIMPORT
clock() # init clock in windows
#Set functions #Set functions
def setCallHud(self, value): def setCallHud(self, value):
self.callHud = value self.callHud = value
@ -132,6 +135,9 @@ class Importer:
def setDropHudCache(self, value): def setDropHudCache(self, value):
self.settings['dropHudCache'] = value self.settings['dropHudCache'] = value
def setStarsArchive(self, value):
self.settings['starsArchive'] = value
# def setWatchTime(self): # def setWatchTime(self):
# self.updated = time() # self.updated = time()
@ -359,10 +365,15 @@ class Importer:
# print "file",counter," updated", os.path.basename(file), stat_info.st_size, self.updatedsize[file], stat_info.st_mtime, self.updatedtime[file] # print "file",counter," updated", os.path.basename(file), stat_info.st_size, self.updatedsize[file], stat_info.st_mtime, self.updatedtime[file]
try: try:
if not os.path.isdir(file): if not os.path.isdir(file):
self.caller.addText("\n"+file) self.caller.addText("\n"+os.path.basename(file))
except KeyError: # TODO: What error happens here? except KeyError: # TODO: What error happens here?
pass pass
self.import_file_dict(self.database, file, self.filelist[file][0], self.filelist[file][1], None) (stored, duplicates, partial, errors, ttime) = self.import_file_dict(self.database, file, self.filelist[file][0], self.filelist[file][1], None)
try:
if not os.path.isdir(file):
self.caller.addText(" %d stored, %d duplicates, %d partial, %d errors (time = %f)" % (stored, duplicates, partial, errors, ttime))
except KeyError: # TODO: Again, what error happens here? fix when we find out ..
pass
self.updatedsize[file] = stat_info.st_size self.updatedsize[file] = stat_info.st_size
self.updatedtime[file] = time() self.updatedtime[file] = time()
else: else:
@ -393,7 +404,7 @@ class Importer:
if os.path.isdir(file): if os.path.isdir(file):
self.addToDirList[file] = [site] + [filter] self.addToDirList[file] = [site] + [filter]
return return (0,0,0,0,0)
conv = None conv = None
(stored, duplicates, partial, errors, ttime) = (0, 0, 0, 0, 0) (stored, duplicates, partial, errors, ttime) = (0, 0, 0, 0, 0)
@ -418,17 +429,33 @@ class Importer:
mod = __import__(filter) mod = __import__(filter)
obj = getattr(mod, filter_name, None) obj = getattr(mod, filter_name, None)
if callable(obj): if callable(obj):
hhc = obj(in_path = file, out_path = out_path, index = 0) # Index into file 0 until changeover hhc = obj(in_path = file, out_path = out_path, index = 0, starsArchive = self.settings['starsArchive']) # Index into file 0 until changeover
if hhc.getStatus() and self.NEWIMPORT == False: if hhc.getStatus() and self.NEWIMPORT == False:
(stored, duplicates, partial, errors, ttime) = self.import_fpdb_file(db, out_path, site, q) (stored, duplicates, partial, errors, ttime) = self.import_fpdb_file(db, out_path, site, q)
elif hhc.getStatus() and self.NEWIMPORT == True: elif hhc.getStatus() and self.NEWIMPORT == True:
#This code doesn't do anything yet #This code doesn't do anything yet
handlist = hhc.getProcessedHands() handlist = hhc.getProcessedHands()
self.pos_in_file[file] = hhc.getLastCharacterRead() self.pos_in_file[file] = hhc.getLastCharacterRead()
to_hud = []
for hand in handlist: for hand in handlist:
#hand.prepInsert() if hand is not None:
#try, except duplicates here?
hand.prepInsert(self.database)
hand.insert(self.database) hand.insert(self.database)
if self.callHud and hand.dbid_hands != 0:
to_hud.append(hand.dbid_hands)
else:
log.error("Hand processed but empty")
self.database.commit()
#pipe the Hands.id out to the HUD
for hid in 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" % (hid) + os.linesep)
errors = getattr(hhc, 'numErrors')
stored = getattr(hhc, 'numHands')
else: else:
# conversion didn't work # conversion didn't work
# TODO: appropriate response? # TODO: appropriate response?
@ -472,10 +499,13 @@ class Importer:
self.pos_in_file[file] = inputFile.tell() self.pos_in_file[file] = inputFile.tell()
inputFile.close() inputFile.close()
x = clock()
(stored, duplicates, partial, errors, ttime, handsId) = self.import_fpdb_lines(db, self.lines, starttime, file, site, q) (stored, duplicates, partial, errors, ttime, handsId) = self.import_fpdb_lines(db, self.lines, starttime, file, site, q)
db.commit() db.commit()
ttime = time() - starttime y = clock()
ttime = y - x
#ttime = time() - starttime
if q is None: if q is None:
log.info("Total stored: %(stored)d\tduplicates:%(duplicates)d\terrors:%(errors)d\ttime:%(ttime)s" % locals()) log.info("Total stored: %(stored)d\tduplicates:%(duplicates)d\terrors:%(errors)d\ttime:%(ttime)s" % locals())
@ -554,7 +584,11 @@ class Importer:
#print "call to HUD here. handsId:",handsId #print "call to HUD here. handsId:",handsId
#pipe the Hands.id out to the HUD #pipe the Hands.id out to the HUD
# print "fpdb_import: sending hand to hud", handsId, "pipe =", self.caller.pipe_to_hud # print "fpdb_import: sending hand to hud", handsId, "pipe =", self.caller.pipe_to_hud
try:
self.caller.pipe_to_hud.stdin.write("%s" % (handsId) + os.linesep) self.caller.pipe_to_hud.stdin.write("%s" % (handsId) + os.linesep)
except IOError: # hud closed
self.callHud = False
pass # continue import without hud
except Exceptions.DuplicateError: except Exceptions.DuplicateError:
duplicates += 1 duplicates += 1
db.rollback() db.rollback()

View File

@ -1241,38 +1241,34 @@ sure to also change the following storage method and table_viewer.prepare_data i
#calculate saw* values #calculate saw* values
isAllIn = False isAllIn = any(i for i in allIns[0][player])
if any(i for i in allIns[0][player]): if isAllIn or len(action_types[1][player]) > 0:
isAllIn = True
if (len(action_types[1][player])>0 or isAllIn):
myStreet1Seen = True myStreet1Seen = True
if any(i for i in allIns[1][player]): if not isAllIn:
isAllIn = True isAllIn = any(i for i in allIns[1][player])
if (len(action_types[2][player])>0 or isAllIn): if isAllIn or len(action_types[2][player]) > 0:
if all(actiontype != "fold" for actiontype in action_types[1][player]):
myStreet2Seen = True myStreet2Seen = True
if any(i for i in allIns[2][player]): if not isAllIn:
isAllIn = True isAllAin = any(i for i in allIns[2][player])
if (len(action_types[3][player])>0 or isAllIn): if isAllIn or len(action_types[3][player]) > 0:
if all(actiontype != "fold" for actiontype in action_types[2][player]):
myStreet3Seen = True myStreet3Seen = True
#print "base:", base #print "base:", base
if base == "hold": if base == "hold":
mySawShowdown = True mySawShowdown = not any(actiontype == "fold" for actiontype in action_types[3][player])
if any(actiontype == "fold" for actiontype in action_types[3][player]):
mySawShowdown = False
else: else:
#print "in else" #print "in else"
if any(i for i in allIns[3][player]): if not isAllIn:
isAllIn = True isAllIn = any(i for i in allIns[3][player])
if (len(action_types[4][player])>0 or isAllIn): if isAllIn or len(action_types[4][player]) > 0:
#print "in if" #print "in if"
myStreet4Seen = True myStreet4Seen = True
mySawShowdown = True mySawShowdown = not any(actiontype == "fold" for actiontype in action_types[4][player])
if any(actiontype == "fold" for actiontype in action_types[4][player]):
mySawShowdown = False
if myStreet1Seen: if myStreet1Seen:
result['playersAtStreet1'] += 1 result['playersAtStreet1'] += 1
@ -1288,9 +1284,7 @@ sure to also change the following storage method and table_viewer.prepare_data i
#flop stuff #flop stuff
street = 1 street = 1
if myStreet1Seen: if myStreet1Seen:
if any(actiontype == "bet" for actiontype in action_types[street][player]): myStreet1Aggr = any(actiontype == "bet" for actiontype in action_types[street][player])
myStreet1Aggr = True
myStreet1Calls = action_types[street][player].count('call') myStreet1Calls = action_types[street][player].count('call')
myStreet1Bets = action_types[street][player].count('bet') myStreet1Bets = action_types[street][player].count('bet')
# street1Raises = action_types[street][player].count('raise') bet count includes raises for now # street1Raises = action_types[street][player].count('raise') bet count includes raises for now
@ -1310,9 +1304,7 @@ sure to also change the following storage method and table_viewer.prepare_data i
#turn stuff - copy of flop with different vars #turn stuff - copy of flop with different vars
street = 2 street = 2
if myStreet2Seen: if myStreet2Seen:
if any(actiontype == "bet" for actiontype in action_types[street][player]): myStreet2Aggr = any(actiontype == "bet" for actiontype in action_types[street][player])
myStreet2Aggr = True
myStreet2Calls = action_types[street][player].count('call') myStreet2Calls = action_types[street][player].count('call')
myStreet2Bets = action_types[street][player].count('bet') myStreet2Bets = action_types[street][player].count('bet')
# street2Raises = action_types[street][player].count('raise') bet count includes raises for now # street2Raises = action_types[street][player].count('raise') bet count includes raises for now
@ -1332,9 +1324,7 @@ sure to also change the following storage method and table_viewer.prepare_data i
#river stuff - copy of flop with different vars #river stuff - copy of flop with different vars
street = 3 street = 3
if myStreet3Seen: if myStreet3Seen:
if any(actiontype == "bet" for actiontype in action_types[street][player]): myStreet3Aggr = any(actiontype == "bet" for actiontype in action_types[street][player])
myStreet3Aggr = True
myStreet3Calls = action_types[street][player].count('call') myStreet3Calls = action_types[street][player].count('call')
myStreet3Bets = action_types[street][player].count('bet') myStreet3Bets = action_types[street][player].count('bet')
# street3Raises = action_types[street][player].count('raise') bet count includes raises for now # street3Raises = action_types[street][player].count('raise') bet count includes raises for now
@ -1354,9 +1344,7 @@ sure to also change the following storage method and table_viewer.prepare_data i
#stud river stuff - copy of flop with different vars #stud river stuff - copy of flop with different vars
street = 4 street = 4
if myStreet4Seen: if myStreet4Seen:
if any(actiontype == "bet" for actiontype in action_types[street][player]): myStreet4Aggr = any(actiontype == "bet" for actiontype in action_types[street][player])
myStreet4Aggr=True
myStreet4Calls = action_types[street][player].count('call') myStreet4Calls = action_types[street][player].count('call')
myStreet4Bets = action_types[street][player].count('bet') myStreet4Bets = action_types[street][player].count('bet')
# street4Raises = action_types[street][player].count('raise') bet count includes raises for now # street4Raises = action_types[street][player].count('raise') bet count includes raises for now

View File

@ -11,6 +11,18 @@ keys=fileFormatter,stderrFormatter
level=INFO level=INFO
handlers=consoleHandler,fileHandler handlers=consoleHandler,fileHandler
[logger_fpdb]
level=INFO
handlers=consoleHandler,fileHandler
qualname=fpdb
propagate=0
[logger_logview]
level=INFO
handlers=consoleHandler,fileHandler
qualname=logview
propagate=0
[logger_parser] [logger_parser]
level=INFO level=INFO
handlers=consoleHandler,fileHandler handlers=consoleHandler,fileHandler
@ -24,7 +36,7 @@ qualname=importer
propagate=0 propagate=0
[logger_config] [logger_config]
level=DEBUG level=INFO
handlers=consoleHandler,fileHandler handlers=consoleHandler,fileHandler
qualname=config qualname=config
propagate=0 propagate=0

View File

@ -0,0 +1,55 @@
***** Betfair Poker Hand History for Game 100000000 *****
PL $0.05/$0.10 Omaha - Sunday, October 18, 20:00:00 GMT 2009
Table Death 1 6-max (Real Money)
Seat 2 is the button
Total number of active players : 6
Seat 1: Player6 ( $1 )
Seat 2: Player3 ( $9.38 )
Seat 3: Player2 ( $2.82 )
Seat 4: Player4 ( $4.13 )
Seat 5: Player5 ( $28.77 )
Seat 6: Player1 ( $6.46 )
Player2 posts small blind [$0.05]
Player4 posts big blind [$0.10]
Player6 posts big blind [$0.10]
** Dealing down cards **
Dealt to Player6 [ 7c, 6c, 5h, Jh ]
Player5 folds
Player1 calls [$0.10]
Player6 checks
Player3 calls [$0.10]
Player2 raises to [$0.30]
Player4 calls [$0.20]
Player1 calls [$0.20]
Player6 goes all-in
Player6 raises to [$1]
Player3 calls [$0.90]
Player2 calls [$0.70]
Player4 calls [$0.70]
Player1 calls [$0.70]
** Dealing Flop ** [ 4d, 5d, 6d ]
Player2 checks
Player4 checks
Player1 checks
Player3 checks
** Dealing Turn ** [ 3s ]
Player2 checks
Player4 bets [$0.10]
Player1 calls [$0.10]
Player3 folds
Player2 folds
** Dealing River ** [ 4c ]
Player4 goes all-in
Player4 bets [$3.03]
Player1 calls [$3.03]
** Showdown **
Player6 shows [ 7c, 6c, 5h, Jh ] a straight, Seven to Three
Player4 shows [ 7d, 8c, 3d, 6h ] a straight flush, Seven to Three
Player1 shows [ 3h, 4h, Td, 4s ] four of a kind, Fours
** Hand Conclusion **
Player4 wins $6.26 from side pot #1 with a straight flush, Seven to Three
Player4 wins $4.44 from main pot with a straight flush, Seven to Three
************ Game 100000000 ends ************

View File

@ -0,0 +1,11 @@
PokerStars Game #25979907808: Omaha Pot Limit ($0.05/$0.10 USD) - 2009/03/15 6:20:33 ET
Table 'Waterman' 6-max Seat #1 is the button
Seat 1: s0rrow ($11.65 in chips)
s0rrow: posts small blind $0.05
ritalinIV: is sitting out
Hand cancelled
*** SUMMARY ***
Seat 1: s0rrow (button) collected ($0)

View File

@ -0,0 +1,43 @@
PokerStars Game #36185273365: Hold'em No Limit ($0.05/$0.10 USD) - 2009/12/03 9:16:10 ET
Table 'Eurynome IV' 6-max Seat #3 is the button
Seat 1: s0rrow ($16.10 in chips)
Seat 2: chrisbiz ($9.45 in chips)
Seat 3: papajohn77 ($6.55 in chips)
Seat 4: WSOFish ($21.05 in chips)
Seat 5: drefron ($10 in chips)
Seat 6: garegerret ($10.60 in chips)
WSOFish: posts small blind $0.05
drefron: posts big blind $0.10
*** HOLE CARDS ***
Dealt to s0rrow [5s As]
garegerret: folds
s0rrow: raises $0.20 to $0.30
chrisbiz: calls $0.30
papajohn77: folds
WSOFish: folds
drefron: folds
*** FLOP *** [8c 4c 4d]
s0rrow: checks
chrisbiz: bets $0.40
s0rrow: raises $1 to $1.40
chrisbiz: calls $1
*** TURN *** [8c 4c 4d] [Kc]
s0rrow: bets $3.20
chrisbiz: calls $3.20
*** RIVER *** [8c 4c 4d Kc] [2s]
s0rrow: bets $11.20 and is all-in
chrisbiz: folds
Uncalled bet ($11.20) returned to s0rrow
s0rrow collected $9.50 from pot
*** SUMMARY ***
Total pot $9.95 | Rake $0.45
Board [8c 4c 4d Kc 2s]
Seat 1: s0rrow collected ($9.50)
Seat 2: chrisbiz folded on the River
Seat 3: papajohn77 (button) folded before Flop (didn't bet)
Seat 4: WSOFish (small blind) folded before Flop
Seat 5: drefron (big blind) folded before Flop
Seat 6: garegerret folded before Flop (didn't bet)

View File

@ -0,0 +1,602 @@
PokerStars Game #35874998500: Omaha Hi/Lo Pot Limit ($0.01/$0.02 USD) - 2009/11/26 10:36:51 ET
Table 'Gaby II' 6-max Seat #3 is the button
Seat 1: EricSteph261 ($11.27 in chips)
Seat 2: UnderMeSensi ($3.33 in chips)
Seat 3: supermeXXX ($1.19 in chips)
Seat 4: xgz520 ($1.81 in chips)
Seat 5: s0rrow ($3 in chips)
Seat 6: tiger48475 ($5 in chips)
xgz520: posts small blind $0.01
s0rrow: posts big blind $0.02
*** HOLE CARDS ***
Dealt to s0rrow [2h 2c 3s 9h]
tiger48475: folds
EricSteph261: folds
UnderMeSensi: raises $0.05 to $0.07
supermeXXX: folds
xgz520: folds
s0rrow: calls $0.05
*** FLOP *** [Jd 5c Kc]
s0rrow: checks
UnderMeSensi: checks
*** TURN *** [Jd 5c Kc] [4c]
s0rrow: checks
UnderMeSensi: bets $0.08
s0rrow: calls $0.08
*** RIVER *** [Jd 5c Kc 4c] [Th]
s0rrow: checks
UnderMeSensi: bets $0.31
EricSteph261 is sitting out
s0rrow: folds
Uncalled bet ($0.31) returned to UnderMeSensi
UnderMeSensi collected $0.31 from pot
UnderMeSensi: doesn't show hand
*** SUMMARY ***
Total pot $0.31 | Rake $0
Board [Jd 5c Kc 4c Th]
Seat 1: EricSteph261 folded before Flop (didn't bet)
Seat 2: UnderMeSensi collected ($0.31)
Seat 3: supermeXXX (button) folded before Flop (didn't bet)
Seat 4: xgz520 (small blind) folded before Flop
Seat 5: s0rrow (big blind) folded on the River
Seat 6: tiger48475 folded before Flop (didn't bet)
PokerStars Game #35875026976: Omaha Hi/Lo Pot Limit ($0.01/$0.02 USD) - 2009/11/26 10:37:39 ET
Table 'Gaby II' 6-max Seat #4 is the button
Seat 2: UnderMeSensi ($3.49 in chips)
Seat 3: supermeXXX ($1.19 in chips)
Seat 4: xgz520 ($1.80 in chips)
Seat 5: s0rrow ($2.85 in chips)
Seat 6: tiger48475 ($5 in chips)
s0rrow: posts small blind $0.01
tiger48475: posts big blind $0.02
*** HOLE CARDS ***
Dealt to s0rrow [4d 3s 8d Jd]
UnderMeSensi: raises $0.05 to $0.07
supermeXXX: folds
xgz520: folds
s0rrow: folds
tiger48475: folds
Uncalled bet ($0.05) returned to UnderMeSensi
xgz520 leaves the table
UnderMeSensi collected $0.05 from pot
UnderMeSensi: doesn't show hand
*** SUMMARY ***
Total pot $0.05 | Rake $0
Seat 2: UnderMeSensi collected ($0.05)
Seat 3: supermeXXX folded before Flop (didn't bet)
Seat 4: xgz520 (button) folded before Flop (didn't bet)
Seat 5: s0rrow (small blind) folded before Flop
Seat 6: tiger48475 (big blind) folded before Flop
PokerStars Game #35875034981: Omaha Hi/Lo Pot Limit ($0.01/$0.02 USD) - 2009/11/26 10:37:53 ET
Table 'Gaby II' 6-max Seat #5 is the button
Seat 2: UnderMeSensi ($3.52 in chips)
Seat 3: supermeXXX ($1.19 in chips)
Seat 5: s0rrow ($2.84 in chips)
Seat 6: tiger48475 ($5 in chips)
tiger48475: posts small blind $0.01
UnderMeSensi: posts big blind $0.02
*** HOLE CARDS ***
Dealt to s0rrow [Qh 6c Th 9c]
supermeXXX: raises $0.04 to $0.06
s0rrow: calls $0.06
tiger48475: folds
UnderMeSensi: calls $0.04
*** FLOP *** [5h 4d 2d]
UnderMeSensi: checks
supermeXXX: bets $0.10
s0rrow: folds
UnderMeSensi: calls $0.10
*** TURN *** [5h 4d 2d] [Jd]
UnderMeSensi: checks
supermeXXX: checks
*** RIVER *** [5h 4d 2d Jd] [6h]
UnderMeSensi: checks
supermeXXX: checks
*** SHOW DOWN ***
UnderMeSensi: shows [7c 6s 7h As] (HI: a pair of Sevens; LO: 6,5,4,2,A)
supermeXXX: shows [Ah 2h Kh 2s] (HI: three of a kind, Deuces; LO: 6,5,4,2,A)
supermeXXX collected $0.20 from pot
UnderMeSensi collected $0.10 from pot
supermeXXX collected $0.09 from pot
*** SUMMARY ***
Total pot $0.39 | Rake $0
Board [5h 4d 2d Jd 6h]
Seat 2: UnderMeSensi (big blind) showed [7c 6s 7h As] and won ($0.10) with HI: a pair of Sevens; LO: 6,5,4,2,A
Seat 3: supermeXXX showed [Ah 2h Kh 2s] and won ($0.29) with HI: three of a kind, Deuces; LO: 6,5,4,2,A
Seat 5: s0rrow (button) folded on the Flop
Seat 6: tiger48475 (small blind) folded before Flop
PokerStars Game #35875059163: Omaha Hi/Lo Pot Limit ($0.01/$0.02 USD) - 2009/11/26 10:38:34 ET
Table 'Gaby II' 6-max Seat #6 is the button
Seat 2: UnderMeSensi ($3.46 in chips)
Seat 3: supermeXXX ($1.32 in chips)
Seat 5: s0rrow ($2.78 in chips)
Seat 6: tiger48475 ($5 in chips)
UnderMeSensi: posts small blind $0.01
supermeXXX: posts big blind $0.02
*** HOLE CARDS ***
Dealt to s0rrow [Ts Qs 9d 7c]
s0rrow: raises $0.04 to $0.06
tiger48475: folds
UnderMeSensi: calls $0.05
diyi69 joins the table at seat #4
supermeXXX: folds
*** FLOP *** [3h Ah 5d]
UnderMeSensi: checks
s0rrow: checks
*** TURN *** [3h Ah 5d] [Kc]
UnderMeSensi: checks
s0rrow: bets $0.14
UnderMeSensi: folds
Uncalled bet ($0.14) returned to s0rrow
s0rrow collected $0.14 from pot
*** SUMMARY ***
Total pot $0.14 | Rake $0
Board [3h Ah 5d Kc]
Seat 2: UnderMeSensi (small blind) folded on the Turn
Seat 3: supermeXXX (big blind) folded before Flop
Seat 5: s0rrow collected ($0.14)
Seat 6: tiger48475 (button) folded before Flop (didn't bet)
PokerStars Game #35875079294: Omaha Hi/Lo Pot Limit ($0.01/$0.02 USD) - 2009/11/26 10:39:09 ET
Table 'Gaby II' 6-max Seat #2 is the button
Seat 2: UnderMeSensi ($3.40 in chips)
Seat 3: supermeXXX ($1.30 in chips)
Seat 4: diyi69 ($1 in chips)
Seat 5: s0rrow ($2.86 in chips)
Seat 6: tiger48475 ($5 in chips)
supermeXXX: posts small blind $0.01
diyi69: posts big blind $0.02
*** HOLE CARDS ***
Dealt to s0rrow [8s 6d 7s 2s]
s0rrow: folds
tiger48475: folds
UnderMeSensi: folds
supermeXXX: calls $0.01
diyi69 has timed out
diyi69: checks
*** FLOP *** [As Js 5h]
supermeXXX: bets $0.04
diyi69 has timed out
diyi69: folds
Uncalled bet ($0.04) returned to supermeXXX
diyi69 is sitting out
supermeXXX collected $0.04 from pot
*** SUMMARY ***
Total pot $0.04 | Rake $0
Board [As Js 5h]
Seat 2: UnderMeSensi (button) folded before Flop (didn't bet)
Seat 3: supermeXXX (small blind) collected ($0.04)
Seat 4: diyi69 (big blind) folded on the Flop
Seat 5: s0rrow folded before Flop (didn't bet)
Seat 6: tiger48475 folded before Flop (didn't bet)
PokerStars Game #35875131707: Omaha Hi/Lo Pot Limit ($0.01/$0.02 USD) - 2009/11/26 10:40:40 ET
Table 'Gaby II' 6-max Seat #3 is the button
Seat 2: UnderMeSensi ($3.40 in chips)
Seat 3: supermeXXX ($1.32 in chips)
Seat 5: s0rrow ($2.86 in chips)
Seat 6: tiger48475 ($5 in chips)
s0rrow: posts small blind $0.01
tiger48475: posts big blind $0.02
*** HOLE CARDS ***
Dealt to s0rrow [7c As 4d 4h]
UnderMeSensi: calls $0.02
supermeXXX: folds
s0rrow: calls $0.01
tiger48475: checks
*** FLOP *** [Ks 9d Ts]
s0rrow: checks
tiger48475: bets $0.06
UnderMeSensi: calls $0.06
s0rrow: folds
*** TURN *** [Ks 9d Ts] [7h]
tiger48475: checks
EricSteph261 has returned
UnderMeSensi: checks
*** RIVER *** [Ks 9d Ts 7h] [4s]
tiger48475: checks
UnderMeSensi: bets $0.10
tiger48475: folds
Uncalled bet ($0.10) returned to UnderMeSensi
UnderMeSensi collected $0.18 from pot
UnderMeSensi: doesn't show hand
*** SUMMARY ***
Total pot $0.18 | Rake $0
Board [Ks 9d Ts 7h 4s]
Seat 2: UnderMeSensi collected ($0.18)
Seat 3: supermeXXX (button) folded before Flop (didn't bet)
Seat 5: s0rrow (small blind) folded on the Flop
Seat 6: tiger48475 (big blind) folded on the River
PokerStars Game #35875159084: Omaha Hi/Lo Pot Limit ($0.01/$0.02 USD) - 2009/11/26 10:41:27 ET
Table 'Gaby II' 6-max Seat #5 is the button
Seat 1: EricSteph261 ($11.27 in chips)
Seat 2: UnderMeSensi ($3.50 in chips)
Seat 3: supermeXXX ($1.32 in chips)
Seat 5: s0rrow ($2.84 in chips)
Seat 6: tiger48475 ($5 in chips)
tiger48475: posts small blind $0.01
EricSteph261: posts big blind $0.02
*** HOLE CARDS ***
Dealt to s0rrow [Jc 3h 2s Qc]
UnderMeSensi: calls $0.02
supermeXXX: calls $0.02
s0rrow: raises $0.08 to $0.10
tiger48475: folds
EricSteph261: folds
UnderMeSensi: calls $0.08
supermeXXX: folds
*** FLOP *** [Ac 5s Js]
UnderMeSensi: checks
s0rrow: bets $0.20
UnderMeSensi: calls $0.20
*** TURN *** [Ac 5s Js] [8c]
UnderMeSensi: checks
s0rrow: bets $0.50
UnderMeSensi: calls $0.50
*** RIVER *** [Ac 5s Js 8c] [Jd]
UnderMeSensi: bets $1.60
s0rrow: calls $1.60
*** SHOW DOWN ***
UnderMeSensi: shows [7s 9s Jh 3c] (HI: three of a kind, Jacks; LO: 8,7,5,3,A)
s0rrow: shows [Jc 3h 2s Qc] (HI: three of a kind, Jacks - Ace+Queen kicker; LO: 8,5,3,2,A)
s0rrow collected $2.33 from pot
s0rrow collected $2.32 from pot
*** SUMMARY ***
Total pot $4.85 | Rake $0.20
Board [Ac 5s Js 8c Jd]
Seat 1: EricSteph261 (big blind) folded before Flop
Seat 2: UnderMeSensi showed [7s 9s Jh 3c] and lost with HI: three of a kind, Jacks; LO: 8,7,5,3,A
Seat 3: supermeXXX folded before Flop
Seat 5: s0rrow (button) showed [Jc 3h 2s Qc] and won ($4.65) with HI: three of a kind, Jacks; LO: 8,5,3,2,A
Seat 6: tiger48475 (small blind) folded before Flop
PokerStars Game #35875194885: Omaha Hi/Lo Pot Limit ($0.01/$0.02 USD) - 2009/11/26 10:42:28 ET
Table 'Gaby II' 6-max Seat #6 is the button
Seat 1: EricSteph261 ($11.25 in chips)
Seat 2: UnderMeSensi ($1.10 in chips)
Seat 3: supermeXXX ($1.30 in chips)
Seat 5: s0rrow ($5.09 in chips)
Seat 6: tiger48475 ($5 in chips)
EricSteph261: posts small blind $0.01
UnderMeSensi: posts big blind $0.02
*** HOLE CARDS ***
Dealt to s0rrow [7s 3c 3h 8d]
supermeXXX: folds
s0rrow: raises $0.02 to $0.04
tiger48475: calls $0.04
EricSteph261: calls $0.03
UnderMeSensi: calls $0.02
*** FLOP *** [8c 3s 4s]
EricSteph261: checks
UnderMeSensi: checks
s0rrow: bets $0.14
tiger48475: folds
EricSteph261: folds
UnderMeSensi: folds
Uncalled bet ($0.14) returned to s0rrow
s0rrow collected $0.16 from pot
*** SUMMARY ***
Total pot $0.16 | Rake $0
Board [8c 3s 4s]
Seat 1: EricSteph261 (small blind) folded on the Flop
Seat 2: UnderMeSensi (big blind) folded on the Flop
Seat 3: supermeXXX folded before Flop (didn't bet)
Seat 5: s0rrow collected ($0.16)
Seat 6: tiger48475 (button) folded on the Flop
PokerStars Game #35875219121: Omaha Hi/Lo Pot Limit ($0.01/$0.02 USD) - 2009/11/26 10:43:08 ET
Table 'Gaby II' 6-max Seat #1 is the button
Seat 1: EricSteph261 ($11.21 in chips)
Seat 2: UnderMeSensi ($1.06 in chips)
Seat 3: supermeXXX ($1.30 in chips)
Seat 5: s0rrow ($5.21 in chips)
Seat 6: tiger48475 ($5 in chips)
UnderMeSensi: posts small blind $0.01
supermeXXX: posts big blind $0.02
*** HOLE CARDS ***
Dealt to s0rrow [Ks Qd Kd Kc]
s0rrow: raises $0.04 to $0.06
tiger48475: folds
EricSteph261: calls $0.06
UnderMeSensi: calls $0.05
supermeXXX: calls $0.04
*** FLOP *** [2d Jh 5h]
UnderMeSensi: checks
supermeXXX: checks
s0rrow: checks
EricSteph261: checks
*** TURN *** [2d Jh 5h] [Js]
UnderMeSensi: checks
supermeXXX: checks
s0rrow: checks
EricSteph261: checks
*** RIVER *** [2d Jh 5h Js] [7s]
UnderMeSensi: checks
supermeXXX: checks
s0rrow: checks
EricSteph261: checks
*** SHOW DOWN ***
UnderMeSensi: shows [5d 6c As 9d] (HI: two pair, Jacks and Fives; LO: 7,6,5,2,A)
supermeXXX: shows [6s Th 7c Ac] (HI: two pair, Jacks and Sevens; LO: 7,6,5,2,A)
s0rrow: shows [Ks Qd Kd Kc] (HI: two pair, Kings and Jacks)
EricSteph261: shows [4s 9c 3d 2c] (HI: two pair, Jacks and Deuces; LO: 7,5,4,3,2)
s0rrow collected $0.12 from pot
EricSteph261 collected $0.12 from pot
*** SUMMARY ***
Total pot $0.24 | Rake $0
Board [2d Jh 5h Js 7s]
Seat 1: EricSteph261 (button) showed [4s 9c 3d 2c] and won ($0.12) with HI: two pair, Jacks and Deuces; LO: 7,5,4,3,2
Seat 2: UnderMeSensi (small blind) showed [5d 6c As 9d] and lost with HI: two pair, Jacks and Fives; LO: 7,6,5,2,A
Seat 3: supermeXXX (big blind) showed [6s Th 7c Ac] and lost with HI: two pair, Jacks and Sevens; LO: 7,6,5,2,A
Seat 5: s0rrow showed [Ks Qd Kd Kc] and won ($0.12) with HI: two pair, Kings and Jacks
Seat 6: tiger48475 folded before Flop (didn't bet)
PokerStars Game #35875246335: Omaha Hi/Lo Pot Limit ($0.01/$0.02 USD) - 2009/11/26 10:43:54 ET
Table 'Gaby II' 6-max Seat #2 is the button
Seat 1: EricSteph261 ($11.27 in chips)
Seat 2: UnderMeSensi ($1 in chips)
Seat 3: supermeXXX ($1.24 in chips)
Seat 5: s0rrow ($5.27 in chips)
Seat 6: tiger48475 ($5 in chips)
supermeXXX: posts small blind $0.01
s0rrow: posts big blind $0.02
*** HOLE CARDS ***
Dealt to s0rrow [Jd Kc 6h Jc]
tiger48475: folds
EricSteph261: calls $0.02
UnderMeSensi is disconnected
UnderMeSensi has timed out while disconnected
UnderMeSensi: folds
UnderMeSensi is sitting out
supermeXXX: calls $0.01
s0rrow: checks
*** FLOP *** [8d 7s Qh]
supermeXXX: bets $0.02
s0rrow: folds
EricSteph261: calls $0.02
*** TURN *** [8d 7s Qh] [As]
supermeXXX: bets $0.04
EricSteph261: calls $0.04
*** RIVER *** [8d 7s Qh As] [5d]
supermeXXX: checks
EricSteph261: checks
*** SHOW DOWN ***
supermeXXX: shows [Kh Qd 9s Th] (HI: a pair of Queens)
EricSteph261: shows [Jh 2d 5s 6c] (HI: a pair of Fives; LO: 7,6,5,2,A)
supermeXXX collected $0.09 from pot
EricSteph261 collected $0.09 from pot
*** SUMMARY ***
Total pot $0.18 | Rake $0
Board [8d 7s Qh As 5d]
Seat 1: EricSteph261 showed [Jh 2d 5s 6c] and won ($0.09) with HI: a pair of Fives; LO: 7,6,5,2,A
Seat 2: UnderMeSensi (button) folded before Flop (didn't bet)
Seat 3: supermeXXX (small blind) showed [Kh Qd 9s Th] and won ($0.09) with HI: a pair of Queens
Seat 5: s0rrow (big blind) folded on the Flop
Seat 6: tiger48475 folded before Flop (didn't bet)
PokerStars Game #35875293439: Omaha Hi/Lo Pot Limit ($0.01/$0.02 USD) - 2009/11/26 10:45:14 ET
Table 'Gaby II' 6-max Seat #3 is the button
Seat 1: EricSteph261 ($11.28 in chips)
Seat 3: supermeXXX ($1.25 in chips)
Seat 5: s0rrow ($5.25 in chips)
Seat 6: tiger48475 ($5 in chips)
s0rrow: posts small blind $0.01
tiger48475: posts big blind $0.02
*** HOLE CARDS ***
Dealt to s0rrow [9c 8h 8s 3c]
EricSteph261: calls $0.02
supermeXXX: calls $0.02
s0rrow: calls $0.01
tiger48475: checks
*** FLOP *** [Ah 2d Qc]
s0rrow: checks
tiger48475: checks
EricSteph261: checks
supermeXXX: checks
*** TURN *** [Ah 2d Qc] [3d]
s0rrow: checks
tiger48475: checks
EricSteph261: checks
supermeXXX: checks
*** RIVER *** [Ah 2d Qc 3d] [6s]
s0rrow: checks
tiger48475: checks
EricSteph261: checks
supermeXXX: checks
*** SHOW DOWN ***
s0rrow: shows [9c 8h 8s 3c] (HI: a pair of Eights; LO: 8,6,3,2,A)
tiger48475: shows [3s 5s Ts Th] (HI: a pair of Tens; LO: 6,5,3,2,A)
EricSteph261: shows [As Ks Jh 7h] (HI: a pair of Aces; LO: 7,6,3,2,A)
supermeXXX: mucks hand
EricSteph261 collected $0.04 from pot
tiger48475 collected $0.04 from pot
*** SUMMARY ***
Total pot $0.08 | Rake $0
Board [Ah 2d Qc 3d 6s]
Seat 1: EricSteph261 showed [As Ks Jh 7h] and won ($0.04) with HI: a pair of Aces; LO: 7,6,3,2,A
Seat 3: supermeXXX (button) mucked [9h 9s 4c Kc]
Seat 5: s0rrow (small blind) showed [9c 8h 8s 3c] and lost with HI: a pair of Eights; LO: 8,6,3,2,A
Seat 6: tiger48475 (big blind) showed [3s 5s Ts Th] and won ($0.04) with HI: a pair of Tens; LO: 6,5,3,2,A
PokerStars Game #35875328026: Omaha Hi/Lo Pot Limit ($0.01/$0.02 USD) - 2009/11/26 10:46:13 ET
Table 'Gaby II' 6-max Seat #5 is the button
Seat 1: EricSteph261 ($11.30 in chips)
Seat 3: supermeXXX ($1.23 in chips)
Seat 5: s0rrow ($5.23 in chips)
Seat 6: tiger48475 ($5.02 in chips)
tiger48475: posts small blind $0.01
EricSteph261: posts big blind $0.02
*** HOLE CARDS ***
Dealt to s0rrow [Qd 6h 8s 6c]
supermeXXX: calls $0.02
s0rrow: folds
tiger48475: calls $0.01
EricSteph261: checks
*** FLOP *** [Kc Ac 5s]
tiger48475: checks
EricSteph261: checks
supermeXXX: checks
*** TURN *** [Kc Ac 5s] [3h]
tiger48475: checks
EricSteph261: checks
supermeXXX: checks
*** RIVER *** [Kc Ac 5s 3h] [Qh]
tiger48475: bets $0.06
EricSteph261: folds
EricSteph261 is sitting out
supermeXXX: folds
Uncalled bet ($0.06) returned to tiger48475
tiger48475 collected $0.06 from pot
*** SUMMARY ***
Total pot $0.06 | Rake $0
Board [Kc Ac 5s 3h Qh]
Seat 1: EricSteph261 (big blind) folded on the River
Seat 3: supermeXXX folded on the River
Seat 5: s0rrow (button) folded before Flop (didn't bet)
Seat 6: tiger48475 (small blind) collected ($0.06)
PokerStars Game #35875356253: Omaha Hi/Lo Pot Limit ($0.01/$0.02 USD) - 2009/11/26 10:47:00 ET
Table 'Gaby II' 6-max Seat #6 is the button
Seat 3: supermeXXX ($1.21 in chips)
Seat 5: s0rrow ($5.23 in chips)
Seat 6: tiger48475 ($5.06 in chips)
supermeXXX: posts small blind $0.01
s0rrow: posts big blind $0.02
*** HOLE CARDS ***
Dealt to s0rrow [8h Jd 5d 8d]
tiger48475: folds
supermeXXX: calls $0.01
s0rrow: checks
*** FLOP *** [Ks 9s 6c]
supermeXXX: bets $0.02
s0rrow: calls $0.02
*** TURN *** [Ks 9s 6c] [Qc]
supermeXXX: bets $0.02
s0rrow: calls $0.02
*** RIVER *** [Ks 9s 6c Qc] [Ad]
supermeXXX: checks
s0rrow: checks
*** SHOW DOWN ***
supermeXXX: shows [Tc 7d 8c 3s] (HI: high card Ace)
s0rrow: shows [8h Jd 5d 8d] (HI: a pair of Eights)
s0rrow collected $0.12 from pot
No low hand qualified
*** SUMMARY ***
Total pot $0.12 | Rake $0
Board [Ks 9s 6c Qc Ad]
Seat 3: supermeXXX (small blind) showed [Tc 7d 8c 3s] and lost with HI: high card Ace
Seat 5: s0rrow (big blind) showed [8h Jd 5d 8d] and won ($0.12) with HI: a pair of Eights
Seat 6: tiger48475 (button) folded before Flop (didn't bet)
PokerStars Game #35875379792: Omaha Hi/Lo Pot Limit ($0.01/$0.02 USD) - 2009/11/26 10:47:39 ET
Table 'Gaby II' 6-max Seat #3 is the button
Seat 3: supermeXXX ($1.15 in chips)
Seat 5: s0rrow ($5.29 in chips)
Seat 6: tiger48475 ($5.06 in chips)
s0rrow: posts small blind $0.01
tiger48475: posts big blind $0.02
*** HOLE CARDS ***
Dealt to s0rrow [9c 5h 3s Th]
supermeXXX: calls $0.02
s0rrow: calls $0.01
tiger48475: checks
*** FLOP *** [Jc 3h Jd]
s0rrow: checks
tiger48475: checks
supermeXXX: checks
*** TURN *** [Jc 3h Jd] [6d]
s0rrow: checks
tiger48475: bets $0.06
supermeXXX: folds
EricSteph261 has returned
s0rrow: calls $0.06
*** RIVER *** [Jc 3h Jd 6d] [5c]
s0rrow: checks
tiger48475: bets $0.14
s0rrow: folds
Uncalled bet ($0.14) returned to tiger48475
tiger48475 collected $0.18 from pot
*** SUMMARY ***
Total pot $0.18 | Rake $0
Board [Jc 3h Jd 6d 5c]
Seat 3: supermeXXX (button) folded on the Turn
Seat 5: s0rrow (small blind) folded on the River
Seat 6: tiger48475 (big blind) collected ($0.18)
PokerStars Game #35875409365: Omaha Hi/Lo Pot Limit ($0.01/$0.02 USD) - 2009/11/26 10:48:29 ET
Table 'Gaby II' 6-max Seat #5 is the button
Seat 1: EricSteph261 ($11.28 in chips)
Seat 3: supermeXXX ($1.13 in chips)
Seat 5: s0rrow ($5.21 in chips)
Seat 6: tiger48475 ($5.16 in chips)
tiger48475: posts small blind $0.01
EricSteph261: posts big blind $0.02
*** HOLE CARDS ***
Dealt to s0rrow [6h 3c Th 2s]
supermeXXX: calls $0.02
s0rrow: calls $0.02
tiger48475: calls $0.01
EricSteph261 has timed out
EricSteph261: checks
*** FLOP *** [9d 5s Jh]
tiger48475: bets $0.06
EricSteph261 has timed out
EricSteph261: folds
EricSteph261 is sitting out
supermeXXX: calls $0.06
s0rrow: calls $0.06
*** TURN *** [9d 5s Jh] [Ks]
tiger48475: checks
supermeXXX: bets $0.10
s0rrow: folds
tiger48475: calls $0.10
*** RIVER *** [9d 5s Jh Ks] [9s]
tiger48475: checks
supermeXXX: checks
*** SHOW DOWN ***
tiger48475: shows [6s 9h 9c Ad] (HI: four of a kind, Nines)
supermeXXX: mucks hand
tiger48475 collected $0.46 from pot
No low hand qualified
*** SUMMARY ***
Total pot $0.46 | Rake $0
Board [9d 5s Jh Ks 9s]
Seat 1: EricSteph261 (big blind) folded on the Flop
Seat 3: supermeXXX mucked [Qd Tc 5h Ts]
Seat 5: s0rrow (button) folded on the Turn
Seat 6: tiger48475 (small blind) showed [6s 9h 9c Ad] and won ($0.46) with HI: four of a kind, Nines

View File

@ -0,0 +1,96 @@
PokerStars Game #35874676388: 7 Card Stud Hi/Lo Limit ($0.04/$0.08 USD) - 2009/11/26 10:27:46 ET
Table 'Dawn II' 8-max
Seat 1: u.pressure ($11.17 in chips)
Seat 2: 123smoothie ($0.99 in chips)
Seat 3: gashpor ($1.40 in chips)
Seat 4: denny501 ($0.71 in chips)
Seat 5: s0rrow ($1.52 in chips)
Seat 6: TomSludge ($1.58 in chips)
Seat 7: Soroka69 ($0.83 in chips)
Seat 8: rdiezchang ($2.05 in chips)
u.pressure: posts the ante $0.01
123smoothie: posts the ante $0.01
gashpor: posts the ante $0.01
denny501: posts the ante $0.01
s0rrow: posts the ante $0.01
TomSludge: posts the ante $0.01
Soroka69: posts the ante $0.01
rdiezchang: posts the ante $0.01
*** 3rd STREET ***
Dealt to u.pressure [Td]
Dealt to 123smoothie [4c]
Dealt to gashpor [5d]
Dealt to denny501 [2c]
Dealt to s0rrow [7c 3s 5h]
Dealt to TomSludge [8s]
Dealt to Soroka69 [7d]
Dealt to rdiezchang [Ad]
denny501: brings in for $0.02
s0rrow: calls $0.02
TomSludge: folds
Soroka69: calls $0.02
rdiezchang: calls $0.02
u.pressure: folds
123smoothie: calls $0.02
gashpor: calls $0.02
*** 4th STREET ***
Dealt to 123smoothie [4c] [3c]
Dealt to gashpor [5d] [Qd]
Dealt to denny501 [2c] [7s]
Dealt to s0rrow [7c 3s 5h] [Qc]
Dealt to Soroka69 [7d] [5s]
Dealt to rdiezchang [Ad] [Js]
rdiezchang: checks
123smoothie: checks
gashpor: checks
denny501: folds
denny501 leaves the table
s0rrow: checks
Soroka69: checks
*** 5th STREET ***
Dealt to 123smoothie [4c 3c] [9s]
Dealt to gashpor [5d Qd] [Jd]
Dealt to s0rrow [7c 3s 5h Qc] [Kc]
Dealt to Soroka69 [7d 5s] [5c]
Dealt to rdiezchang [Ad Js] [Ts]
LainaRahat joins the table at seat #4
Soroka69: checks
rdiezchang: checks
123smoothie: checks
gashpor: bets $0.08
s0rrow: calls $0.08
Soroka69: calls $0.08
rdiezchang: folds
123smoothie: folds
*** 6th STREET ***
Dealt to gashpor [5d Qd Jd] [9d]
Dealt to s0rrow [7c 3s 5h Qc Kc] [6d]
Dealt to Soroka69 [7d 5s 5c] [2s]
Soroka69: checks
gashpor: bets $0.08
s0rrow: calls $0.08
Soroka69: calls $0.08
*** RIVER ***
Dealt to s0rrow [7c 3s 5h Qc Kc 6d] [4d]
Soroka69: checks
gashpor: bets $0.08
s0rrow: calls $0.08
Soroka69: folds
*** SHOW DOWN ***
gashpor: shows [4h 3d 5d Qd Jd 9d 6h] (HI: a flush, Queen high)
s0rrow: shows [7c 3s 5h Qc Kc 6d 4d] (HI: a straight, Three to Seven; LO: 7,6,5,4,3)
gashpor collected $0.40 from pot
s0rrow collected $0.40 from pot
*** SUMMARY ***
Total pot $0.84 | Rake $0.04
Seat 1: u.pressure folded on the 3rd Street (didn't bet)
Seat 2: 123smoothie folded on the 5th Street
Seat 3: gashpor showed [4h 3d 5d Qd Jd 9d 6h] and won ($0.40) with HI: a flush, Queen high
Seat 4: denny501 folded on the 4th Street
Seat 5: s0rrow showed [7c 3s 5h Qc Kc 6d 4d] and won ($0.40) with HI: a straight, Three to Seven; LO: 7,6,5,4,3
Seat 6: TomSludge folded on the 3rd Street (didn't bet)
Seat 7: Soroka69 folded on the River
Seat 8: rdiezchang folded on the 5th Street

29
pyfpdb/test1.py Executable file
View File

@ -0,0 +1,29 @@
#!/usr/bin/env python
"""test1.py
Test if python is working.
"""
# Copyright 2008, Ray E. Barker
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
########################################################################
import sys
print "\npython is working!"
print "\npress return to finish"
sys.stdin.readline()

57
pyfpdb/test2.py Executable file
View File

@ -0,0 +1,57 @@
#!/usr/bin/env python
"""test2.py
Test if gtk is working.
"""
# Copyright 2008, Ray E. Barker
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
########################################################################
import sys
try:
import pygtk
pygtk.require('2.0')
import gtk
win = gtk.Window(gtk.WINDOW_TOPLEVEL)
win.set_title("Test GTK")
win.set_border_width(1)
win.set_default_size(600, 500)
win.set_resizable(True)
#win.show()
dia = gtk.Dialog("Test GTK",
win,
gtk.DIALOG_MODAL | gtk.DIALOG_DESTROY_WITH_PARENT,
(gtk.STOCK_CLOSE, gtk.RESPONSE_OK))
dia.set_default_size(500, 300)
l = gtk.Label("GTK is working!")
dia.vbox.add(l)
l.show()
response = dia.run()
if response == gtk.RESPONSE_ACCEPT:
pass
dia.destroy()
except:
print "\nError:", sys.exc_info()
print "\npress return to finish"
sys.stdin.readline()

View File

@ -1,21 +1,34 @@
# -*- coding: utf-8 -*- # -*- coding: utf-8 -*-
import BetfairToFpdb import BetfairToFpdb
from Hand import *
import py import py
import Configuration
import Database
import SQL
import fpdb_import
def checkGameInfo(hhc, header, info): config = Configuration.Config(file = "HUD_config.test.xml")
assert hhc.determineGameType(header) == info db = Database.Database(config)
sql = SQL.Sql(db_server = 'sqlite')
def testGameInfo(): settings = {}
hhc = BetfairToFpdb.Betfair(autostart=False) settings.update(config.get_db_parameters())
pairs = ( settings.update(config.get_tv_parameters())
(u"""***** Betfair Poker Hand History for Game 472386869 ***** settings.update(config.get_import_parameters())
NL $0.02/$0.04 Texas Hold'em - Sunday, January 25, 10:10:42 GMT 2009 settings.update(config.get_default_paths())
Table Rookie 191 6-max (Real Money)
Seat 1 is the button
Total number of active players : 6""",
{'type':'ring', 'base':"hold", 'category':'holdem', 'limitType':'nl', 'sb':'0.02', 'bb':'0.04', 'currency':'USD'}),
)
for (header, info) in pairs: def testFlopImport():
yield checkGameInfo, hhc, header, info db.recreate_tables()
importer = fpdb_import.Importer(False, settings, config)
importer.setDropIndexes("don't drop")
importer.setFailOnError(True)
importer.setThreads(-1)
importer.addBulkImportImportFileOrDir(
"""regression-test-files/cash/Betfair/Flop/PLO-6max-USD-0.05-0.10-200909.All.in.river.splitpot.txt""", site="Betfair")
importer.setCallHud(False)
(stored, dups, partial, errs, ttime) = importer.runImport()
importer.clearFileList()
# Should actually do some testing here
assert 1 == 1

View File

@ -74,12 +74,45 @@ def testFlopImport():
# """regression-test-files/tour/Stars/Flop/NLHE-USD-MTT-5r-200710.txt""", site="PokerStars") # """regression-test-files/tour/Stars/Flop/NLHE-USD-MTT-5r-200710.txt""", site="PokerStars")
importer.addBulkImportImportFileOrDir( importer.addBulkImportImportFileOrDir(
"""regression-test-files/cash/Stars/Flop/PLO8-6max-USD-0.01-0.02-200911.txt""", site="PokerStars") """regression-test-files/cash/Stars/Flop/PLO8-6max-USD-0.01-0.02-200911.txt""", site="PokerStars")
#HID - 36185273365
# Besides the horrible play it contains lots of useful cases
# Preflop: raise, then 3bet chance for seat 2
# Flop: Checkraise by hero, 4bet chance not taken by villain
# Turn: Turn continuation bet by hero, called
# River: hero (continuation bets?) all-in and is not called
importer.addBulkImportImportFileOrDir(
"""regression-test-files/cash/Stars/Flop/NLHE-6max-USD-0.05-0.10-200912.Stats-comparision.txt""", site="PokerStars")
importer.setCallHud(False) importer.setCallHud(False)
(stored, dups, partial, errs, ttime) = importer.runImport() (stored, dups, partial, errs, ttime) = importer.runImport()
print "DEBUG: stored: %s dups: %s partial: %s errs: %s ttime: %s" %(stored, dups, partial, errs, ttime)
importer.clearFileList() importer.clearFileList()
# Should actually do some testing here col = { 'sawShowdown': 2
assert 1 == 1 }
q = """SELECT
s.name,
p.name,
hp.sawShowdown
FROM
Hands as h,
Sites as s,
Gametypes as g,
HandsPlayers as hp,
Players as p
WHERE
h.siteHandNo = 36185273365
and g.id = h.gametypeid
and hp.handid = h.id
and p.id = hp.playerid
and s.id = p.siteid"""
c = db.get_cursor()
c.execute(q)
result = c.fetchall()
for row, data in enumerate(result):
print "DEBUG: result[%s]: %s" %(row, result[row])
# Assert if any sawShowdown = True
assert result[row][col['sawShowdown']] == 0
def testStudImport(): def testStudImport():
db.recreate_tables() db.recreate_tables()