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

This commit is contained in:
sqlcoder 2010-06-05 16:54:18 +01:00
commit 30d5cf56ca
17 changed files with 180 additions and 65 deletions

View File

@ -1,3 +1,10 @@
free-poker-tools (0.20~git20100305) unstable; urgency=low
* New snapshot
* Version bumped to 0.20
-- Mika Bostrom <bostik+fpdb@bostik.iki.fi> Fri, 05 Mar 2010 08:38:52 +0200
free-poker-tools (0.12~git20100122) unstable; urgency=low
* New snapshot release with reworked import code

View File

@ -3,8 +3,10 @@ import re
import codecs
import Options
import HandHistoryConverter
import Configuration
(options, argv) = Options.fpdb_options()
config = Configuration.Config()
filter = options.hhc
@ -13,7 +15,7 @@ filter_name = filter.replace("ToFpdb", "")
mod = __import__(filter)
obj = getattr(mod, filter_name, None)
hhc = obj(autostart=False)
hhc = obj(config, autostart=False)
if os.path.exists(options.infile):
in_fh = codecs.open(options.infile, 'r', "utf8")
@ -31,7 +33,7 @@ for a in m:
uniq = set(players)
for i, name in enumerate(uniq, 1):
for i, name in enumerate(uniq):
filecontents = filecontents.replace(name, 'Player%d' %i)
print filecontents

View File

@ -26,7 +26,9 @@ import Configuration
encoder_to_utf = codecs.lookup('utf-8')
encoder_to_sys = codecs.lookup(Configuration.LOCALE_ENCODING)
coder_hex = codecs.lookup('hex_codec')
hex_coding = False #FIXME: Should only be on if db is not UTF8 - test in Database.py?
# I'm saving a few cycles with this one
not_needed1, not_needed2, not_needed3 = False, False, False
if Configuration.LOCALE_ENCODING == 'UTF8':
@ -75,3 +77,19 @@ def to_gui(s):
except UnicodeEncodeError:
sys.stderr.write('Could not encode: "%s"\n' % s)
raise
def to_hex(s):
try:
out = coder_hex.encode(s)[0]
return out
except UnicodeDecodeError:
sys.stderr.write('Could not convert: "%s"\n' % s)
return s
def from_hex(s):
try:
out = coder_hex.decode(s)[0]
return out
except UnicodeDecodeError:
sys.stderr.write('Could not convert: "%s"\n' % s)
return s

View File

@ -193,7 +193,7 @@ class Database:
# alter table t add constraint c foreign key (fkcol) references tab(rcol)
# (fkcol is used for foreigh key name)
# mysql to list indexes:
# mysql to list indexes: (CG - "LIST INDEXES" should work too)
# SELECT table_name, index_name, non_unique, column_name
# FROM INFORMATION_SCHEMA.STATISTICS
# WHERE table_name = 'tbl_name'
@ -223,6 +223,7 @@ class Database:
# Note: index names must be unique across a schema
# CREATE INDEX idx ON tab(col)
# DROP INDEX idx
# SELECT * FROM PG_INDEXES
# SQLite notes:
@ -1075,7 +1076,7 @@ class Database:
c = self.get_cursor()
c.execute(self.sql.query['createSettingsTable'])
log.debug(self.sql.query['createSitesTable'])
log.debug("Creating tables")
c.execute(self.sql.query['createSitesTable'])
c.execute(self.sql.query['createGametypesTable'])
c.execute(self.sql.query['createPlayersTable'])
@ -1088,7 +1089,8 @@ class Database:
c.execute(self.sql.query['createHandsActionsTable'])
c.execute(self.sql.query['createHudCacheTable'])
# create unique indexes:
# Create unique indexes:
log.debug("Creating unique indexes")
c.execute(self.sql.query['addTourneyIndex'])
c.execute(self.sql.query['addHandsIndex'])
c.execute(self.sql.query['addPlayersIndex'])
@ -1162,7 +1164,8 @@ class Database:
self.connection.set_isolation_level(0) # allow table/index operations to work
for idx in self.indexes[self.backend]:
if self.backend == self.MYSQL_INNODB:
print "creating mysql index ", idx['tab'], idx['col']
print "Creating mysql index %s %s" %(idx['tab'], idx['col'])
log.debug("Creating sqlite index %s %s" %(idx['tab'], idx['col']))
try:
s = "create index %s on %s(%s)" % (idx['col'],idx['tab'],idx['col'])
self.get_cursor().execute(s)
@ -1170,13 +1173,15 @@ class Database:
print " create idx failed: " + str(sys.exc_info())
elif self.backend == self.PGSQL:
# mod to use tab_col for index name?
print "creating pg index ", idx['tab'], idx['col']
print "Creating pg index %s %s" %(idx['tab'], idx['col'])
log.debug("Creating sqlite index %s %s" %(idx['tab'], idx['col']))
try:
s = "create index %s_%s_idx on %s(%s)" % (idx['tab'], idx['col'], idx['tab'], idx['col'])
self.get_cursor().execute(s)
except:
print " create idx failed: " + str(sys.exc_info())
elif self.backend == self.SQLITE:
print "Creating sqlite index %s %s" %(idx['tab'], idx['col'])
log.debug("Creating sqlite index %s %s" %(idx['tab'], idx['col']))
try:
s = "create index %s_%s_idx on %s(%s)" % (idx['tab'], idx['col'], idx['tab'], idx['col'])
@ -1184,7 +1189,7 @@ class Database:
except:
log.debug("Create idx failed: " + str(sys.exc_info()))
else:
print "Only MySQL, Postgres and SQLite supported so far"
print "Unknown database: MySQL, Postgres and SQLite supported"
return -1
if self.backend == self.PGSQL:
self.connection.set_isolation_level(1) # go back to normal isolation level
@ -1215,8 +1220,15 @@ class Database:
% (idx['tab'],idx['col']) )
except:
print " drop idx failed: " + str(sys.exc_info())
elif self.backend == self.SQLITE:
print "Dropping sqlite index ", idx['tab'], idx['col']
try:
self.get_cursor().execute( "drop index %s_%s_idx"
% (idx['tab'],idx['col']) )
except:
print " drop idx failed: " + str(sys.exc_info())
else:
print "Only MySQL and Postgres supported so far"
print "Only MySQL, Postgres and SQLITE supported, what are you trying to use?"
return -1
if self.backend == self.PGSQL:
self.connection.set_isolation_level(1) # go back to normal isolation level

