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

Conflicts:
	pyfpdb/GuiTableViewer.py
This commit is contained in:
Mika Bostrom 2009-08-12 08:30:31 +03:00
commit 89dccac169
23 changed files with 1861 additions and 799 deletions

2
.gitignore vendored Normal file
View File

@ -0,0 +1,2 @@
*.pyc
*~

334
pyfpdb/AbsoluteToFpdb.py Normal file
View File

@ -0,0 +1,334 @@
#!/usr/bin/env 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 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
########################################################################
# TODO: I have no idea if AP has multi-currency options, i just copied the regex out of Everleaf converter for the currency symbols.. weeeeee - Eric
import sys
import logging
from HandHistoryConverter import *
# Class for converting Absolute HH format.
class Absolute(HandHistoryConverter):
# Static regexes
re_SplitHands = re.compile(r"\n\n\n+")
re_TailSplitHands = re.compile(r"(\n\n\n+)")
#Stage #1571362962: Holdem No Limit $0.02 - 2009-08-05 15:24:06 (ET)
#Table: TORONTO AVE (Real Money) Seat #6 is the dealer
#Seat 6 - FETS63 ($0.75 in chips)
#Board [10s 5d Kh Qh 8c]
re_GameInfo = re.compile(ur"^Stage #([0-9]+): (?P<GAME>Holdem|) (?P<LIMIT>No Limit|) (?P<CURRENCY>\$| €|)(?P<BB>[0-9]*[.0-9]+)", re.MULTILINE)
re_HandInfo = re.compile(ur"^Stage #(?P<HID>[0-9]+): .*(?P<DATETIME>\d\d\d\d-\d\d-\d\d \d\d:\d\d:\d\d).*\nTable: (?P<TABLE>.*) \(Real Money\)", re.MULTILINE)
re_Button = re.compile(ur"Seat #(?P<BUTTON>[0-9]) is the ?[dead]* dealer$", re.MULTILINE) # TODO: that's not the right way to match for "dead" dealer is it?
re_PlayerInfo = re.compile(ur"^Seat (?P<SEAT>[0-9]) - (?P<PNAME>.*) \((?:\$| €|)(?P<CASH>[0-9]*[.0-9]+) in chips\)", re.MULTILINE)
re_Board = re.compile(ur"\[(?P<CARDS>[^\]]*)\]? *$", re.MULTILINE)
# re_GameInfo = re.compile(ur"^(Blinds )?(?P<CURRENCY>\$| €|)(?P<SB>[.0-9]+)/(?:\$| €)?(?P<BB>[.0-9]+) (?P<LIMIT>NL|PL|) ?(?P<GAME>(Holdem|Omaha|7 Card Stud))", re.MULTILINE)
#re.compile(ur"^(Blinds )?(?P<CURRENCY>\$| €|)(?P<SB>[.0-9]+)/(?:\$| €)?(?P<BB>[.0-9]+) (?P<LIMIT>NL|PL|) (?P<GAME>(Hold\'em|Omaha|7 Card Stud))", re.MULTILINE)
# re_HandInfo = re.compile(ur".*#(?P<HID>[0-9]+)\n.*\n(Blinds )?(?:\$| €|)(?P<SB>[.0-9]+)/(?:\$| €|)(?P<BB>[.0-9]+) (?P<GAMETYPE>.*) - (?P<DATETIME>\d\d\d\d/\d\d/\d\d - \d\d:\d\d:\d\d)\nTable (?P<TABLE>.+$)", re.MULTILINE)
# re_Button = re.compile(ur"^Seat (?P<BUTTON>\d+) is the button", re.MULTILINE)
# re_PlayerInfo = re.compile(ur"^Seat (?P<SEAT>[0-9]+): (?P<PNAME>.*) \(\s+((?:\$| €|) (?P<CASH>[.0-9]+) (USD|EUR|)|new player|All-in) \)", re.MULTILINE)
# re_Board = re.compile(ur"\[ (?P<CARDS>.+) \]")
def __init__(self, in_path = '-', out_path = '-', follow = False, autostart=True, debugging=False, index=0):
"""\
in_path (default '-' = sys.stdin)
out_path (default '-' = sys.stdout)
follow : whether to tail -f the input
autostart: whether to run the thread (or you can call start() yourself)
debugging: if False, pass on partially supported game types. If true, have a go and error..."""
#print "DEBUG: XXXXXXXXXXXXXXX"
HandHistoryConverter.__init__(self, in_path, out_path, sitename="Absolute", follow=follow, index=index)
logging.info("Initialising Absolute converter class")
self.filetype = "text"
self.codepage = "cp1252"
self.siteId = 8 # Needs to match id entry in Sites database
self.debugging = debugging
if autostart:
self.start()
# otherwise you need to call start yourself.
def compilePlayerRegexs(self, hand):
players = set([player[1] for player in hand.players])
if not players <= self.compiledPlayers: # x <= y means 'x is subset of y'
# we need to recompile the player regexs.
self.compiledPlayers = players
player_re = "(?P<PNAME>" + "|".join(map(re.escape, players)) + ")"
logging.debug("player_re: "+ player_re)
#(?P<CURRENCY>\$| €|)(?P<BB>[0-9]*[.0-9]+)
self.re_PostSB = re.compile(ur"^%s - Posts small blind (?:\$| €|)(?P<SB>[0-9]*[.0-9]+)" % player_re, re.MULTILINE)
self.re_PostBB = re.compile(ur"^%s - Posts big blind (?:\$| €|)(?P<BB>[0-9]*[.0-9]+)" % player_re, re.MULTILINE)
# TODO: Absolute posting when coming in new: %s - Posts $0.02 .. should that be a new Post line? where do we need to add support for that? *confused*
self.re_PostBoth = re.compile(ur"^%s - Posts dead (?:\$| €|)(?P<SBBB>[0-9]*[.0-9]+)" % player_re, re.MULTILINE)
self.re_Action = re.compile(ur"^%s - (?P<ATYPE>Bets |Raises |All-In |All-In\(Raise\) |Calls |Folds|Checks)?\$?(?P<BET>[0-9]*[.0-9]+)?" % player_re, re.MULTILINE)
# print "^%s - (?P<ATYPE>Bets |Raises |All-In |All-In\(Raise\) |Calls |Folds|Checks)?\$?(?P<BET>[0-9]*[.0-9]+)?" % player_re
self.re_ShowdownAction = re.compile(ur"^%s - Shows \[(?P<CARDS>.*)\]" % player_re, re.MULTILINE)
self.re_CollectPot = re.compile(ur"^Seat [0-9]: %s(?: \(dealer\)| \(big blind\)| \(small blind\)|) (?:won|collected) Total \((?:\$| €|)(?P<POT>[0-9]*[.0-9]+)\)" % player_re, re.MULTILINE)
#self.re_PostSB = re.compile(ur"^%s: posts small blind \[(?:\$| €|) (?P<SB>[.0-9]+)" % player_re, re.MULTILINE)
#self.re_PostBB = re.compile(ur"^%s: posts big blind \[(?:\$| €|) (?P<BB>[.0-9]+)" % player_re, re.MULTILINE)
#self.re_PostBoth = re.compile(ur"^%s: posts both blinds \[(?:\$| €|) (?P<SBBB>[.0-9]+)" % player_re, re.MULTILINE)
#self.re_Antes = re.compile(ur"^%s: posts ante \[(?:\$| €|) (?P<ANTE>[.0-9]+)" % player_re, re.MULTILINE)
#self.re_BringIn = re.compile(ur"^%s posts bring-in (?:\$| €|)(?P<BRINGIN>[.0-9]+)\." % player_re, re.MULTILINE)
self.re_HeroCards = re.compile(ur"^Dealt to %s \[(?P<CARDS>.*)\]" % player_re, re.MULTILINE)
#self.re_Action = re.compile(ur"^%s(?P<ATYPE>: bets| checks| raises| calls| folds)(\s\[(?:\$| €|) (?P<BET>[.\d]+) (USD|EUR|)\])?" % player_re, re.MULTILINE)
#self.re_Action = re.compile(ur"^%s(?P<ATYPE>: bets| checks| raises| calls| folds| complete to)(\s\[?(?:\$| €|) ?(?P<BET>\d+\.?\d*)\.?\s?(USD|EUR|)\]?)?" % player_re, re.MULTILINE)
#self.re_ShowdownAction = re.compile(ur"^%s shows \[ (?P<CARDS>.*) \]" % player_re, re.MULTILINE)
#self.re_CollectPot = re.compile(ur"^%s wins (?:\$| €|) (?P<POT>[.\d]+) (USD|EUR|chips)(.*?\[ (?P<CARDS>.*?) \])?" % player_re, re.MULTILINE)
#self.re_SitsOut = re.compile(ur"^%s sits out" % player_re, re.MULTILINE)
def readSupportedGames(self):
return [["ring", "hold", "nl"],
["ring", "hold", "pl"],
["ring", "hold", "fl"],
["ring", "studhi", "fl"],
["ring", "omahahi", "pl"]
]
def determineGameType(self, handText):
"""return dict with keys/values:
'type' in ('ring', 'tour')
'limitType' in ('nl', 'cn', 'pl', 'cp', 'fl')
'base' in ('hold', 'stud', 'draw')
'category' in ('holdem', 'omahahi', omahahilo', 'razz', 'studhi', 'studhilo', 'fivedraw', '27_1draw', '27_3draw', 'badugi')
'hilo' in ('h','l','s')
'smallBlind' int?
'bigBlind' int?
'smallBet'
'bigBet'
'currency' in ('USD', 'EUR', 'T$', <countrycode>)
or None if we fail to get the info """
info = {'type':'ring'}
m = self.re_GameInfo.search(handText)
if not m:
return None
mg = m.groupdict()
# translations from captured groups to our info strings
limits = { 'No Limit':'nl', 'PL':'pl', '':'fl' }
games = { # base, category
"Holdem" : ('hold','holdem'),
'Omaha' : ('hold','omahahi'),
'Razz' : ('stud','razz'),
'7 Card Stud' : ('stud','studhi')
}
currencies = { u'':'EUR', '$':'USD', '':'T$' }
if 'LIMIT' in mg:
info['limitType'] = limits[mg['LIMIT']]
if 'GAME' in mg:
(info['base'], info['category']) = games[mg['GAME']]
if 'SB' in mg:
info['sb'] = mg['SB']
else:
info['sb'] = str(float(mg['BB']) * 0.5) # TODO: Apparently AP doesn't provide small blind info!? must search to see if it's posted, I guess
if 'BB' in mg:
info['bb'] = mg['BB']
if 'CURRENCY' in mg:
info['currency'] = currencies[mg['CURRENCY']]
if info['currency'] == 'T$':
info['type'] = 'tour'
# NB: SB, BB must be interpreted as blinds or bets depending on limit type.
return info
def readHandInfo(self, hand):
m = self.re_HandInfo.search(hand.handText)
if(m == None):
logging.info("Didn't match re_HandInfo")
logging.info(hand.handText)
return None
logging.debug("HID %s, Table %s" % (m.group('HID'), m.group('TABLE')))
hand.handid = m.group('HID')
hand.tablename = m.group('TABLE')
hand.maxseats = 6 # assume 6-max unless we have proof it's a larger/smaller game, since absolute doesn't give seat max info
hand.starttime = datetime.datetime.strptime(m.group('DATETIME'), "%Y-%m-%d %H:%M:%S")
return
def readPlayerStacks(self, hand):
m = self.re_PlayerInfo.finditer(hand.handText)
for a in m:
seatnum = int(a.group('SEAT'))
hand.addPlayer(seatnum, a.group('PNAME'), a.group('CASH'))
if seatnum > 6:
hand.maxseats = 10 # absolute does 2/4/6/8/10 games
# TODO: implement lookup list by table-name to determine maxes, then fall back to 6 default/10 here, if there's no entry in the list?
def markStreets(self, hand):
# PREFLOP = ** Dealing down cards **
# This re fails if, say, river is missing; then we don't get the ** that starts the river.
#m = re.search('(\*\* Dealing down cards \*\*\n)(?P<PREFLOP>.*?\n\*\*)?( Dealing Flop \*\* \[ (?P<FLOP1>\S\S), (?P<FLOP2>\S\S), (?P<FLOP3>\S\S) \])?(?P<FLOP>.*?\*\*)?( Dealing Turn \*\* \[ (?P<TURN1>\S\S) \])?(?P<TURN>.*?\*\*)?( Dealing River \*\* \[ (?P<RIVER1>\S\S) \])?(?P<RIVER>.*)', hand.handText,re.DOTALL)
if hand.gametype['base'] == 'hold':
m = re.search(r"\*\*\* POCKET CARDS \*\*\*(?P<PREFLOP>.+(?=\*\*\* FLOP \*\*\*)|.+)"
r"(\*\*\* FLOP \*\*\*(?P<FLOP>.+(?=\*\*\* TURN \*\*\*)|.+))?"
r"(\*\*\* TURN \*\*\*(?P<TURN>.+(?=\*\*\* RIVER \*\*\*)|.+))?"
r"(\*\*\* RIVER \*\*\*(?P<RIVER>.+))?", hand.handText, re.DOTALL)
elif hand.gametype['base'] == 'stud': # TODO: Not implemented yet
m = re.search(r"(?P<ANTES>.+(?=\*\* Dealing down cards \*\*)|.+)"
r"(\*\* Dealing down cards \*\*(?P<THIRD>.+(?=\*\*\*\* dealing 4th street \*\*\*\*)|.+))?"
r"(\*\*\*\* dealing 4th street \*\*\*\*(?P<FOURTH>.+(?=\*\*\*\* dealing 5th street \*\*\*\*)|.+))?"
r"(\*\*\*\* dealing 5th street \*\*\*\*(?P<FIFTH>.+(?=\*\*\*\* dealing 6th street \*\*\*\*)|.+))?"
r"(\*\*\*\* dealing 6th street \*\*\*\*(?P<SIXTH>.+(?=\*\*\*\* dealing river \*\*\*\*)|.+))?"
r"(\*\*\*\* dealing river \*\*\*\*(?P<SEVENTH>.+))?", hand.handText,re.DOTALL)
hand.addStreets(m)
def readCommunityCards(self, hand, street): # street has been matched by markStreets, so exists in this hand
# If this has been called, street is a street which gets dealt community cards by type hand
# but it might be worth checking somehow.
# if street in ('FLOP','TURN','RIVER'): # a list of streets which get dealt community cards (i.e. all but PREFLOP)
logging.debug("readCommunityCards (%s)" % street)
m = self.re_Board.search(hand.streets[street])
cards = m.group('CARDS')
cards = [validCard(card) for card in cards.split(' ')]
hand.setCommunityCards(street=street, cards=cards)
def readAntes(self, hand):
logging.debug("reading antes")
m = self.re_Antes.finditer(hand.handText)
for player in m:
logging.debug("hand.addAnte(%s,%s)" %(player.group('PNAME'), player.group('ANTE')))
hand.addAnte(player.group('PNAME'), player.group('ANTE'))
def readBringIn(self, hand):
m = self.re_BringIn.search(hand.handText,re.DOTALL)
if m:
logging.debug("Player bringing in: %s for %s" %(m.group('PNAME'), m.group('BRINGIN')))
hand.addBringIn(m.group('PNAME'), m.group('BRINGIN'))
else:
logging.warning("No bringin found.")
def readBlinds(self, hand):
m = self.re_PostSB.search(hand.handText)
if m is not None:
hand.addBlind(m.group('PNAME'), 'small blind', m.group('SB'))
else:
logging.debug("No small blind")
hand.addBlind(None, None, None)
for a in self.re_PostBB.finditer(hand.handText):
hand.addBlind(a.group('PNAME'), 'big blind', a.group('BB'))
for a in self.re_PostBoth.finditer(hand.handText):
hand.addBlind(a.group('PNAME'), 'both', a.group('SBBB'))
def readButton(self, hand):
hand.buttonpos = int(self.re_Button.search(hand.handText).group('BUTTON'))
def readHeroCards(self, hand):
m = self.re_HeroCards.search(hand.handText)
if m:
hand.hero = m.group('PNAME')
# "2c, qh" -> ["2c","qc"]
# Also works with Omaha hands.
cards = m.group('CARDS')
cards = [validCard(card) for card in cards.split(' ')]
# hand.addHoleCards(cards, m.group('PNAME'))
hand.addHoleCards('PREFLOP', hand.hero, closed=cards, shown=False, mucked=False, dealt=True)
else:
#Not involved in hand
hand.involved = False
def readStudPlayerCards(self, hand, street):
# lol. see Plymouth.txt
logging.warning("Absolute readStudPlayerCards is only a stub.")
#~ if street in ('THIRD', 'FOURTH', 'FIFTH', 'SIXTH'):
#~ hand.addPlayerCards(player = player.group('PNAME'), street = street, closed = [], open = [])
def readAction(self, hand, street):
logging.debug("readAction (%s)" % street)
m = self.re_Action.finditer(hand.streets[street])
for action in m:
logging.debug("%s %s" % (action.group('ATYPE'), action.groupdict()))
if action.group('ATYPE') == 'Raises ' or action.group('ATYPE') == 'All-In(Raise) ':
hand.addCallandRaise( street, action.group('PNAME'), action.group('BET') )
elif action.group('ATYPE') == 'Calls ':
hand.addCall( street, action.group('PNAME'), action.group('BET') )
elif action.group('ATYPE') == 'Bets ' or action.group('ATYPE') == 'All-In ':
hand.addBet( street, action.group('PNAME'), action.group('BET') )
elif action.group('ATYPE') == 'Folds':
hand.addFold( street, action.group('PNAME'))
elif action.group('ATYPE') == 'Checks':
hand.addCheck( street, action.group('PNAME'))
elif action.group('ATYPE') == ' complete to': # TODO: not supported yet ?
hand.addComplete( street, action.group('PNAME'), action.group('BET'))
else:
logging.debug("Unimplemented readAction: %s %s" %(action.group('PNAME'),action.group('ATYPE'),))
def readShowdownActions(self, hand):
"""Reads lines where holecards are reported in a showdown"""
logging.debug("readShowdownActions")
for shows in self.re_ShowdownAction.finditer(hand.handText):
cards = shows.group('CARDS')
cards = [validCard(card) for card in cards.split(' ')]
logging.debug("readShowdownActions %s %s" %(cards, shows.group('PNAME')))
hand.addShownCards(cards, shows.group('PNAME'))
def readCollectPot(self,hand):
for m in self.re_CollectPot.finditer(hand.handText):
hand.addCollectPot(player=m.group('PNAME'),pot=m.group('POT'))
def readShownCards(self,hand):
"""Reads lines where hole & board cards are mixed to form a hand (summary lines)"""
for m in self.re_CollectPot.finditer(hand.handText):
try:
if m.group('CARDS') is not None:
cards = m.group('CARDS')
cards = [validCard(card) for card in cards.split(' ')]
player = m.group('PNAME')
logging.debug("readShownCards %s cards=%s" % (player, cards))
# hand.addShownCards(cards=None, player=m.group('PNAME'), holeandboard=cards)
hand.addShownCards(cards=cards, player=m.group('PNAME'))
except IndexError:
pass # there's no "PLAYER - Mucks" at AP that I can see
def validCard(card):
card = card.strip()
if card == '10s': card = 'Ts'
if card == '10h': card = 'Th'
if card == '10d': card = 'Td'
if card == '10c': card = 'Tc'
return card
if __name__ == "__main__":
parser = OptionParser()
parser.add_option("-i", "--input", dest="ipath", help="parse input hand history", default="-")
parser.add_option("-o", "--output", dest="opath", help="output translation to", default="-")
parser.add_option("-f", "--follow", dest="follow", help="follow (tail -f) the input", action="store_true", default=False)
parser.add_option("-q", "--quiet",
action="store_const", const=logging.CRITICAL, dest="verbosity", default=logging.INFO)
parser.add_option("-v", "--verbose",
action="store_const", const=logging.INFO, dest="verbosity")
parser.add_option("--vv",
action="store_const", const=logging.DEBUG, dest="verbosity")
(options, args) = parser.parse_args()
LOG_FILENAME = './logging.out'
logging.basicConfig(filename=LOG_FILENAME,level=options.verbosity)
e = Absolute(in_path = options.ipath, out_path = options.opath, follow = options.follow, autostart=True, debugging=True)