View File

@ -67,12 +67,12 @@ class DerivedStats():
self.handsplayers[player[1]]['street%dCBDone' %i] = False
self.handsplayers[player[1]]['street%dCheckCallRaiseChance' %i] = False
self.handsplayers[player[1]]['street%dCheckCallRaiseDone' %i] = False
self.handsplayers[player[1]]['otherRaisedStreet%d' %i] = False
self.handsplayers[player[1]]['foldToOtherRaisedStreet%d' %i] = False
#FIXME - Everything below this point is incomplete.
self.handsplayers[player[1]]['tourneyTypeId'] = 1
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
@ -139,6 +139,8 @@ class DerivedStats():
self.handsplayers[player[1]]['seatNo'] = player[0]
self.handsplayers[player[1]]['startCash'] = int(100 * Decimal(player[2]))
# XXX: enumerate(list, start=x) is python 2.6 syntax; 'start'
#for i, street in enumerate(hand.actionStreets[2:], start=1):
for i, street in enumerate(hand.actionStreets[2:]):
self.seen(self.hand, i+1)
@ -146,6 +148,8 @@ class DerivedStats():
self.aggr(self.hand, i)
self.calls(self.hand, i)
self.bets(self.hand, i)
if i>0:
self.folds(self.hand, i)
# Winnings is a non-negative value of money collected from the pot, which already includes the
# rake taken out. hand.collectees is Decimal, database requires cents
@ -368,8 +372,8 @@ class DerivedStats():
name = self.lastBetOrRaiser(hand.actionStreets[i+1])
if name:
chance = self.noBetsBefore(hand.actionStreets[i+2], name)
self.handsplayers[name]['street%dCBChance' % (i+1)] = True
if chance == True:
self.handsplayers[name]['street%dCBChance' % (i+1)] = True
self.handsplayers[name]['street%dCBDone' % (i+1)] = self.betStreet(hand.actionStreets[i+2], name)
def calcCheckCallRaise(self, hand):
@ -380,6 +384,7 @@ class DerivedStats():
CG: CheckCall would be a much better name for this.
"""
# XXX: enumerate(list, start=x) is python 2.6 syntax; 'start'
#for i, street in enumerate(hand.actionStreets[2:], start=1):
for i, street in enumerate(hand.actionStreets[2:]):
actions = hand.actions[hand.actionStreets[i+1]]
@ -408,10 +413,16 @@ class DerivedStats():
def aggr(self, hand, i):
aggrers = set()
others = set()
# Growl - actionStreets contains 'BLINDSANTES', which isn't actually an action street
firstAggrMade=False
for act in hand.actions[hand.actionStreets[i+1]]:
if firstAggrMade:
others.add(act[0])
if act[1] in ('completes', 'bets', 'raises'):
aggrers.add(act[0])
firstAggrMade=True
for player in hand.players:
#print "DEBUG: actionStreet[%s]: %s" %(hand.actionStreets[i+1], i)
@ -420,6 +431,12 @@ class DerivedStats():
else:
self.handsplayers[player[1]]['street%sAggr' % i] = False
if i > 0 and len(aggrers) > 0:
for playername in others:
self.handsplayers[playername]['otherRaisedStreet%s' % i] = True
#print "DEBUG: otherRaised detected on handid %s for %s on actionStreet[%s]: %s"
# %(hand.handid, playername, hand.actionStreets[i+1], i)
def calls(self, hand, i):
callers = []
for act in hand.actions[hand.actionStreets[i+1]]:
@ -429,11 +446,19 @@ class DerivedStats():
# CG - I'm sure this stat is wrong
# Best guess is that raise = 2 bets
def bets(self, hand, i):
betters = []
for act in hand.actions[hand.actionStreets[i+1]]:
if act[1] in ('bets'):
self.handsplayers[act[0]]['street%sBets' % i] = 1 + self.handsplayers[act[0]]['street%sBets' % i]
def folds(self, hand, i):
for act in hand.actions[hand.actionStreets[i+1]]:
if act[1] in ('folds'):
if self.handsplayers[act[0]]['otherRaisedStreet%s' % i] == True:
self.handsplayers[act[0]]['foldToOtherRaisedStreet%s' % i] = True
#print "DEBUG: fold detected on handid %s for %s on actionStreet[%s]: %s"
# %(hand.handid, act[0],hand.actionStreets[i+1], i)
def countPlayers(self, hand):
pass

View File

@ -876,7 +876,7 @@ class Filters(threading.Thread):
t2 = self.end_date.get_text()
if t1 == '':
t1 = '1970-01-01'
t1 = '1970-01-02'
if t2 == '':
t2 = '2020-12-12'

View File

@ -27,7 +27,7 @@ class Fulltilt(HandHistoryConverter):
sitename = "Fulltilt"
filetype = "text"
codepage = ["utf-16", "cp1252"]
codepage = ["utf-16", "cp1252", "utf-8"]
siteId = 1 # Needs to match id entry in Sites database
# Static regexes

View File

@ -33,7 +33,7 @@ try:
from matplotlib.backends.backend_gtkagg import NavigationToolbar2GTKAgg as NavigationToolbar
from matplotlib.finance import candlestick2
from numpy import diff, nonzero, sum, cumsum, max, min
from numpy import diff, nonzero, sum, cumsum, max, min, append
# from matplotlib.dates import DateFormatter, WeekdayLocator, HourLocator, \
# DayLocator, MONDAY, timezone
@ -184,7 +184,7 @@ class GuiSessionViewer (threading.Thread):
sitenos.append(siteids[site])
_q = self.sql.query['getPlayerId']
_name = Charset.to_utf8(heroes[site])
print 'DEBUG(_name) :: %s' % _name
#print 'DEBUG(_name) :: %s' % _name
self.cursor.execute(_q, (_name,)) # arg = tuple
result = self.db.cursor.fetchall()
if len(result) == 1:
@ -241,6 +241,9 @@ class GuiSessionViewer (threading.Thread):
#end def fillStatsFrame(self, vbox):
def generateDatasets(self, playerids, sitenos, limits, seats):
THRESHOLD = 1800 # Minimum number of seconds between consecutive hands before being considered a new session
PADDING = 5 # Additional time in minutes to add to a session, session startup, shutdown etc (FiXME: user configurable)
# Get a list of all handids and their timestampts
#FIXME: Query still need to filter on blind levels
@ -255,23 +258,31 @@ class GuiSessionViewer (threading.Thread):
q = q.replace("<ampersand_s>", "%s")
self.db.cursor.execute(q)
THRESHOLD = 1800
hands = self.db.cursor.fetchall()
# Take that list and create an array of the time between hands
times = map(lambda x:long(x[0]), hands)
handids = map(lambda x:int(x[1]), hands)
winnings = map(lambda x:float(x[4]), hands)
print "DEBUG: len(times) %s" %(len(times))
#print "DEBUG: len(times) %s" %(len(times))
diffs = diff(times) # This array is the difference in starttime between consecutive hands
index = nonzero(diff(times) > THRESHOLD) # This array represents the indexes into 'times' for start/end times of sessions
# ie. times[index[0][0]] is the end of the first session
diffs2 = append(diffs,THRESHOLD + 1) # Append an additional session to the end of the diffs, so the next line
# includes an index into the last 'session'
index = nonzero(diffs2 > THRESHOLD) # This array represents the indexes into 'times' for start/end times of sessions
# times[index[0][0]] is the end of the first session,
#print "DEBUG: len(index[0]) %s" %(len(index[0]))
if len(index[0]) > 0:
#print "DEBUG: index[0][0] %s" %(index[0][0])
#print "DEBUG: index %s" %(index)
pass
else:
index = [[0]]
#print "DEBUG: index %s" %(index)
#print "DEBUG: index[0][0] %s" %(index[0][0])
pass
total = 0
last_idx = 0
first_idx = 0
lowidx = 0
uppidx = 0
opens = []
@ -281,27 +292,36 @@ class GuiSessionViewer (threading.Thread):
results = []
cum_sum = cumsum(winnings)
cum_sum = cum_sum/100
sid = 1
# Take all results and format them into a list for feeding into gui model.
for i in range(len(index[0])):
sid = i # Session id
hds = index[0][i] - last_idx # Number of hands in session
hds = index[0][i] - first_idx + 1 # Number of hands in session
if hds > 0:
stime = strftime("%d/%m/%Y %H:%M", localtime(times[last_idx])) # Formatted start time
stime = strftime("%d/%m/%Y %H:%M", localtime(times[first_idx])) # Formatted start time
etime = strftime("%d/%m/%Y %H:%M", localtime(times[index[0][i]])) # Formatted end time
hph = (times[index[0][i]] - times[last_idx])/60 # Hands per hour
won = sum(winnings[last_idx:index[0][i]])/100.0
hwm = max(cum_sum[last_idx:index[0][i]])
lwm = min(cum_sum[last_idx:index[0][i]])
#print "DEBUG: range: (%s, %s) - (min, max): (%s, %s)" %(last_idx, index[0][i], hwm, lwm)
minutesplayed = (times[index[0][i]] - times[first_idx])/60
if minutesplayed == 0:
minutesplayed = 1
minutesplayed = minutesplayed + PADDING
hph = hds*60/minutesplayed # Hands per hour
won = sum(winnings[first_idx:index[0][i]])/100.0
hwm = max(cum_sum[first_idx:index[0][i]])
lwm = min(cum_sum[first_idx:index[0][i]])
open = (sum(winnings[:first_idx]))/100
close = (sum(winnings[:index[0][i]]))/100
#print "DEBUG: range: (%s, %s) - (min, max): (%s, %s) - (open,close): (%s, %s)" %(first_idx, index[0][i], lwm, hwm, open, close)
results.append([sid, hds, stime, etime, hph, won])
opens.append((sum(winnings[:last_idx]))/100)
closes.append((sum(winnings[:index[0][i]]))/100)
opens.append(open)
closes.append(close)
highs.append(hwm)
lows.append(lwm)
#print "Hands in session %4s: %4s Start: %s End: %s HPH: %s Profit: %s" %(sid, hds, stime, etime, hph, won)
total = total + (index[0][i] - last_idx)
last_idx = index[0][i] + 1
#print "DEBUG: Hands in session %4s: %4s Start: %s End: %s HPH: %s Profit: %s" %(sid, hds, stime, etime, hph, won)
total = total + (index[0][i] - first_idx)
first_idx = index[0][i] + 1
sid = sid+1
else:
print "hds <= 0"
return (results, opens, closes, highs, lows)
@ -330,11 +350,6 @@ class GuiSessionViewer (threading.Thread):
def generateGraph(self, opens, closes, highs, lows):
self.clearGraphData()
#FIXME: Weird - first data entry is crashing this for me
opens = opens[1:]
closes = closes[1:]
highs = highs[1:]
lows = lows[1:]
# print "DEBUG:"
# print "highs = %s" % highs
# print "lows = %s" % lows

View File

@ -274,15 +274,16 @@ If a player has None chips he won't be added."""
self.streets.update(match.groupdict())
log.debug("markStreets:\n"+ str(self.streets))
else:
tmp = self.handText[0:100]
log.error("markstreets didn't match")
log.error(" - Assuming hand cancelled")
self.cancelled = True
raise FpdbParseError
raise FpdbParseError("FpdbParseError: markStreets appeared to fail: First 100 chars: '%s'" % tmp)
def checkPlayerExists(self,player):
if player not in [p[1] for p in self.players]:
print "checkPlayerExists", player, "fail"
raise FpdbParseError
print "DEBUG: checkPlayerExists %s fail" % player
raise FpdbParseError("checkPlayerExists: '%s' failed." % player)
@ -1487,9 +1488,9 @@ class Pot(object):
if self.sym is None:
self.sym = "C"
if self.total is None:
print "call Pot.end() before printing pot total"
print "DEBUG: call Pot.end() before printing pot total"
# NB if I'm sure end() is idempotent, call it here.
raise FpdbParseError
raise FpdbParseError("FpdbError in printing Hand object")
ret = "Total pot %s%.2f" % (self.sym, self.total)
if len(self.pots) < 2:

View File

@ -62,7 +62,7 @@ class HandHistoryConverter():
codepage = "cp1252"
def __init__(self, config, in_path = '-', out_path = '-', follow=False, index=0, autostart=True, starsArchive=False):
def __init__(self, config, in_path = '-', out_path = '-', follow=False, index=0, autostart=True, starsArchive=False, ftpArchive=False):
"""\
in_path (default '-' = sys.stdin)
out_path (default '-' = sys.stdout)
@ -75,6 +75,7 @@ follow : whether to tail -f the input"""
self.index = index
self.starsArchive = starsArchive
self.ftpArchive = ftpArchive
self.in_path = in_path
self.out_path = out_path
@ -136,8 +137,7 @@ Otherwise, finish at EOF.
self.numHands += 1
except FpdbParseError, e:
self.numErrors += 1
log.warning("Failed to convert hand %s" % e.hid)
log.warning("Exception msg: '%s'" % str(e))
log.warning("HHC.start(follow): processHand failed: Exception msg: '%s'" % e)
log.debug(handText)
else:
handsList = self.allHandsAsList()
@ -151,8 +151,7 @@ Otherwise, finish at EOF.
self.processedHands.append(self.processHand(handText))
except FpdbParseError, e:
self.numErrors += 1
log.warning("Failed to convert hand %s" % e.hid)
log.warning("Exception msg: '%s'" % str(e))
log.warning("HHC.start(): processHand failed: Exception msg: '%s'" % e)
log.debug(handText)
self.numHands = len(handsList)
endtime = time.time()
@ -247,6 +246,11 @@ which it expects to find at self.re_TailSplitHands -- see for e.g. Everleaf.py.
m = re.compile('^Hand #\d+', re.MULTILINE)
self.obs = m.sub('', self.obs)
if self.ftpArchive == True:
log.debug("Converting ftpArchive format to readable")
m = re.compile('^\*\*\*\*\*\*+\s#\s\d+\s\*\*\*\*\*+$', re.MULTILINE)
self.obs = m.sub('', self.obs)
if self.obs is None or self.obs == "":
log.info("Read no hands.")
return []