View File

@ -584,19 +584,20 @@ class Config:
return paths return paths
def get_frames(self, site = "PokerStars"): def get_frames(self, site = "PokerStars"):
if site not in self.supported_sites: return False
return self.supported_sites[site].use_frames == True return self.supported_sites[site].use_frames == True
def get_default_colors(self, site = "PokerStars"): def get_default_colors(self, site = "PokerStars"):
colors = {} colors = {}
if self.supported_sites[site].hudopacity == "": if site not in self.supported_sites or self.supported_sites[site].hudopacity == "":
colors['hudopacity'] = 0.90 colors['hudopacity'] = 0.90
else: else:
colors['hudopacity'] = float(self.supported_sites[site].hudopacity) colors['hudopacity'] = float(self.supported_sites[site].hudopacity)
if self.supported_sites[site].hudbgcolor == "": if site not in self.supported_sites or self.supported_sites[site].hudbgcolor == "":
colors['hudbgcolor'] = "#FFFFFF" colors['hudbgcolor'] = "#FFFFFF"
else: else:
colors['hudbgcolor'] = self.supported_sites[site].hudbgcolor colors['hudbgcolor'] = self.supported_sites[site].hudbgcolor
if self.supported_sites[site].hudfgcolor == "": if site not in self.supported_sites or self.supported_sites[site].hudfgcolor == "":
colors['hudfgcolor'] = "#000000" colors['hudfgcolor'] = "#000000"
else: else:
colors['hudfgcolor'] = self.supported_sites[site].hudfgcolor colors['hudfgcolor'] = self.supported_sites[site].hudfgcolor
@ -604,6 +605,8 @@ class Config:
def get_default_font(self, site = 'PokerStars'): def get_default_font(self, site = 'PokerStars'):
(font, font_size) = ("Sans", "8") (font, font_size) = ("Sans", "8")
if site not in self.supported_sites:
return ("Sans", "8")
if self.supported_sites[site].font == "": if self.supported_sites[site].font == "":
font = "Sans" font = "Sans"
else: else:

View File

@ -98,7 +98,7 @@ class Database:
foreignKeys = [ foreignKeys = [
[ ] # no db with index 0 [ ] # no db with index 0
, [ ] # no db with index 1 , [ ] # no db with index 1
, [ # foreign keys for mysql , [ # foreign keys for mysql (index 2)
{'fktab':'Hands', 'fkcol':'gametypeId', 'rtab':'Gametypes', 'rcol':'id', 'drop':1} {'fktab':'Hands', 'fkcol':'gametypeId', 'rtab':'Gametypes', 'rcol':'id', 'drop':1}
, {'fktab':'HandsPlayers', 'fkcol':'handId', 'rtab':'Hands', 'rcol':'id', 'drop':1} , {'fktab':'HandsPlayers', 'fkcol':'handId', 'rtab':'Hands', 'rcol':'id', 'drop':1}
, {'fktab':'HandsPlayers', 'fkcol':'playerId', 'rtab':'Players', 'rcol':'id', 'drop':1} , {'fktab':'HandsPlayers', 'fkcol':'playerId', 'rtab':'Players', 'rcol':'id', 'drop':1}
@ -107,7 +107,7 @@ class Database:
, {'fktab':'HudCache', 'fkcol':'playerId', 'rtab':'Players', 'rcol':'id', 'drop':0} , {'fktab':'HudCache', 'fkcol':'playerId', 'rtab':'Players', 'rcol':'id', 'drop':0}
, {'fktab':'HudCache', 'fkcol':'tourneyTypeId', 'rtab':'TourneyTypes', 'rcol':'id', 'drop':1} , {'fktab':'HudCache', 'fkcol':'tourneyTypeId', 'rtab':'TourneyTypes', 'rcol':'id', 'drop':1}
] ]
, [ # foreign keys for postgres , [ # foreign keys for postgres (index 3)
{'fktab':'Hands', 'fkcol':'gametypeId', 'rtab':'Gametypes', 'rcol':'id', 'drop':1} {'fktab':'Hands', 'fkcol':'gametypeId', 'rtab':'Gametypes', 'rcol':'id', 'drop':1}
, {'fktab':'HandsPlayers', 'fkcol':'handId', 'rtab':'Hands', 'rcol':'id', 'drop':1} , {'fktab':'HandsPlayers', 'fkcol':'handId', 'rtab':'Hands', 'rcol':'id', 'drop':1}
, {'fktab':'HandsPlayers', 'fkcol':'playerId', 'rtab':'Players', 'rcol':'id', 'drop':1} , {'fktab':'HandsPlayers', 'fkcol':'playerId', 'rtab':'Players', 'rcol':'id', 'drop':1}
@ -116,6 +116,8 @@ class Database:
, {'fktab':'HudCache', 'fkcol':'playerId', 'rtab':'Players', 'rcol':'id', 'drop':0} , {'fktab':'HudCache', 'fkcol':'playerId', 'rtab':'Players', 'rcol':'id', 'drop':0}
, {'fktab':'HudCache', 'fkcol':'tourneyTypeId', 'rtab':'TourneyTypes', 'rcol':'id', 'drop':1} , {'fktab':'HudCache', 'fkcol':'tourneyTypeId', 'rtab':'TourneyTypes', 'rcol':'id', 'drop':1}
] ]
, [ # no foreign keys in sqlite (index 4)
]
] ]
@ -233,9 +235,15 @@ class Database:
self.fdb.reconnect(due_to_error=False) self.fdb.reconnect(due_to_error=False)
def get_backend_name(self): def get_backend_name(self):
"""Reconnects the DB""" """Returns the name of the currently used backend"""
return self.fdb.get_backend_name() if self.backend==2:
return "MySQL InnoDB"
elif self.backend==3:
return "PostgreSQL"
elif self.backend==4:
return "SQLite"
else:
raise fpdb_simple.FpdbError("invalid backend")
def get_table_name(self, hand_id): def get_table_name(self, hand_id):
c = self.connection.cursor() c = self.connection.cursor()
@ -465,11 +473,39 @@ class Database:
result = c.fetchall() result = c.fetchall()
return result return result
def get_last_insert_id(self): def get_last_insert_id(self, cursor=None):
ret = None
try: try:
ret = self.fdb.getLastInsertId() if self.backend == self.MYSQL_INNODB:
ret = self.connection.insert_id()
if ret < 1 or ret > 999999999:
print "getLastInsertId(): problem fetching insert_id? ret=", ret
ret = -1
elif self.backend == self.PGSQL:
# some options:
# currval(hands_id_seq) - use name of implicit seq here
# lastval() - still needs sequences set up?
# insert ... returning is useful syntax (but postgres specific?)
# see rules (fancy trigger type things)
c = self.get_cursor()
ret = c.execute ("SELECT lastval()")
row = c.fetchone()
if not row:
print "getLastInsertId(%s): problem fetching lastval? row=" % seq, row
ret = -1
else:
ret = row[0]
elif self.backend == self.SQLITE:
ret = cursor.lastrowid
else:
print "getLastInsertId(): unknown backend ", self.backend
ret = -1
except: except:
print "get_last_insert_id error:", str(sys.exc_value) ret = -1
err = traceback.extract_tb(sys.exc_info()[2])
print "***get_last_insert_id error: " + str(sys.exc_info()[1])
print "\n".join( [e[0]+':'+str(e[1])+" "+e[2] for e in err] )
raise
return ret return ret
@ -847,6 +883,7 @@ class Database:
self.commit() self.commit()
except: except:
err = traceback.extract_tb(sys.exc_info()[2])[-1]
print "***Error dropping tables: "+err[2]+"("+str(err[1])+"): "+str(sys.exc_info()[1]) print "***Error dropping tables: "+err[2]+"("+str(err[1])+"): "+str(sys.exc_info()[1])
self.rollback() self.rollback()
raise raise
@ -920,6 +957,11 @@ class Database:
c.execute("INSERT INTO Sites (name,currency) VALUES ('PokerStars', 'USD')") c.execute("INSERT INTO Sites (name,currency) VALUES ('PokerStars', 'USD')")
c.execute("INSERT INTO Sites (name,currency) VALUES ('Everleaf', 'USD')") c.execute("INSERT INTO Sites (name,currency) VALUES ('Everleaf', 'USD')")
c.execute("INSERT INTO Sites (name,currency) VALUES ('Win2day', 'USD')") c.execute("INSERT INTO Sites (name,currency) VALUES ('Win2day', 'USD')")
c.execute("INSERT INTO Sites (name,currency) VALUES ('OnGame', 'USD')")
c.execute("INSERT INTO Sites (name,currency) VALUES ('UltimateBet', 'USD')")
c.execute("INSERT INTO Sites (name,currency) VALUES ('Betfair', 'USD')")
c.execute("INSERT INTO Sites (name,currency) VALUES ('Absolute', 'USD')")
c.execute("INSERT INTO Sites (name,currency) VALUES ('PartyPoker', 'USD')")
if self.backend == self.SQLITE: if self.backend == self.SQLITE:
c.execute("INSERT INTO TourneyTypes VALUES (NULL, 1, 0, 0, 0, 0);") c.execute("INSERT INTO TourneyTypes VALUES (NULL, 1, 0, 0, 0, 0);")
else: else:
@ -934,12 +976,14 @@ class Database:
try: try:
stime = time() stime = time()
self.connection.cursor().execute(self.sql.query['clearHudCache']) self.get_cursor().execute(self.sql.query['clearHudCache'])
self.connection.cursor().execute(self.sql.query['rebuildHudCache']) self.get_cursor().execute(self.sql.query['rebuildHudCache'])
self.commit() self.commit()
print "Rebuild hudcache took %.1f seconds" % (time() - stime,) print "Rebuild hudcache took %.1f seconds" % (time() - stime,)
except: except:
err = traceback.extract_tb(sys.exc_info()[2])[-1]
print "Error rebuilding hudcache:", str(sys.exc_value) print "Error rebuilding hudcache:", str(sys.exc_value)
print err
#end def rebuild_hudcache #end def rebuild_hudcache
@ -996,15 +1040,26 @@ class Database:
def insertPlayer(self, name, site_id): def insertPlayer(self, name, site_id):
result = None result = None
c = self.get_cursor() c = self.get_cursor()
c.execute ("SELECT id FROM Players WHERE name=%s", (name,)) q = "SELECT name, id FROM Players WHERE siteid=%s and name=%s"
tmp=c.fetchall() q = q.replace('%s', self.sql.query['placeholder'])
if (len(tmp)==0): #new player
c.execute ("INSERT INTO Players (name, siteId) VALUES (%s, %s)", (name, site_id))
#Get last id might be faster here.
c.execute ("SELECT id FROM Players WHERE name=%s", (name,))
tmp=c.fetchall()
return tmp[0][0]
#print "DEBUG: name: %s site: %s" %(name, site_id)
c.execute (q, (site_id, name))
tmp = c.fetchone()
if (tmp == None): #new player
c.execute ("INSERT INTO Players (name, siteId) VALUES (%s, %s)".replace('%s',self.sql.query['placeholder'])
,(name, site_id))
#Get last id might be faster here.
#c.execute ("SELECT id FROM Players WHERE name=%s", (name,))
tmp = [self.get_last_insert_id(c)]
return tmp[0]
def insertGameTypes(self, row):
c = self.get_cursor()
c.execute( self.sql.query['insertGameTypes'], row )
return [self.get_last_insert_id(c)]
def store_the_hand(self, h): def store_the_hand(self, h):
"""Take a HandToWrite object and store it in the db""" """Take a HandToWrite object and store it in the db"""
@ -1064,6 +1119,76 @@ class Database:
return result return result
#end def store_the_hand #end def store_the_hand
def storeHand(self, p):
#stores into table hands:
q = """INSERT INTO Hands (
tablename,
gametypeid,
sitehandno,
handstart,
importtime,
maxseats,
boardcard1,
boardcard2,
boardcard3,
boardcard4,
boardcard5
)
VALUES
(%s, %s, %s, %s, %s, %s, %s, %s, %s, %s)"""
#--- texture,
#-- playersVpi,
#-- playersAtStreet1,
#-- playersAtStreet2,
#-- playersAtStreet3,
#-- playersAtStreet4,
#-- playersAtShowdown,
#-- street0Raises,
#-- street1Raises,
#-- street2Raises,
#-- street3Raises,
#-- street4Raises,
#-- street1Pot,
#-- street2Pot,
#-- street3Pot,
#-- street4Pot,
#-- showdownPot
#-- seats,
q = q.replace('%s', self.sql.query['placeholder'])
self.cursor.execute(q, (
p['tableName'],
p['siteHandNo'],
p['gametypeid'],
p['handStart'],
datetime.today(), #importtime
# len(p['names']), #seats
p['maxSeats'],
p['boardcard1'],
p['boardcard2'],
p['boardcard3'],
p['boardcard4'],
p['boardcard5'])
# hudCache['playersVpi'],
# hudCache['playersAtStreet1'],
# hudCache['playersAtStreet2'],
# hudCache['playersAtStreet3'],
# hudCache['playersAtStreet4'],
# hudCache['playersAtShowdown'],
# hudCache['street0Raises'],
# hudCache['street1Raises'],
# hudCache['street2Raises'],
# hudCache['street3Raises'],
# hudCache['street4Raises'],
# hudCache['street1Pot'],
# hudCache['street2Pot'],
# hudCache['street3Pot'],
# hudCache['street4Pot'],
# hudCache['showdownPot']
)
#return getLastInsertId(backend, conn, cursor)
# def storeHand
def storeHands(self, backend, site_hand_no, gametype_id def storeHands(self, backend, site_hand_no, gametype_id
,hand_start_time, names, tableName, maxSeats, hudCache ,hand_start_time, names, tableName, maxSeats, hudCache
,board_values, board_suits): ,board_values, board_suits):
@ -1071,7 +1196,8 @@ class Database:
cards = [Card.cardFromValueSuit(v,s) for v,s in zip(board_values,board_suits)] cards = [Card.cardFromValueSuit(v,s) for v,s in zip(board_values,board_suits)]
#stores into table hands: #stores into table hands:
try: try:
self.get_cursor().execute ("""INSERT INTO Hands c = self.get_cursor()
c.execute ("""INSERT INTO Hands
(siteHandNo, gametypeId, handStart, seats, tableName, importTime, maxSeats (siteHandNo, gametypeId, handStart, seats, tableName, importTime, maxSeats
,boardcard1,boardcard2,boardcard3,boardcard4,boardcard5 ,boardcard1,boardcard2,boardcard3,boardcard4,boardcard5
,playersVpi, playersAtStreet1, playersAtStreet2 ,playersVpi, playersAtStreet1, playersAtStreet2
@ -1084,7 +1210,7 @@ class Database:
VALUES VALUES
(%s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, (%s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s,
%s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s) %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s)
""" """.replace('%s', self.sql.query['placeholder'])
, (site_hand_no, gametype_id, hand_start_time, len(names), tableName, datetime.today(), maxSeats , (site_hand_no, gametype_id, hand_start_time, len(names), tableName, datetime.today(), maxSeats
,cards[0], cards[1], cards[2], cards[3], cards[4] ,cards[0], cards[1], cards[2], cards[3], cards[4]
,hudCache['playersVpi'], hudCache['playersAtStreet1'], hudCache['playersAtStreet2'] ,hudCache['playersVpi'], hudCache['playersAtStreet1'], hudCache['playersAtStreet2']
@ -1094,7 +1220,7 @@ class Database:
,hudCache['street2Pot'], hudCache['street3Pot'], hudCache['street4Pot'] ,hudCache['street2Pot'], hudCache['street3Pot'], hudCache['street4Pot']
,hudCache['showdownPot'] ,hudCache['showdownPot']
)) ))
ret = self.get_last_insert_id() ret = self.get_last_insert_id(c)
except: except:
ret = -1 ret = -1
raise fpdb_simple.FpdbError( "storeHands error: " + str(sys.exc_value) ) raise fpdb_simple.FpdbError( "storeHands error: " + str(sys.exc_value) )
@ -1163,7 +1289,8 @@ class Database:
hudCache['street0Calls'][i], hudCache['street1Calls'][i], hudCache['street2Calls'][i], hudCache['street3Calls'][i], hudCache['street4Calls'][i], hudCache['street0Calls'][i], hudCache['street1Calls'][i], hudCache['street2Calls'][i], hudCache['street3Calls'][i], hudCache['street4Calls'][i],
hudCache['street0Bets'][i], hudCache['street1Bets'][i], hudCache['street2Bets'][i], hudCache['street3Bets'][i], hudCache['street4Bets'][i] hudCache['street0Bets'][i], hudCache['street1Bets'][i], hudCache['street2Bets'][i], hudCache['street3Bets'][i], hudCache['street4Bets'][i]
) ) ) )
self.get_cursor().executemany (""" c = self.get_cursor()
c.executemany ("""
INSERT INTO HandsPlayers INSERT INTO HandsPlayers
(handId, playerId, startCash, position, tourneyTypeId, (handId, playerId, startCash, position, tourneyTypeId,
card1, card2, card3, card4, startCards, winnings, rake, seatNo, totalProfit, card1, card2, card3, card4, startCards, winnings, rake, seatNo, totalProfit,
@ -1186,13 +1313,9 @@ class Database:
VALUES (%s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, 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, %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)""".replace('%s', self.sql.query['placeholder'])
,inserts ) ,inserts )
result.append( self.get_last_insert_id() ) result.append( self.get_last_insert_id(c) ) # wrong? not used currently
#cursor.execute("SELECT id FROM HandsPlayers WHERE handId=%s AND playerId+0=%s", (hands_id, player_ids[i]))
#result.append(cursor.fetchall()[0][0])
result.append( self.get_last_insert_id() )
except: except:
raise fpdb_simple.FpdbError( "store_hands_players_holdem_omaha error: " + str(sys.exc_value) ) raise fpdb_simple.FpdbError( "store_hands_players_holdem_omaha error: " + str(sys.exc_value) )
@ -1215,13 +1338,14 @@ class Database:
card6 = Card.cardFromValueSuit(card_values[i][5], card_suits[i][5]) card6 = Card.cardFromValueSuit(card_values[i][5], card_suits[i][5])
card7 = Card.cardFromValueSuit(card_values[i][6], card_suits[i][6]) card7 = Card.cardFromValueSuit(card_values[i][6], card_suits[i][6])
self.get_cursor().execute ("""INSERT INTO HandsPlayers c = self.get_cursor()
c.execute ("""INSERT INTO HandsPlayers
(handId, playerId, startCash, ante, tourneyTypeId, (handId, playerId, startCash, ante, tourneyTypeId,
card1, card2, card1, card2,
card3, card4, card3, card4,
card5, card6, card5, card6,
card7, winnings, rake, seatNo) card7, winnings, rake, seatNo)
VALUES (%s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s)""", VALUES (%s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s)""".replace('%s', self.sql.query['placeholder']),
(hands_id, player_ids[i], start_cashes[i], antes[i], 1, (hands_id, player_ids[i], start_cashes[i], antes[i], 1,
card1, card2, card1, card2,
card3, card4, card3, card4,
@ -1229,7 +1353,7 @@ class Database:
card7, winnings[i], rakes[i], seatNos[i])) card7, winnings[i], rakes[i], seatNos[i]))
#cursor.execute("SELECT id FROM HandsPlayers WHERE handId=%s AND playerId+0=%s", (hands_id, player_ids[i])) #cursor.execute("SELECT id FROM HandsPlayers WHERE handId=%s AND playerId+0=%s", (hands_id, player_ids[i]))
#result.append(cursor.fetchall()[0][0]) #result.append(cursor.fetchall()[0][0])
result.append( self.get_last_insert_id() ) result.append( self.get_last_insert_id(c) )
except: except:
raise fpdb_simple.FpdbError( "store_hands_players_stud error: " + str(sys.exc_value) ) raise fpdb_simple.FpdbError( "store_hands_players_stud error: " + str(sys.exc_value) )
@ -1292,7 +1416,8 @@ class Database:
hudCache['street3Bets'][i], hudCache['street4Bets'][i] hudCache['street3Bets'][i], hudCache['street4Bets'][i]
) ) ) )
self.get_cursor().executemany (""" c = self.get_cursor()
c.executemany ("""
INSERT INTO HandsPlayers INSERT INTO HandsPlayers
(handId, playerId, startCash, position, tourneyTypeId, (handId, playerId, startCash, position, tourneyTypeId,
card1, card2, card3, card4, startCards, winnings, rake, tourneysPlayersId, seatNo, totalProfit, card1, card2, card3, card4, startCards, winnings, rake, tourneysPlayersId, seatNo, totalProfit,
@ -1316,10 +1441,10 @@ class Database:
(%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, %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)""".replace('%s', self.sql.query['placeholder'])
,inserts ) ,inserts )
result.append( self.get_last_insert_id() ) result.append( self.get_last_insert_id(c) )
#cursor.execute("SELECT id FROM HandsPlayers WHERE handId=%s AND playerId+0=%s", (hands_id, player_ids[i])) #cursor.execute("SELECT id FROM HandsPlayers WHERE handId=%s AND playerId+0=%s", (hands_id, player_ids[i]))
#result.append(cursor.fetchall()[0][0]) #result.append(cursor.fetchall()[0][0])
except: except:
@ -1335,14 +1460,15 @@ class Database:
try: try:
result=[] result=[]
for i in xrange(len(player_ids)): for i in xrange(len(player_ids)):
self.get_cursor().execute ("""INSERT INTO HandsPlayers c = self.get_cursor()
c.execute ("""INSERT INTO HandsPlayers
(handId, playerId, startCash, ante, (handId, playerId, startCash, ante,
card1Value, card1Suit, card2Value, card2Suit, card1Value, card1Suit, card2Value, card2Suit,
card3Value, card3Suit, card4Value, card4Suit, card3Value, card3Suit, card4Value, card4Suit,
card5Value, card5Suit, card6Value, card6Suit, card5Value, card5Suit, card6Value, card6Suit,
card7Value, card7Suit, winnings, rake, tourneysPlayersId, seatNo) card7Value, card7Suit, winnings, rake, tourneysPlayersId, seatNo)
VALUES (%s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, 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)""".replace('%s', self.sql.query['placeholder']),
(hands_id, player_ids[i], start_cashes[i], antes[i], (hands_id, player_ids[i], start_cashes[i], antes[i],
card_values[i][0], card_suits[i][0], card_values[i][1], card_suits[i][1], card_values[i][0], card_suits[i][0], card_values[i][1], card_suits[i][1],
card_values[i][2], card_suits[i][2], card_values[i][3], card_suits[i][3], card_values[i][2], card_suits[i][2], card_values[i][3], card_suits[i][3],
@ -1350,7 +1476,7 @@ class Database:
card_values[i][6], card_suits[i][6], winnings[i], rakes[i], tourneys_players_ids[i], seatNos[i])) card_values[i][6], card_suits[i][6], winnings[i], rakes[i], tourneys_players_ids[i], seatNos[i]))
#cursor.execute("SELECT id FROM HandsPlayers WHERE handId=%s AND playerId+0=%s", (hands_id, player_ids[i])) #cursor.execute("SELECT id FROM HandsPlayers WHERE handId=%s AND playerId+0=%s", (hands_id, player_ids[i]))
#result.append(cursor.fetchall()[0][0]) #result.append(cursor.fetchall()[0][0])
result.append( self.get_last_insert_id() ) result.append( self.get_last_insert_id(c) )
except: except:
raise fpdb_simple.FpdbError( "store_hands_players_stud_tourney error: " + str(sys.exc_value) ) raise fpdb_simple.FpdbError( "store_hands_players_stud_tourney error: " + str(sys.exc_value) )
@ -1488,7 +1614,8 @@ class Database:
AND position=%s AND position=%s
AND tourneyTypeId+0=%s AND tourneyTypeId+0=%s
AND styleKey=%s AND styleKey=%s
""", (row[6], row[7], row[8], row[9], row[10], """.replace('%s', self.sql.query['placeholder'])
,(row[6], row[7], row[8], row[9], row[10],
row[11], row[12], row[13], row[14], row[15], row[11], row[12], row[13], row[14], row[15],
row[16], row[17], row[18], row[19], row[20], row[16], row[17], row[18], row[19], row[20],
row[21], row[22], row[23], row[24], row[25], row[21], row[22], row[23], row[24], row[25],
@ -1501,11 +1628,14 @@ class Database:
row[56], row[57], row[58], row[59], row[60], row[56], row[57], row[58], row[59], row[60],
row[1], row[2], row[3], str(row[4]), row[5], styleKey)) row[1], row[2], row[3], str(row[4]), row[5], styleKey))
# Test statusmessage to see if update worked, do insert if not # Test statusmessage to see if update worked, do insert if not
#print "storehud2, upd num =", num #print "storehud2, upd num =", num.rowcount
# num is a cursor in sqlite
if ( (backend == self.PGSQL and cursor.statusmessage != "UPDATE 1") if ( (backend == self.PGSQL and cursor.statusmessage != "UPDATE 1")
or (backend == self.MYSQL_INNODB and num == 0) ): or (backend == self.MYSQL_INNODB and num == 0)
or (backend == self.SQLITE and num.rowcount == 0)
):
#print "playerid before insert:",row[2]," num = ", num #print "playerid before insert:",row[2]," num = ", num
cursor.execute("""INSERT INTO HudCache num = cursor.execute("""INSERT INTO HudCache
(gametypeId, playerId, activeSeats, position, tourneyTypeId, styleKey, (gametypeId, playerId, activeSeats, position, tourneyTypeId, styleKey,
HDs, street0VPI, street0Aggr, street0_3BChance, street0_3BDone, HDs, street0VPI, street0Aggr, street0_3BChance, street0_3BDone,
street1Seen, street2Seen, street3Seen, street4Seen, sawShowdown, street1Seen, street2Seen, street3Seen, street4Seen, sawShowdown,
@ -1529,14 +1659,14 @@ class Database:
%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)""".replace('%s', self.sql.query['placeholder'])
, (row[1], row[2], row[3], row[4], row[5], styleKey, row[6], row[7], row[8], row[9], row[10] , (row[1], row[2], row[3], row[4], row[5], styleKey, row[6], row[7], row[8], row[9], row[10]
,row[11], row[12], row[13], row[14], row[15], row[16], row[17], row[18], row[19], row[20] ,row[11], row[12], row[13], row[14], row[15], row[16], row[17], row[18], row[19], row[20]
,row[21], row[22], row[23], row[24], row[25], row[26], row[27], row[28], row[29], row[30] ,row[21], row[22], row[23], row[24], row[25], row[26], row[27], row[28], row[29], row[30]
,row[31], row[32], row[33], row[34], row[35], row[36], row[37], row[38], row[39], row[40] ,row[31], row[32], row[33], row[34], row[35], row[36], row[37], row[38], row[39], row[40]
,row[41], row[42], row[43], row[44], row[45], row[46], row[47], row[48], row[49], row[50] ,row[41], row[42], row[43], row[44], row[45], row[46], row[47], row[48], row[49], row[50]
,row[51], row[52], row[53], row[54], row[55], row[56], row[57], row[58], row[59], row[60]) ) ,row[51], row[52], row[53], row[54], row[55], row[56], row[57], row[58], row[59], row[60]) )
#print "hopefully inserted hud data line: ", cursor.statusmessage #print "hopefully inserted hud data line: ", cursor.rowcount
# message seems to be "INSERT 0 1" # message seems to be "INSERT 0 1"
else: else:
#print "updated(2) hud data line" #print "updated(2) hud data line"
@ -1552,7 +1682,8 @@ class Database:
def store_tourneys(self, tourneyTypeId, siteTourneyNo, entries, prizepool, startTime): def store_tourneys(self, tourneyTypeId, siteTourneyNo, entries, prizepool, startTime):
try: try:
cursor = self.get_cursor() cursor = self.get_cursor()
cursor.execute("SELECT id FROM Tourneys WHERE siteTourneyNo=%s AND tourneyTypeId+0=%s", (siteTourneyNo, tourneyTypeId)) cursor.execute("SELECT id FROM Tourneys WHERE siteTourneyNo=%s AND tourneyTypeId+0=%s".replace('%s', self.sql.query['placeholder'])
, (siteTourneyNo, tourneyTypeId))
tmp=cursor.fetchone() tmp=cursor.fetchone()
#print "tried SELECTing tourneys.id, result:",tmp #print "tried SELECTing tourneys.id, result:",tmp
@ -1561,7 +1692,8 @@ class Database:
except TypeError:#means we have to create new one except TypeError:#means we have to create new one
cursor.execute("""INSERT INTO Tourneys cursor.execute("""INSERT INTO Tourneys
(tourneyTypeId, siteTourneyNo, entries, prizepool, startTime) (tourneyTypeId, siteTourneyNo, entries, prizepool, startTime)
VALUES (%s, %s, %s, %s, %s)""", (tourneyTypeId, siteTourneyNo, entries, prizepool, startTime)) VALUES (%s, %s, %s, %s, %s)""".replace('%s', self.sql.query['placeholder'])
,(tourneyTypeId, siteTourneyNo, entries, prizepool, startTime))
cursor.execute("SELECT id FROM Tourneys WHERE siteTourneyNo=%s AND tourneyTypeId+0=%s", (siteTourneyNo, tourneyTypeId)) cursor.execute("SELECT id FROM Tourneys WHERE siteTourneyNo=%s AND tourneyTypeId+0=%s", (siteTourneyNo, tourneyTypeId))
tmp=cursor.fetchone() tmp=cursor.fetchone()
#print "created new tourneys.id:",tmp #print "created new tourneys.id:",tmp
@ -1581,7 +1713,8 @@ class Database:
#print "ranks:",ranks #print "ranks:",ranks
#print "winnings:",winnings #print "winnings:",winnings
for i in xrange(len(player_ids)): for i in xrange(len(player_ids)):
cursor.execute("SELECT id FROM TourneysPlayers WHERE tourneyId=%s AND playerId+0=%s", (tourney_id, player_ids[i])) cursor.execute("SELECT id FROM TourneysPlayers WHERE tourneyId=%s AND playerId+0=%s".replace('%s', self.sql.query['placeholder'])
,(tourney_id, player_ids[i]))
tmp=cursor.fetchone() tmp=cursor.fetchone()
#print "tried SELECTing tourneys_players.id:",tmp #print "tried SELECTing tourneys_players.id:",tmp
@ -1589,10 +1722,10 @@ class Database:
len(tmp) len(tmp)
except TypeError: except TypeError:
cursor.execute("""INSERT INTO TourneysPlayers cursor.execute("""INSERT INTO TourneysPlayers
(tourneyId, playerId, payinAmount, rank, winnings) VALUES (%s, %s, %s, %s, %s)""", (tourneyId, playerId, payinAmount, rank, winnings) VALUES (%s, %s, %s, %s, %s)""".replace('%s', self.sql.query['placeholder']),
(tourney_id, player_ids[i], payin_amounts[i], ranks[i], winnings[i])) (tourney_id, player_ids[i], payin_amounts[i], ranks[i], winnings[i]))
cursor.execute("SELECT id FROM TourneysPlayers WHERE tourneyId=%s AND playerId+0=%s", cursor.execute("SELECT id FROM TourneysPlayers WHERE tourneyId=%s AND playerId+0=%s".replace('%s', self.sql.query['placeholder']),
(tourney_id, player_ids[i])) (tourney_id, player_ids[i]))
tmp=cursor.fetchone() tmp=cursor.fetchone()
#print "created new tourneys_players.id:",tmp #print "created new tourneys_players.id:",tmp

View File

@ -17,6 +17,7 @@
import threading import threading
import subprocess import subprocess
import traceback
import pygtk import pygtk
pygtk.require('2.0') pygtk.require('2.0')

View File

@ -74,7 +74,10 @@ class GuiBulkImport():
cb_hmodel = self.cb_drophudcache.get_model() cb_hmodel = self.cb_drophudcache.get_model()
cb_hindex = self.cb_drophudcache.get_active() cb_hindex = self.cb_drophudcache.get_active()
self.lab_info.set_text("Importing") # doesn't display :-( self.lab_info.set_markup('<span foreground="blue">Importing ...</span>') # uses pango markup!
while gtk.events_pending(): # see http://faq.pygtk.org/index.py?req=index for more hints (3.7)
gtk.main_iteration(False)
if cb_index: if cb_index:
self.importer.setDropIndexes(cb_model[cb_index][0]) self.importer.setDropIndexes(cb_model[cb_index][0])
else: else:

View File

@ -20,6 +20,7 @@ import pygtk
pygtk.require('2.0') pygtk.require('2.0')
import gtk import gtk
import os import os
import traceback
from time import * from time import *
#import pokereval #import pokereval
@ -72,20 +73,19 @@ class GuiGraphViewer (threading.Thread):
self.mainHBox.show() self.mainHBox.show()
self.leftPanelBox = self.filters.get_vbox() self.leftPanelBox = self.filters.get_vbox()
self.graphBox = gtk.VBox(False, 0)
self.graphBox.show()
self.hpane = gtk.HPaned() self.hpane = gtk.HPaned()
self.hpane.pack1(self.leftPanelBox) self.hpane.pack1(self.leftPanelBox)
self.mainHBox.add(self.hpane)
# hierarchy: self.mainHBox / self.hpane / self.graphBox / self.canvas / self.fig / self.ax
self.graphBox = gtk.VBox(False, 0)
self.graphBox.show()
self.hpane.pack2(self.graphBox) self.hpane.pack2(self.graphBox)
self.hpane.show() self.hpane.show()
self.mainHBox.add(self.hpane)
self.fig = None self.fig = None
#self.exportButton.set_sensitive(False) #self.exportButton.set_sensitive(False)
self.fig = Figure(figsize=(5,4), dpi=100)
self.canvas = None self.canvas = None
@ -125,14 +125,31 @@ class GuiGraphViewer (threading.Thread):
#end def get_vbox #end def get_vbox
def clearGraphData(self): def clearGraphData(self):
try:
try:
if self.canvas:
self.graphBox.remove(self.canvas)
except:
pass
if self.fig != None:
self.fig.clear() self.fig.clear()
self.fig = Figure(figsize=(5,4), dpi=100)
if self.canvas is not None: if self.canvas is not None:
self.canvas.destroy() self.canvas.destroy()
self.canvas = FigureCanvas(self.fig) # a gtk.DrawingArea self.canvas = FigureCanvas(self.fig) # a gtk.DrawingArea
except:
err = traceback.extract_tb(sys.exc_info()[2])[-1]
print "***Error: "+err[2]+"("+str(err[1])+"): "+str(sys.exc_info()[1])
raise
def generateGraph(self, widget, data): def generateGraph(self, widget, data):
print "generateGraph: start"
try:
self.clearGraphData() self.clearGraphData()
print "after cleardata"
sitenos = [] sitenos = []
playerids = [] playerids = []
@ -141,6 +158,7 @@ class GuiGraphViewer (threading.Thread):
heroes = self.filters.getHeroes() heroes = self.filters.getHeroes()
siteids = self.filters.getSiteIds() siteids = self.filters.getSiteIds()
limits = self.filters.getLimits() limits = self.filters.getLimits()
print "got filter data"
# Which sites are selected? # Which sites are selected?
for site in sites: for site in sites:
if sites[site] == True: if sites[site] == True:
@ -164,10 +182,12 @@ class GuiGraphViewer (threading.Thread):
return return
#Set graph properties #Set graph properties
print "add_subplot"
self.ax = self.fig.add_subplot(111) self.ax = self.fig.add_subplot(111)
#Get graph data from DB #Get graph data from DB
starttime = time() starttime = time()
print "get line: playerids =", playerids, "sitenos =", sitenos, "limits =", limits
line = self.getRingProfitGraph(playerids, sitenos, limits) line = self.getRingProfitGraph(playerids, sitenos, limits)
print "Graph generated in: %s" %(time() - starttime) print "Graph generated in: %s" %(time() - starttime)
@ -182,7 +202,7 @@ class GuiGraphViewer (threading.Thread):
#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 = "All Hands, " + sitename + str(name) + "\nProfit: $" + str(line[-1]) + "\nTotal Hands: " + str(len(line))
text = "All Hands, " + "\nProfit: $" + str(line[-1]) + "\nTotal Hands: " + str(len(line)) text = "All Hands, " + "\nProfit: $" + str(line[-1]) + "\nTotal Hands: " + str(len(line))
self.ax.annotate(text, self.ax.annotate(text,
@ -198,6 +218,10 @@ class GuiGraphViewer (threading.Thread):
self.canvas.show() self.canvas.show()
self.canvas.draw() self.canvas.draw()
#self.exportButton.set_sensitive(True) #self.exportButton.set_sensitive(True)
except:
err = traceback.extract_tb(sys.exc_info()[2])[-1]
print "***Error: "+err[2]+"("+str(err[1])+"): "+str(sys.exc_info()[1])
#end of def showClicked #end of def showClicked
def getRingProfitGraph(self, names, sites, limits): def getRingProfitGraph(self, names, sites, limits):

View File

@ -81,7 +81,7 @@ class GuiPlayerStats (threading.Thread):
, ["hand", False, "Hand", 0.0, "%s"] # true not allowed for this line , ["hand", False, "Hand", 0.0, "%s"] # true not allowed for this line
, ["plposition", False, "Posn", 1.0, "%s"] # true not allowed for this line (set in code) , ["plposition", False, "Posn", 1.0, "%s"] # true not allowed for this line (set in code)
, ["n", True, "Hds", 1.0, "%d"] , ["n", True, "Hds", 1.0, "%d"]
, ["avgseats", True, "Seats", 1.0, "%3.1f"] , ["avgseats", False, "Seats", 1.0, "%3.1f"]
, ["vpip", True, "VPIP", 1.0, "%3.1f"] , ["vpip", True, "VPIP", 1.0, "%3.1f"]
, ["pfr", True, "PFR", 1.0, "%3.1f"] , ["pfr", True, "PFR", 1.0, "%3.1f"]
, ["pf3", True, "PF3", 1.0, "%3.1f"] , ["pf3", True, "PF3", 1.0, "%3.1f"]
@ -132,7 +132,7 @@ class GuiPlayerStats (threading.Thread):
self.stats_vbox = gtk.VBox(False, 0) self.stats_vbox = gtk.VBox(False, 0)
self.stats_vbox.show() self.stats_vbox.show()
self.stats_frame.add(self.stats_vbox) self.stats_frame.add(self.stats_vbox)
self.fillStatsFrame(self.stats_vbox) # self.fillStatsFrame(self.stats_vbox)
self.main_hbox.pack_start(self.filters.get_vbox()) self.main_hbox.pack_start(self.filters.get_vbox())
self.main_hbox.pack_start(self.stats_frame, expand=True, fill=True) self.main_hbox.pack_start(self.stats_frame, expand=True, fill=True)
@ -167,7 +167,9 @@ class GuiPlayerStats (threading.Thread):
for site in sites: for site in sites:
if sites[site] == True: if sites[site] == True:
sitenos.append(siteids[site]) sitenos.append(siteids[site])
self.cursor.execute(self.sql.query['getPlayerId'], (heroes[site],)) # Nasty hack to deal with multiple sites + same player name -Eric
que = self.sql.query['getPlayerId'] + " AND siteId=%d" % siteids[site]
self.cursor.execute(que, (heroes[site],))
result = self.db.cursor.fetchall() result = self.db.cursor.fetchall()
if len(result) == 1: if len(result) == 1:
playerids.append(result[0][0]) playerids.append(result[0][0])

View File

@ -22,17 +22,10 @@ import gtk
import os import os
import fpdb_simple import fpdb_simple
try:
import MySQLdb
except: # Try to make postgres case cleaner, and kill the error note
try:
import psycopg2
except ImportError:
pass
import fpdb_import import fpdb_import
import fpdb_db import fpdb_db
class GuiTableViewer (threading.Thread): class GuiTableViewer (threading.Thread):
def hudDivide (self, a, b): def hudDivide (self, a, b):
if b==0: if b==0:
@ -188,25 +181,25 @@ class GuiTableViewer (threading.Thread):
"""runs when user clicks read names""" """runs when user clicks read names"""
#print "start of table_viewer.read_names_clicked" #print "start of table_viewer.read_names_clicked"
self.db.reconnect() self.db.reconnect()
self.cursor=self.db.cursor self.cursor=self.db.get_cursor()
#self.hands_id=self.last_read_hand_id #self.hands_id=self.last_read_hand_id
self.db.cursor.execute("SELECT gametypeId FROM Hands WHERE id=%s", (self.hands_id, )) self.cursor.execute("SELECT gametypeId FROM Hands WHERE id=%s", (self.hands_id, ))
self.gametype_id=self.db.cursor.fetchone()[0] self.gametype_id=self.cursor.fetchone()[0]
self.cursor.execute("SELECT category FROM Gametypes WHERE id=%s", (self.gametype_id, )) self.cursor.execute("SELECT category FROM Gametypes WHERE id=%s", (self.gametype_id, ))
self.category=self.db.cursor.fetchone()[0] self.category=self.cursor.fetchone()[0]
#print "self.gametype_id", self.gametype_id," category:", self.category, " self.hands_id:", self.hands_id #print "self.gametype_id", self.gametype_id," category:", self.category, " self.hands_id:", self.hands_id
self.db.cursor.execute("""SELECT DISTINCT Players.id FROM HandsPlayers self.cursor.execute("""SELECT DISTINCT Players.id FROM HandsPlayers
INNER JOIN Players ON HandsPlayers.playerId=Players.id INNER JOIN Players ON HandsPlayers.playerId=Players.id
WHERE handId=%s""", (self.hands_id, )) WHERE handId=%s""", (self.hands_id, ))
self.player_ids=self.db.cursor.fetchall() self.player_ids=self.cursor.fetchall()
#print "self.player_ids:",self.player_ids #print "self.player_ids:",self.player_ids
self.db.cursor.execute("""SELECT DISTINCT Players.name FROM HandsPlayers self.cursor.execute("""SELECT DISTINCT Players.name FROM HandsPlayers
INNER JOIN Players ON HandsPlayers.playerId=Players.id INNER JOIN Players ON HandsPlayers.playerId=Players.id
WHERE handId=%s""", (self.hands_id, )) WHERE handId=%s""", (self.hands_id, ))
self.player_names=self.db.cursor.fetchall() self.player_names=self.cursor.fetchall()
#print "self.player_names:",self.player_names #print "self.player_names:",self.player_names
#end def table_viewer.read_names_clicked #end def table_viewer.read_names_clicked
@ -215,12 +208,7 @@ class GuiTableViewer (threading.Thread):
#print "start of table_viewer.import_clicked" #print "start of table_viewer.import_clicked"
self.inputFile=self.filename_tbuffer.get_text(self.filename_tbuffer.get_start_iter(), self.filename_tbuffer.get_end_iter()) self.inputFile=self.filename_tbuffer.get_text(self.filename_tbuffer.get_start_iter(), self.filename_tbuffer.get_end_iter())
self.server=self.db.host self.importer = fpdb_import.Importer(self, self.settings, self.config)
self.database=self.db.database
self.user=self.db.user
self.password=self.db.password
self.importer = fpdb_import.Importer(self, self.settings)
self.importer.setMinPrint(0) self.importer.setMinPrint(0)
self.importer.setQuiet(False) self.importer.setQuiet(False)
self.importer.setFailOnError(False) self.importer.setFailOnError(False)
@ -244,13 +232,14 @@ class GuiTableViewer (threading.Thread):
return self.main_vbox return self.main_vbox
#end def get_vbox #end def get_vbox
def __init__(self, db, settings, debug=True): def __init__(self, db, settings, config=None, debug=True):
"""Constructor for table_viewer""" """Constructor for table_viewer"""
self.debug=debug self.debug=debug
#print "start of table_viewer constructor" #print "start of table_viewer constructor"
self.db=db self.db = db
self.cursor=db.cursor self.cursor = db.get_cursor()
self.settings=settings self.settings = settings
self.config = config
self.main_vbox = gtk.VBox(False, 0) self.main_vbox = gtk.VBox(False, 0)
self.main_vbox.show() self.main_vbox.show()

View File

@ -203,6 +203,96 @@
<location seat="9" x="70" y="53"> </location> <location seat="9" x="70" y="53"> </location>
</layout> </layout>
</site> </site>
<site enabled="False"
site_name="Absolute"
table_finder="AbsolutePoker.exe"
screen_name="YOUR SCREEN NAME HERE"
site_path=""
HH_path=""
decoder="everleaf_decode_table"
converter="AbsoluteToFpdb"
supported_games="holdem">
<layout fav_seat="0" height="547" max="8" width="794">
<location seat="1" x="640" y="64"> </location>
<location seat="2" x="650" y="230"> </location>
<location seat="3" x="650" y="385"> </location>
<location seat="4" x="588" y="425"> </location>
<location seat="5" x="92" y="425"> </location>
<location seat="6" x="0" y="373"> </location>
<location seat="7" x="0" y="223"> </location>
<location seat="8" x="25" y="50"> </location>
</layout>
<layout fav_seat="0" height="547" max="6" width="794">
<location seat="1" x="640" y="58"> </location>
<location seat="2" x="654" y="288"> </location>
<location seat="3" x="615" y="424"> </location>
<location seat="4" x="70" y="421"> </location>
<location seat="5" x="0" y="280"> </location>
<location seat="6" x="70" y="58"> </location>
</layout>
<layout fav_seat="0" height="547" max="2" width="794">
<location seat="1" x="651" y="288"> </location>
<location seat="2" x="10" y="288"> </location>
</layout>
<layout fav_seat="0" height="547" max="9" width="794">
<location seat="1" x="634" y="38"> </location>
<location seat="2" x="667" y="184"> </location>
<location seat="3" x="667" y="321"> </location>
<location seat="4" x="667" y="445"> </location>
<location seat="5" x="337" y="459"> </location>
<location seat="6" x="0" y="400"> </location>
<location seat="7" x="0" y="322"> </location>
<location seat="8" x="0" y="181"> </location>
<location seat="9" x="70" y="53"> </location>
</layout>
</site>
<site enabled="False"
site_name="PartyPoker"
table_finder="PartyPoker.exe"
screen_name="YOUR SCREEN NAME HERE"
site_path=""
HH_path=""
decoder="everleaf_decode_table"
converter="PartyPokerToFpdb"
supported_games="holdem">
<layout fav_seat="0" height="547" max="8" width="794">
<location seat="1" x="640" y="64"> </location>
<location seat="2" x="650" y="230"> </location>
<location seat="3" x="650" y="385"> </location>
<location seat="4" x="588" y="425"> </location>
<location seat="5" x="92" y="425"> </location>
<location seat="6" x="0" y="373"> </location>
<location seat="7" x="0" y="223"> </location>
<location seat="8" x="25" y="50"> </location>
</layout>
<layout fav_seat="0" height="547" max="6" width="794">
<location seat="1" x="640" y="58"> </location>
<location seat="2" x="654" y="288"> </location>
<location seat="3" x="615" y="424"> </location>
<location seat="4" x="70" y="421"> </location>
<location seat="5" x="0" y="280"> </location>
<location seat="6" x="70" y="58"> </location>
</layout>
<layout fav_seat="0" height="547" max="2" width="794">
<location seat="1" x="651" y="288"> </location>
<location seat="2" x="10" y="288"> </location>
</layout>
<layout fav_seat="0" height="547" max="9" width="794">
<location seat="1" x="634" y="38"> </location>
<location seat="2" x="667" y="184"> </location>
<location seat="3" x="667" y="321"> </location>
<location seat="4" x="667" y="445"> </location>
<location seat="5" x="337" y="459"> </location>
<location seat="6" x="0" y="400"> </location>
<location seat="7" x="0" y="322"> </location>
<location seat="8" x="0" y="181"> </location>
<location seat="9" x="70" y="53"> </location>
</layout>
</site>
</supported_sites> </supported_sites>
<supported_games> <supported_games>
@ -337,10 +427,13 @@
<hhc site="Full Tilt Poker" converter="FulltiltToFpdb"/> <hhc site="Full Tilt Poker" converter="FulltiltToFpdb"/>
<hhc site="Everleaf" converter="EverleafToFpdb"/> <hhc site="Everleaf" converter="EverleafToFpdb"/>
<hhc site="Win2day" converter="Win2dayToFpdb"/> <hhc site="Win2day" converter="Win2dayToFpdb"/>
<hhc site="Absolute" converter="AbsoluteToFpdb"/>
<hhc site="PartyPoker" converter="PartyPokerToFpdb"/>
</hhcs> </hhcs>
<supported_databases> <supported_databases>
<database db_name="fpdb" db_server="mysql" db_ip="localhost" db_user="fpdb" db_pass="YOUR MYSQL PASSWORD" db_type="fpdb"></database> <database db_name="fpdb" db_server="mysql" db_ip="localhost" db_user="fpdb" db_pass="YOUR MYSQL PASSWORD" db_type="fpdb"></database>
<!-- <database db_ip="localhost" db_name="fpdb" db_pass="fpdb" db_server="sqlite" db_type="fpdb" db_user="fpdb"/> -->
</supported_databases> </supported_databases>
</FreePokerToolsConfig> </FreePokerToolsConfig>

View File

@ -37,7 +37,7 @@ import traceback
if not options.errorsToConsole: if not options.errorsToConsole:
print "Note: error output is being diverted to fpdb-error-log.txt and HUD-error.txt. Any major error will be reported there _only_." print "Note: error output is being diverted to fpdb-error-log.txt and HUD-error.txt. Any major error will be reported there _only_."
errorFile = open('fpdb-error-log.txt', 'w', 0) errorFile = open('HUD-error.txt', 'w', 0)
sys.stderr = errorFile sys.stderr = errorFile
import thread import thread

View File

@ -40,7 +40,7 @@ class Hand(object):
LCS = {'H':'h', 'D':'d', 'C':'c', 'S':'s'} LCS = {'H':'h', 'D':'d', 'C':'c', 'S':'s'}
SYMBOL = {'USD': '$', 'EUR': u'$', 'T$': '', 'play': ''} SYMBOL = {'USD': '$', 'EUR': u'$', 'T$': '', 'play': ''}
MS = {'horse' : 'HORSE', '8game' : '8-Game', 'hose' : 'HOSE', 'ha': 'HA'} MS = {'horse' : 'HORSE', '8game' : '8-Game', 'hose' : 'HOSE', 'ha': 'HA'}
SITEIDS = {'Fulltilt':1, 'PokerStars':2, 'Everleaf':3, 'Win2day':4, 'OnGame':5, 'UltimateBet':6, 'Betfair':7} SITEIDS = {'Fulltilt':1, 'PokerStars':2, 'Everleaf':3, 'Win2day':4, 'OnGame':5, 'UltimateBet':6, 'Betfair':7, 'Absolute':8, 'PartyPoker':9 }
def __init__(self, sitename, gametype, handText, builtFrom = "HHC"): def __init__(self, sitename, gametype, handText, builtFrom = "HHC"):
@ -185,31 +185,49 @@ db: a connected fpdb_db object"""
# TODO: # TODO:
# Players - base playerid and siteid tuple # Players - base playerid and siteid tuple
sqlids = db.getSqlPlayerIDs([p[1] for p in self.players], self.siteId) sqlids = db.getSqlPlayerIDs([p[1] for p in self.players], self.siteId)
#Gametypes
print "DEBUG: self.gametype %s" % self.gametype
#Nice way to discover if the game is already listed in the db?
#Also this is using an old method from fpdb_simple - should probably conform to the rest of the inserts
hilo = "h"
if self.gametype['category'] in ['studhilo', 'omahahilo']:
hilo = "s"
elif self.gametype['category'] in ['razz','27_3draw','badugi']:
hilo = "l"
#FIXME - the two zeros are small_bet and big_bet for limit
gtid = db.insertGameTypes( (self.siteId, self.gametype['type'], self.gametype['base'],
self.gametype['category'], self.gametype['limitType'], hilo,
self.gametype['sb'], self.gametype['bb'], 0, 0) )
# HudCache data to come from DerivedStats class # HudCache data to come from DerivedStats class
# HandsActions - all actions for all players for all streets - self.actions # HandsActions - all actions for all players for all streets - self.actions
# BoardCards - Skip - no longer necessary
# Hands - Summary information of hand indexed by handId - gameinfo # Hands - Summary information of hand indexed by handId - gameinfo
#hh['siteHandNo'] = self.handid #This should be moved to prepInsert
# gametypeId SMALLINT UNSIGNED NOT NULL, FOREIGN KEY (gametypeId) REFERENCES Gametypes(id), hh = {}
# hh['siteHandNo'] = self.handid
#hh['handStart'] = self.starttime hh['handStart'] = self.starttime
# seats TINYINT NOT NULL, # seats TINYINT NOT NULL,
# hh['tableName'] = self.tablename
#hh['tableName'] = self.tablenam hh['maxSeats'] = self.maxseats
#hh['maxSeats'] = self.maxseats
# boardcard1 smallint, /* 0=none, 1-13=2-Ah 14-26=2-Ad 27-39=2-Ac 40-52=2-As */ # boardcard1 smallint, /* 0=none, 1-13=2-Ah 14-26=2-Ad 27-39=2-Ac 40-52=2-As */
# boardcard2 smallint, # boardcard2 smallint,
# boardcard3 smallint, # boardcard3 smallint,
# boardcard4 smallint, # boardcard4 smallint,
# boardcard5 smallint, # boardcard5 smallint,
# Flop turn and river may all be empty - add (likely) too many elements and trim with range # Flop turn and river may all be empty - add (likely) too many elements and trim with range
# boardcards = board['FLOP'] + board['TURN'] + board['RIVER'] + [u'0x', u'0x', u'0x', u'0x', u'0x'] boardcards = self.board['FLOP'] + self.board['TURN'] + self.board['RIVER'] + [u'0x', u'0x', u'0x', u'0x', u'0x']
# cards = [Card.cardFromValueSuit(v,s) for v,s in boardcards[0:4]] cards = [Card.encodeCard(c) for c in boardcards[0:5]]
# hh['boardcard1'] = cards[0] hh['boardcard1'] = cards[0]
# hh['boardcard2'] = cards[1] hh['boardcard2'] = cards[1]
# hh['boardcard3'] = cards[2] hh['boardcard3'] = cards[2]
# hh['boardcard4'] = cards[3] hh['boardcard4'] = cards[3]
# hh['boardcard5'] = cards[4] hh['boardcard5'] = cards[4]
print hh
# texture smallint, # texture smallint,
# playersVpi SMALLINT NOT NULL, /* num of players vpi */ # playersVpi SMALLINT NOT NULL, /* num of players vpi */
# Needs to be recorded # Needs to be recorded
@ -244,7 +262,7 @@ db: a connected fpdb_db object"""
# showdownPot INT, /* pot size at sd/street7 */ # showdownPot INT, /* pot size at sd/street7 */
# comment TEXT, # comment TEXT,
# commentTs DATETIME # commentTs DATETIME
# handid = db.storeHand(hh) handid = db.storeHand(hh)
# HandsPlayers - ? ... Do we fix winnings? # HandsPlayers - ? ... Do we fix winnings?
# Tourneys ? # Tourneys ?
# TourneysPlayers # TourneysPlayers
@ -453,6 +471,7 @@ Add a raise on [street] by [player] to [amountTo]
def addCheck(self, street, player): def addCheck(self, street, player):
#print "DEBUG: %s %s checked" % (street, player) #print "DEBUG: %s %s checked" % (street, player)
logging.debug("%s %s checks" % (street, player))
self.checkPlayerExists(player) self.checkPlayerExists(player)
self.actions[street].append((player, 'checks')) self.actions[street].append((player, 'checks'))

View File

@ -1,4 +1,5 @@
#!/usr/bin/python #!/usr/bin/python
# -*- coding: utf-8 -*-
#Copyright 2008 Carl Gherardi #Copyright 2008 Carl Gherardi
#This program is free software: you can redistribute it and/or modify #This program is free software: you can redistribute it and/or modify
@ -58,10 +59,10 @@ class HandHistoryConverter():
else: else:
# TODO: out_path should be sanity checked. # TODO: out_path should be sanity checked.
out_dir = os.path.dirname(self.out_path) out_dir = os.path.dirname(self.out_path)
if not os.path.isdir(out_dir): if not os.path.isdir(out_dir) and out_dir != '':
logging.info("Creatin directory '%s'" % out_dir) logging.info("Creatin directory '%s'" % out_dir)
os.makedirs(out_dir) os.makedirs(out_dir)
self.out_fh = open(self.out_path, 'w') self.out_fh = codecs.open(self.out_path, 'w', 'cp1252')
self.sitename = sitename self.sitename = sitename
self.follow = follow self.follow = follow
@ -95,9 +96,14 @@ Otherwise, finish at eof.
else: else:
handsList = self.allHandsAsList() handsList = self.allHandsAsList()
logging.info("Parsing %d hands" % len(handsList)) logging.info("Parsing %d hands" % len(handsList))
nBadHangs = 0
for handText in handsList: for handText in handsList:
try:
self.processedHands.append(self.processHand(handText)) self.processedHands.append(self.processHand(handText))
numHands= len(handsList) except Exception, e: # TODO: it's better to replace it with s-t like HhcEception
nBadHangs += 1
logging.error("Caught exception while parsing hand: %s" % str(e))
numHands = len(handsList) - nBadHangs
endtime = time.time() endtime = time.time()
print "read %d hands in %.3f seconds" % (numHands, endtime - starttime) print "read %d hands in %.3f seconds" % (numHands, endtime - starttime)
if self.out_fh != sys.stdout: if self.out_fh != sys.stdout:

View File

@ -60,6 +60,8 @@ class Hud:
def __init__(self, parent, table, max, poker_game, config, db_connection): def __init__(self, parent, table, max, poker_game, config, db_connection):
# __init__ is (now) intended to be called from the stdin thread, so it # __init__ is (now) intended to be called from the stdin thread, so it
# cannot touch the gui # cannot touch the gui
if parent == None: # running from cli ..
self.parent = self
self.parent = parent self.parent = parent
self.table = table self.table = table
self.config = config self.config = config
@ -125,6 +127,7 @@ class Hud:
self.menu = gtk.Menu() self.menu = gtk.Menu()
self.item1 = gtk.MenuItem('Kill this HUD') self.item1 = gtk.MenuItem('Kill this HUD')
self.menu.append(self.item1) self.menu.append(self.item1)
if self.parent != None:
self.item1.connect("activate", self.parent.kill_hud, self.table_name) self.item1.connect("activate", self.parent.kill_hud, self.table_name)
self.item1.show() self.item1.show()
@ -233,7 +236,7 @@ class Hud:
# Need range here, not xrange -> need the actual list # Need range here, not xrange -> need the actual list
adj = range(0, self.max + 1) # default seat adjustments = no adjustment adj = range(0, self.max + 1) # default seat adjustments = no adjustment
# does the user have a fav_seat? # does the user have a fav_seat?
if int(config.supported_sites[self.table.site].layout[self.max].fav_seat) > 0: if self.table.site != None and int(config.supported_sites[self.table.site].layout[self.max].fav_seat) > 0:
try: try:
fav_seat = config.supported_sites[self.table.site].layout[self.max].fav_seat fav_seat = config.supported_sites[self.table.site].layout[self.max].fav_seat
actual_seat = self.get_actual_seat(config.supported_sites[self.table.site].screen_name) actual_seat = self.get_actual_seat(config.supported_sites[self.table.site].screen_name)
@ -600,15 +603,17 @@ if __name__== "__main__":
c = Configuration.Config() c = Configuration.Config()
#tables = Tables.discover(c) #tables = Tables.discover(c)
t = Tables.discover_table_by_name(c, "Motorway") t = Tables.discover_table_by_name(c, "Patriot Dr")
if t is None: if t is None:
print "Table not found." print "Table not found."
db = Database.Database(c, 'fpdb', 'holdem') db = Database.Database(c, 'fpdb', 'holdem')
stat_dict = db.get_stats_from_hand(1)
# for t in tables: # for t in tables:
win = Hud(t, 10, 'holdem', c, db) win = Hud(None, t, 10, 'holdem', c, db) # parent, table, max, poker_game, config, db_connection
win.create(1, c) win.create(1, c, stat_dict, None) # hand, config, stat_dict, cards):
# t.get_details() # t.get_details()
win.update(8300, db, c) win.update(8300, c) # self, hand, config):
gtk.main() gtk.main()

460
pyfpdb/PartyPokerToFpdb.py Normal file
View File

@ -0,0 +1,460 @@
#!/usr/bin/env python
# -*- coding: utf-8 -*-
#
# Copyright 2009, Grigorij Indigirkin
#
# 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
from collections import defaultdict
from HandHistoryConverter import *
# PartyPoker HH Format
class PartyPoker(HandHistoryConverter):
class ParsingException(Exception):
"Usage: raise ParsingException(<msg>[, hh=<hh>])"
def __init__(self, *args, **kwargs):
if len(args)==0: args=[''] + list(args)
msg, args = args[0], args[1:]
if 'hh' in kwargs:
msg += self.wrapHh(kwargs['hh'])
del kwargs['hh']
return Exception.__init__(self, msg, *args, **kwargs)
def wrapHh(self, hh):
return ("\n\nHand history attached below:\n"
"%(DELIMETER)s\n%(HH)s\n%(DELIMETER)s") % \
{'DELIMETER': '#'*50, 'HH': hh}
############################################################
# Class Variables
sym = {'USD': "\$", }
# Static regexes
# $5 USD NL Texas Hold'em - Saturday, July 25, 07:53:52 EDT 2009
# NL Texas Hold'em $1 USD Buy-in Trny:45685440 Level:8 Blinds-Antes(600/1 200 -50) - Sunday, May 17, 11:25:07 MSKS 2009
re_GameInfoRing = re.compile("""
(?P<CURRENCY>\$|)\s*(?P<RINGLIMIT>\d+)\s*(?:USD)?\s*
(?P<LIMIT>(NL))\s+
(?P<GAME>(Texas\ Hold\'em))
\s*\-\s*
(?P<DATETIME>.+)
""", re.VERBOSE)
re_GameInfoTrny = re.compile("""
(?P<LIMIT>(NL))\s+
(?P<GAME>(Texas\ Hold\'em))\s+
(?P<BUYIN>\$?[.0-9]+)\s*(?P<BUYIN_CURRENCY>USD)?\s*Buy-in\s+
Trny:\s?(?P<TOURNO>\d+)\s+
Level:\s*(?P<LEVEL>\d+)\s+
Blinds(?:-Antes)?\(
(?P<SB>[.0-9 ]+)\s*
/(?P<BB>[.0-9 ]+)
(?:\s*-\s*(?P<ANTE>[.0-9 ]+)\$?)?
\)
\s*\-\s*
(?P<DATETIME>.+)
""", re.VERBOSE)
re_Hid = re.compile("^Game \#(?P<HID>\d+) starts.")
re_PlayerInfo = re.compile("""
Seat\s(?P<SEAT>\d+):\s
(?P<PNAME>.*)\s
\(\s*\$?(?P<CASH>[0-9,.]+)\s*(?:USD|)\s*\)
""" ,
re.VERBOSE)
re_HandInfo = re.compile("""
^Table\s+
(?P<TTYPE>[a-zA-Z0-9 ]+)\s+
(?: \#|\(|)(?P<TABLE>\d+)\)?\s+
(?:[^ ]+\s+\#(?P<MTTTABLE>\d+).+)? # table number for mtt
\((?P<PLAY>Real|Play)\s+Money\)\s+ # FIXME: check if play money is correct
Seat\s+(?P<BUTTON>\d+)\sis\sthe\sbutton
""",
re.MULTILINE|re.VERBOSE)
re_SplitHands = re.compile('\x00+')
re_TailSplitHands = re.compile('(\x00+)')
lineSplitter = '\n'
re_Button = re.compile('Seat (?P<BUTTON>\d+) is the button', re.MULTILINE)
re_Board = re.compile(r"\[(?P<CARDS>.+)\]")
re_NoSmallBlind = re.compile('^There is no Small Blind in this hand as the Big Blind of the previous hand left the table')
def __init__(self, in_path = '-', out_path = '-', follow = False, autostart=True, index=0):
"""\
in_path (default '-' = sys.stdin)
out_path (default '-' = sys.stdout)
follow : whether to tail -f the input"""
HandHistoryConverter.__init__(self, in_path, out_path, sitename="PartyPoker", follow=follow, index=index)
logging.info("Initialising PartyPoker converter class")
self.filetype = "text"
self.codepage = "cp1252" # FIXME: wtf?
self.siteId = 9 # Needs to match id entry in Sites database
self._gameType = None # cached reg-parse result
if autostart:
self.start()
def allHandsAsList(self):
list = HandHistoryConverter.allHandsAsList(self)
return filter(lambda text: len(text.strip()), list)
def compilePlayerRegexs(self, hand):
players = set([player[1] for player in hand.players])
if not players <= self.compiledPlayers: # x <= y means 'x is subset of y'
self.compiledPlayers = players
player_re = "(?P<PNAME>" + "|".join(map(re.escape, players)) + ")"
subst = {'PLYR': player_re, 'CUR_SYM': hand.SYMBOL[hand.gametype['currency']],
'CUR': hand.gametype['currency'] if hand.gametype['currency']!='T$' else ''}
for key in ('CUR_SYM', 'CUR'):
subst[key] = re.escape(subst[key])
logging.debug("player_re: " + subst['PLYR'])
logging.debug("CUR_SYM: " + subst['CUR_SYM'])
logging.debug("CUR: " + subst['CUR'])
self.re_PostSB = re.compile(
r"^%(PLYR)s posts small blind \[%(CUR_SYM)s(?P<SB>[.0-9]+) ?%(CUR)s\]\." % subst,
re.MULTILINE)
self.re_PostBB = re.compile(
r"^%(PLYR)s posts big blind \[%(CUR_SYM)s(?P<BB>[.0-9]+) ?%(CUR)s\]\." % subst,
re.MULTILINE)
self.re_Antes = re.compile(
r"^%(PLYR)s posts ante \[%(CUR_SYM)s(?P<ANTE>[.0-9]+) ?%(CUR)s\]\." % subst,
re.MULTILINE)
self.re_HeroCards = re.compile(
r"^Dealt to %(PLYR)s \[\s*(?P<NEWCARDS>.+)\s*\]" % subst,
re.MULTILINE)
self.re_Action = re.compile(r"""
^%(PLYR)s\s+(?P<ATYPE>bets|checks|raises|calls|folds|is\sall-In)
(?:\s+\[%(CUR_SYM)s(?P<BET>[.,\d]+)\s*%(CUR)s\])?
""" % subst,
re.MULTILINE|re.VERBOSE)
self.re_ShownCards = re.compile(
r"^%s (?P<SHOWED>(?:doesn\'t )?shows?) " % player_re +
r"\[ *(?P<CARDS>.+) *\](?P<COMBINATION>.+)\.",
re.MULTILINE)
self.re_CollectPot = re.compile(
r""""^%(PLYR)s \s+ wins \s+
%(CUR_SYM)s(?P<POT>[.\d]+)\s*%(CUR)s""" % subst,
re.MULTILINE|re.VERBOSE)
def readSupportedGames(self):
return [["ring", "hold", "nl"],
#["ring", "hold", "pl"],
#["ring", "hold", "fl"],
["tour", "hold", "nl"],
#["tour", "hold", "pl"],
#["tour", "hold", "fl"],
]
def _getGameType(self, handText):
if self._gameType is None:
# let's determine whether hand is trny
# and whether 5-th line contains head line
headLine = handText.split(self.lineSplitter)[4]
for headLineContainer in headLine, handText:
for regexp in self.re_GameInfoTrny, self.re_GameInfoRing:
m = regexp.search(headLineContainer)
if m is not None:
self._gameType = m
return self._gameType
return self._gameType
def determineGameType(self, handText):
"""inspect the handText and return the gametype dict
gametype dict is:
{'limitType': xxx, 'base': xxx, 'category': xxx}"""
logging.debug(self.ParsingException().wrapHh( handText ))
info = {}
m = self._getGameType(handText)
if m is None:
return None
mg = m.groupdict()
# translations from captured groups to fpdb info strings
limits = { 'NL':'nl',
# 'Pot Limit':'pl', 'Limit':'fl'
}
games = { # base, category
"Texas Hold'em" : ('hold','holdem'),
#'Omaha' : ('hold','omahahi'),
}
currencies = { '$':'USD', '':'T$' }
for expectedField in ['LIMIT', 'GAME']:
if mg[expectedField] is None:
raise self.ParsingException(
"Cannot fetch field '%s'" % expectedField,
hh = handText)
try:
info['limitType'] = limits[mg['LIMIT']]
except:
raise self.ParsingException(
"Unknown limit '%s'" % mg['LIMIT'],
hh = handText)
try:
(info['base'], info['category']) = games[mg['GAME']]
except:
raise self.ParsingException(
"Unknown game type '%s'" % mg['GAME'],
hh = handText)
if 'TOURNO' in mg:
info['type'] = 'tour'
else:
info['type'] = 'ring'
if info['type'] == 'ring':
info['sb'], info['bb'] = ringBlinds(mg['RINGLIMIT'])
# FIXME: there are only $ and play money availible for cash
info['currency'] = currencies[mg['CURRENCY']]
else:
info['sb'] = renderTrnyMoney(mg['SB'])
info['bb'] = renderTrnyMoney(mg['BB'])
info['currency'] = 'T$'
# NB: SB, BB must be interpreted as blinds or bets depending on limit type.
return info
def readHandInfo(self, hand):
info = {}
m = self.re_HandInfo.search(hand.handText,re.DOTALL)
if m:
info.update(m.groupdict())
else:
raise self.ParsingException("Cannot read Handinfo for current hand", hh=hand.handText)
m = self._getGameType(hand.handText)
if m: info.update(m.groupdict())
m = self.re_Hid.search(hand.handText)
if m: info.update(m.groupdict())
# FIXME: it's a hack cause party doesn't supply hand.maxseats info
#hand.maxseats = ???
hand.mixed = None
logging.debug("readHandInfo: %s" % info)
for key in info:
if key == 'DATETIME':
#Saturday, July 25, 07:53:52 EDT 2009
#Thursday, July 30, 21:40:41 MSKS 2009
m2 = re.search("\w+, (?P<M>\w+) (?P<D>\d+), (?P<H>\d+):(?P<MIN>\d+):(?P<S>\d+) (?P<TZ>[A-Z]+) (?P<Y>\d+)", info[key])
# we cant use '%B' due to locale problems
months = ['January', 'February', 'March', 'April','May', 'June',
'July','August','September','October','November','December']
month = months.index(m2.group('M')) + 1
datetimestr = "%s/%s/%s %s:%s:%s" % (m2.group('Y'), month,m2.group('D'),m2.group('H'),m2.group('MIN'),m2.group('S'))
hand.starttime = datetime.datetime.strptime(datetimestr, "%Y/%m/%d %H:%M:%S")
# FIXME: some timezone correction required
#tzShift = defaultdict(lambda:0, {'EDT': -5, 'EST': -6, 'MSKS': 3})
#hand.starttime -= datetime.timedelta(hours=tzShift[m2.group('TZ')])
if key == 'HID':
hand.handid = info[key]
if key == 'TABLE':
hand.tablename = info[key]
if key == 'BUTTON':
hand.buttonpos = info[key]
if key == 'TOURNO':
hand.tourNo = info[key]
if key == 'BUYIN':
#FIXME: it's dirty hack T_T
cur = info[key][0] if info[key][0] not in '0123456789' else ''
hand.buyin = info[key] + '+%s0' % cur
if key == 'LEVEL':
hand.level = info[key]
if key == 'PLAY' and info['PLAY'] != 'Real':
# TODO: play money wasn't tested
# hand.currency = 'play' # overrides previously set value
hand.gametype['currency'] = 'play'
def readButton(self, hand):
m = self.re_Button.search(hand.handText)
if m:
hand.buttonpos = int(m.group('BUTTON'))
else:
logging.info('readButton: not found')
def readPlayerStacks(self, hand):
logging.debug("readPlayerStacks")
m = self.re_PlayerInfo.finditer(hand.handText)
players = []
for a in m:
hand.addPlayer(int(a.group('SEAT')), a.group('PNAME'),
renderTrnyMoney(a.group('CASH')))
def markStreets(self, hand):
# PREFLOP = ** Dealing down cards **
# This re fails if, say, river is missing; then we don't get the ** that starts the river.
assert hand.gametype['base'] == "hold", \
"wtf! There're no %s games on party" % hand.gametype['base']
m = re.search(
r"\*{2} Dealing down cards \*{2}"
r"(?P<PREFLOP>.+?)"
r"(?:\*{2} Dealing Flop \*{2} (?P<FLOP>\[ \S\S, \S\S, \S\S \].+?))?"
r"(?:\*{2} Dealing Turn \*{2} (?P<TURN>\[ \S\S \].+?))?"
r"(?:\*{2} Dealing River \*{2} (?P<RIVER>\[ \S\S \].+?))?$"
, hand.handText,re.DOTALL)
hand.addStreets(m)
def readCommunityCards(self, hand, street):
if street in ('FLOP','TURN','RIVER'):
m = self.re_Board.search(hand.streets[street])
hand.setCommunityCards(street, renderCards(m.group('CARDS')))
def readAntes(self, hand):
logging.debug("reading antes")
m = self.re_Antes.finditer(hand.handText)
for player in m:
hand.addAnte(player.group('PNAME'), player.group('ANTE'))
def readBringIn(self, hand):
m = self.re_BringIn.search(hand.handText,re.DOTALL)
if m:
hand.addBringIn(m.group('PNAME'), m.group('BRINGIN'))
def readBlinds(self, hand):
noSmallBlind = bool(self.re_NoSmallBlind.search(hand.handText))
if hand.gametype['type'] == 'ring':
try:
assert noSmallBlind==False
m = self.re_PostSB.search(hand.handText)
hand.addBlind(m.group('PNAME'), 'small blind', m.group('SB'))
except: # no small blind
hand.addBlind(None, None, None)
for a in self.re_PostBB.finditer(hand.handText):
hand.addBlind(a.group('PNAME'), 'big blind', a.group('BB'))
else:
# party doesn't track blinds for tournaments
# so there're some cra^Wcaclulations
if hand.buttonpos == 0:
self.readButton(hand)
# NOTE: code below depends on Hand's implementation
# playersMap - dict {seat: (pname,stack)}
playersMap = dict([(f[0], f[1:3]) for f in hand.players])
maxSeat = max(playersMap)
def findFirstNonEmptySeat(startSeat):
while startSeat not in playersMap:
if startSeat >= maxSeat:
startSeat = 0
startSeat += 1
return startSeat
smartMin = lambda A,B: A if float(A) <= float(B) else B
if noSmallBlind:
hand.addBlind(None, None, None)
else:
smallBlindSeat = findFirstNonEmptySeat(int(hand.buttonpos) + 1)
blind = smartMin(hand.sb, playersMap[smallBlindSeat][1])
hand.addBlind(playersMap[smallBlindSeat][0], 'small blind', blind)
bigBlindSeat = findFirstNonEmptySeat(smallBlindSeat + 1)
blind = smartMin(hand.bb, playersMap[bigBlindSeat][1])
hand.addBlind(playersMap[bigBlindSeat][0], 'small blind', blind)
def readHeroCards(self, hand):
# we need to grab hero's cards
for street in ('PREFLOP',):
if street in hand.streets.keys():
m = self.re_HeroCards.finditer(hand.streets[street])
for found in m:
hand.hero = found.group('PNAME')
newcards = renderCards(found.group('NEWCARDS'))
hand.addHoleCards(street, hand.hero, closed=newcards, shown=False, mucked=False, dealt=True)
def readAction(self, hand, street):
m = self.re_Action.finditer(hand.streets[street])
for action in m:
acts = action.groupdict()
if action.group('ATYPE') in ('raises','is all-In'):
hand.addRaiseBy( street, action.group('PNAME'), action.group('BET') )
elif action.group('ATYPE') == 'calls':
hand.addCall( street, action.group('PNAME'), action.group('BET') )
elif action.group('ATYPE') == 'bets':
hand.addBet( street, action.group('PNAME'), action.group('BET') )
elif action.group('ATYPE') == 'folds':
hand.addFold( street, action.group('PNAME'))
elif action.group('ATYPE') == 'checks':
hand.addCheck( street, action.group('PNAME'))
else:
print "DEBUG: unimplemented readAction: '%s' '%s'" %(action.group('PNAME'),action.group('ATYPE'),)
def readShowdownActions(self, hand):
# all action in readShownCards
pass
def readCollectPot(self,hand):
for m in self.re_CollectPot.finditer(hand.handText):
hand.addCollectPot(player=m.group('PNAME'),pot=m.group('POT'))
def readShownCards(self,hand):
for m in self.re_ShownCards.finditer(hand.handText):
if m.group('CARDS') is not None:
cards = renderCards(m.group('CARDS'))
(shown, mucked) = (False, False)
if m.group('SHOWED') == "show": shown = True
else: mucked = True
hand.addShownCards(cards=cards, player=m.group('PNAME'), shown=shown, mucked=mucked)
def ringBlinds(ringLimit):
"Returns blinds for current limit"
ringLimit = float(ringLimit)
if ringLimit == 5.: ringLimit = 4.
return ('%.2f' % (ringLimit/200.), '%.2f' % (ringLimit/100.) )
def renderTrnyMoney(money):
"renders 'numbers' like '1 200' and '2,000'"
return money.replace(' ', '').replace(',', '')
def renderCards(string):
"splits strings like ' Js, 4d '"
cards = string.strip().split(' ')
return filter(len, map(lambda x: x.strip(' ,'), cards))
if __name__ == "__main__":
parser = OptionParser()
parser.add_option("-i", "--input", dest="ipath", help="parse input hand history")
parser.add_option("-o", "--output", dest="opath", help="output translation to", default="-")
parser.add_option("-f", "--follow", dest="follow", help="follow (tail -f) the input", action="store_true", default=False)
parser.add_option("-q", "--quiet",
action="store_const", const=logging.CRITICAL, dest="verbosity", default=logging.INFO)
parser.add_option("-v", "--verbose",
action="store_const", const=logging.INFO, dest="verbosity")
parser.add_option("--vv",
action="store_const", const=logging.DEBUG, dest="verbosity")
(options, args) = parser.parse_args()
#LOG_FILENAME = './logging.out'
logging.basicConfig(level=options.verbosity)
e = PartyPoker(in_path = options.ipath, out_path = options.opath, follow = options.follow)

View File

@ -32,7 +32,7 @@ class PokerStars(HandHistoryConverter):
mixes = { 'HORSE': 'horse', '8-Game': '8game', 'HOSE': 'hose'} # Legal mixed games mixes = { 'HORSE': 'horse', '8-Game': '8game', 'HOSE': 'hose'} # Legal mixed games
sym = {'USD': "\$", 'CAD': "\$", 'T$': "", "EUR": "\x80", "GBP": "\xa3"} # ADD Euro, Sterling, etc HERE sym = {'USD': "\$", 'CAD': "\$", 'T$': "", "EUR": "\x80", "GBP": "\xa3"} # ADD Euro, Sterling, etc HERE
substitutions = { substitutions = {
'LEGAL_ISO' : "USD|EUR|GBP|CAD", # legal ISO currency codes 'LEGAL_ISO' : "USD|EUR|GBP|CAD|FPP", # legal ISO currency codes
'LS' : "\$|\x80|\xa3" # legal currency symbols ADD Euro, Sterling, etc HERE 'LS' : "\$|\x80|\xa3" # legal currency symbols ADD Euro, Sterling, etc HERE
} }

View File

@ -1,9 +1,7 @@
#!/usr/bin/env python #!/usr/bin/env python
"""SQL.py """Returns a dict of SQL statements used in fpdb.
Set up all of the SQL statements for a given game and database type.
""" """
# Copyright 2008, Ray E. Barker # Copyright 2008-2009, Ray E. Barker
# #
# This program is free software; you can redistribute it and/or modify # 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 # it under the terms of the GNU General Public License as published by
@ -35,134 +33,8 @@ import re
class Sql: class Sql:
def __init__(self, game = 'holdem', type = 'PT3', db_server = 'mysql'): def __init__(self, game = 'holdem', type = 'fpdb', db_server = 'mysql'):
self.query = {} self.query = {}
############################################################################
#
# Support for the ptracks database, a cut down PT2 stud database.
# You can safely ignore this unless you are me.
#
if game == 'razz' and type == 'ptracks':
self.query['get_table_name'] = "select table_name from game where game_id = %s"
self.query['get_last_hand'] = "select max(game_id) from game"
self.query['get_recent_hands'] = "select game_id from game where game_id > %(last_hand)d"
self.query['get_xml'] = "select xml from hand_history where game_id = %s"
self.query['get_player_id'] = """
select player_id from players
where screen_name = %(player)s
"""
self.query['get_hand_info'] = """
SELECT
game_id,
CONCAT(hole_card_1, hole_card_2, hole_card_3, hole_card_4, hole_card_5, hole_card_6, hole_card_7) AS hand,
total_won-total_bet AS net
FROM game_players
WHERE game_id = %s AND player_id = 3
"""
self.query['get_cards'] = """
select
seat_number,
screen_name,
hole_card_1,
hole_card_2,
hole_card_3,
hole_card_4,
hole_card_5,
hole_card_6,
hole_card_7
from game_players, players
where game_id = %s and game_players.player_id = players.player_id
order by seat_number
"""
self.query['get_stats_from_hand'] = """
SELECT player_id,
count(*) AS n,
sum(pre_fourth_raise_n) AS pfr,
sum(fourth_raise_n) AS raise_n_2,
sum(fourth_ck_raise_n) AS cr_n_2,
sum(fifth_bet_raise_n) AS br_n_3,
sum(fifth_bet_ck_raise_n) AS cr_n_3,
sum(sixth_bet_raise_n) AS br_n_4,
sum(sixth_bet_ck_raise_n) AS cr_n_4,
sum(river_bet_raise_n) AS br_n_5,
sum(river_bet_ck_raise_n) AS cr_n_5,
sum(went_to_showdown_n) AS sd,
sum(saw_fourth_n) AS saw_f,
sum(raised_first_pf) AS first_pfr,
sum(vol_put_money_in_pot) AS vpip,
sum(limp_with_prev_callers) AS limp_w_callers,
sum(ppossible_actions) AS poss_a_pf,
sum(pfold) AS fold_pf,
sum(pcheck) AS check_pf,
sum(praise) AS raise_pf,
sum(pcall) AS raise_pf,
sum(limp_call_reraise_pf) AS limp_call_pf,
sum(pfr_check) AS check_after_raise,
sum(pfr_call) AS call_after_raise,
sum(pfr_fold) AS fold_after_raise,
sum(pfr_bet) AS bet_after_raise,
sum(pfr_raise) AS raise_after_raise,
sum(folded_to_river_bet) AS fold_to_r_bet,
sum(fpossible_actions) AS poss_a_2,
sum(ffold) AS fold_2,
sum(fcheck) AS check_2,
sum(fbet) AS bet_2,
sum(fraise) AS raise_2,
sum(fcall) AS raise_2,
sum(fifpossible_actions) AS poss_a_3,
sum(fiffold) AS fold_3,
sum(fifcheck) AS check_3,
sum(fifbet) AS bet_3,
sum(fifraise) AS raise_3,
sum(fifcall) AS call_3,
sum(spossible_actions) AS poss_a_4,
sum(sfold) AS fold_4,
sum(scheck) AS check_4,
sum(sbet) AS bet_4,
sum(sraise) AS raise_4,
sum(scall) AS call_4,
sum(rpossible_actions) AS poss_a_5,
sum(rfold) AS fold_5,
sum(rcheck) AS check_5,
sum(rbet) AS bet_5,
sum(rraise) AS raise_5,
sum(rcall) AS call_5,
sum(cold_call_pf) AS cc_pf,
sum(saw_fifth_n) AS saw_3,
sum(saw_sixth_n) AS saw_4,
sum(saw_river_n) AS saw_5
FROM game_players
WHERE player_id in
(SELECT player_id FROM game_players
WHERE game_id = %s AND NOT player_id = %s)
GROUP BY player_id
"""
# alternate form of WHERE for above
# WHERE game_id = %(hand)d AND NOT player_id = %(hero)d)
# WHERE game_id = %s AND NOT player_id = %s)
self.query['get_players_from_hand'] = """
SELECT game_players.player_id, seat_number, screen_name
FROM game_players INNER JOIN players ON (game_players.player_id = players.player_id)
WHERE game_id = %s
"""
###############################################################################3 ###############################################################################3
# Support for the Free Poker DataBase = fpdb http://fpdb.sourceforge.net/ # Support for the Free Poker DataBase = fpdb http://fpdb.sourceforge.net/
# #
@ -410,16 +282,37 @@ class Sql:
elif db_server == 'sqlite': elif db_server == 'sqlite':
self.query['createHandsTable'] = """CREATE TABLE Hands ( self.query['createHandsTable'] = """CREATE TABLE Hands (
id INTEGER PRIMARY KEY, id INTEGER PRIMARY KEY,
tableName TEXT(20), tableName TEXT(20) NOT NULL,
siteHandNo INTEGER, siteHandNo INT NOT NULL,
gametypeId INTEGER, gametypeId INT NOT NULL,
handStart REAL, handStart REAL NOT NULL,
importTime REAL, importTime REAL NOT NULL,
seats INTEGER, seats INT NOT NULL,
maxSeats INTEGER, maxSeats INT NOT NULL,
boardcard1 INT, /* 0=none, 1-13=2-Ah 14-26=2-Ad 27-39=2-Ac 40-52=2-As */
boardcard2 INT,
boardcard3 INT,
boardcard4 INT,
boardcard5 INT,
texture INT,
playersVpi INT NOT NULL, /* num of players vpi */
playersAtStreet1 INT NOT NULL, /* num of players seeing flop/street4 */
playersAtStreet2 INT NOT NULL,
playersAtStreet3 INT NOT NULL,
playersAtStreet4 INT NOT NULL,
playersAtShowdown INT NOT NULL,
street0Raises INT NOT NULL, /* num small bets paid to see flop/street4, including blind */
street1Raises INT NOT NULL, /* num small bets paid to see turn/street5 */
street2Raises INT NOT NULL, /* num big bets paid to see river/street6 */
street3Raises INT NOT NULL, /* num big bets paid to see sd/street7 */
street4Raises INT NOT NULL, /* num big bets paid to see showdown */
street1Pot INT, /* pot size at flop/street4 */
street2Pot INT, /* pot size at turn/street5 */
street3Pot INT, /* pot size at river/street6 */
street4Pot INT, /* pot size at sd/street7 */
showdownPot INT, /* pot size at sd/street7 */
comment TEXT, comment TEXT,
commentTs REAL, commentTs REAL)"""
FOREIGN KEY(gametypeId) REFERENCES Gametypes(id) ON DELETE CASCADE)"""
################################ ################################
@ -919,78 +812,78 @@ class Sql:
styleKey CHAR(7) NOT NULL, /* 1st char is style (A/T/H/S), other 6 are the key */ styleKey CHAR(7) NOT NULL, /* 1st char is style (A/T/H/S), other 6 are the key */
HDs INT NOT NULL, HDs INT NOT NULL,
wonWhenSeenStreet1 FLOAT NOT NULL, wonWhenSeenStreet1 FLOAT,
wonWhenSeenStreet2 FLOAT, wonWhenSeenStreet2 FLOAT,
wonWhenSeenStreet3 FLOAT, wonWhenSeenStreet3 FLOAT,
wonWhenSeenStreet4 FLOAT, wonWhenSeenStreet4 FLOAT,
wonAtSD FLOAT NOT NULL, wonAtSD FLOAT,
street0VPI INT NOT NULL, street0VPI INT,
street0Aggr INT NOT NULL, street0Aggr INT,
street0_3BChance INT NOT NULL, street0_3BChance INT,
street0_3BDone INT NOT NULL, street0_3BDone INT,
street0_4BChance INT, street0_4BChance INT,
street0_4BDone INT, street0_4BDone INT,
other3BStreet0 INT, other3BStreet0 INT,
other4BStreet0 INT, other4BStreet0 INT,
street1Seen INT NOT NULL, street1Seen INT,
street2Seen INT NOT NULL, street2Seen INT,
street3Seen INT NOT NULL, street3Seen INT,
street4Seen INT NOT NULL, street4Seen INT,
sawShowdown INT NOT NULL, sawShowdown INT,
street1Aggr INT NOT NULL, street1Aggr INT,
street2Aggr INT NOT NULL, street2Aggr INT,
street3Aggr INT NOT NULL, street3Aggr INT,
street4Aggr INT NOT NULL, street4Aggr INT,
otherRaisedStreet0 INT, otherRaisedStreet0 INT,
otherRaisedStreet1 INT NOT NULL, otherRaisedStreet1 INT,
otherRaisedStreet2 INT NOT NULL, otherRaisedStreet2 INT,
otherRaisedStreet3 INT NOT NULL, otherRaisedStreet3 INT,
otherRaisedStreet4 INT NOT NULL, otherRaisedStreet4 INT,
foldToOtherRaisedStreet0 INT, foldToOtherRaisedStreet0 INT,
foldToOtherRaisedStreet1 INT NOT NULL, foldToOtherRaisedStreet1 INT,
foldToOtherRaisedStreet2 INT NOT NULL, foldToOtherRaisedStreet2 INT,
foldToOtherRaisedStreet3 INT NOT NULL, foldToOtherRaisedStreet3 INT,
foldToOtherRaisedStreet4 INT NOT NULL, foldToOtherRaisedStreet4 INT,
stealAttemptChance INT NOT NULL, stealAttemptChance INT,
stealAttempted INT NOT NULL, stealAttempted INT,
foldBbToStealChance INT NOT NULL, foldBbToStealChance INT,
foldedBbToSteal INT NOT NULL, foldedBbToSteal INT,
foldSbToStealChance INT NOT NULL, foldSbToStealChance INT,
foldedSbToSteal INT NOT NULL, foldedSbToSteal INT,
street1CBChance INT NOT NULL, street1CBChance INT,
street1CBDone INT NOT NULL, street1CBDone INT,
street2CBChance INT NOT NULL, street2CBChance INT,
street2CBDone INT NOT NULL, street2CBDone INT,
street3CBChance INT NOT NULL, street3CBChance INT,
street3CBDone INT NOT NULL, street3CBDone INT,
street4CBChance INT NOT NULL, street4CBChance INT,
street4CBDone INT NOT NULL, street4CBDone INT,
foldToStreet1CBChance INT NOT NULL, foldToStreet1CBChance INT,
foldToStreet1CBDone INT NOT NULL, foldToStreet1CBDone INT,
foldToStreet2CBChance INT NOT NULL, foldToStreet2CBChance INT,
foldToStreet2CBDone INT NOT NULL, foldToStreet2CBDone INT,
foldToStreet3CBChance INT NOT NULL, foldToStreet3CBChance INT,
foldToStreet3CBDone INT NOT NULL, foldToStreet3CBDone INT,
foldToStreet4CBChance INT NOT NULL, foldToStreet4CBChance INT,
foldToStreet4CBDone INT NOT NULL, foldToStreet4CBDone INT,
totalProfit INT NOT NULL, totalProfit INT,
street1CheckCallRaiseChance INT NOT NULL, street1CheckCallRaiseChance INT,
street1CheckCallRaiseDone INT NOT NULL, street1CheckCallRaiseDone INT,
street2CheckCallRaiseChance INT NOT NULL, street2CheckCallRaiseChance INT,
street2CheckCallRaiseDone INT NOT NULL, street2CheckCallRaiseDone INT,
street3CheckCallRaiseChance INT NOT NULL, street3CheckCallRaiseChance INT,
street3CheckCallRaiseDone INT NOT NULL, street3CheckCallRaiseDone INT,
street4CheckCallRaiseChance INT NOT NULL, street4CheckCallRaiseChance INT,
street4CheckCallRaiseDone INT NOT NULL, street4CheckCallRaiseDone INT,
street0Calls INT, street0Calls INT,
street1Calls INT, street1Calls INT,
@ -1020,16 +913,16 @@ class Sql:
styleKey CHAR(7) NOT NULL, /* 1st char is style (A/T/H/S), other 6 are the key */ styleKey CHAR(7) NOT NULL, /* 1st char is style (A/T/H/S), other 6 are the key */
HDs INT, HDs INT,
wonWhenSeenStreet1 FLOAT NOT NULL, wonWhenSeenStreet1 FLOAT,
wonWhenSeenStreet2 FLOAT, wonWhenSeenStreet2 FLOAT,
wonWhenSeenStreet3 FLOAT, wonWhenSeenStreet3 FLOAT,
wonWhenSeenStreet4 FLOAT, wonWhenSeenStreet4 FLOAT,
wonAtSD FLOAT NOT NULL, wonAtSD FLOAT,
street0VPI INT NOT NULL, street0VPI INT,
street0Aggr INT, street0Aggr INT,
street0_3BChance INT NOT NULL, street0_3BChance INT,
street0_3BDone INT NOT NULL, street0_3BDone INT,
street0_4BChance INT, street0_4BChance INT,
street0_4BDone INT, street0_4BDone INT,
other3BStreet0 INT, other3BStreet0 INT,
@ -1119,16 +1012,16 @@ class Sql:
styleKey TEXT NOT NULL, /* 1st char is style (A/T/H/S), other 6 are the key */ styleKey TEXT NOT NULL, /* 1st char is style (A/T/H/S), other 6 are the key */
HDs INT, HDs INT,
wonWhenSeenStreet1 REAL NOT NULL, wonWhenSeenStreet1 REAL,
wonWhenSeenStreet2 REAL, wonWhenSeenStreet2 REAL,
wonWhenSeenStreet3 REAL, wonWhenSeenStreet3 REAL,
wonWhenSeenStreet4 REAL, wonWhenSeenStreet4 REAL,
wonAtSD REAL NOT NULL, wonAtSD REAL,
street0VPI INT NOT NULL, street0VPI INT,
street0Aggr INT, street0Aggr INT,
street0_3BChance INT NOT NULL, street0_3BChance INT,
street0_3BDone INT NOT NULL, street0_3BDone INT,
street0_4BChance INT, street0_4BChance INT,
street0_4BDone INT, street0_4BDone INT,
other3BStreet0 INT, other3BStreet0 INT,
@ -1646,6 +1539,11 @@ class Sql:
select coalesce(max(id),0) select coalesce(max(id),0)
from Hands from Hands
where handStart < now() at time zone 'UTC' - interval '1 day'""" where handStart < now() at time zone 'UTC' - interval '1 day'"""
elif db_server == 'sqlite':
self.query['get_hand_1day_ago'] = """
select coalesce(max(id),0)
from Hands
where handStart < strftime('%J', 'now') - 1"""
# not used yet ... # not used yet ...
# gets a date, would need to use handsplayers (not hudcache) to get exact hand Id # gets a date, would need to use handsplayers (not hudcache) to get exact hand Id
@ -2084,7 +1982,7 @@ class Sql:
when stats.PlPosition = 1 then 'CO' when stats.PlPosition = 1 then 'CO'
when stats.PlPosition = 2 then 'MP' when stats.PlPosition = 2 then 'MP'
when stats.PlPosition = 5 then 'EP' when stats.PlPosition = 5 then 'EP'
else '??' else 'xx'
end AS PlPosition end AS PlPosition
,stats.n ,stats.n
,stats.vpip ,stats.vpip
@ -2218,7 +2116,7 @@ class Sql:
when stats.PlPosition = 1 then 'CO' when stats.PlPosition = 1 then 'CO'
when stats.PlPosition = 2 then 'MP' when stats.PlPosition = 2 then 'MP'
when stats.PlPosition = 5 then 'EP' when stats.PlPosition = 5 then 'EP'
else '??' else 'xx'
end AS PlPosition end AS PlPosition
,stats.n ,stats.n
,stats.vpip ,stats.vpip
@ -2515,7 +2413,7 @@ class Sql:
,hp.tourneyTypeId ,hp.tourneyTypeId
,date_format(h.handStart, 'd%y%m%d') ,date_format(h.handStart, 'd%y%m%d')
""" """
else: # assume postgres elif db_server == 'postgresql':
self.query['rebuildHudCache'] = """ self.query['rebuildHudCache'] = """
INSERT INTO HudCache INSERT INTO HudCache
(gametypeId (gametypeId
@ -2663,6 +2561,154 @@ class Sql:
,hp.tourneyTypeId ,hp.tourneyTypeId
,to_char(h.handStart, 'YYMMDD') ,to_char(h.handStart, 'YYMMDD')
""" """
else: # assume sqlite
self.query['rebuildHudCache'] = """
INSERT INTO HudCache
(gametypeId
,playerId
,activeSeats
,position
,tourneyTypeId
,styleKey
,HDs
,wonWhenSeenStreet1
,wonAtSD
,street0VPI
,street0Aggr
,street0_3BChance
,street0_3BDone
,street1Seen
,street2Seen
,street3Seen
,street4Seen
,sawShowdown
,street1Aggr
,street2Aggr
,street3Aggr
,street4Aggr
,otherRaisedStreet1
,otherRaisedStreet2
,otherRaisedStreet3
,otherRaisedStreet4
,foldToOtherRaisedStreet1
,foldToOtherRaisedStreet2
,foldToOtherRaisedStreet3
,foldToOtherRaisedStreet4
,stealAttemptChance
,stealAttempted
,foldBbToStealChance
,foldedBbToSteal
,foldSbToStealChance
,foldedSbToSteal
,street1CBChance
,street1CBDone
,street2CBChance
,street2CBDone
,street3CBChance
,street3CBDone
,street4CBChance
,street4CBDone
,foldToStreet1CBChance
,foldToStreet1CBDone
,foldToStreet2CBChance
,foldToStreet2CBDone
,foldToStreet3CBChance
,foldToStreet3CBDone
,foldToStreet4CBChance
,foldToStreet4CBDone
,totalProfit
,street1CheckCallRaiseChance
,street1CheckCallRaiseDone
,street2CheckCallRaiseChance
,street2CheckCallRaiseDone
,street3CheckCallRaiseChance
,street3CheckCallRaiseDone
,street4CheckCallRaiseChance
,street4CheckCallRaiseDone
)
SELECT h.gametypeId
,hp.playerId
,h.seats
,case when hp.position = 'B' then 'B'
when hp.position = 'S' then 'S'
when hp.position = '0' then 'D'
when hp.position = '1' then 'C'
when hp.position = '2' then 'M'
when hp.position = '3' then 'M'
when hp.position = '4' then 'M'
when hp.position = '5' then 'E'
when hp.position = '6' then 'E'
when hp.position = '7' then 'E'
when hp.position = '8' then 'E'
when hp.position = '9' then 'E'
else 'E'
end AS hc_position
,hp.tourneyTypeId
,'d' || substr(strftime('%Y%m%d', h.handStart),3,7)
,count(1)
,sum(wonWhenSeenStreet1)
,sum(wonAtSD)
,sum(CAST(street0VPI as integer))
,sum(CAST(street0Aggr as integer))
,sum(CAST(street0_3BChance as integer))
,sum(CAST(street0_3BDone as integer))
,sum(CAST(street1Seen as integer))
,sum(CAST(street2Seen as integer))
,sum(CAST(street3Seen as integer))
,sum(CAST(street4Seen as integer))
,sum(CAST(sawShowdown as integer))
,sum(CAST(street1Aggr as integer))
,sum(CAST(street2Aggr as integer))
,sum(CAST(street3Aggr as integer))
,sum(CAST(street4Aggr as integer))
,sum(CAST(otherRaisedStreet1 as integer))
,sum(CAST(otherRaisedStreet2 as integer))
,sum(CAST(otherRaisedStreet3 as integer))
,sum(CAST(otherRaisedStreet4 as integer))
,sum(CAST(foldToOtherRaisedStreet1 as integer))
,sum(CAST(foldToOtherRaisedStreet2 as integer))
,sum(CAST(foldToOtherRaisedStreet3 as integer))
,sum(CAST(foldToOtherRaisedStreet4 as integer))
,sum(CAST(stealAttemptChance as integer))
,sum(CAST(stealAttempted as integer))
,sum(CAST(foldBbToStealChance as integer))
,sum(CAST(foldedBbToSteal as integer))
,sum(CAST(foldSbToStealChance as integer))
,sum(CAST(foldedSbToSteal as integer))
,sum(CAST(street1CBChance as integer))
,sum(CAST(street1CBDone as integer))
,sum(CAST(street2CBChance as integer))
,sum(CAST(street2CBDone as integer))
,sum(CAST(street3CBChance as integer))
,sum(CAST(street3CBDone as integer))
,sum(CAST(street4CBChance as integer))
,sum(CAST(street4CBDone as integer))
,sum(CAST(foldToStreet1CBChance as integer))
,sum(CAST(foldToStreet1CBDone as integer))
,sum(CAST(foldToStreet2CBChance as integer))
,sum(CAST(foldToStreet2CBDone as integer))
,sum(CAST(foldToStreet3CBChance as integer))
,sum(CAST(foldToStreet3CBDone as integer))
,sum(CAST(foldToStreet4CBChance as integer))
,sum(CAST(foldToStreet4CBDone as integer))
,sum(CAST(totalProfit as integer))
,sum(CAST(street1CheckCallRaiseChance as integer))
,sum(CAST(street1CheckCallRaiseDone as integer))
,sum(CAST(street2CheckCallRaiseChance as integer))
,sum(CAST(street2CheckCallRaiseDone as integer))
,sum(CAST(street3CheckCallRaiseChance as integer))
,sum(CAST(street3CheckCallRaiseDone as integer))
,sum(CAST(street4CheckCallRaiseChance as integer))
,sum(CAST(street4CheckCallRaiseDone as integer))
FROM HandsPlayers hp
INNER JOIN Hands h ON (h.id = hp.handId)
GROUP BY h.gametypeId
,hp.playerId
,h.seats
,hc_position
,hp.tourneyTypeId
,'d' || substr(strftime('%Y%m%d', h.handStart),3,7)
"""
if db_server == 'mysql': if db_server == 'mysql':
self.query['analyze'] = """ self.query['analyze'] = """
@ -2681,13 +2727,51 @@ class Sql:
else: # assume postgres else: # assume postgres
self.query['lockForInsert'] = "" self.query['lockForInsert'] = ""
self.query['getGametypeFL'] = """SELECT id
FROM Gametypes
WHERE siteId=%s
AND type=%s
AND category=%s
AND limitType=%s
AND smallBet=%s
AND bigBet=%s
"""
self.query['getGametypeNL'] = """SELECT id
FROM Gametypes
WHERE siteId=%s
AND type=%s
AND category=%s
AND limitType=%s
AND smallBlind=%s
AND bigBlind=%s
"""
self.query['insertGameTypes'] = """INSERT INTO Gametypes
(siteId, type, base, category, limitType
,hiLo, smallBlind, bigBlind, smallBet, bigBet)
VALUES (%s, %s, %s, %s, %s, %s, %s, %s, %s, %s)"""
self.query['isAlreadyInDB'] = """SELECT id FROM Hands
WHERE gametypeId=%s AND siteHandNo=%s
"""
if db_server == 'mysql':
self.query['placeholder'] = u'%s'
elif db_server == 'postgresql':
self.query['placeholder'] = u'%s'
elif db_server == 'sqlite':
self.query['placeholder'] = u'?'
# If using sqlite, use the ? placeholder instead of %s
if db_server == 'sqlite': if db_server == 'sqlite':
for k,q in self.query.iteritems(): for k,q in self.query.iteritems():
self.query[k] = re.sub('%s','?',q) self.query[k] = re.sub('%s','?',q)
if __name__== "__main__": if __name__== "__main__":
# just print the default queries and exit # just print the default queries and exit
s = Sql(game = 'razz', type = 'ptracks') s = Sql()
for key in s.query: for key in s.query:
print "For query " + key + ", sql =" print "For query " + key + ", sql ="
print s.query[key] print s.query[key]

View File

@ -234,7 +234,7 @@ def discover_nt_by_name(c, tablename):
#print "Tables.py: tablename =", tablename, "title =", titles[hwnd] #print "Tables.py: tablename =", tablename, "title =", titles[hwnd]
try: try:
# this can blow up in XP on some windows, eg firefox displaying http://docs.python.org/tutorial/classes.html # this can blow up in XP on some windows, eg firefox displaying http://docs.python.org/tutorial/classes.html
if not tablename in titles[hwnd]: continue if not tablename.lower() in titles[hwnd].lower(): continue
except: except:
continue continue
if 'History for table:' in titles[hwnd]: continue # Everleaf Network HH viewer window if 'History for table:' in titles[hwnd]: continue # Everleaf Network HH viewer window
@ -302,6 +302,8 @@ def decode_windows(c, title, hwnd):
return info return info
def win_enum_handler(hwnd, titles): def win_enum_handler(hwnd, titles):
str = win32gui.GetWindowText(hwnd)
if str != "":
titles[hwnd] = win32gui.GetWindowText(hwnd) titles[hwnd] = win32gui.GetWindowText(hwnd)
################################################################### ###################################################################

View File

@ -531,7 +531,7 @@ This program is licensed under the AGPL3, see docs"""+os.sep+"agpl-3.0.txt")
def tab_table_viewer(self, widget, data=None): def tab_table_viewer(self, widget, data=None):
"""opens a table viewer tab""" """opens a table viewer tab"""
#print "start of tab_table_viewer" #print "start of tab_table_viewer"
new_tv_thread=GuiTableViewer.GuiTableViewer(self.db.fdb, self.settings) new_tv_thread = GuiTableViewer.GuiTableViewer(self.db, self.settings, self.config)
self.threads.append(new_tv_thread) self.threads.append(new_tv_thread)
tv_tab=new_tv_thread.get_vbox() tv_tab=new_tv_thread.get_vbox()
self.add_and_display_tab(tv_tab, "Table Viewer") self.add_and_display_tab(tv_tab, "Table Viewer")

View File

@ -64,7 +64,7 @@ class fpdb_db:
if backend==fpdb_db.MYSQL_INNODB: if backend==fpdb_db.MYSQL_INNODB:
import MySQLdb import MySQLdb
try: try:
self.db = MySQLdb.connect(host = host, user = user, passwd = password, db = database, use_unicode=True, charset="utf8") self.db = MySQLdb.connect(host = host, user = user, passwd = password, db = database, use_unicode=True)
except: except:
raise fpdb_simple.FpdbError("MySQL connection failed") raise fpdb_simple.FpdbError("MySQL connection failed")
elif backend==fpdb_db.PGSQL: elif backend==fpdb_db.PGSQL:
@ -155,105 +155,4 @@ class fpdb_db:
return (self.host, self.database, self.user, self.password) return (self.host, self.database, self.user, self.password)
#end def get_db_info #end def get_db_info
def getLastInsertId(self, cursor=None):
try:
if self.backend == self.MYSQL_INNODB:
ret = self.db.insert_id()
if ret < 1 or ret > 999999999:
print "getLastInsertId(): problem fetching insert_id? ret=", ret
ret = -1
elif self.backend == self.PGSQL:
# some options:
# currval(hands_id_seq) - use name of implicit seq here
# lastval() - still needs sequences set up?
# insert ... returning is useful syntax (but postgres specific?)
# see rules (fancy trigger type things)
c = self.db.cursor()
ret = c.execute ("SELECT lastval()")
row = c.fetchone()
if not row:
print "getLastInsertId(%s): problem fetching lastval? row=" % seq, row
ret = -1
else:
ret = row[0]
elif self.backend == fpdb_db.SQLITE:
ret = cursor.lastrowid
else:
print "getLastInsertId(): unknown backend ", self.backend
ret = -1
except:
ret = -1
print "getLastInsertId error:", str(sys.exc_value), " ret =", ret
raise fpdb_simple.FpdbError( "getLastInsertId error: " + str(sys.exc_value) )
return ret
def storeHand(self, p):
#stores into table hands:
self.cursor.execute ("""INSERT INTO Hands (
tablename,
sitehandno,
gametypeid,
handstart,
importtime,
seats,
maxseats,
boardcard1,
boardcard2,
boardcard3,
boardcard4,
boardcard5,
-- texture,
playersVpi,
playersAtStreet1,
playersAtStreet2,
playersAtStreet3,
playersAtStreet4,
playersAtShowdown,
street0Raises,
street1Raises,
street2Raises,
street3Raises,
street4Raises,
-- street1Pot,
-- street2Pot,
-- street3Pot,
-- street4Pot,
-- showdownPot
)
VALUES
(%s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s,
%s, %s, %s, %s, %s, %s, %s)""",
(
p['tablename'],
p['sitehandno'],
p['gametypeid'],
p['handStart'],
datetime.datetime.today(),
len(p['names']),
p['maxSeats'],
p['boardcard1'],
p['boardcard2'],
p['boardcard3'],
p['boardcard4'],
p['boardcard5'],
hudCache['playersVpi'],
hudCache['playersAtStreet1'],
hudCache['playersAtStreet2'],
hudCache['playersAtStreet3'],
hudCache['playersAtStreet4'],
hudCache['playersAtShowdown'],
hudCache['street0Raises'],
hudCache['street1Raises'],
hudCache['street2Raises'],
hudCache['street3Raises'],
hudCache['street4Raises'],
hudCache['street1Pot'],
hudCache['street2Pot'],
hudCache['street3Pot'],
hudCache['street4Pot'],
hudCache['showdownPot']
)
)
#return getLastInsertId(backend, conn, cursor)
#end class fpdb_db #end class fpdb_db

View File

@ -85,6 +85,8 @@ class Importer:
#self.settings.setdefault("forceThreads", 2) # NOT USED NOW #self.settings.setdefault("forceThreads", 2) # NOT USED NOW
self.settings.setdefault("writeQSize", 1000) # no need to change self.settings.setdefault("writeQSize", 1000) # no need to change
self.settings.setdefault("writeQMaxWait", 10) # not used self.settings.setdefault("writeQMaxWait", 10) # not used
self.settings.setdefault("dropIndexes", "don't drop")
self.settings.setdefault("dropHudCache", "don't drop")
self.writeq = None self.writeq = None
self.database = Database.Database(self.config, sql = self.sql) self.database = Database.Database(self.config, sql = self.sql)
@ -130,6 +132,9 @@ class Importer:
# self.updated = time() # self.updated = time()
def clearFileList(self): def clearFileList(self):
self.updatedsize = {}
self.updatetime = {}
self.pos_in_file = {}
self.filelist = {} self.filelist = {}
def closeDBs(self): def closeDBs(self):
@ -197,7 +202,7 @@ class Importer:
print "Started at", start, "--", len(self.filelist), "files to import.", self.settings['dropIndexes'] print "Started at", start, "--", len(self.filelist), "files to import.", self.settings['dropIndexes']
if self.settings['dropIndexes'] == 'auto': if self.settings['dropIndexes'] == 'auto':
self.settings['dropIndexes'] = self.calculate_auto2(self.database, 12.0, 500.0) self.settings['dropIndexes'] = self.calculate_auto2(self.database, 12.0, 500.0)
if self.settings['dropHudCache'] == 'auto': if 'dropHudCache' in self.settings and self.settings['dropHudCache'] == 'auto':
self.settings['dropHudCache'] = self.calculate_auto2(self.database, 25.0, 500.0) # returns "drop"/"don't drop" self.settings['dropHudCache'] = self.calculate_auto2(self.database, 25.0, 500.0) # returns "drop"/"don't drop"
if self.settings['dropIndexes'] == 'drop': if self.settings['dropIndexes'] == 'drop':
@ -239,7 +244,7 @@ class Importer:
self.database.afterBulkImport() self.database.afterBulkImport()
else: else:
print "No need to rebuild indexes." print "No need to rebuild indexes."
if self.settings['dropHudCache'] == 'drop': if 'dropHudCache' in self.settings and self.settings['dropHudCache'] == 'drop':
self.database.rebuild_hudcache() self.database.rebuild_hudcache()
else: else:
print "No need to rebuild hudcache." print "No need to rebuild hudcache."
@ -377,7 +382,7 @@ class Importer:
# Load filter, process file, pass returned filename to import_fpdb_file # Load filter, process file, pass returned filename to import_fpdb_file
if self.writeq != None: if self.settings['threads'] > 0 and self.writeq != None:
print "\nConverting " + file + " (" + str(q.qsize()) + ")" print "\nConverting " + file + " (" + str(q.qsize()) + ")"
else: else:
print "\nConverting " + file print "\nConverting " + file

View File

@ -79,7 +79,7 @@ def mainParser(settings, siteID, category, hand, config, db = None, writeq = Non
rebuyOrAddon = -1 rebuyOrAddon = -1
tourneyTypeId = 1 tourneyTypeId = 1
fpdb_simple.isAlreadyInDB(db.get_cursor(), gametypeID, siteHandNo) fpdb_simple.isAlreadyInDB(db, gametypeID, siteHandNo)
hand = fpdb_simple.filterCrap(hand, isTourney) hand = fpdb_simple.filterCrap(hand, isTourney)
@ -93,7 +93,7 @@ def mainParser(settings, siteID, category, hand, config, db = None, writeq = Non
seatLines.append(line) seatLines.append(line)
names = fpdb_simple.parseNames(seatLines) names = fpdb_simple.parseNames(seatLines)
playerIDs = fpdb_simple.recognisePlayerIDs(db.get_cursor(), names, siteID) # inserts players as needed playerIDs = fpdb_simple.recognisePlayerIDs(db, names, siteID) # inserts players as needed
tmp = fpdb_simple.parseCashesAndSeatNos(seatLines) tmp = fpdb_simple.parseCashesAndSeatNos(seatLines)
startCashes = tmp['startCashes'] startCashes = tmp['startCashes']
seatNos = tmp['seatNos'] seatNos = tmp['seatNos']
@ -141,7 +141,7 @@ def mainParser(settings, siteID, category, hand, config, db = None, writeq = Non
fpdb_simple.checkPositions(positions) fpdb_simple.checkPositions(positions)
c = db.get_cursor() c = db.get_cursor()
c.execute("SELECT limitType FROM Gametypes WHERE id=%s",(gametypeID, )) c.execute("SELECT limitType FROM Gametypes WHERE id=%s" % (db.sql.query['placeholder'],), (gametypeID, ))
limit_type = c.fetchone()[0] limit_type = c.fetchone()[0]
fpdb_simple.convert3B4B(category, limit_type, actionTypes, actionAmounts) fpdb_simple.convert3B4B(category, limit_type, actionTypes, actionAmounts)

View File

@ -403,10 +403,11 @@ def isActionLine(line):
#end def isActionLine #end def isActionLine
#returns whether this is a duplicate #returns whether this is a duplicate
def isAlreadyInDB(cursor, gametypeID, siteHandNo): def isAlreadyInDB(db, gametypeID, siteHandNo):
#print "isAlreadyInDB gtid,shand:",gametypeID, siteHandNo #print "isAlreadyInDB gtid,shand:",gametypeID, siteHandNo
cursor.execute ("SELECT id FROM Hands WHERE gametypeId=%s AND siteHandNo=%s", (gametypeID, siteHandNo)) c = db.get_cursor()
result=cursor.fetchall() c.execute( db.sql.query['isAlreadyInDB'], (gametypeID, siteHandNo))
result = c.fetchall()
if (len(result)>=1): if (len(result)>=1):
raise DuplicateError ("dupl") raise DuplicateError ("dupl")
#end isAlreadyInDB #end isAlreadyInDB
@ -901,9 +902,11 @@ def recogniseGametypeID(backend, db, cursor, topline, smallBlindLine, site_id, c
#print "recogniseGametypeID small_bet/blind:",small_bet,"big bet/blind:", big_bet,"limit type:",limit_type #print "recogniseGametypeID small_bet/blind:",small_bet,"big bet/blind:", big_bet,"limit type:",limit_type
if (limit_type=="fl"): if (limit_type=="fl"):
cursor.execute ("SELECT id FROM Gametypes WHERE siteId=%s AND type=%s AND category=%s AND limitType=%s AND smallBet=%s AND bigBet=%s", (site_id, type, category, limit_type, small_bet, big_bet)) cursor.execute ( db.sql.query['getGametypeFL']
, (site_id, type, category, limit_type, small_bet, big_bet))
else: else:
cursor.execute ("SELECT id FROM Gametypes WHERE siteId=%s AND type=%s AND category=%s AND limitType=%s AND smallBlind=%s AND bigBlind=%s", (site_id, type, category, limit_type, small_bet, big_bet)) cursor.execute ( db.sql.query['getGametypeNL']
, (site_id, type, category, limit_type, small_bet, big_bet))
result=cursor.fetchone() result=cursor.fetchone()
#print "recgt1 result=",result #print "recgt1 result=",result
#ret=result[0] #ret=result[0]
@ -938,25 +941,16 @@ def recogniseGametypeID(backend, db, cursor, topline, smallBlindLine, site_id, c
small_blind=float2int(smallBlindLine[pos:]) small_blind=float2int(smallBlindLine[pos:])
else: else:
small_blind=0 small_blind=0
cursor.execute( """INSERT INTO Gametypes(siteId, type, base, category, limitType result = db.insertGameTypes( (site_id, type, base, category, limit_type, hiLo
,hiLo, smallBlind, bigBlind, smallBet, bigBet)
VALUES (%s, %s, %s, %s, %s, %s, %s, %s, %s, %s)"""
, (site_id, type, base, category, limit_type, hiLo
,small_blind, big_blind, small_bet, big_bet) ) ,small_blind, big_blind, small_bet, big_bet) )
#cursor.execute ("SELECT id FROM Gametypes WHERE siteId=%s AND type=%s AND category=%s #cursor.execute ("SELECT id FROM Gametypes WHERE siteId=%s AND type=%s AND category=%s
#AND limitType=%s AND smallBet=%s AND bigBet=%s", (site_id, type, category, limit_type, small_bet, big_bet)) #AND limitType=%s AND smallBet=%s AND bigBet=%s", (site_id, type, category, limit_type, small_bet, big_bet))
else: else:
cursor.execute( """INSERT INTO Gametypes(siteId, type, base, category, limitType result = db.insertGameTypes( (site_id, type, base, category, limit_type, hiLo
,hiLo, smallBlind, bigBlind, smallBet, bigBet) ,small_bet, big_bet, 0, 0) )#remember, for these bet means blind
VALUES (%s, %s, %s, %s, %s, %s, %s, %s, %s, %s)"""
, (site_id, type, base, category, limit_type
,hiLo, small_bet, big_bet, 0, 0))#remember, for these bet means blind
#cursor.execute ("SELECT id FROM Gametypes WHERE siteId=%s AND type=%s AND category=%s #cursor.execute ("SELECT id FROM Gametypes WHERE siteId=%s AND type=%s AND category=%s
#AND limitType=%s AND smallBlind=%s AND bigBlind=%s", (site_id, type, category, limit_type, small_bet, big_bet)) #AND limitType=%s AND smallBlind=%s AND bigBlind=%s", (site_id, type, category, limit_type, small_bet, big_bet))
#result=(db.insert_id(),)
result=(db.get_last_insert_id(),)
return result[0] return result[0]
#end def recogniseGametypeID #end def recogniseGametypeID
@ -993,17 +987,21 @@ def recogniseTourneyTypeId(cursor, siteId, buyin, fee, knockout, rebuyOrAddon):
# result.append(tmp[0][0]) # result.append(tmp[0][0])
# return result # return result
def recognisePlayerIDs(cursor, names, site_id): def recognisePlayerIDs(db, names, site_id):
q = "SELECT name,id FROM Players WHERE name=%s" % " OR name=".join(["%s" for n in names]) c = db.get_cursor()
cursor.execute(q, names) # get all playerids by the names passed in q = "SELECT name,id FROM Players WHERE siteid=%d and (name=%s)" %(site_id, " OR name=".join([db.sql.query['placeholder'] for n in names]))
ids = dict(cursor.fetchall()) # convert to dict c.execute(q, names) # get all playerids by the names passed in
ids = dict(c.fetchall()) # convert to dict
if len(ids) != len(names): if len(ids) != len(names):
notfound = [n for n in names if n not in ids] # make list of names not in database notfound = [n for n in names if n not in ids] # make list of names not in database
if notfound: # insert them into database if notfound: # insert them into database
cursor.executemany("INSERT INTO Players (name, siteId) VALUES (%s, "+str(site_id)+")", [(n,) for n in notfound]) q_ins = "INSERT INTO Players (name, siteId) VALUES (%s, "+str(site_id)+")"
q2 = "SELECT name,id FROM Players WHERE name=%s" % " OR name=".join(["%s" for n in notfound]) q_ins = q_ins.replace('%s', db.sql.query['placeholder'])
cursor.execute(q2, notfound) # get their new ids c.executemany(q_ins, [(n,) for n in notfound])
tmp = cursor.fetchall() q2 = "SELECT name,id FROM Players WHERE siteid=%d and (name=%s)" % (site_id, " OR name=".join(["%s" for n in notfound]))
q2 = q2.replace('%s', db.sql.query['placeholder'])
c.execute(q2, notfound) # get their new ids
tmp = c.fetchall()
for n,id in tmp: # put them all into the same dict for n,id in tmp: # put them all into the same dict
ids[n] = id ids[n] = id
# return them in the SAME ORDER that they came in in the names argument, rather than the order they came out of the DB # return them in the SAME ORDER that they came in in the names argument, rather than the order they came out of the DB