View File

@ -448,6 +448,8 @@ class Hud:
if os.name == 'nt':
if not win32gui.IsWindow(self.table.number):
self.parent.kill_hud(self, self.table.name)
self.parent.kill_hud(self, self.table.name.split(" ")[0])
#table.name is only a valid handle for ring games ! we are not killing tourney tables here.
return False
# anyone know how to do this in unix, or better yet, trap the X11 error that is triggered when executing the get_origin() for a closed window?
if self.table.gdkhandle is not None:

View File

@ -261,6 +261,7 @@ class PartyPoker(HandHistoryConverter):
if v[0] in self.pot.returned:
self.collected[i][1] = Decimal(v[1]) - self.pot.returned[v[0]]
self.collectees[v[0]] -= self.pot.returned[v[0]]
self.pot.returned[v[0]] = 0
return origTotalPot()
return totalPot
instancemethod = type(hand.totalPot)
@ -359,8 +360,14 @@ class PartyPoker(HandHistoryConverter):
if hand.gametype['type'] == 'ring':
try:
assert noSmallBlind==False
m = self.re_PostSB.search(hand.handText)
liveBlind = True
for m in self.re_PostSB.finditer(hand.handText):
if liveBlind:
hand.addBlind(m.group('PNAME'), 'small blind', m.group('SB'))
liveBlind = False
else:
# Post dead blinds as ante
hand.addBlind(m.group('PNAME'), 'secondsb', m.group('SB'))
except: # no small blind
hand.addBlind(None, None, None)
@ -432,7 +439,7 @@ class PartyPoker(HandHistoryConverter):
if street == 'PREFLOP' and \
playerName in [item[0] for item in hand.actions['BLINDSANTES'] if item[2]!='ante']:
# preflop raise from blind
hand.addRaiseBy( street, playerName, amount )
hand.addCallandRaise( street, playerName, amount )
else:
hand.addCallandRaise( street, playerName, amount )
elif actionType == 'calls':

View File

@ -137,13 +137,16 @@ class PokerStars(HandHistoryConverter):
info = {}
m = self.re_GameInfo.search(handText)
if not m:
print "DEBUG: determineGameType(): did not match"
return None
tmp = handText[0:100]
log.error("determineGameType: Unable to recognise gametype from: '%s'" % tmp)
log.error("determineGameType: Raising FpdbParseError")
raise FpdbParseError("Unable to recognise gametype from: '%s'" % tmp)
mg = m.groupdict()
# translations from captured groups to fpdb info strings
Lim_Blinds = { '0.04': ('0.01', '0.02'), '0.10': ('0.02', '0.05'), '0.20': ('0.05', '0.10'),
'0.50': ('0.10', '0.25'), '1.00': ('0.25', '0.50'), '2.00': ('0.50', '1.00'),
'2': ('0.50', '1.00'), '4': ('1.00', '2.00'), '6': ('1.00', '3.00'),
'4.00': ('1.00', '2.00'), '6.00': ('1.00', '3.00'), '10.00': ('2.00', '5.00'),
'20.00': ('5.00', '10.00'), '30.00': ('10.00', '15.00'), '60.00': ('15.00', '30.00'),
'100.00': ('25.00', '50.00'),'200.00': ('50.00', '100.00'),'400.00': ('100.00', '200.00'),
@ -185,8 +188,13 @@ class PokerStars(HandHistoryConverter):
info['type'] = 'tour'
if info['limitType'] == 'fl' and info['bb'] is not None and info['type'] == 'ring' and info['base'] != 'stud':
try:
info['sb'] = Lim_Blinds[mg['BB']][0]
info['bb'] = Lim_Blinds[mg['BB']][1]
except KeyError:
log.error("determineGameType: Lim_Blinds has no lookup for '%s'" % mg['BB'])
log.error("determineGameType: Raising FpdbParseError")
raise FpdbParseError("Lim_Blinds has no lookup for '%s'" % mg['BB'])
# NB: SB, BB must be interpreted as blinds or bets depending on limit type.
return info

View File

@ -51,6 +51,18 @@ class Sql:
WHERE type='table'
ORDER BY name;"""
################################
# List indexes
################################
if db_server == 'mysql':
self.query['list_tables'] = """SHOW INDEXES"""
elif db_server == 'postgresql':
self.query['list_tables'] = """SELECT tablename, indexname FROM PG_INDEXES"""
elif db_server == 'sqlite':
self.query['list_tables'] = """SELECT name FROM sqlite_master
WHERE type='index'
ORDER BY name;"""
##################################################################
# Drop Tables - MySQL, PostgreSQL and SQLite all share same syntax
##################################################################

View File

@ -57,6 +57,7 @@ import re
# FreePokerTools modules
import Configuration
import Database
import Charset
re_Places = re.compile("_[0-9]$")
@ -67,7 +68,7 @@ import codecs
encoder = codecs.lookup(Configuration.LOCALE_ENCODING)
def do_tip(widget, tip):
(_tip, _len) = encoder.encode(tip)
_tip = Charset.to_utf8(tip)
widget.set_tooltip_text(_tip)
def do_stat(stat_dict, player = 24, stat = 'vpip'):
@ -277,7 +278,7 @@ def fold_f(stat_dict, player):
""" Folded flop/4th."""
stat = 0.0
try:
stat = float(stat_dict[player]['fold_2'])/fold(stat_dict[player]['saw_f'])
stat = float(stat_dict[player]['fold_2'])/float(stat_dict[player]['saw_f'])
return (stat,
'%3.1f' % (100*stat) + '%',
'ff=%3.1f' % (100*stat) + '%',

View File

@ -110,7 +110,7 @@ import Database
import Configuration
import Exceptions
VERSION = "0.12"
VERSION = "0.20"
class fpdb:

View File

@ -468,6 +468,7 @@ class Importer:
errors = getattr(hhc, 'numErrors')
stored = getattr(hhc, 'numHands')
stored -= duplicates
stored -= errors
else:
# conversion didn't work
# TODO: appropriate response?