Merge branch 'master' of git://git.assembla.com/free_poker_tools
Conflicts: pyfpdb/Database.py pyfpdb/fpdb_db.py Reverted to upstream versions
This commit is contained in:
commit
74d571a938
|
@ -34,12 +34,12 @@ class Betfair(HandHistoryConverter):
|
|||
re_PlayerInfo = re.compile("Seat (?P<SEAT>[0-9]+): (?P<PNAME>.*)\s\(\s(\$(?P<CASH>[.0-9]+)) \)")
|
||||
re_Board = re.compile(ur"\[ (?P<CARDS>.+) \]")
|
||||
|
||||
def __init__(self, in_path = '-', out_path = '-', follow = False, autostart=True):
|
||||
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="Betfair", follow=follow) # Call super class init.
|
||||
HandHistoryConverter.__init__(self, in_path, out_path, sitename="Betfair", follow=follow, index) # Call super class init.
|
||||
logging.info("Initialising Betfair converter class")
|
||||
self.filetype = "text"
|
||||
self.codepage = "cp1252"
|
||||
|
|
|
@ -24,25 +24,37 @@ def twoStartCards(value1, suit1, value2, suit2):
|
|||
(y+2) represents rank of second card (2=2 .. 14=Ace)
|
||||
If x > y then pair is suited, if x < y then unsuited"""
|
||||
if value1 < 2 or value2 < 2:
|
||||
return(0)
|
||||
if (suit1 == suit2 and value1 < value2) or (suit1 != suit2 and value2 > value1):
|
||||
return(13 * (value2-2) + (value1-1))
|
||||
ret = 0
|
||||
if value1 == value2: # pairs
|
||||
ret = (13 * (value2-2) + (value2-1) )
|
||||
elif suit1 == suit2:
|
||||
if value1 > value2:
|
||||
ret = 13 * (value1-2) + (value2-1)
|
||||
else:
|
||||
ret = 13 * (value2-2) + (value1-1)
|
||||
else:
|
||||
return(13 * (value1-2) + (value2-1))
|
||||
if value1 > value2:
|
||||
ret = 13 * (value2-2) + (value2-1)
|
||||
else:
|
||||
ret = 13 * (value1-2) + (value2-1)
|
||||
|
||||
# print "twoStartCards(", value1, suit1, value2, suit2, ")=", ret
|
||||
return ret
|
||||
|
||||
def twoStartCardString(card):
|
||||
""" Function to convert an int representing 2 holdem hole cards (as created by twoStartCards)
|
||||
into a string like AQo """
|
||||
if card <= 0:
|
||||
return 'xx'
|
||||
else:
|
||||
ret = 'xx'
|
||||
if card > 0:
|
||||
card -= 1
|
||||
s = ('2', '3', '4', '5', '6', '7', '8', '9', 'T', 'J', 'Q', 'K', 'A')
|
||||
x = card/13
|
||||
y = card - 13*x
|
||||
if x == y: return(s[x] + s[y])
|
||||
elif x > y: return(s[x] + s[y] + 's')
|
||||
else: return(s[y] + s[x] + 'o')
|
||||
x = card / 13
|
||||
y = card - 13 * x
|
||||
if x == y: ret = s[x] + s[y]
|
||||
elif x > y: ret = s[x] + s[y] + 's'
|
||||
else: ret = s[y] + s[x] + 'o'
|
||||
# print "twoStartCardString(", card ,") = " + ret
|
||||
return ret
|
||||
|
||||
def fourStartCards(value1, suit1, value2, suit2, value3, suit3, value4, suit4):
|
||||
""" Function to convert 4 value,suit pairs into a Omaha style starting hand,
|
||||
|
@ -94,5 +106,23 @@ def valueSuitFromCard(card):
|
|||
, '2s', '3s', '4s', '5s', '6s', '7s', '8s', '9s', 'Ts', 'Js', 'Qs', 'Ks', 'As'
|
||||
][card] )
|
||||
|
||||
def encodeCard(cardString):
|
||||
"""Take a card string (Ah) and convert it to the db card code (1)."""
|
||||
try:
|
||||
return {'2h': 1, '3h': 2, '4h': 3, '5h': 4, '6h': 5, '7h': 6, '8h': 7, '9h': 8, 'Th': 9, 'Jh': 10, 'Qh': 11, 'Kh': 12, 'Ah': 13,
|
||||
'2d': 14, '3d': 15, '4d': 16, '5d': 17, '6d': 18, '7d': 19, '8d': 20, '9d': 21, 'Td': 22, 'Jd': 23, 'Qd': 24, 'Kd': 25, 'Ad': 26,
|
||||
'2c': 27, '3c': 28, '4c': 29, '5c': 30, '6c': 31, '7c': 32, '8c': 33, '9c': 34, 'Tc': 35, 'Jc': 36, 'Qc': 27, 'Kc': 38, 'Ac': 39,
|
||||
'2s': 40, '3s': 41, '4s': 42, '5s': 43, '6s': 44, '7s': 45, '8s': 46, '9s': 47, 'Ts': 48, 'Js': 49, 'Qs': 50, 'Ks': 51, 'As': 52,
|
||||
' ': 0
|
||||
}[cardString]
|
||||
except:
|
||||
return 0 # everthing that isn't known is a unknown!
|
||||
|
||||
if __name__ == '__main__':
|
||||
print "fpdb card encoding(same as pokersource)"
|
||||
for i in xrange(1, 14):
|
||||
print "card %2d = %s card %2d = %s card %2d = %s card %2d = %s" % \
|
||||
(i, valueSuitFromCard(i), i+13, valueSuitFromCard(i+13), i+26, valueSuitFromCard(i+26), i+39, valueSuitFromCard(i+39))
|
||||
|
||||
print
|
||||
print encodeCard('7c')
|
|
@ -521,6 +521,8 @@ class Config:
|
|||
db['db-backend'] = 2
|
||||
elif string.lower(self.supported_databases[name].db_server) == 'postgresql':
|
||||
db['db-backend'] = 3
|
||||
elif string.lower(self.supported_databases[name].db_server) == 'sqlite':
|
||||
db['db-backend'] = 4
|
||||
else: db['db-backend'] = None # this is big trouble
|
||||
return db
|
||||
|
||||
|
|
1482
pyfpdb/Database.py
1482
pyfpdb/Database.py
File diff suppressed because it is too large
Load Diff
|
@ -37,7 +37,7 @@ class Everleaf(HandHistoryConverter):
|
|||
re_Board = re.compile(ur"\[ (?P<CARDS>.+) \]")
|
||||
|
||||
|
||||
def __init__(self, in_path = '-', out_path = '-', follow = False, autostart=True, debugging=False):
|
||||
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)
|
||||
|
@ -45,7 +45,7 @@ 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="Everleaf", follow=follow)
|
||||
HandHistoryConverter.__init__(self, in_path, out_path, sitename="Everleaf", follow=follow, index=index)
|
||||
logging.info("Initialising Everleaf converter class")
|
||||
self.filetype = "text"
|
||||
self.codepage = "cp1252"
|
||||
|
@ -237,11 +237,14 @@ or None if we fail to get the info """
|
|||
# Also works with Omaha hands.
|
||||
cards = m.group('CARDS')
|
||||
cards = [card.strip() for card in cards.split(',')]
|
||||
hand.addHoleCards(cards, m.group('PNAME'))
|
||||
# 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("Everleaf readStudPlayerCards is only a stub.")
|
||||
|
@ -292,7 +295,8 @@ or None if we fail to get the info """
|
|||
cards = 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=None, player=m.group('PNAME'), holeandboard=cards)
|
||||
hand.addShownCards(cards=cards, player=m.group('PNAME'))
|
||||
|
||||
|
||||
|
||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -23,25 +23,49 @@ import logging
|
|||
from HandHistoryConverter import *
|
||||
|
||||
# Fulltilt HH Format converter
|
||||
# TODO: cat tourno and table to make table name for tournaments
|
||||
|
||||
class Fulltilt(HandHistoryConverter):
|
||||
|
||||
# Static regexes
|
||||
re_GameInfo = re.compile('- (?P<CURRENCY>\$|)?(?P<SB>[.0-9]+)/\$?(?P<BB>[.0-9]+) (Ante \$(?P<ANTE>[.0-9]+) )?- (?P<LIMIT>(No Limit|Pot Limit|Limit))? (?P<GAME>(Hold\'em|Omaha Hi|Razz))')
|
||||
re_GameInfo = re.compile('''(?:(?P<TOURNAMENT>.+)\s\((?P<TOURNO>\d+)\),\s)?
|
||||
.+
|
||||
-\s(?P<CURRENCY>\$|)?
|
||||
(?P<SB>[.0-9]+)/
|
||||
\$?(?P<BB>[.0-9]+)\s
|
||||
(Ante\s\$?(?P<ANTE>[.0-9]+)\s)?-\s
|
||||
(?P<LIMIT>(No\sLimit|Pot\sLimit|Limit))?\s
|
||||
(?P<GAME>(Hold\'em|Omaha\sHi|Omaha\sH/L|7\sCard\sStud|Stud\sH/L|Razz|Stud\sHi))
|
||||
''', re.VERBOSE)
|
||||
re_SplitHands = re.compile(r"\n\n+")
|
||||
re_TailSplitHands = re.compile(r"(\n\n+)")
|
||||
re_HandInfo = re.compile('.*#(?P<HID>[0-9]+): Table (?P<TABLE>[- a-zA-Z]+) (\((?P<TABLEATTRIBUTES>.+)\) )?- \$?(?P<SB>[.0-9]+)/\$?(?P<BB>[.0-9]+) (Ante \$(?P<ANTE>[.0-9]+) )?- (?P<GAMETYPE>[a-zA-Z\' ]+) - (?P<DATETIME>.*)')
|
||||
re_HandInfo = re.compile('''.*\#(?P<HID>[0-9]+):\s
|
||||
(?:(?P<TOURNAMENT>.+)\s\((?P<TOURNO>\d+)\),\s)?
|
||||
Table\s
|
||||
(?P<PLAY>Play\sChip\s|PC)?
|
||||
(?P<TABLE>[-\s\da-zA-Z]+)\s
|
||||
(\((?P<TABLEATTRIBUTES>.+)\)\s)?-\s
|
||||
\$?(?P<SB>[.0-9]+)/\$?(?P<BB>[.0-9]+)\s(Ante\s\$?(?P<ANTE>[.0-9]+)\s)?-\s
|
||||
(?P<GAMETYPE>[a-zA-Z\/\'\s]+)\s-\s
|
||||
(?P<DATETIME>.*)
|
||||
''', re.VERBOSE)
|
||||
re_Button = re.compile('^The button is in seat #(?P<BUTTON>\d+)', re.MULTILINE)
|
||||
re_PlayerInfo = re.compile('Seat (?P<SEAT>[0-9]+): (?P<PNAME>.*) \(\$(?P<CASH>[.0-9]+)\)\n')
|
||||
re_PlayerInfo = re.compile('Seat (?P<SEAT>[0-9]+): (?P<PNAME>.*) \(\$?(?P<CASH>[,.0-9]+)\)$', re.MULTILINE)
|
||||
re_Board = re.compile(r"\[(?P<CARDS>.+)\]")
|
||||
|
||||
# These regexes are for FTP only
|
||||
re_Mixed = re.compile(r'\s\-\s(?P<MIXED>HA|HORSE|HOSE)\s\-\s', re.VERBOSE)
|
||||
re_Max = re.compile("(?P<MAX>\d+)( max)?", re.MULTILINE)
|
||||
# NB: if we ever match "Full Tilt Poker" we should also match "FullTiltPoker", which PT Stud erroneously exports.
|
||||
|
||||
def __init__(self, in_path = '-', out_path = '-', follow = False, autostart=True):
|
||||
mixes = { 'HORSE': 'horse', '7-Game': '7game', 'HOSE': 'hose', 'HA': 'ha'}
|
||||
|
||||
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="Fulltilt", follow=follow)
|
||||
HandHistoryConverter.__init__(self, in_path, out_path, sitename="Fulltilt", follow=follow, index=index)
|
||||
logging.info("Initialising Fulltilt converter class")
|
||||
self.filetype = "text"
|
||||
self.codepage = "cp1252"
|
||||
|
@ -63,19 +87,24 @@ follow : whether to tail -f the input"""
|
|||
self.re_BringIn = re.compile(r"^%s brings in for \$?(?P<BRINGIN>[.0-9]+)" % player_re, re.MULTILINE)
|
||||
self.re_PostBoth = re.compile(r"^%s posts small \& big blinds \[\$? (?P<SBBB>[.0-9]+)" % player_re, re.MULTILINE)
|
||||
self.re_HeroCards = re.compile(r"^Dealt to %s(?: \[(?P<OLDCARDS>.+?)\])?( \[(?P<NEWCARDS>.+?)\])" % player_re, re.MULTILINE)
|
||||
self.re_Action = re.compile(r"^%s(?P<ATYPE> bets| checks| raises to| completes it to| calls| folds)(\s\$(?P<BET>[.\d]+))?" % player_re, re.MULTILINE)
|
||||
self.re_Action = re.compile(r"^%s(?P<ATYPE> bets| checks| raises to| completes it to| calls| folds)( \$?(?P<BET>[.,\d]+))?" % player_re, re.MULTILINE)
|
||||
self.re_ShowdownAction = re.compile(r"^%s shows \[(?P<CARDS>.*)\]" % player_re, re.MULTILINE)
|
||||
self.re_CollectPot = re.compile(r"^Seat (?P<SEAT>[0-9]+): %s (\(button\) |\(small blind\) |\(big blind\) )?(collected|showed \[.*\] and won) \(\$(?P<POT>[.\d]+)\)(, mucked| with.*)" % player_re, re.MULTILINE)
|
||||
self.re_SitsOut = re.compile(r"^%s sits out" % player_re, re.MULTILINE)
|
||||
self.re_ShownCards = re.compile(r"^Seat (?P<SEAT>[0-9]+): %s \(.*\) showed \[(?P<CARDS>.*)\].*" % player_re, re.MULTILINE)
|
||||
|
||||
|
||||
def readSupportedGames(self):
|
||||
return [["ring", "hold", "nl"],
|
||||
["ring", "hold", "pl"],
|
||||
["ring", "hold", "fl"],
|
||||
|
||||
["ring", "stud", "fl"],
|
||||
["ring", "omaha", "pl"]
|
||||
|
||||
["tour", "hold", "nl"],
|
||||
["tour", "hold", "pl"],
|
||||
["tour", "hold", "fl"],
|
||||
|
||||
["tour", "stud", "fl"],
|
||||
]
|
||||
|
||||
def determineGameType(self, handText):
|
||||
|
@ -88,7 +117,6 @@ follow : whether to tail -f the input"""
|
|||
m = self.re_GameInfo.search(handText)
|
||||
if not m:
|
||||
return None
|
||||
|
||||
mg = m.groupdict()
|
||||
|
||||
# translations from captured groups to our info strings
|
||||
|
@ -96,39 +124,41 @@ follow : whether to tail -f the input"""
|
|||
games = { # base, category
|
||||
"Hold'em" : ('hold','holdem'),
|
||||
'Omaha Hi' : ('hold','omahahi'),
|
||||
'Omaha H/L' : ('hold','omahahilo'),
|
||||
'Razz' : ('stud','razz'),
|
||||
'7 Card Stud' : ('stud','studhi')
|
||||
'Stud Hi' : ('stud','studhi'),
|
||||
'Stud H/L' : ('stud','studhilo')
|
||||
}
|
||||
currencies = { u' €':'EUR', '$':'USD', '':'T$' }
|
||||
if 'LIMIT' in mg:
|
||||
info['limitType'] = limits[mg['LIMIT']]
|
||||
if 'GAME' in mg:
|
||||
info['limitType'] = limits[mg['LIMIT']]
|
||||
info['sb'] = mg['SB']
|
||||
info['bb'] = mg['BB']
|
||||
if mg['GAME'] != None:
|
||||
(info['base'], info['category']) = games[mg['GAME']]
|
||||
if 'SB' in mg:
|
||||
info['sb'] = mg['SB']
|
||||
if 'BB' in mg:
|
||||
info['bb'] = mg['BB']
|
||||
if 'CURRENCY' in mg:
|
||||
if mg['CURRENCY'] != None:
|
||||
info['currency'] = currencies[mg['CURRENCY']]
|
||||
if mg['TOURNO'] == None: info['type'] = "ring"
|
||||
else: 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,re.DOTALL)
|
||||
|
||||
if(m == None):
|
||||
logging.info("Didn't match re_HandInfo")
|
||||
logging.info(hand.handText)
|
||||
return None
|
||||
|
||||
hand.handid = m.group('HID')
|
||||
hand.tablename = m.group('TABLE')
|
||||
hand.starttime = datetime.datetime.strptime(m.group('DATETIME'), "%H:%M:%S ET - %Y/%m/%d")
|
||||
hand.maxseats = 8 # assume 8-max until we see otherwise
|
||||
if m.group('TABLEATTRIBUTES'):
|
||||
m2 = re.search("(deep )?(\d+)( max)?", m.group('TABLEATTRIBUTES'))
|
||||
hand.maxseats = int(m2.group(2))
|
||||
m2 = self.re_Max.search(m.group('TABLEATTRIBUTES'))
|
||||
if m2: hand.maxseats = int(m2.group('MAX'))
|
||||
|
||||
hand.tourNo = m.group('TOURNO')
|
||||
if m.group('PLAY') != None:
|
||||
hand.gametype['currency'] = 'play'
|
||||
|
||||
# These work, but the info is already in the Hand class - should be used for tourneys though.
|
||||
# m.group('SB')
|
||||
# m.group('BB')
|
||||
|
@ -190,6 +220,7 @@ follow : whether to tail -f the input"""
|
|||
m = self.re_Antes.finditer(hand.handText)
|
||||
for player in m:
|
||||
logging.debug("hand.addAnte(%s,%s)" %(player.group('PNAME'), player.group('ANTE')))
|
||||
# if player.group() !=
|
||||
hand.addAnte(player.group('PNAME'), player.group('ANTE'))
|
||||
|
||||
def readBringIn(self, hand):
|
||||
|
@ -198,79 +229,46 @@ follow : whether to tail -f the input"""
|
|||
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")
|
||||
logging.warning("No bringin found, handid =%s" % hand.handid)
|
||||
|
||||
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 == None):
|
||||
#Not involved in hand
|
||||
hand.involved = False
|
||||
else:
|
||||
hand.hero = m.group('PNAME')
|
||||
# "2c, qh" -> set(["2c","qc"])
|
||||
# Also works with Omaha hands.
|
||||
cards = m.group('NEWCARDS')
|
||||
cards = [c.strip() for c in cards.split(' ')]
|
||||
hand.addHoleCards(cards, m.group('PNAME'))
|
||||
# streets PREFLOP, PREDRAW, and THIRD are special cases beacause
|
||||
# we need to grab hero's cards
|
||||
for street in ('PREFLOP', 'DEAL'):
|
||||
if street in hand.streets.keys():
|
||||
m = self.re_HeroCards.finditer(hand.streets[street])
|
||||
for found in m:
|
||||
# if m == None:
|
||||
# hand.involved = False
|
||||
# else:
|
||||
hand.hero = found.group('PNAME')
|
||||
newcards = found.group('NEWCARDS').split(' ')
|
||||
hand.addHoleCards(street, hand.hero, closed=newcards, shown=False, mucked=False, dealt=True)
|
||||
|
||||
for street, text in hand.streets.iteritems():
|
||||
if not text or street in ('PREFLOP', 'DEAL'): continue # already done these
|
||||
m = self.re_HeroCards.finditer(hand.streets[street])
|
||||
for found in m:
|
||||
player = found.group('PNAME')
|
||||
if found.group('NEWCARDS') == None:
|
||||
newcards = []
|
||||
else:
|
||||
newcards = found.group('NEWCARDS').split(' ')
|
||||
if found.group('OLDCARDS') == None:
|
||||
oldcards = []
|
||||
else:
|
||||
oldcards = found.group('OLDCARDS').split(' ')
|
||||
|
||||
if street == 'THIRD' and len(oldcards) == 2: # hero in stud game
|
||||
hand.hero = player
|
||||
hand.dealt.add(player) # need this for stud??
|
||||
hand.addHoleCards(street, player, closed=oldcards, open=newcards, shown=False, mucked=False, dealt=False)
|
||||
else:
|
||||
hand.addHoleCards(street, player, open=newcards, closed=oldcards, shown=False, mucked=False, dealt=False)
|
||||
|
||||
def readStudPlayerCards(self, hand, street):
|
||||
# This could be the most tricky one to get right.
|
||||
# It looks for cards dealt in 'street',
|
||||
# which may or may not be in the section of the hand designated 'street' by markStreets earlier.
|
||||
# Here's an example at FTP of what 'THIRD' and 'FOURTH' look like to hero PokerAscetic
|
||||
#
|
||||
#"*** 3RD STREET ***
|
||||
#Dealt to BFK23 [Th]
|
||||
#Dealt to cutiepr1nnymaid [8c]
|
||||
#Dealt to PokerAscetic [7c 8s] [3h]
|
||||
#..."
|
||||
#
|
||||
#"*** 4TH STREET ***
|
||||
#Dealt to cutiepr1nnymaid [8c] [2s]
|
||||
#Dealt to PokerAscetic [7c 8s 3h] [5s]
|
||||
#..."
|
||||
#Note that hero's first two holecards are only reported at 3rd street as 'old' cards.
|
||||
logging.debug("readStudPlayerCards")
|
||||
m = self.re_HeroCards.finditer(hand.streets[street])
|
||||
for player in m:
|
||||
logging.debug(player.groupdict())
|
||||
(pname, oldcards, newcards) = (player.group('PNAME'), player.group('OLDCARDS'), player.group('NEWCARDS'))
|
||||
if oldcards:
|
||||
oldcards = [c.strip() for c in oldcards.split(' ')]
|
||||
if newcards:
|
||||
newcards = [c.strip() for c in newcards.split(' ')]
|
||||
# options here:
|
||||
# (1) we trust the hand will know what to do -- probably check that the old cards match what it already knows, and add the newcards to this street.
|
||||
# (2) we're the experts at this particular history format and we know how we're going to be called (once for each street in Hand.streetList)
|
||||
# so call addPlayerCards with the appropriate information.
|
||||
# I favour (2) here but I'm afraid it is rather stud7-specific.
|
||||
# in the following, the final list of cards will be in 'newcards' whilst if the first list exists (most of the time it does) it will be in 'oldcards'
|
||||
if street=='ANTES':
|
||||
return
|
||||
elif street=='THIRD':
|
||||
# we'll have observed hero holecards in CARDS and thirdstreet open cards in 'NEWCARDS'
|
||||
# hero: [xx][o]
|
||||
# others: [o]
|
||||
hand.addPlayerCards(player = player.group('PNAME'), street = street, closed = oldcards, open = newcards)
|
||||
elif street in ('FOURTH', 'FIFTH', 'SIXTH'):
|
||||
# 4th:
|
||||
# hero: [xxo] [o]
|
||||
# others: [o] [o]
|
||||
# 5th:
|
||||
# hero: [xxoo] [o]
|
||||
# others: [oo] [o]
|
||||
# 6th:
|
||||
# hero: [xxooo] [o]
|
||||
# others: [ooo] [o]
|
||||
hand.addPlayerCards(player = player.group('PNAME'), street = street, open = newcards)
|
||||
# we may additionally want to check the earlier streets tally with what we have but lets trust it for now.
|
||||
elif street=='SEVENTH' and newcards:
|
||||
# hero: [xxoooo] [x]
|
||||
# others: not reported.
|
||||
hand.addPlayerCards(player = player.group('PNAME'), street = street, closed = newcards)
|
||||
|
||||
def readAction(self, hand, street):
|
||||
m = self.re_Action.finditer(hand.streets[street])
|
||||
|
@ -308,6 +306,29 @@ follow : whether to tail -f the input"""
|
|||
cards = cards.split(' ')
|
||||
hand.addShownCards(cards=cards, player=m.group('PNAME'))
|
||||
|
||||
def guessMaxSeats(self, hand):
|
||||
"""Return a guess at max_seats when not specified in HH."""
|
||||
mo = self.maxOccSeat(hand)
|
||||
|
||||
if mo == 10: return 10 #that was easy
|
||||
|
||||
if hand.gametype['base'] == 'stud':
|
||||
if mo <= 8: return 8
|
||||
else: return mo
|
||||
|
||||
if hand.gametype['base'] == 'draw':
|
||||
if mo <= 6: return 6
|
||||
else: return mo
|
||||
|
||||
if mo == 2: return 2
|
||||
if mo <= 6: return 6
|
||||
return 9
|
||||
|
||||
def readOther(self, hand):
|
||||
m = self.re_Mixed.search(self.in_path)
|
||||
if m == None: hand.mixed = None
|
||||
else:
|
||||
hand.mixed = self.mixes[m.groupdict()['MIXED']]
|
||||
|
||||
if __name__ == "__main__":
|
||||
parser = OptionParser()
|
||||
|
|
|
@ -154,31 +154,40 @@ class GuiAutoImport (threading.Thread):
|
|||
# results to the same pipe. This means that self.path should be a a list of dirs
|
||||
# to watch.
|
||||
if widget.get_active(): # toggled on
|
||||
self.doAutoImportBool = True
|
||||
widget.set_label(u' _Stop Autoimport ')
|
||||
if self.pipe_to_hud is None:
|
||||
if os.name == 'nt':
|
||||
command = "python HUD_main.py" + " " + self.settings['cl_options']
|
||||
bs = 0 # windows is not happy with line buffing here
|
||||
self.pipe_to_hud = subprocess.Popen(command, bufsize = bs, stdin = subprocess.PIPE,
|
||||
universal_newlines=True)
|
||||
else:
|
||||
command = os.path.join(sys.path[0], 'HUD_main.py')
|
||||
cl = [command, ] + string.split(self.settings['cl_options'])
|
||||
self.pipe_to_hud = subprocess.Popen(cl, bufsize = 1, stdin = subprocess.PIPE,
|
||||
universal_newlines=True)
|
||||
# - Does the lock acquisition need to be more sophisticated for multiple dirs?
|
||||
# (see comment above about what to do if pipe already open)
|
||||
# - Ideally we want to release the lock if the auto-import is killed by some
|
||||
# kind of exception - is this possible?
|
||||
if self.settings['global_lock'].acquire(False): # returns false immediately if lock not acquired
|
||||
print "\nGlobal lock taken ..."
|
||||
self.doAutoImportBool = True
|
||||
widget.set_label(u' _Stop Autoimport ')
|
||||
if self.pipe_to_hud is None:
|
||||
if os.name == 'nt':
|
||||
command = "python HUD_main.py" + " " + self.settings['cl_options']
|
||||
bs = 0 # windows is not happy with line buffing here
|
||||
self.pipe_to_hud = subprocess.Popen(command, bufsize = bs, stdin = subprocess.PIPE,
|
||||
universal_newlines=True)
|
||||
else:
|
||||
command = os.path.join(sys.path[0], 'HUD_main.py')
|
||||
cl = [command, ] + string.split(self.settings['cl_options'])
|
||||
self.pipe_to_hud = subprocess.Popen(cl, bufsize = 1, stdin = subprocess.PIPE,
|
||||
universal_newlines=True)
|
||||
|
||||
# Add directories to importer object.
|
||||
for site in self.input_settings:
|
||||
self.importer.addImportDirectory(self.input_settings[site][0], True, site, self.input_settings[site][1])
|
||||
print "Adding import directories - Site: " + site + " dir: "+ str(self.input_settings[site][0])
|
||||
self.do_import()
|
||||
# Add directories to importer object.
|
||||
for site in self.input_settings:
|
||||
self.importer.addImportDirectory(self.input_settings[site][0], True, site, self.input_settings[site][1])
|
||||
print "Adding import directories - Site: " + site + " dir: "+ str(self.input_settings[site][0])
|
||||
self.do_import()
|
||||
|
||||
interval=int(self.intervalEntry.get_text())
|
||||
gobject.timeout_add(interval*1000, self.do_import)
|
||||
interval=int(self.intervalEntry.get_text())
|
||||
gobject.timeout_add(interval*1000, self.do_import)
|
||||
else:
|
||||
print "auto-import aborted - global lock not available"
|
||||
else: # toggled off
|
||||
self.settings['global_lock'].release()
|
||||
self.doAutoImportBool = False # do_import will return this and stop the gobject callback timer
|
||||
print "Stopping autoimport"
|
||||
print "Stopping autoimport - global lock released."
|
||||
if self.pipe_to_hud.poll() is not None:
|
||||
print "HUD already terminated"
|
||||
else:
|
||||
|
@ -186,8 +195,6 @@ class GuiAutoImport (threading.Thread):
|
|||
self.pipe_to_hud.communicate('\n') # waits for process to terminate
|
||||
self.pipe_to_hud = None
|
||||
self.startButton.set_label(u' _Start Autoimport ')
|
||||
|
||||
|
||||
|
||||
#end def GuiAutoImport.startClicked
|
||||
|
||||
|
|
|
@ -34,6 +34,7 @@ import Configuration
|
|||
|
||||
class GuiBulkImport():
|
||||
|
||||
# not used
|
||||
def import_dir(self):
|
||||
"""imports a directory, non-recursive. todo: move this to fpdb_import so CLI can use it"""
|
||||
|
||||
|
@ -49,47 +50,57 @@ class GuiBulkImport():
|
|||
self.importer.RunImportThreaded()
|
||||
|
||||
def load_clicked(self, widget, data=None):
|
||||
# get the dir to import from the chooser
|
||||
self.inputFile = self.chooser.get_filename()
|
||||
# Does the lock acquisition need to be more sophisticated for multiple dirs?
|
||||
# (see comment above about what to do if pipe already open)
|
||||
if self.settings['global_lock'].acquire(False): # returns false immediately if lock not acquired
|
||||
try:
|
||||
print "\nGlobal lock taken ..."
|
||||
# get the dir to import from the chooser
|
||||
self.inputFile = self.chooser.get_filename()
|
||||
|
||||
# get the import settings from the gui and save in the importer
|
||||
self.importer.setHandCount(int(self.spin_hands.get_text()))
|
||||
self.importer.setMinPrint(int(self.spin_hands.get_text()))
|
||||
self.importer.setQuiet(self.chk_st_st.get_active())
|
||||
self.importer.setFailOnError(self.chk_fail.get_active())
|
||||
self.importer.setThreads(int(self.spin_threads.get_text()))
|
||||
self.importer.setHandsInDB(self.n_hands_in_db)
|
||||
cb_model = self.cb_dropindexes.get_model()
|
||||
cb_index = self.cb_dropindexes.get_active()
|
||||
if cb_index:
|
||||
self.importer.setDropIndexes(cb_model[cb_index][0])
|
||||
# get the import settings from the gui and save in the importer
|
||||
self.importer.setHandCount(int(self.spin_hands.get_text()))
|
||||
self.importer.setMinPrint(int(self.spin_hands.get_text()))
|
||||
self.importer.setQuiet(self.chk_st_st.get_active())
|
||||
self.importer.setFailOnError(self.chk_fail.get_active())
|
||||
self.importer.setThreads(int(self.spin_threads.get_text()))
|
||||
self.importer.setHandsInDB(self.n_hands_in_db)
|
||||
cb_model = self.cb_dropindexes.get_model()
|
||||
cb_index = self.cb_dropindexes.get_active()
|
||||
if cb_index:
|
||||
self.importer.setDropIndexes(cb_model[cb_index][0])
|
||||
else:
|
||||
self.importer.setDropIndexes("auto")
|
||||
sitename = self.cbfilter.get_model()[self.cbfilter.get_active()][0]
|
||||
self.lab_info.set_text("Importing")
|
||||
|
||||
self.importer.addBulkImportImportFileOrDir(self.inputFile, site = sitename)
|
||||
self.importer.setCallHud(False)
|
||||
starttime = time()
|
||||
(stored, dups, partial, errs, ttime) = self.importer.runImport()
|
||||
ttime = time() - starttime
|
||||
if ttime == 0:
|
||||
ttime = 1
|
||||
print 'GuiBulkImport.load done: Stored: %d \tDuplicates: %d \tPartial: %d \tErrors: %d in %s seconds - %d/sec'\
|
||||
% (stored, dups, partial, errs, ttime, stored / ttime)
|
||||
self.importer.clearFileList()
|
||||
|
||||
self.lab_info.set_text("Import finished")
|
||||
except:
|
||||
print "bulkimport.loadclicked error: "+str(sys.exc_value)
|
||||
pass
|
||||
self.settings['global_lock'].release()
|
||||
else:
|
||||
self.importer.setDropIndexes("auto")
|
||||
sitename = self.cbfilter.get_model()[self.cbfilter.get_active()][0]
|
||||
self.lab_info.set_text("Importing")
|
||||
|
||||
self.importer.addBulkImportImportFileOrDir(self.inputFile, site = sitename)
|
||||
self.importer.setCallHud(False)
|
||||
starttime = time()
|
||||
(stored, dups, partial, errs, ttime) = self.importer.runImport()
|
||||
ttime = time() - starttime
|
||||
if ttime == 0:
|
||||
ttime = 1
|
||||
print 'GuiBulkImport.import_dir done: Stored: %d \tDuplicates: %d \tPartial: %d \tErrors: %d in %s seconds - %d/sec'\
|
||||
% (stored, dups, partial, errs, ttime, stored / ttime)
|
||||
self.importer.clearFileList()
|
||||
|
||||
self.lab_info.set_text("Import finished")
|
||||
print "bulk-import aborted - global lock not available"
|
||||
|
||||
def get_vbox(self):
|
||||
"""returns the vbox of this thread"""
|
||||
return self.vbox
|
||||
|
||||
def __init__(self, settings, config):
|
||||
def __init__(self, settings, config, sql = None):
|
||||
self.settings = settings
|
||||
self.config = config
|
||||
self.importer = fpdb_import.Importer(self, self.settings,
|
||||
config)
|
||||
self.importer = fpdb_import.Importer(self, self.settings, config, sql)
|
||||
|
||||
self.vbox = gtk.VBox(False, 0)
|
||||
self.vbox.show()
|
||||
|
@ -196,10 +207,11 @@ class GuiBulkImport():
|
|||
self.load_button.show()
|
||||
|
||||
# see how many hands are in the db and adjust accordingly
|
||||
tcursor = self.importer.fdb.db.cursor()
|
||||
tcursor = self.importer.database.cursor
|
||||
tcursor.execute("Select count(1) from Hands")
|
||||
row = tcursor.fetchone()
|
||||
tcursor.close()
|
||||
self.importer.database.rollback()
|
||||
self.n_hands_in_db = row[0]
|
||||
if self.n_hands_in_db == 0:
|
||||
self.cb_dropindexes.set_active(2)
|
||||
|
@ -252,7 +264,8 @@ def main(argv=None):
|
|||
else:
|
||||
#Do something useful
|
||||
importer = fpdb_import.Importer(False,settings, config)
|
||||
importer.setDropIndexes("auto")
|
||||
# importer.setDropIndexes("auto")
|
||||
importer.setDropIndexes("don't drop")
|
||||
importer.setFailOnError(options.failOnError)
|
||||
importer.addBulkImportImportFileOrDir(os.path.expanduser(options.filename), site=options.filtername)
|
||||
importer.setCallHud(False)
|
||||
|
|
|
@ -38,20 +38,19 @@ except:
|
|||
and HUD are NOT affected by this problem."""
|
||||
|
||||
import fpdb_import
|
||||
import fpdb_db
|
||||
import Database
|
||||
import Filters
|
||||
|
||||
class GuiGraphViewer (threading.Thread):
|
||||
|
||||
def __init__(self, querylist, config, debug=True):
|
||||
"""Constructor for GraphViewer"""
|
||||
self.debug=debug
|
||||
#print "start of GraphViewer constructor"
|
||||
self.db = fpdb_db.fpdb_db() # sets self.fdb.db self.fdb.cursor and self.fdb.sql
|
||||
self.db.do_connect(config)
|
||||
|
||||
self.sql = querylist
|
||||
self.conf = config
|
||||
self.debug = debug
|
||||
#print "start of GraphViewer constructor"
|
||||
self.db = Database.Database(self.conf, sql=self.sql)
|
||||
|
||||
|
||||
filters_display = { "Heroes" : True,
|
||||
"Sites" : True,
|
||||
|
@ -63,7 +62,7 @@ class GuiGraphViewer (threading.Thread):
|
|||
"Button2" : True
|
||||
}
|
||||
|
||||
self.filters = Filters.Filters(self.db, config, querylist, display = filters_display)
|
||||
self.filters = Filters.Filters(self.db, self.conf, self.sql, display = filters_display)
|
||||
self.filters.registerButton1Name("Refresh Graph")
|
||||
self.filters.registerButton1Callback(self.generateGraph)
|
||||
self.filters.registerButton2Name("Export to File")
|
||||
|
@ -90,7 +89,7 @@ class GuiGraphViewer (threading.Thread):
|
|||
self.canvas = None
|
||||
|
||||
|
||||
self.db.db.rollback()
|
||||
self.db.rollback()
|
||||
|
||||
#################################
|
||||
#
|
||||
|
@ -126,7 +125,7 @@ class GuiGraphViewer (threading.Thread):
|
|||
#end def get_vbox
|
||||
|
||||
def clearGraphData(self):
|
||||
self.fig.clf()
|
||||
self.fig.clear()
|
||||
if self.canvas is not None:
|
||||
self.canvas.destroy()
|
||||
|
||||
|
@ -154,7 +153,7 @@ class GuiGraphViewer (threading.Thread):
|
|||
if not sitenos:
|
||||
#Should probably pop up here.
|
||||
print "No sites selected - defaulting to PokerStars"
|
||||
sitenos = [2]
|
||||
return
|
||||
|
||||
if not playerids:
|
||||
print "No player ids found"
|
||||
|
@ -197,6 +196,7 @@ class GuiGraphViewer (threading.Thread):
|
|||
|
||||
self.graphBox.add(self.canvas)
|
||||
self.canvas.show()
|
||||
self.canvas.draw()
|
||||
#self.exportButton.set_sensitive(True)
|
||||
#end of def showClicked
|
||||
|
||||
|
@ -205,7 +205,7 @@ class GuiGraphViewer (threading.Thread):
|
|||
# print "DEBUG: getRingProfitGraph"
|
||||
start_date, end_date = self.filters.getDates()
|
||||
|
||||
#Buggered if I can find a way to do this 'nicely' take a list of intergers and longs
|
||||
#Buggered if I can find a way to do this 'nicely' take a list of integers and longs
|
||||
# and turn it into a tuple readale by sql.
|
||||
# [5L] into (5) not (5,) and [5L, 2829L] into (5, 2829)
|
||||
nametest = str(tuple(names))
|
||||
|
@ -229,7 +229,7 @@ class GuiGraphViewer (threading.Thread):
|
|||
self.db.cursor.execute(tmp)
|
||||
#returns (HandId,Winnings,Costs,Profit)
|
||||
winnings = self.db.cursor.fetchall()
|
||||
self.db.db.rollback()
|
||||
self.db.rollback()
|
||||
|
||||
if(winnings == ()):
|
||||
return None
|
||||
|
|
|
@ -20,34 +20,35 @@ import pygtk
|
|||
pygtk.require('2.0')
|
||||
import gtk
|
||||
import os
|
||||
import sys
|
||||
from time import time, strftime
|
||||
|
||||
import Card
|
||||
import fpdb_import
|
||||
import Database
|
||||
import fpdb_db
|
||||
import Filters
|
||||
import FpdbSQLQueries
|
||||
|
||||
class GuiPlayerStats (threading.Thread):
|
||||
def __init__(self, config, querylist, mainwin, debug=True):
|
||||
self.debug=debug
|
||||
self.conf=config
|
||||
self.main_window=mainwin
|
||||
self.debug = debug
|
||||
self.conf = config
|
||||
self.main_window = mainwin
|
||||
self.sql = querylist
|
||||
|
||||
self.MYSQL_INNODB = 2
|
||||
self.PGSQL = 3
|
||||
self.SQLITE = 4
|
||||
|
||||
|
||||
# create new db connection to avoid conflicts with other threads
|
||||
self.db = fpdb_db.fpdb_db()
|
||||
self.db.do_connect(self.conf)
|
||||
self.cursor=self.db.cursor
|
||||
self.sql = querylist
|
||||
self.db = Database.Database(self.conf, sql=self.sql)
|
||||
self.cursor = self.db.cursor
|
||||
|
||||
settings = {}
|
||||
settings.update(config.get_db_parameters())
|
||||
settings.update(config.get_tv_parameters())
|
||||
settings.update(config.get_import_parameters())
|
||||
settings.update(config.get_default_paths())
|
||||
settings.update(self.conf.get_db_parameters())
|
||||
settings.update(self.conf.get_tv_parameters())
|
||||
settings.update(self.conf.get_import_parameters())
|
||||
settings.update(self.conf.get_default_paths())
|
||||
|
||||
# text used on screen stored here so that it can be configured
|
||||
self.filterText = {'handhead':'Hand Breakdown for all levels listed above'
|
||||
|
@ -66,7 +67,7 @@ class GuiPlayerStats (threading.Thread):
|
|||
"Button2" : True
|
||||
}
|
||||
|
||||
self.filters = Filters.Filters(self.db, config, querylist, display = filters_display)
|
||||
self.filters = Filters.Filters(self.db, self.conf, self.sql, display = filters_display)
|
||||
self.filters.registerButton1Name("_Filters")
|
||||
self.filters.registerButton1Callback(self.showDetailFilter)
|
||||
self.filters.registerButton2Name("_Refresh")
|
||||
|
@ -216,7 +217,7 @@ class GuiPlayerStats (threading.Thread):
|
|||
flags = [True]
|
||||
self.addTable(vbox1, 'playerDetailedStats', flags, playerids, sitenos, limits, seats, groups, dates)
|
||||
|
||||
self.db.db.commit()
|
||||
self.db.rollback()
|
||||
print "Stats page displayed in %4.2f seconds" % (time() - starttime)
|
||||
#end def fillStatsFrame(self, vbox):
|
||||
|
||||
|
@ -280,8 +281,10 @@ class GuiPlayerStats (threading.Thread):
|
|||
if column[colalias] == 'plposition':
|
||||
if value == 'B':
|
||||
value = 'BB'
|
||||
if value == 'S':
|
||||
elif value == 'S':
|
||||
value = 'SB'
|
||||
elif value == '0':
|
||||
value = 'Btn'
|
||||
else:
|
||||
if column[colalias] == 'game':
|
||||
if holecards:
|
||||
|
@ -379,7 +382,8 @@ class GuiPlayerStats (threading.Thread):
|
|||
|
||||
# Group by position?
|
||||
if groups['posn']:
|
||||
query = query.replace("<position>", 'hp.position')
|
||||
#query = query.replace("<position>", "case hp.position when '0' then 'Btn' else hp.position end")
|
||||
query = query.replace("<position>", "hp.position")
|
||||
# set flag in self.columns to show posn column
|
||||
[x for x in self.columns if x[0] == 'plposition'][0][1] = True
|
||||
else:
|
||||
|
|
|
@ -23,29 +23,28 @@ import os
|
|||
from time import time, strftime
|
||||
|
||||
import fpdb_import
|
||||
import fpdb_db
|
||||
import Database
|
||||
import Filters
|
||||
import FpdbSQLQueries
|
||||
|
||||
class GuiPositionalStats (threading.Thread):
|
||||
def __init__(self, config, querylist, debug=True):
|
||||
self.debug=debug
|
||||
self.conf=config
|
||||
self.debug = debug
|
||||
self.conf = config
|
||||
self.sql = querylist
|
||||
self.MYSQL_INNODB = 2
|
||||
self.PGSQL = 3
|
||||
self.SQLITE = 4
|
||||
|
||||
# create new db connection to avoid conflicts with other threads
|
||||
self.db = fpdb_db.fpdb_db()
|
||||
self.db.do_connect(self.conf)
|
||||
self.cursor=self.db.cursor
|
||||
self.sql = querylist
|
||||
self.db = Database.Database(self.conf, sql=self.sql)
|
||||
self.cursor = self.db.cursor
|
||||
|
||||
settings = {}
|
||||
settings.update(config.get_db_parameters())
|
||||
settings.update(config.get_tv_parameters())
|
||||
settings.update(config.get_import_parameters())
|
||||
settings.update(config.get_default_paths())
|
||||
settings.update(self.conf.get_db_parameters())
|
||||
settings.update(self.conf.get_tv_parameters())
|
||||
settings.update(self.conf.get_import_parameters())
|
||||
settings.update(self.conf.get_default_paths())
|
||||
|
||||
filters_display = { "Heroes" : True,
|
||||
"Sites" : True,
|
||||
|
@ -59,7 +58,7 @@ class GuiPositionalStats (threading.Thread):
|
|||
"Button2" : False
|
||||
}
|
||||
|
||||
self.filters = Filters.Filters(self.db, config, querylist, display = filters_display)
|
||||
self.filters = Filters.Filters(self.db, self.conf, self.sql, display = filters_display)
|
||||
self.filters.registerButton1Name("Refresh")
|
||||
self.filters.registerButton1Callback(self.refreshStats)
|
||||
|
||||
|
@ -319,7 +318,7 @@ class GuiPositionalStats (threading.Thread):
|
|||
row = row + 1
|
||||
vbox.show_all()
|
||||
|
||||
self.db.db.rollback()
|
||||
self.db.rollback()
|
||||
print "Positional Stats page displayed in %4.2f seconds" % (time() - starttime)
|
||||
#end def fillStatsFrame(self, vbox):
|
||||
|
||||
|
|
|
@ -25,29 +25,28 @@ from numpy import diff, nonzero
|
|||
|
||||
import Card
|
||||
import fpdb_import
|
||||
import fpdb_db
|
||||
import Database
|
||||
import Filters
|
||||
import FpdbSQLQueries
|
||||
|
||||
class GuiSessionViewer (threading.Thread):
|
||||
def __init__(self, config, querylist, debug=True):
|
||||
self.debug=debug
|
||||
self.conf=config
|
||||
self.debug = debug
|
||||
self.conf = config
|
||||
self.sql = querylist
|
||||
self.MYSQL_INNODB = 2
|
||||
self.PGSQL = 3
|
||||
self.SQLITE = 4
|
||||
|
||||
# create new db connection to avoid conflicts with other threads
|
||||
self.db = fpdb_db.fpdb_db()
|
||||
self.db.do_connect(self.conf)
|
||||
self.cursor=self.db.cursor
|
||||
self.sql = querylist
|
||||
self.db = Database.Database(self.conf, sql=self.sql)
|
||||
self.cursor = self.db.cursor
|
||||
|
||||
settings = {}
|
||||
settings.update(config.get_db_parameters())
|
||||
settings.update(config.get_tv_parameters())
|
||||
settings.update(config.get_import_parameters())
|
||||
settings.update(config.get_default_paths())
|
||||
settings.update(self.conf.get_db_parameters())
|
||||
settings.update(self.conf.get_tv_parameters())
|
||||
settings.update(self.conf.get_import_parameters())
|
||||
settings.update(self.conf.get_default_paths())
|
||||
|
||||
# text used on screen stored here so that it can be configured
|
||||
self.filterText = {'handhead':'Hand Breakdown for all levels listed above'
|
||||
|
@ -66,7 +65,7 @@ class GuiSessionViewer (threading.Thread):
|
|||
"Button2" : True
|
||||
}
|
||||
|
||||
self.filters = Filters.Filters(self.db, settings, config, querylist, display = filters_display)
|
||||
self.filters = Filters.Filters(self.db, self.conf, self.sql, display = filters_display)
|
||||
self.filters.registerButton2Name("_Refresh")
|
||||
self.filters.registerButton2Callback(self.refreshStats)
|
||||
|
||||
|
@ -195,7 +194,7 @@ class GuiSessionViewer (threading.Thread):
|
|||
flags = [True]
|
||||
self.addTable(vbox1, 'playerDetailedStats', flags, playerids, sitenos, limits, seats)
|
||||
|
||||
self.db.db.commit()
|
||||
self.db.rollback()
|
||||
print "Stats page displayed in %4.2f seconds" % (time() - starttime)
|
||||
#end def fillStatsFrame(self, vbox):
|
||||
|
||||
|
|
|
@ -159,6 +159,50 @@
|
|||
<location seat="9" x="70" y="53"> </location>
|
||||
</layout>
|
||||
</site>
|
||||
|
||||
<site enabled="False"
|
||||
site_name="Win2day"
|
||||
table_finder="Win2day.exe"
|
||||
screen_name="YOUR SCREEN NAME HERE"
|
||||
site_path=""
|
||||
HH_path=""
|
||||
decoder="everleaf_decode_table"
|
||||
converter="Win2dayToFpdb"
|
||||
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_games>
|
||||
|
@ -292,6 +336,7 @@
|
|||
<hhc site="PokerStars" converter="PokerStarsToFpdb"/>
|
||||
<hhc site="Full Tilt Poker" converter="FulltiltToFpdb"/>
|
||||
<hhc site="Everleaf" converter="EverleafToFpdb"/>
|
||||
<hhc site="Win2day" converter="Win2dayToFpdb"/>
|
||||
</hhcs>
|
||||
|
||||
<supported_databases>
|
||||
|
@ -300,4 +345,3 @@
|
|||
|
||||
</FreePokerToolsConfig>
|
||||
|
||||
|
||||
|
|
350
pyfpdb/Hand.py
350
pyfpdb/Hand.py
|
@ -32,14 +32,14 @@ import pprint
|
|||
import DerivedStats
|
||||
import Card
|
||||
|
||||
class Hand:
|
||||
class Hand(object):
|
||||
|
||||
###############################################################3
|
||||
# Class Variables
|
||||
UPS = {'a':'A', 't':'T', 'j':'J', 'q':'Q', 'k':'K', 'S':'s', 'C':'c', 'H':'h', 'D':'d'}
|
||||
LCS = {'H':'h', 'D':'d', 'C':'c', 'S':'s'}
|
||||
SYMBOL = {'USD': '$', 'EUR': u'E', 'T$': '', 'play': ''}
|
||||
MS = {'horse' : 'HORSE', '8game' : '8-Game', 'hose' : 'HOSE'}
|
||||
SYMBOL = {'USD': '$', 'EUR': u'$', 'T$': '', 'play': ''}
|
||||
MS = {'horse' : 'HORSE', '8game' : '8-Game', 'hose' : 'HOSE', 'ha': 'HA'}
|
||||
|
||||
|
||||
def __init__(self, sitename, gametype, handText, builtFrom = "HHC"):
|
||||
|
@ -51,7 +51,7 @@ class Hand:
|
|||
self.handid = 0
|
||||
self.tablename = ""
|
||||
self.hero = ""
|
||||
self.maxseats = 10
|
||||
self.maxseats = None
|
||||
self.counted_seats = 0
|
||||
self.buttonpos = 0
|
||||
self.tourNo = None
|
||||
|
@ -81,7 +81,6 @@ class Hand:
|
|||
self.holecards[street] = {} # dict from player names to holecards
|
||||
self.discards[street] = {} # dict from player names to dicts by street ... of tuples ... of discarded holecards
|
||||
# Collections indexed by player names
|
||||
# self.holecards = {} # dict from player names to dicts by street ... of tuples ... of holecards
|
||||
self.stacks = {}
|
||||
self.collected = [] #list of ?
|
||||
self.collectees = {} # dict from player names to amounts collected (?)
|
||||
|
@ -92,12 +91,14 @@ class Hand:
|
|||
self.shown = set() # cards were shown
|
||||
self.mucked = set() # cards were mucked at showdown
|
||||
|
||||
# self.action = []
|
||||
# Things to do with money
|
||||
self.pot = Pot()
|
||||
self.totalpot = None
|
||||
self.totalcollected = None
|
||||
self.rake = None
|
||||
# currency symbol for this hand
|
||||
self.sym = self.SYMBOL[self.gametype['currency']] # save typing! delete this attr when done
|
||||
self.pot.setSym(self.sym)
|
||||
|
||||
def __str__(self):
|
||||
vars = ( ("BB", self.bb),
|
||||
|
@ -171,6 +172,9 @@ dealt whether they were seen in a 'dealt to' line
|
|||
|
||||
self.holecards[street][player] = [open, closed]
|
||||
|
||||
def prepInsert(self, db):
|
||||
pass
|
||||
|
||||
def insert(self, db):
|
||||
""" Function to insert Hand into database
|
||||
Should not commit, and do minimal selects. Callers may want to cache commits
|
||||
|
@ -259,6 +263,7 @@ chips (string) the chips the player has at the start of the hand (can be None)
|
|||
If a player has None chips he won't be added."""
|
||||
logging.debug("addPlayer: %s %s (%s)" % (seat, name, chips))
|
||||
if chips is not None:
|
||||
chips = re.sub(u',', u'', chips) #some sites have commas
|
||||
self.players.append([seat, name, chips])
|
||||
self.stacks[name] = Decimal(chips)
|
||||
self.pot.addPlayer(name)
|
||||
|
@ -297,6 +302,7 @@ If a player has None chips he won't be added."""
|
|||
def addAnte(self, player, ante):
|
||||
logging.debug("%s %s antes %s" % ('ANTES', player, ante))
|
||||
if player is not None:
|
||||
ante = re.sub(u',', u'', ante) #some sites have commas
|
||||
self.bets['ANTES'][player].append(Decimal(ante))
|
||||
self.stacks[player] -= Decimal(ante)
|
||||
act = (player, 'posts', "ante", ante, self.stacks[player]==0)
|
||||
|
@ -315,6 +321,7 @@ If a player has None chips he won't be added."""
|
|||
|
||||
logging.debug("addBlind: %s posts %s, %s" % (player, blindtype, amount))
|
||||
if player is not None:
|
||||
amount = re.sub(u',', u'', amount) #some sites have commas
|
||||
self.bets['PREFLOP'][player].append(Decimal(amount))
|
||||
self.stacks[player] -= Decimal(amount)
|
||||
#print "DEBUG %s posts, stack %s" % (player, self.stacks[player])
|
||||
|
@ -332,6 +339,8 @@ If a player has None chips he won't be added."""
|
|||
|
||||
|
||||
def addCall(self, street, player=None, amount=None):
|
||||
if amount:
|
||||
amount = re.sub(u',', u'', amount) #some sites have commas
|
||||
logging.debug("%s %s calls %s" %(street, player, amount))
|
||||
# Potentially calculate the amount of the call if not supplied
|
||||
# corner cases include if player would be all in
|
||||
|
@ -359,6 +368,7 @@ Add a raise by amountBy on [street] by [player]
|
|||
# then: C = Bp - Bc (amount to call)
|
||||
# Rt = Bp + Rb (raise to)
|
||||
#
|
||||
amountBy = re.sub(u',', u'', amountBy) #some sites have commas
|
||||
self.checkPlayerExists(player)
|
||||
Rb = Decimal(amountBy)
|
||||
Bp = self.lastBet[street]
|
||||
|
@ -376,6 +386,7 @@ Add a raise by amountBy on [street] by [player]
|
|||
"""\
|
||||
For sites which by "raises x" mean "calls and raises putting a total of x in the por". """
|
||||
self.checkPlayerExists(player)
|
||||
amount = re.sub(u',', u'', amount) #some sites have commas
|
||||
CRb = Decimal(amount)
|
||||
Bp = self.lastBet[street]
|
||||
Bc = reduce(operator.add, self.bets[street][player], 0)
|
||||
|
@ -391,6 +402,7 @@ Add a raise on [street] by [player] to [amountTo]
|
|||
"""
|
||||
#CG - No idea if this function has been test/verified
|
||||
self.checkPlayerExists(player)
|
||||
amountTo = re.sub(u',', u'', amountTo) #some sites have commas
|
||||
Bp = self.lastBet[street]
|
||||
Bc = reduce(operator.add, self.bets[street][player], 0)
|
||||
Rt = Decimal(amountTo)
|
||||
|
@ -411,6 +423,7 @@ Add a raise on [street] by [player] to [amountTo]
|
|||
|
||||
def addBet(self, street, player, amount):
|
||||
logging.debug("%s %s bets %s" %(street, player, amount))
|
||||
amount = re.sub(u',', u'', amount) #some sites have commas
|
||||
self.checkPlayerExists(player)
|
||||
self.bets[street][player].append(Decimal(amount))
|
||||
self.stacks[player] -= Decimal(amount)
|
||||
|
@ -523,55 +536,64 @@ Map the tuple self.gametype onto the pokerstars string describing it
|
|||
elif act[1] == 'checks':
|
||||
return ("%s: checks " %(act[0]))
|
||||
elif act[1] == 'calls':
|
||||
return ("%s: calls $%s%s" %(act[0], act[2], ' and is all-in' if act[3] else ''))
|
||||
return ("%s: calls %s%s%s" %(act[0], self.sym, act[2], ' and is all-in' if act[3] else ''))
|
||||
elif act[1] == 'bets':
|
||||
return ("%s: bets $%s%s" %(act[0], act[2], ' and is all-in' if act[3] else ''))
|
||||
return ("%s: bets %s%s%s" %(act[0], self.sym, act[2], ' and is all-in' if act[3] else ''))
|
||||
elif act[1] == 'raises':
|
||||
return ("%s: raises $%s to $%s%s" %(act[0], act[2], act[3], ' and is all-in' if act[5] else ''))
|
||||
return ("%s: raises %s%s to %s%s%s" %(act[0], self.sym, act[2], self.sym, act[3], ' and is all-in' if act[5] else ''))
|
||||
elif act[1] == 'completea':
|
||||
return ("%s: completes to $%s%s" %(act[0], act[2], ' and is all-in' if act[3] else ''))
|
||||
return ("%s: completes to %s%s%s" %(act[0], self.sym, act[2], ' and is all-in' if act[3] else ''))
|
||||
elif act[1] == 'posts':
|
||||
if(act[2] == "small blind"):
|
||||
return ("%s: posts small blind $%s%s" %(act[0], act[3], ' and is all-in' if act[4] else ''))
|
||||
return ("%s: posts small blind %s%s%s" %(act[0], self.sym, act[3], ' and is all-in' if act[4] else ''))
|
||||
elif(act[2] == "big blind"):
|
||||
return ("%s: posts big blind $%s%s" %(act[0], act[3], ' and is all-in' if act[4] else ''))
|
||||
return ("%s: posts big blind %s%s%s" %(act[0], self.sym, act[3], ' and is all-in' if act[4] else ''))
|
||||
elif(act[2] == "both"):
|
||||
return ("%s: posts small & big blinds $%s%s" %(act[0], act[3], ' and is all-in' if act[4] else ''))
|
||||
return ("%s: posts small & big blinds %s%s%s" %(act[0], self.sym, act[3], ' and is all-in' if act[4] else ''))
|
||||
elif act[1] == 'bringin':
|
||||
return ("%s: brings in for $%s%s" %(act[0], act[2], ' and is all-in' if act[3] else ''))
|
||||
return ("%s: brings in for %s%s%s" %(act[0], self.sym, act[2], ' and is all-in' if act[3] else ''))
|
||||
elif act[1] == 'discards':
|
||||
return ("%s: discards %s %s%s" %(act[0], act[2], 'card' if act[2] == 1 else 'cards' , " [" + " ".join(self.discards[act[0]]['DRAWONE']) + "]" if self.hero == act[0] else ''))
|
||||
elif act[1] == 'stands pat':
|
||||
return ("%s: stands pat" %(act[0]))
|
||||
|
||||
def getStakesAsString(self):
|
||||
retstring = "%s%s/%s%s" % (self.SYMBOL[self.gametype['currency']], self.sb, self.SYMBOL[self.gametype['currency']], self.bb)
|
||||
return retstring
|
||||
"""Return a string of the stakes of the current hand."""
|
||||
return "%s%s/%s%s" % (self.sym, self.sb, self.sym, self.bb)
|
||||
|
||||
def writeGameLine(self):
|
||||
# print >>fh, ("%s Game #%s: %s ($%s/$%s) - %s" %("PokerStars", self.handid, self.getGameTypeAsString(), self.sb, self.bb, datetime.datetime.strftime(self.starttime,'%Y/%m/%d - %H:%M:%S ET')))
|
||||
game_string = "PokerStars Game #%s: " % self.handid
|
||||
if self.tourNo != None:
|
||||
game_string = game_string + "Tournament #%s, %s %s - Level %s (%s) - " % (self.tourNo,
|
||||
"""Return the first HH line for the current hand."""
|
||||
gs = "PokerStars Game #%s: " % self.handid
|
||||
|
||||
if self.tourNo != None and self.mixed != None: # mixed tournament
|
||||
gs = gs + "Tournament #%s, %s %s (%s) - Level %s (%s) - " % (self.tourNo, self.buyin, self.MS[self.mixed], self.getGameTypeAsString(), self.level, self.getStakesAsString())
|
||||
elif self.tourNo != None: # all other tournaments
|
||||
gs = gs + "Tournament #%s, %s %s - Level %s (%s) - " % (self.tourNo,
|
||||
self.buyin, self.getGameTypeAsString(), self.level, self.getStakesAsString())
|
||||
elif self.mixed != None:
|
||||
game_string = game_string + " %s (%s, %s) - " % (self.MS[self.mixed],
|
||||
elif self.mixed != None: # all other mixed games
|
||||
gs = gs + " %s (%s, %s) - " % (self.MS[self.mixed],
|
||||
self.getGameTypeAsString(), self.getStakesAsString())
|
||||
else:
|
||||
game_string = game_string + " %s (%s) - " % (self.getGameTypeAsString(), self.getStakesAsString())
|
||||
game_string = game_string + datetime.datetime.strftime(self.starttime,'%Y/%m/%d %H:%M:%S ET')
|
||||
return game_string
|
||||
else: # non-mixed cash games
|
||||
gs = gs + " %s (%s) - " % (self.getGameTypeAsString(), self.getStakesAsString())
|
||||
|
||||
return gs + datetime.datetime.strftime(self.starttime,'%Y/%m/%d %H:%M:%S ET')
|
||||
|
||||
|
||||
def writeTableLine(self):
|
||||
table_string = "Table \'%s\' %s-max" % (self.tablename, self.maxseats)
|
||||
if self.gametype['currency'] == 'play':
|
||||
table_string = table_string + " (Play Money)"
|
||||
if self.buttonpos != None:
|
||||
if self.buttonpos != None and self.buttonpos != 0:
|
||||
table_string = table_string + " Seat #%s is the button" % self.buttonpos
|
||||
return table_string
|
||||
|
||||
|
||||
def writeHand(self, fh=sys.__stdout__):
|
||||
# PokerStars format.
|
||||
print >>fh, self.writeGameLine()
|
||||
print >>fh, self.writeTableLine()
|
||||
|
||||
|
||||
class HoldemOmahaHand(Hand):
|
||||
def __init__(self, hhc, sitename, gametype, handText, builtFrom = "HHC", handid=None):
|
||||
if gametype['base'] != 'hold':
|
||||
|
@ -608,6 +630,9 @@ class HoldemOmahaHand(Hand):
|
|||
hhc.readShownCards(self)
|
||||
self.totalPot() # finalise it (total the pot)
|
||||
hhc.getRake(self)
|
||||
if self.maxseats == None:
|
||||
self.maxseats = hhc.guessMaxSeats(self)
|
||||
hhc.readOther(self)
|
||||
elif builtFrom == "DB":
|
||||
if handid is not None:
|
||||
self.select(handid) # Will need a handId
|
||||
|
@ -635,8 +660,8 @@ class HoldemOmahaHand(Hand):
|
|||
def render_stack(context,data):
|
||||
pat = context.tag.patternGenerator('list_item')
|
||||
for player in data:
|
||||
x = "Seat %s: %s ($%s in chips) " %(player[0], player[1],
|
||||
player[2])
|
||||
x = "Seat %s: %s (%s%s in chips) " %(player[0], player[1],
|
||||
self.sym, player[2])
|
||||
context.tag[ pat().fillSlots('playerStack', x)]
|
||||
return context.tag
|
||||
|
||||
|
@ -723,12 +748,8 @@ class HoldemOmahaHand(Hand):
|
|||
|
||||
def writeHand(self, fh=sys.__stdout__):
|
||||
# PokerStars format.
|
||||
# print >>fh, ("%s Game #%s: %s ($%s/$%s) - %s" %("PokerStars", self.handid, self.getGameTypeAsString(), self.sb, self.bb, datetime.datetime.strftime(self.starttime,'%Y/%m/%d - %H:%M:%S ET')))
|
||||
print >>fh, self.writeGameLine()
|
||||
print >>fh, self.writeTableLine()
|
||||
super(HoldemOmahaHand, self).writeHand(fh)
|
||||
|
||||
# print >>fh, ("Table '%s' %d-max Seat #%s is the button" %(self.tablename, self.maxseats, self.buttonpos))
|
||||
|
||||
players_who_act_preflop = set(([x[0] for x in self.actions['PREFLOP']]+[x[0] for x in self.actions['BLINDSANTES']]))
|
||||
logging.debug(self.actions['PREFLOP'])
|
||||
for player in [x for x in self.players if x[1] in players_who_act_preflop]:
|
||||
|
@ -793,16 +814,16 @@ class HoldemOmahaHand(Hand):
|
|||
# Immediately before the summary.
|
||||
# The current importer uses those lines for importing winning rather than the summary
|
||||
for name in self.pot.returned:
|
||||
print >>fh, ("Uncalled bet ($%s) returned to %s" %(self.pot.returned[name],name))
|
||||
print >>fh, ("Uncalled bet (%s%s) returned to %s" %(self.sym, self.pot.returned[name],name))
|
||||
for entry in self.collected:
|
||||
print >>fh, ("%s collected $%s from x pot" %(entry[0], entry[1]))
|
||||
print >>fh, ("%s collected %s%s from x pot" %(entry[0], self.sym, entry[1]))
|
||||
|
||||
print >>fh, ("*** SUMMARY ***")
|
||||
print >>fh, "%s | Rake $%.2f" % (self.pot, self.rake)
|
||||
print >>fh, "%s | Rake %s%.2f" % (self.pot, self.sym, self.rake)
|
||||
|
||||
board = []
|
||||
for s in self.board.values():
|
||||
board += s
|
||||
for street in ["FLOP", "TURN", "RIVER"]:
|
||||
board += self.board[street]
|
||||
if board: # sometimes hand ends preflop without a board
|
||||
print >>fh, ("Board [%s]" % (" ".join(board)))
|
||||
|
||||
|
@ -810,9 +831,9 @@ class HoldemOmahaHand(Hand):
|
|||
seatnum = player[0]
|
||||
name = player[1]
|
||||
if name in self.collectees and name in self.shown:
|
||||
print >>fh, ("Seat %d: %s showed [%s] and won ($%s)" % (seatnum, name, " ".join(self.holecards['PREFLOP'][name][1]), self.collectees[name]))
|
||||
print >>fh, ("Seat %d: %s showed [%s] and won (%s%s)" % (seatnum, name, " ".join(self.holecards['PREFLOP'][name][1]), self.sym, self.collectees[name]))
|
||||
elif name in self.collectees:
|
||||
print >>fh, ("Seat %d: %s collected ($%s)" % (seatnum, name, self.collectees[name]))
|
||||
print >>fh, ("Seat %d: %s collected (%s%s)" % (seatnum, name, self.sym, self.collectees[name]))
|
||||
#~ elif name in self.shown:
|
||||
#~ print >>fh, _("Seat %d: %s showed [%s]" % (seatnum, name, " ".join(self.holecards[name]['PREFLOP'])))
|
||||
elif name in self.folded:
|
||||
|
@ -852,13 +873,14 @@ class DrawHand(Hand):
|
|||
# Read actions in street order
|
||||
for street in self.streetList:
|
||||
if self.streets[street]:
|
||||
# hhc.readCommunityCards(self, street)
|
||||
# hhc.readDrawCards(self, street)
|
||||
hhc.readAction(self, street)
|
||||
hhc.readCollectPot(self)
|
||||
hhc.readShownCards(self)
|
||||
self.totalPot() # finalise it (total the pot)
|
||||
hhc.getRake(self)
|
||||
if self.maxseats == None:
|
||||
self.maxseats = hhc.guessMaxSeats(self)
|
||||
hhc.readOther(self)
|
||||
elif builtFrom == "DB":
|
||||
self.select("dummy") # Will need a handId
|
||||
|
||||
|
@ -898,21 +920,6 @@ class DrawHand(Hand):
|
|||
self.addHoleCards('DRAWTHREE', player, open=[], closed=cards, shown=shown, mucked=mucked, dealt=dealt)
|
||||
|
||||
|
||||
# def addDrawHoleCards(self, newcards, oldcards, player, street, shown=False):
|
||||
# """\
|
||||
#Assigns observed holecards to a player.
|
||||
#cards list of card bigrams e.g. ['2h','Jc']
|
||||
#player (string) name of player
|
||||
#"""
|
||||
# try:
|
||||
# self.checkPlayerExists(player)
|
||||
## if shown and len(cardset) > 0:
|
||||
## self.shown.add(player)
|
||||
# self.holecards[street][player] = (newcards,oldcards)
|
||||
# except FpdbParseError, e:
|
||||
# print "[ERROR] Tried to add holecards for unknown player: %s" % (player,)
|
||||
|
||||
|
||||
def discardDrawHoleCards(self, cards, player, street):
|
||||
logging.debug("discardDrawHoleCards '%s' '%s' '%s'" % (cards, player, street))
|
||||
self.discards[street][player] = set([cards])
|
||||
|
@ -928,64 +935,19 @@ class DrawHand(Hand):
|
|||
self.actions[street].append(act)
|
||||
|
||||
|
||||
# def addShownCards(self, cards, player, holeandboard=None, shown=False, mucked=False):
|
||||
# """\
|
||||
#For when a player shows cards for any reason (for showdown or out of choice).
|
||||
#Card ranks will be uppercased
|
||||
#"""
|
||||
# logging.debug("addShownCards %s hole=%s all=%s" % (player, cards, holeandboard))
|
||||
# if cards is not None:
|
||||
# self.shown.add(player)
|
||||
# self.addHoleCards(cards,player)
|
||||
# elif holeandboard is not None:
|
||||
# holeandboard = set([self.card(c) for c in holeandboard])
|
||||
# board = set([c for s in self.board.values() for c in s])
|
||||
# self.addHoleCards(holeandboard.difference(board),player,shown=True)
|
||||
|
||||
|
||||
# def addHoleCards(self, cards, player, shown, mucked, dealt=False):
|
||||
# """\
|
||||
#Assigns observed holecards to a player.
|
||||
#cards list of card bigrams e.g. ['2h','Jc']
|
||||
#player (string) name of player
|
||||
#shown whether they were revealed at showdown
|
||||
#mucked whether they were mucked at showdown
|
||||
#dealt whether they were seen in a 'dealt to' line
|
||||
#"""
|
||||
## I think this only gets called for shown cards.
|
||||
# logging.debug("addHoleCards %s %s" % (cards, player))
|
||||
# try:
|
||||
# self.checkPlayerExists(player)
|
||||
# except FpdbParseError, e:
|
||||
# print "[ERROR] Tried to add holecards for unknown player: %s" % (player,)
|
||||
# return
|
||||
#
|
||||
# if dealt:
|
||||
# self.dealt.add(player)
|
||||
# if shown:
|
||||
# self.shown.add(player)
|
||||
# if mucked:
|
||||
# self.mucked.add(player)
|
||||
# if player != self.hero: #skip hero, we know his cards
|
||||
# print "player, cards =", player, cards
|
||||
# self.holecards[self.holeStreets[-1]][player] = (cards, set([]))
|
||||
|
||||
def writeHand(self, fh=sys.__stdout__):
|
||||
# PokerStars format.
|
||||
# print >>fh, _("%s Game #%s: %s ($%s/$%s) - %s" %("PokerStars", self.handid, self.getGameTypeAsString(), self.sb, self.bb, time.strftime('%Y/%m/%d %H:%M:%S ET', self.starttime)))
|
||||
print >>fh, self.writeGameLine()
|
||||
# print >>fh, _("Table '%s' %d-max Seat #%s is the button" %(self.tablename, self.maxseats, self.buttonpos))
|
||||
print >>fh, self.writeTableLine()
|
||||
super(DrawHand, self).writeHand(fh)
|
||||
|
||||
players_who_act_ondeal = set(([x[0] for x in self.actions['DEAL']]+[x[0] for x in self.actions['BLINDSANTES']]))
|
||||
|
||||
for player in [x for x in self.players if x[1] in players_who_act_ondeal]:
|
||||
#Only print stacks of players who do something on deal
|
||||
print >>fh, _("Seat %s: %s ($%s in chips) " %(player[0], player[1], player[2]))
|
||||
print >>fh, _("Seat %s: %s (%s%s in chips) " %(player[0], player[1], self.sym, player[2]))
|
||||
|
||||
if 'BLINDSANTES' in self.actions:
|
||||
for act in self.actions['BLINDSANTES']:
|
||||
print >>fh, _("%s: %s %s $%s" %(act[0], act[1], act[2], act[3]))
|
||||
print >>fh, _("%s: %s %s %s%s" %(act[0], act[1], act[2], self.sym, act[3]))
|
||||
|
||||
if 'DEAL' in self.actions:
|
||||
print >>fh, _("*** DEALING HANDS ***")
|
||||
|
@ -1038,12 +1000,12 @@ class DrawHand(Hand):
|
|||
# Immediately before the summary.
|
||||
# The current importer uses those lines for importing winning rather than the summary
|
||||
for name in self.pot.returned:
|
||||
print >>fh, _("Uncalled bet ($%s) returned to %s" %(self.pot.returned[name],name))
|
||||
print >>fh, _("Uncalled bet (%s%s) returned to %s" %(self.sym, self.pot.returned[name],name))
|
||||
for entry in self.collected:
|
||||
print >>fh, _("%s collected $%s from x pot" %(entry[0], entry[1]))
|
||||
print >>fh, _("%s collected %s%s from x pot" %(entry[0], self.sym, entry[1]))
|
||||
|
||||
print >>fh, _("*** SUMMARY ***")
|
||||
print >>fh, "%s | Rake $%.2f" % (self.pot, self.rake)
|
||||
print >>fh, "%s | Rake %s%.2f" % (self.pot, self.sym, self.rake)
|
||||
print >>fh, "\n\n"
|
||||
|
||||
|
||||
|
@ -1058,7 +1020,7 @@ class StudHand(Hand):
|
|||
self.actionStreets = ['ANTES','THIRD','FOURTH','FIFTH','SIXTH','SEVENTH']
|
||||
|
||||
self.streetList = ['ANTES','THIRD','FOURTH','FIFTH','SIXTH','SEVENTH'] # a list of the observed street names in order
|
||||
self.holeStreets = ['ANTES','THIRD','FOURTH','FIFTH','SIXTH','SEVENTH']
|
||||
self.holeStreets = ['THIRD','FOURTH','FIFTH','SIXTH','SEVENTH']
|
||||
Hand.__init__(self, sitename, gametype, handText)
|
||||
self.sb = gametype['sb']
|
||||
self.bb = gametype['bb']
|
||||
|
@ -1073,18 +1035,20 @@ class StudHand(Hand):
|
|||
hhc.readAntes(self)
|
||||
hhc.readBringIn(self)
|
||||
hhc.readHeroCards(self)
|
||||
#hhc.readShowdownActions(self) # not done yet
|
||||
# Read actions in street order
|
||||
for street in self.streetList:
|
||||
for street in self.actionStreets:
|
||||
if street == 'ANTES': continue # OMG--sometime someone folds in the ante round
|
||||
if self.streets[street]:
|
||||
logging.debug(street)
|
||||
logging.debug(self.streets[street])
|
||||
# hhc.readStudPlayerCards(self, street)
|
||||
hhc.readAction(self, street)
|
||||
hhc.readCollectPot(self)
|
||||
hhc.readShownCards(self) # not done yet
|
||||
self.totalPot() # finalise it (total the pot)
|
||||
hhc.getRake(self)
|
||||
if self.maxseats == None:
|
||||
self.maxseats = hhc.guessMaxSeats(self)
|
||||
hhc.readOther(self)
|
||||
elif builtFrom == "DB":
|
||||
self.select("dummy") # Will need a handId
|
||||
|
||||
|
@ -1093,11 +1057,10 @@ class StudHand(Hand):
|
|||
if shown: self.shown.add(player)
|
||||
if mucked: self.mucked.add(player)
|
||||
else:
|
||||
# self.addHoleCards('PREFLOP', player, open=[], closed=cards, shown=shown, mucked=mucked, dealt=dealt)
|
||||
self.addHoleCards('THIRD', player, open=[cards[2]], closed=cards[0:2], shown=shown, mucked=mucked)
|
||||
self.addHoleCards('FOURTH', player, open=[cards[3]], closed=[], shown=shown, mucked=mucked)
|
||||
self.addHoleCards('FIFTH', player, open=[cards[4]], closed=[], shown=shown, mucked=mucked)
|
||||
self.addHoleCards('SIXTH', player, open=[cards[5]], closed=[], shown=shown, mucked=mucked)
|
||||
self.addHoleCards('FOURTH', player, open=[cards[3]], closed=[cards[2]], shown=shown, mucked=mucked)
|
||||
self.addHoleCards('FIFTH', player, open=[cards[4]], closed=cards[2:4], shown=shown, mucked=mucked)
|
||||
self.addHoleCards('SIXTH', player, open=[cards[5]], closed=cards[2:5], shown=shown, mucked=mucked)
|
||||
self.addHoleCards('SEVENTH', player, open=[], closed=[cards[6]], shown=shown, mucked=mucked)
|
||||
|
||||
|
||||
|
@ -1113,46 +1076,9 @@ closed likewise, but known only to player
|
|||
try:
|
||||
self.checkPlayerExists(player)
|
||||
self.holecards[street][player] = (open, closed)
|
||||
# cards = set([self.card(c) for c in cards])
|
||||
# self.holecards[player].update(cards)
|
||||
except FpdbParseError, e:
|
||||
print "[ERROR] Tried to add holecards for unknown player: %s" % (player,)
|
||||
|
||||
# def addHoleCards(self, cards, player, shown, mucked, dealt=False):
|
||||
# """\
|
||||
#Assigns observed holecards to a player.
|
||||
#cards list of card bigrams e.g. ['2h','Jc']
|
||||
#player (string) name of player
|
||||
#shown whether they were revealed at showdown
|
||||
#mucked whether they were mucked at showdown
|
||||
#dealt whether they were seen in a 'dealt to' line
|
||||
#"""
|
||||
##
|
||||
## For stud games we just need to do the routine setting of shown/mucked/etc
|
||||
## and then update the cards 'THIRD' and 'SEVENTH'
|
||||
# logging.debug("addHoleCards %s %s" % (cards, player))
|
||||
# try:
|
||||
# self.checkPlayerExists(player)
|
||||
# except FpdbParseError, e:
|
||||
# print "[ERROR] Tried to add holecards for unknown player: %s" % (player,)
|
||||
# return
|
||||
#
|
||||
# if dealt:
|
||||
# self.dealt.add(player)
|
||||
# if shown:
|
||||
# self.shown.add(player)
|
||||
# if mucked:
|
||||
# self.mucked.add(player)
|
||||
# if player == self.hero:
|
||||
# if len(cards) > 2:
|
||||
# self.holecards['THIRD'][player] = ([cards[0:3]], [])
|
||||
# if len(cards) > 6:
|
||||
# self.holecards['SEVENTH'][player] = ([cards[6]], [])
|
||||
# else:
|
||||
# if len(cards) > 2:
|
||||
# self.holecards['THIRD'][player] = ([cards[0]], cards[1:3])
|
||||
# if len(cards) > 6:
|
||||
# self.holecards['SEVENTH'][player] = ([], [cards[6]])
|
||||
# TODO: def addComplete(self, player, amount):
|
||||
def addComplete(self, street, player, amountTo):
|
||||
# assert street=='THIRD'
|
||||
|
@ -1161,6 +1087,7 @@ closed likewise, but known only to player
|
|||
Add a complete on [street] by [player] to [amountTo]
|
||||
"""
|
||||
logging.debug("%s %s completes %s" % (street, player, amountTo))
|
||||
amountTo = re.sub(u',', u'', amountTo) #some sites have commas
|
||||
self.checkPlayerExists(player)
|
||||
Bp = self.lastBet['THIRD']
|
||||
Bc = reduce(operator.add, self.bets[street][player], 0)
|
||||
|
@ -1188,26 +1115,18 @@ Add a complete on [street] by [player] to [amountTo]
|
|||
|
||||
def writeHand(self, fh=sys.__stdout__):
|
||||
# PokerStars format.
|
||||
# print >>fh, _("%s Game #%s: %s ($%s/$%s) - %s" %("PokerStars", self.handid, self.getGameTypeAsString(), self.sb, self.bb, time.strftime('%Y/%m/%d - %H:%M:%S (ET)', self.starttime)))
|
||||
|
||||
# TODO:
|
||||
# Hole cards are not currently correctly written. Currently the down cards for non-heros
|
||||
# are shown in the "dealt to" lines. They should be hidden in those lines. I tried to fix
|
||||
# but mind got boggled, will try again.
|
||||
# print >>fh, _("%s Game #%s: %s ($%s/$%s) - %s" %("PokerStars", self.handid, self.getGameTypeAsString(), self.sb, self.bb, datetime.datetime.strftime(self.starttime,'%Y/%m/%d - %H:%M:%S ET')))
|
||||
print >>fh, self.writeGameLine()
|
||||
print >>fh, self.writeTableLine()
|
||||
# print >>fh, _("Table '%s' %d-max Seat #%s is the button" %(self.tablename, self.maxseats, self.buttonpos))
|
||||
super(StudHand, self).writeHand(fh)
|
||||
|
||||
players_who_post_antes = set([x[0] for x in self.actions['ANTES']])
|
||||
|
||||
for player in [x for x in self.players if x[1] in players_who_post_antes]:
|
||||
#Only print stacks of players who do something preflop
|
||||
print >>fh, _("Seat %s: %s ($%s)" %(player[0], player[1], player[2]))
|
||||
print >>fh, _("Seat %s: %s (%s%s in chips)" %(player[0], player[1], self.sym, player[2]))
|
||||
|
||||
if 'ANTES' in self.actions:
|
||||
for act in self.actions['ANTES']:
|
||||
print >>fh, _("%s: posts the ante $%s" %(act[0], act[3]))
|
||||
print >>fh, _("%s: posts the ante %s%s" %(act[0], self.sym, act[3]))
|
||||
|
||||
if 'THIRD' in self.actions:
|
||||
dealt = 0
|
||||
|
@ -1218,7 +1137,8 @@ Add a complete on [street] by [player] to [amountTo]
|
|||
dealt+=1
|
||||
if dealt==1:
|
||||
print >>fh, _("*** 3RD STREET ***")
|
||||
print >>fh, _("Dealt to %s:%s%s") % (player, " [" + " ".join(closed) + "] " if closed else " ", "[" + " ".join(open) + "]" if open else "")
|
||||
# print >>fh, _("Dealt to %s:%s%s") % (player, " [" + " ".join(closed) + "] " if closed else " ", "[" + " ".join(open) + "]" if open else "")
|
||||
print >>fh, self.writeHoleCards('THIRD', player)
|
||||
for act in self.actions['THIRD']:
|
||||
#FIXME: Need some logic here for bringin vs completes
|
||||
print >>fh, self.actionString(act)
|
||||
|
@ -1228,15 +1148,10 @@ Add a complete on [street] by [player] to [amountTo]
|
|||
#~ print >>fh, _("*** 4TH STREET ***")
|
||||
for player in [x[1] for x in self.players if x[1] in players_who_post_antes]:
|
||||
if player in self.holecards['FOURTH']:
|
||||
old = []
|
||||
(o,c) = self.holecards['THIRD'][player]
|
||||
if o:old.extend(o)
|
||||
if c:old.extend(c)
|
||||
new = self.holecards['FOURTH'][player][0]
|
||||
dealt+=1
|
||||
if dealt==1:
|
||||
print >>fh, _("*** 4TH STREET ***")
|
||||
print >>fh, _("Dealt to %s:%s%s") % (player, " [" + " ".join(old) + "] " if old else " ", "[" + " ".join(new) + "]" if new else "")
|
||||
print >>fh, self.writeHoleCards('FOURTH', player)
|
||||
for act in self.actions['FOURTH']:
|
||||
print >>fh, self.actionString(act)
|
||||
|
||||
|
@ -1245,16 +1160,10 @@ Add a complete on [street] by [player] to [amountTo]
|
|||
#~ print >>fh, _("*** 5TH STREET ***")
|
||||
for player in [x[1] for x in self.players if x[1] in players_who_post_antes]:
|
||||
if self.holecards['FIFTH'].has_key(player):
|
||||
old = []
|
||||
for street in ('THIRD','FOURTH'):
|
||||
(o,c) = self.holecards[street][player]
|
||||
if o:old.extend(o)
|
||||
if c:old.extend(c)
|
||||
new = self.holecards['FIFTH'][player][0]
|
||||
dealt+=1
|
||||
if dealt==1:
|
||||
print >>fh, _("*** 5TH STREET ***")
|
||||
print >>fh, _("Dealt to %s:%s%s") % (player, " [" + " ".join(old) + "] " if old else " ", "[" + " ".join(new) + "]" if new else "")
|
||||
print >>fh, self.writeHoleCards('FIFTH', player)
|
||||
for act in self.actions['FIFTH']:
|
||||
print >>fh, self.actionString(act)
|
||||
|
||||
|
@ -1263,16 +1172,10 @@ Add a complete on [street] by [player] to [amountTo]
|
|||
#~ print >>fh, _("*** 6TH STREET ***")
|
||||
for player in [x[1] for x in self.players if x[1] in players_who_post_antes]:
|
||||
if self.holecards['SIXTH'].has_key(player):
|
||||
old = []
|
||||
for street in ('THIRD','FOURTH','FIFTH'):
|
||||
(o,c) = self.holecards[street][player]
|
||||
if o:old.extend(o)
|
||||
if c:old.extend(c)
|
||||
new = self.holecards['SIXTH'][player][0]
|
||||
dealt += 1
|
||||
if dealt == 1:
|
||||
print >>fh, _("*** 6TH STREET ***")
|
||||
print >>fh, _("Dealt to %s:%s%s") % (player, " [" + " ".join(old) + "] " if old else " ", "[" + " ".join(new) + "]" if new else "")
|
||||
print >>fh, self.writeHoleCards('SIXTH', player)
|
||||
for act in self.actions['SIXTH']:
|
||||
print >>fh, self.actionString(act)
|
||||
|
||||
|
@ -1281,17 +1184,11 @@ Add a complete on [street] by [player] to [amountTo]
|
|||
# Then we have no 'dealt to' lines, no action lines, but still 7th street should appear.
|
||||
# The only way I can see to know whether to print this line is by knowing the state of the hand
|
||||
# i.e. are all but one players folded; is there an allin showdown; and all that.
|
||||
print >>fh, _("*** 7TH STREET ***")
|
||||
print >>fh, _("*** RIVER ***")
|
||||
for player in [x[1] for x in self.players if x[1] in players_who_post_antes]:
|
||||
if self.holecards['SEVENTH'].has_key(player):
|
||||
old = []
|
||||
for street in ('THIRD','FOURTH','FIFTH','SIXTH'):
|
||||
(o,c) = self.holecards[street][player]
|
||||
if o:old.extend(o)
|
||||
if c:old.extend(c)
|
||||
new = self.holecards['SEVENTH'][player][0]
|
||||
if new:
|
||||
print >>fh, _("Dealt to %s:%s%s") % (player, " [" + " ".join(old) + "] " if old else " ", "[" + " ".join(new) + "]" if new else "")
|
||||
if self.writeHoleCards('SEVENTH', player):
|
||||
print >>fh, self.writeHoleCards('SEVENTH', player)
|
||||
for act in self.actions['SEVENTH']:
|
||||
print >>fh, self.actionString(act)
|
||||
|
||||
|
@ -1310,13 +1207,13 @@ Add a complete on [street] by [player] to [amountTo]
|
|||
# Immediately before the summary.
|
||||
# The current importer uses those lines for importing winning rather than the summary
|
||||
for name in self.pot.returned:
|
||||
print >>fh, _("Uncalled bet ($%s) returned to %s" %(self.pot.returned[name],name))
|
||||
print >>fh, _("Uncalled bet (%s%s) returned to %s" %(self.sym, self.pot.returned[name],name))
|
||||
for entry in self.collected:
|
||||
print >>fh, _("%s collected $%s from x pot" %(entry[0], entry[1]))
|
||||
print >>fh, _("%s collected %s%s from x pot" %(entry[0], self.sym, entry[1]))
|
||||
|
||||
print >>fh, _("*** SUMMARY ***")
|
||||
print >>fh, "%s | Rake $%.2f" % (self.pot, self.rake)
|
||||
#print >>fh, _("Total pot $%s | Rake $%.2f" % (self.totalpot, self.rake)) # TODO: side pots
|
||||
print >>fh, "%s | Rake %s%.2f" % (self.pot, self.sym, self.rake)
|
||||
# TODO: side pots
|
||||
|
||||
board = []
|
||||
for s in self.board.values():
|
||||
|
@ -1328,9 +1225,9 @@ Add a complete on [street] by [player] to [amountTo]
|
|||
seatnum = player[0]
|
||||
name = player[1]
|
||||
if name in self.collectees and name in self.shown:
|
||||
print >>fh, _("Seat %d: %s showed [%s] and won ($%s)" % (seatnum, name, self.join_holecards(name), self.collectees[name]))
|
||||
print >>fh, _("Seat %d: %s showed [%s] and won (%s%s)" % (seatnum, name, self.join_holecards(name), self.sym, self.collectees[name]))
|
||||
elif name in self.collectees:
|
||||
print >>fh, _("Seat %d: %s collected ($%s)" % (seatnum, name, self.collectees[name]))
|
||||
print >>fh, _("Seat %d: %s collected (%s%s)" % (seatnum, name, self.sym, self.collectees[name]))
|
||||
elif name in self.shown:
|
||||
print >>fh, _("Seat %d: %s showed [%s]" % (seatnum, name, self.join_holecards(name)))
|
||||
elif name in self.mucked:
|
||||
|
@ -1343,11 +1240,30 @@ Add a complete on [street] by [player] to [amountTo]
|
|||
print >>fh, "\n\n"
|
||||
|
||||
|
||||
def writeHoleCards(self, street, player):
|
||||
hc = "Dealt to %s [" % player
|
||||
if street == 'THIRD':
|
||||
if player == self.hero:
|
||||
return hc + " ".join(self.holecards[street][player][1]) + " " + " ".join(self.holecards[street][player][0]) + ']'
|
||||
else:
|
||||
return hc + " ".join(self.holecards[street][player][0]) + ']'
|
||||
|
||||
if street == 'SEVENTH' and player != self.hero: return # only write 7th st line for hero, LDO
|
||||
return hc + " ".join(self.holecards[street][player][1]) + "] [" + " ".join(self.holecards[street][player][0]) + "]"
|
||||
|
||||
def join_holecards(self, player):
|
||||
holecards = []
|
||||
for street in self.holeStreets:
|
||||
if self.holecards[street].has_key(player):
|
||||
holecards = holecards + self.holecards[street][player][0]
|
||||
if street == 'THIRD':
|
||||
holecards = holecards + self.holecards[street][player][1] + self.holecards[street][player][0]
|
||||
elif street == 'SEVENTH':
|
||||
if player == self.hero:
|
||||
holecards = holecards + self.holecards[street][player][0]
|
||||
else:
|
||||
holecards = holecards + self.holecards[street][player][1]
|
||||
else:
|
||||
holecards = holecards + self.holecards[street][player][0]
|
||||
return " ".join(holecards)
|
||||
|
||||
class Pot(object):
|
||||
|
@ -1358,6 +1274,10 @@ class Pot(object):
|
|||
self.committed = {}
|
||||
self.total = None
|
||||
self.returned = {}
|
||||
self.sym = u'$' # this is the default currency symbol
|
||||
|
||||
def setSym(self, sym):
|
||||
self.sym = sym
|
||||
|
||||
def addPlayer(self,player):
|
||||
self.committed[player] = Decimal(0)
|
||||
|
@ -1403,31 +1323,19 @@ class Pot(object):
|
|||
# Total pot $124.30 Main pot $98.90. Side pot $23.40. | Rake $2
|
||||
|
||||
def __str__(self):
|
||||
if self.sym is None:
|
||||
self.sym = "C"
|
||||
if self.total is None:
|
||||
print "call Pot.end() before printing pot total"
|
||||
# NB if I'm sure end() is idempotent, call it here.
|
||||
raise FpdbParseError
|
||||
|
||||
|
||||
ret = "Total pot %s%.2f" % (self.sym, self.total)
|
||||
if len(self.pots) < 2:
|
||||
return ret;
|
||||
ret += " Main pot %s%.2f" % (self.sym, self.pots[0])
|
||||
|
||||
if len(self.pots) == 1: # (only use Total pot)
|
||||
return "Total pot $%.2f" % (self.total,)
|
||||
elif len(self.pots) == 2:
|
||||
return "Total pot $%.2f Main pot $%.2f. Side pot $%2.f." % (self.total, self.pots[0], self.pots[1])
|
||||
elif len(self.pots) == 3:
|
||||
return "Total pot $%.2f Main pot $%.2f. Side pot-1 $%2.2f. Side pot-2 $%.2f." % (self.total, self.pots[0], self.pots[1], self.pots[2])
|
||||
elif len(self.pots) == 0:
|
||||
# no small blind and walk in bb (hopefully)
|
||||
return "Total pot $%.2f" % (self.total,)
|
||||
else:
|
||||
return ("too many pots.. no small blind and walk in bb?. self.pots: %s" %(self.pots))
|
||||
# I don't know stars format for a walk in the bb when sb doesn't post.
|
||||
# The thing to do here is raise a Hand error like fpdb import does and file it into errors.txt
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
return ret + ''.join([ (" Side pot %s%.2f." % (self.sym, self.pots[x]) ) for x in xrange(1, len(self.pots)) ])
|
||||
|
||||
def assemble(cnxn, handid):
|
||||
c = cnxn.cursor()
|
||||
|
|
|
@ -28,93 +28,56 @@ import codecs
|
|||
from decimal import Decimal
|
||||
import operator
|
||||
from xml.dom.minidom import Node
|
||||
# from pokereval import PokerEval
|
||||
import time
|
||||
import datetime
|
||||
import gettext
|
||||
|
||||
#from pokerengine.pokercards import *
|
||||
# provides letter2name{}, letter2names{}, visible_card(), not_visible_card(), is_visible(), card_value(), class PokerCards
|
||||
# but it's probably not installed so here are the ones we may want:
|
||||
letter2name = {
|
||||
'A': 'Ace',
|
||||
'K': 'King',
|
||||
'Q': 'Queen',
|
||||
'J': 'Jack',
|
||||
'T': 'Ten',
|
||||
'9': 'Nine',
|
||||
'8': 'Eight',
|
||||
'7': 'Seven',
|
||||
'6': 'Six',
|
||||
'5': 'Five',
|
||||
'4': 'Four',
|
||||
'3': 'Trey',
|
||||
'2': 'Deuce'
|
||||
}
|
||||
|
||||
letter2names = {
|
||||
'A': 'Aces',
|
||||
'K': 'Kings',
|
||||
'Q': 'Queens',
|
||||
'J': 'Jacks',
|
||||
'T': 'Tens',
|
||||
'9': 'Nines',
|
||||
'8': 'Eights',
|
||||
'7': 'Sevens',
|
||||
'6': 'Sixes',
|
||||
'5': 'Fives',
|
||||
'4': 'Fours',
|
||||
'3': 'Treys',
|
||||
'2': 'Deuces'
|
||||
}
|
||||
|
||||
import gettext
|
||||
gettext.install('myapplication')
|
||||
gettext.install('fpdb')
|
||||
|
||||
class HandHistoryConverter():
|
||||
|
||||
READ_CHUNK_SIZE = 10000 # bytes to read at a time from file (in tail mode)
|
||||
def __init__(self, in_path = '-', out_path = '-', sitename = None, follow=False):
|
||||
logging.info("HandHistory init called")
|
||||
def __init__(self, in_path = '-', out_path = '-', sitename = None, follow=False, index=0):
|
||||
logging.info("HandHistory init")
|
||||
|
||||
# default filetype and codepage. Subclasses should set these properly.
|
||||
self.filetype = "text"
|
||||
self.codepage = "utf8"
|
||||
|
||||
self.index = 0
|
||||
|
||||
self.in_path = in_path
|
||||
self.out_path = out_path
|
||||
if self.out_path == '-':
|
||||
# write to stdout
|
||||
|
||||
self.processedHands = []
|
||||
|
||||
if in_path == '-':
|
||||
self.in_fh = sys.stdin
|
||||
|
||||
if out_path == '-':
|
||||
self.out_fh = sys.stdout
|
||||
else:
|
||||
# TODO: out_path should be sanity checked before opening. Perhaps in fpdb_import?
|
||||
# I'm not sure what we're looking for, although we don't want out_path==in_path!='-'
|
||||
self.out_fh = open(self.out_path, 'w') # doomswitch is now on :|
|
||||
# TODO: out_path should be sanity checked.
|
||||
self.out_fh = open(self.out_path, 'w')
|
||||
|
||||
self.sitename = sitename
|
||||
self.follow = follow
|
||||
self.compiledPlayers = set()
|
||||
self.maxseats = 10
|
||||
|
||||
def __str__(self):
|
||||
#TODO : I got rid of most of the hhdir stuff.
|
||||
tmp = "HandHistoryConverter: '%s'\n" % (self.sitename)
|
||||
#tmp = tmp + "\thhbase: '%s'\n" % (self.hhbase)
|
||||
#tmp = tmp + "\thhdir: '%s'\n" % (self.hhdir)
|
||||
tmp = tmp + "\tfiletype: '%s'\n" % (self.filetype)
|
||||
tmp = tmp + "\tinfile: '%s'\n" % (self.in_path)
|
||||
tmp = tmp + "\toutfile: '%s'\n" % (self.out_path)
|
||||
#tmp = tmp + "\tgametype: '%s'\n" % (self.gametype[0])
|
||||
#tmp = tmp + "\tgamebase: '%s'\n" % (self.gametype[1])
|
||||
#tmp = tmp + "\tlimit: '%s'\n" % (self.gametype[2])
|
||||
#tmp = tmp + "\tsb/bb: '%s/%s'\n" % (self.gametype[3], self.gametype[4])
|
||||
return tmp
|
||||
return """
|
||||
HandHistoryConverter: '%(sitename)s'
|
||||
filetype: '%(filetype)s'
|
||||
in_path: '%(in_path)s'
|
||||
out_path: '%(out_path)s'
|
||||
""" % { 'sitename':self.sitename, 'filetype':self.filetype, 'in_path':self.in_path, 'out_path':self.out_path }
|
||||
|
||||
def start(self):
|
||||
"""process a hand at a time from the input specified by in_path.
|
||||
If in follow mode, wait for more data to turn up.
|
||||
Otherwise, finish at eof...
|
||||
Otherwise, finish at eof.
|
||||
|
||||
"""
|
||||
"""
|
||||
starttime = time.time()
|
||||
if not self.sanityCheck():
|
||||
print "Cowardly refusing to continue after failed sanity check"
|
||||
|
@ -129,7 +92,7 @@ Otherwise, finish at eof...
|
|||
handsList = self.allHandsAsList()
|
||||
logging.info("Parsing %d hands" % len(handsList))
|
||||
for handText in handsList:
|
||||
self.processHand(handText)
|
||||
self.processedHands.append(self.processHand(handText))
|
||||
numHands= len(handsList)
|
||||
endtime = time.time()
|
||||
print "read %d hands in %.3f seconds" % (numHands, endtime - starttime)
|
||||
|
@ -213,6 +176,7 @@ which it expects to find at self.re_TailSplitHands -- see for e.g. Everleaf.py.
|
|||
def processHand(self, handText):
|
||||
gametype = self.determineGameType(handText)
|
||||
logging.debug("gametype %s" % gametype)
|
||||
hand = None
|
||||
if gametype is None:
|
||||
l = None
|
||||
gametype = "unmatched"
|
||||
|
@ -224,9 +188,7 @@ which it expects to find at self.re_TailSplitHands -- see for e.g. Everleaf.py.
|
|||
base = gametype['base']
|
||||
limit = gametype['limitType']
|
||||
l = [type] + [base] + [limit]
|
||||
hand = None
|
||||
if l in self.readSupportedGames():
|
||||
hand = None
|
||||
if gametype['base'] == 'hold':
|
||||
logging.debug("hand = Hand.HoldemOmahaHand(self, self.sitename, gametype, handtext)")
|
||||
hand = Hand.HoldemOmahaHand(self, self.sitename, gametype, handText)
|
||||
|
@ -240,6 +202,7 @@ which it expects to find at self.re_TailSplitHands -- see for e.g. Everleaf.py.
|
|||
if hand:
|
||||
# print hand
|
||||
hand.writeHand(self.out_fh)
|
||||
return hand
|
||||
else:
|
||||
logging.info("Unsupported game type: %s" % gametype)
|
||||
# TODO: pity we don't know the HID at this stage. Log the entire hand?
|
||||
|
@ -306,6 +269,11 @@ or None if we fail to get the info """
|
|||
def readAction(self, hand, street): abstract
|
||||
def readCollectPot(self, hand): abstract
|
||||
def readShownCards(self, hand): abstract
|
||||
|
||||
# Some sites do odd stuff that doesn't fall in to the normal HH parsing.
|
||||
# e.g., FTP doesn't put mixed game info in the HH, but puts in in the
|
||||
# file name. Use readOther() to clean up those messes.
|
||||
def readOther(self, hand): pass
|
||||
|
||||
# Some sites don't report the rake. This will be called at the end of the hand after the pot total has been calculated
|
||||
# an inheriting class can calculate it for the specific site if need be.
|
||||
|
@ -350,6 +318,7 @@ or None if we fail to get the info """
|
|||
self.filetype = filetype
|
||||
self.codepage = codepage
|
||||
|
||||
#This function doesn't appear to be used
|
||||
def splitFileIntoHands(self):
|
||||
hands = []
|
||||
self.obs = self.obs.strip()
|
||||
|
@ -371,7 +340,9 @@ or None if we fail to get the info """
|
|||
else:
|
||||
logging.debug("Opening %s with %s" % (self.in_path, self.codepage))
|
||||
in_fh = codecs.open(self.in_path, 'r', self.codepage)
|
||||
in_fh.seek(self.index)
|
||||
self.obs = in_fh.read()
|
||||
self.index = in_fh.tell()
|
||||
in_fh.close()
|
||||
elif(self.filetype == "xml"):
|
||||
try:
|
||||
|
@ -380,10 +351,39 @@ or None if we fail to get the info """
|
|||
except:
|
||||
traceback.print_exc(file=sys.stderr)
|
||||
|
||||
def guessMaxSeats(self, hand):
|
||||
"""Return a guess at max_seats when not specified in HH."""
|
||||
mo = self.maxOccSeat(hand)
|
||||
|
||||
if mo == 10: return 10 #that was easy
|
||||
|
||||
if hand.gametype['base'] == 'stud':
|
||||
if mo <= 8: return 8
|
||||
else: return mo
|
||||
|
||||
if hand.gametype['base'] == 'draw':
|
||||
if mo <= 6: return 6
|
||||
else: return mo
|
||||
|
||||
if mo == 2: return 2
|
||||
if mo <= 6: return 6
|
||||
return 10
|
||||
|
||||
def maxOccSeat(self, hand):
|
||||
max = 0
|
||||
for player in hand.players:
|
||||
if player[0] > max: max = player[0]
|
||||
return max
|
||||
|
||||
def getStatus(self):
|
||||
#TODO: Return a status of true if file processed ok
|
||||
return True
|
||||
|
||||
def getProcessedHands(self):
|
||||
return self.processedHands
|
||||
|
||||
def getProcessedFile(self):
|
||||
return self.out_path
|
||||
|
||||
def getLastCharacterRead(self):
|
||||
return self.index
|
||||
|
|
|
@ -235,12 +235,8 @@ class Hud:
|
|||
# does the user have a fav_seat?
|
||||
if int(config.supported_sites[self.table.site].layout[self.max].fav_seat) > 0:
|
||||
try:
|
||||
sys.stderr.write("site = %s, max = %d, fav seat = %d\n" % (self.table.site, self.max, config.supported_sites[self.table.site].layout[self.max].fav_seat))
|
||||
fav_seat = config.supported_sites[self.table.site].layout[self.max].fav_seat
|
||||
sys.stderr.write("found fav seat = %d\n" % fav_seat)
|
||||
# actual_seat = self.db_connection.get_actual_seat(hand, config.supported_sites[self.table.site].screen_name)
|
||||
actual_seat = self.get_actual_seat(config.supported_sites[self.table.site].screen_name)
|
||||
sys.stderr.write("found actual seat = %d\n" % actual_seat)
|
||||
for i in xrange(0, self.max + 1):
|
||||
j = actual_seat + i
|
||||
if j > self.max:
|
||||
|
@ -273,7 +269,6 @@ class Hud:
|
|||
self.cards = cards
|
||||
sys.stderr.write("------------------------------------------------------------\nCreating hud from hand %s\n" % hand)
|
||||
adj = self.adj_seats(hand, config)
|
||||
sys.stderr.write("adj = %s\n" % adj)
|
||||
loc = self.config.get_locations(self.table.site, self.max)
|
||||
|
||||
# create the stat windows
|
||||
|
@ -282,7 +277,6 @@ class Hud:
|
|||
if i in self.stat_windows:
|
||||
self.stat_windows[i].relocate(x, y)
|
||||
else:
|
||||
sys.stderr.write("actual seat = %d, x = %d, y= %d\n" % (i, x, y))
|
||||
self.stat_windows[i] = Stat_Window(game = config.supported_games[self.poker_game],
|
||||
parent = self,
|
||||
table = self.table,
|
||||
|
|
|
@ -294,6 +294,7 @@ class Stud_cards:
|
|||
def update_gui(self, new_hand_id):
|
||||
self.clear()
|
||||
for c, cards in self.parent.hud.cards.iteritems():
|
||||
if c == 'common': continue
|
||||
self.grid_contents[(1, c - 1)].set_text(self.get_screen_name(c))
|
||||
for i in ((0, cards[0]), (1, cards[1]), (2, cards[2]), (3, cards[3]),
|
||||
(4, cards[4]), (5, cards[5]), (6, cards[6])):
|
||||
|
@ -462,7 +463,6 @@ class Flop_Mucked(Aux_Seats):
|
|||
if n_cards > 0 and i != 'common':
|
||||
n_sd = n_sd + 1
|
||||
if n_sd < 2:
|
||||
print "skipping, n_sd =", n_sd
|
||||
return
|
||||
|
||||
super(Flop_Mucked, self).update_gui(new_hand_id)
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
#!/usr/bin/env python
|
||||
#!/usr/bin/env python
|
||||
# -*- coding: utf-8 -*-
|
||||
#
|
||||
# Copyright 2008, Carl Gherardi
|
||||
|
@ -55,12 +55,12 @@ class PokerStars(HandHistoryConverter):
|
|||
|
||||
mixes = { 'HORSE': 'horse', '8-Game': '8game', 'HOSE': 'hose'}
|
||||
|
||||
def __init__(self, in_path = '-', out_path = '-', follow = False, autostart=True):
|
||||
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="PokerStars", follow=follow)
|
||||
HandHistoryConverter.__init__(self, in_path, out_path, sitename="PokerStars", follow=follow, index=index)
|
||||
logging.info("Initialising PokerStars converter class")
|
||||
self.filetype = "text"
|
||||
self.codepage = "cp1252"
|
||||
|
@ -298,7 +298,7 @@ follow : whether to tail -f the input"""
|
|||
hand.addHoleCards(street, hand.hero, closed=newcards, shown=False, mucked=False, dealt=True)
|
||||
|
||||
for street, text in hand.streets.iteritems():
|
||||
if street in ('PREFLOP', 'DEAL'): continue # already done these
|
||||
if not text or street in ('PREFLOP', 'DEAL'): continue # already done these
|
||||
m = self.re_HeroCards.finditer(hand.streets[street])
|
||||
for found in m:
|
||||
player = found.group('PNAME')
|
||||
|
@ -398,7 +398,7 @@ follow : whether to tail -f the input"""
|
|||
|
||||
|
||||
def readShowdownActions(self, hand):
|
||||
# TODO: pick up mucks also
|
||||
# TODO: pick up mucks also??
|
||||
for shows in self.re_ShowdownAction.finditer(hand.handText):
|
||||
cards = shows.group('CARDS').split(' ')
|
||||
hand.addShownCards(cards, shows.group('PNAME'))
|
||||
|
@ -421,7 +421,7 @@ follow : whether to tail -f the input"""
|
|||
|
||||
if __name__ == "__main__":
|
||||
parser = OptionParser()
|
||||
parser.add_option("-i", "--input", dest="ipath", help="parse input hand history", default="regression-test-files/pokerstars/HH20090226 Natalie V - $0.10-$0.20 - HORSE.txt")
|
||||
parser.add_option("-i", "--input", dest="ipath", help="parse input hand history", default="regression-test-files/stars/horse/HH20090226 Natalie V - $0.10-$0.20 - HORSE.txt")
|
||||
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",
|
||||
|
|
1844
pyfpdb/SQL.py
1844
pyfpdb/SQL.py
File diff suppressed because it is too large
Load Diff
233
pyfpdb/Stats.py
233
pyfpdb/Stats.py
|
@ -22,6 +22,8 @@
|
|||
########################################################################
|
||||
|
||||
# How to write a new stat:
|
||||
# 0 Do not use a name like "xyz_2". Names ending in _ and a single digit are
|
||||
# used to indicate the number of decimal places the user wants to see in the Hud.
|
||||
# 1 You can see a listing of all the raw stats (e.g., from the HudCache table)
|
||||
# by running Database.py as a stand along program. You need to combine
|
||||
# those raw stats to get stats to present to the HUD. If you need more
|
||||
|
@ -50,16 +52,34 @@
|
|||
# pyGTK modules
|
||||
import pygtk
|
||||
import gtk
|
||||
import re
|
||||
|
||||
# FreePokerTools modules
|
||||
import Configuration
|
||||
import Database
|
||||
|
||||
|
||||
re_Places = re.compile("_[0-9]$")
|
||||
re_Percent = re.compile("%$")
|
||||
|
||||
|
||||
def do_tip(widget, tip):
|
||||
widget.set_tooltip_text(tip)
|
||||
|
||||
def do_stat(stat_dict, player = 24, stat = 'vpip'):
|
||||
return eval("%(stat)s(stat_dict, %(player)d)" % {'stat': stat, 'player': player})
|
||||
match = re_Places.search(stat)
|
||||
if match == None:
|
||||
result = eval("%(stat)s(stat_dict, %(player)d)" % {'stat': stat, 'player': player})
|
||||
else:
|
||||
base = stat[0:-2]
|
||||
places = int(stat[-1:])
|
||||
result = eval("%(stat)s(stat_dict, %(player)d)" % {'stat': base, 'player': player})
|
||||
match = re_Percent.search(result[1])
|
||||
if match == None:
|
||||
result = (result[0], "%.*f" % (places, result[0]), result[2], result[3], result[4], result[5])
|
||||
else:
|
||||
result = (result[0], "%.*f%%" % (places, 100*result[0]), result[2], result[3], result[4], result[5])
|
||||
return result
|
||||
|
||||
# OK, for reference the tuple returned by the stat is:
|
||||
# 0 - The stat, raw, no formating, eg 0.33333333
|
||||
|
@ -108,26 +128,6 @@ def vpip(stat_dict, player):
|
|||
'Voluntarily Put In Pot %'
|
||||
)
|
||||
|
||||
def vpip_0(stat_dict, player):
|
||||
""" Voluntarily put $ in the pot (no decimals)."""
|
||||
stat = 0.0
|
||||
try:
|
||||
stat = float(stat_dict[player]['vpip'])/float(stat_dict[player]['n'])
|
||||
return (stat,
|
||||
'%2.0f' % (100*stat) + '%',
|
||||
'v=%2.0f' % (100*stat) + '%',
|
||||
'vpip=%2.0f' % (100*stat) + '%',
|
||||
'(%d/%d)' % (stat_dict[player]['vpip'], stat_dict[player]['n']),
|
||||
'vpip'
|
||||
)
|
||||
except: return (stat,
|
||||
'%2.0f' % (0) + '%',
|
||||
'w=%2.0f' % (0) + '%',
|
||||
'wtsd=%2.0f' % (0) + '%',
|
||||
'(%d/%d)' % (0, 0),
|
||||
'wtsd'
|
||||
)
|
||||
|
||||
def pfr(stat_dict, player):
|
||||
""" Preflop (3rd street) raise."""
|
||||
stat = 0.0
|
||||
|
@ -149,27 +149,6 @@ def pfr(stat_dict, player):
|
|||
'Pre-Flop Raise %'
|
||||
)
|
||||
|
||||
def pfr_0(stat_dict, player):
|
||||
""" Preflop (3rd street) raise (no decimals)."""
|
||||
stat = 0.0
|
||||
try:
|
||||
stat = float(stat_dict[player]['pfr'])/float(stat_dict[player]['n'])
|
||||
return (stat,
|
||||
'%2.0f' % (100*stat) + '%',
|
||||
'p=%2.0f' % (100*stat) + '%',
|
||||
'pfr=%2.0f' % (100*stat) + '%',
|
||||
'(%d/%d)' % (stat_dict[player]['pfr'], stat_dict[player]['n']),
|
||||
'pfr'
|
||||
)
|
||||
except:
|
||||
return (stat,
|
||||
'%2.0f' % (0) + '%',
|
||||
'p=%2.0f' % (0) + '%',
|
||||
'pfr=%2.0f' % (0) + '%',
|
||||
'(%d/%d)' % (0, 0),
|
||||
'pfr'
|
||||
)
|
||||
|
||||
def wtsd(stat_dict, player):
|
||||
""" Went to SD when saw flop/4th."""
|
||||
stat = 0.0
|
||||
|
@ -191,27 +170,6 @@ def wtsd(stat_dict, player):
|
|||
'% went to showdown'
|
||||
)
|
||||
|
||||
def wtsd_0(stat_dict, player):
|
||||
""" Went to SD when saw flop/4th."""
|
||||
stat = 0.0
|
||||
try:
|
||||
stat = float(stat_dict[player]['sd'])/float(stat_dict[player]['saw_f'])
|
||||
return (stat,
|
||||
'%2.0f' % (100*stat) + '%',
|
||||
'w=%2.0f' % (100*stat) + '%',
|
||||
'wtsd=%2.0f' % (100*stat) + '%',
|
||||
'(%d/%d)' % (stat_dict[player]['sd'], stat_dict[player]['saw_f']),
|
||||
'% went to showdown'
|
||||
)
|
||||
except:
|
||||
return (stat,
|
||||
'%2.0f' % (0) + '%',
|
||||
'w=%2.0f' % (0) + '%',
|
||||
'wtsd=%2.0f' % (0) + '%',
|
||||
'(%d/%d)' % (0, 0),
|
||||
'% went to showdown'
|
||||
)
|
||||
|
||||
def wmsd(stat_dict, player):
|
||||
""" Won $ at showdown."""
|
||||
stat = 0.0
|
||||
|
@ -233,28 +191,7 @@ def wmsd(stat_dict, player):
|
|||
'% won money at showdown'
|
||||
)
|
||||
|
||||
def wmsd_0(stat_dict, player):
|
||||
""" Won $ at showdown."""
|
||||
stat = 0.0
|
||||
try:
|
||||
stat = float(stat_dict[player]['wmsd'])/float(stat_dict[player]['sd'])
|
||||
return (stat,
|
||||
'%2.0f' % (100*stat) + '%',
|
||||
'w=%2.0f' % (100*stat) + '%',
|
||||
'wmsd=%2.0f' % (100*stat) + '%',
|
||||
'(%5.1f/%d)' % (float(stat_dict[player]['wmsd']), stat_dict[player]['sd']),
|
||||
'% won money at showdown'
|
||||
)
|
||||
except:
|
||||
return (stat,
|
||||
'%2.0f' % (0) + '%',
|
||||
'w=%2.0f' % (0) + '%',
|
||||
'wmsd=%2.0f' % (0) + '%',
|
||||
'(%d/%d)' % (0, 0),
|
||||
'% won money at showdown'
|
||||
)
|
||||
|
||||
def profit100_0(stat_dict, player):
|
||||
def profit100(stat_dict, player):
|
||||
""" Profit won per 100 hands (no decimal places)."""
|
||||
stat = 0.0
|
||||
try:
|
||||
|
@ -355,27 +292,6 @@ def steal(stat_dict, player):
|
|||
)
|
||||
except:
|
||||
return (stat, 'NA', 'st=NA', 'steal=NA', '(0/0)', '% steal attempted')
|
||||
|
||||
def steal_0(stat_dict, player):
|
||||
""" Steal %."""
|
||||
stat = 0.0
|
||||
try:
|
||||
stat = float(stat_dict[player]['steal'])/float(stat_dict[player]['steal_opp'])
|
||||
return (stat,
|
||||
'%2.0f' % (100*stat) + '%',
|
||||
'st=%2.0f' % (100*stat) + '%',
|
||||
'steal=%2.0f' % (100*stat) + '%',
|
||||
'(%d/%d)' % (stat_dict[player]['steal'], stat_dict[player]['steal_opp']),
|
||||
'% steal attempted'
|
||||
)
|
||||
except:
|
||||
return (stat,
|
||||
'%2.0f' % (0) + '%',
|
||||
'st=%2.0f' % (0) + '%',
|
||||
'steal=%2.0f' % (0) + '%',
|
||||
'(%d/%d)' % (0, 0),
|
||||
'% steal attempted'
|
||||
)
|
||||
|
||||
def f_SB_steal(stat_dict, player):
|
||||
""" Folded SB to steal."""
|
||||
|
@ -417,27 +333,7 @@ def f_BB_steal(stat_dict, player):
|
|||
'(0/0)',
|
||||
'% folded BB to steal')
|
||||
|
||||
def f_BB_steal_0(stat_dict, player):
|
||||
""" Folded BB to steal."""
|
||||
stat = 0.0
|
||||
try:
|
||||
stat = float(stat_dict[player]['bbnotdef'])/float(stat_dict[player]['bbstolen'])
|
||||
return (stat,
|
||||
'%2.0f' % (100*stat) + '%',
|
||||
'fBB=%2.0f' % (100*stat) + '%',
|
||||
'fBB_s=%2.0f' % (100*stat) + '%',
|
||||
'(%d/%d)' % (stat_dict[player]['bbnotdef'], stat_dict[player]['bbstolen']),
|
||||
'% folded BB to steal'
|
||||
)
|
||||
except:
|
||||
return (stat,
|
||||
'NA',
|
||||
'fBB=NA',
|
||||
'fBB_s=NA',
|
||||
'(0/0)',
|
||||
'% folded BB to steal')
|
||||
|
||||
def three_B_0(stat_dict, player):
|
||||
def three_B(stat_dict, player):
|
||||
""" Three bet preflop/3rd."""
|
||||
stat = 0.0
|
||||
try:
|
||||
|
@ -479,7 +375,7 @@ def WMsF(stat_dict, player):
|
|||
'% won$/saw flop/4th'
|
||||
)
|
||||
|
||||
def a_freq_1(stat_dict, player):
|
||||
def a_freq1(stat_dict, player):
|
||||
""" Flop/4th aggression frequency."""
|
||||
stat = 0.0
|
||||
try:
|
||||
|
@ -500,7 +396,7 @@ def a_freq_1(stat_dict, player):
|
|||
'Aggression Freq flop/4th'
|
||||
)
|
||||
|
||||
def a_freq_2(stat_dict, player):
|
||||
def a_freq2(stat_dict, player):
|
||||
""" Turn/5th aggression frequency."""
|
||||
stat = 0.0
|
||||
try:
|
||||
|
@ -521,7 +417,7 @@ def a_freq_2(stat_dict, player):
|
|||
'Aggression Freq turn/5th'
|
||||
)
|
||||
|
||||
def a_freq_3(stat_dict, player):
|
||||
def a_freq3(stat_dict, player):
|
||||
""" River/6th aggression frequency."""
|
||||
stat = 0.0
|
||||
try:
|
||||
|
@ -542,7 +438,7 @@ def a_freq_3(stat_dict, player):
|
|||
'Aggression Freq river/6th'
|
||||
)
|
||||
|
||||
def a_freq_4(stat_dict, player):
|
||||
def a_freq4(stat_dict, player):
|
||||
""" 7th street aggression frequency."""
|
||||
stat = 0.0
|
||||
try:
|
||||
|
@ -590,35 +486,8 @@ def a_freq_123(stat_dict, player):
|
|||
'(%d/%d)' % (0, 0),
|
||||
'Post-Flop Aggression Freq'
|
||||
)
|
||||
|
||||
def a_freq_123_0(stat_dict, player):
|
||||
""" Post-Flop aggression frequency (no decimals)."""
|
||||
stat = 0.0
|
||||
try:
|
||||
stat = float( stat_dict[player]['aggr_1'] + stat_dict[player]['aggr_2'] + stat_dict[player]['aggr_3']) / float( stat_dict[player]['saw_1'] + stat_dict[player]['saw_2'] + stat_dict[player]['saw_3']);
|
||||
return (stat,
|
||||
'%2.0f' % (100*stat) + '%',
|
||||
'afq=%2.0f' % (100*stat) + '%',
|
||||
'postf_aggfq=%2.0f' % (100*stat) + '%',
|
||||
'(%d/%d)' % ( stat_dict[player]['aggr_1']
|
||||
+ stat_dict[player]['aggr_2']
|
||||
+ stat_dict[player]['aggr_3']
|
||||
, stat_dict[player]['saw_1']
|
||||
+ stat_dict[player]['saw_2']
|
||||
+ stat_dict[player]['saw_3']
|
||||
),
|
||||
'Post-Flop Aggression Freq'
|
||||
)
|
||||
except:
|
||||
return (stat,
|
||||
'%2.0f' % (0) + '%',
|
||||
'a3=%2.0f' % (0) + '%',
|
||||
'a_fq_3=%2.0f' % (0) + '%',
|
||||
'(%d/%d)' % (0, 0),
|
||||
'Post-Flop Aggression Freq'
|
||||
)
|
||||
|
||||
def cb_1(stat_dict, player):
|
||||
def cb1(stat_dict, player):
|
||||
""" Flop continuation bet."""
|
||||
stat = 0.0
|
||||
try:
|
||||
|
@ -639,7 +508,7 @@ def cb_1(stat_dict, player):
|
|||
'% continuation bet flop/4th'
|
||||
)
|
||||
|
||||
def cb_2(stat_dict, player):
|
||||
def cb2(stat_dict, player):
|
||||
""" Turn continuation bet."""
|
||||
stat = 0.0
|
||||
try:
|
||||
|
@ -660,7 +529,7 @@ def cb_2(stat_dict, player):
|
|||
'% continuation bet turn/5th'
|
||||
)
|
||||
|
||||
def cb_3(stat_dict, player):
|
||||
def cb3(stat_dict, player):
|
||||
""" River continuation bet."""
|
||||
stat = 0.0
|
||||
try:
|
||||
|
@ -681,7 +550,7 @@ def cb_3(stat_dict, player):
|
|||
'% continuation bet river/6th'
|
||||
)
|
||||
|
||||
def cb_4(stat_dict, player):
|
||||
def cb4(stat_dict, player):
|
||||
""" 7th street continuation bet."""
|
||||
stat = 0.0
|
||||
try:
|
||||
|
@ -702,7 +571,7 @@ def cb_4(stat_dict, player):
|
|||
'% continuation bet 7th'
|
||||
)
|
||||
|
||||
def ffreq_1(stat_dict, player):
|
||||
def ffreq1(stat_dict, player):
|
||||
""" Flop/4th fold frequency."""
|
||||
stat = 0.0
|
||||
try:
|
||||
|
@ -723,7 +592,7 @@ def ffreq_1(stat_dict, player):
|
|||
'% fold frequency flop/4th'
|
||||
)
|
||||
|
||||
def ffreq_2(stat_dict, player):
|
||||
def ffreq2(stat_dict, player):
|
||||
""" Turn/5th fold frequency."""
|
||||
stat = 0.0
|
||||
try:
|
||||
|
@ -744,7 +613,7 @@ def ffreq_2(stat_dict, player):
|
|||
'% fold frequency turn/5th'
|
||||
)
|
||||
|
||||
def ffreq_3(stat_dict, player):
|
||||
def ffreq3(stat_dict, player):
|
||||
""" River/6th fold frequency."""
|
||||
stat = 0.0
|
||||
try:
|
||||
|
@ -765,7 +634,7 @@ def ffreq_3(stat_dict, player):
|
|||
'% fold frequency river/6th'
|
||||
)
|
||||
|
||||
def ffreq_4(stat_dict, player):
|
||||
def ffreq4(stat_dict, player):
|
||||
""" 7th fold frequency."""
|
||||
stat = 0.0
|
||||
try:
|
||||
|
@ -804,24 +673,24 @@ if __name__== "__main__":
|
|||
print "player = ", player, do_stat(stat_dict, player = player, stat = 'fold_f')
|
||||
print "player = ", player, do_stat(stat_dict, player = player, stat = 'wmsd')
|
||||
print "player = ", player, do_stat(stat_dict, player = player, stat = 'steal')
|
||||
print "player = ", player, do_stat(stat_dict, player = player, stat = 'f_sb_steal')
|
||||
print "player = ", player, do_stat(stat_dict, player = player, stat = 'f_bb_steal')
|
||||
print "player = ", player, do_stat(stat_dict, player = player, stat = 'three_b_0')
|
||||
print "player = ", player, do_stat(stat_dict, player = player, stat = 'wmsf')
|
||||
print "player = ", player, do_stat(stat_dict, player = player, stat = 'a_freq_1')
|
||||
print "player = ", player, do_stat(stat_dict, player = player, stat = 'a_freq_2')
|
||||
print "player = ", player, do_stat(stat_dict, player = player, stat = 'a_freq_3')
|
||||
print "player = ", player, do_stat(stat_dict, player = player, stat = 'a_freq_4')
|
||||
print "player = ", player, do_stat(stat_dict, player = player, stat = 'f_SB_steal')
|
||||
print "player = ", player, do_stat(stat_dict, player = player, stat = 'f_BB_steal')
|
||||
print "player = ", player, do_stat(stat_dict, player = player, stat = 'three_B_0')
|
||||
print "player = ", player, do_stat(stat_dict, player = player, stat = 'WMsF')
|
||||
print "player = ", player, do_stat(stat_dict, player = player, stat = 'a_freq1')
|
||||
print "player = ", player, do_stat(stat_dict, player = player, stat = 'a_freq2')
|
||||
print "player = ", player, do_stat(stat_dict, player = player, stat = 'a_freq3')
|
||||
print "player = ", player, do_stat(stat_dict, player = player, stat = 'a_freq4')
|
||||
print "player = ", player, do_stat(stat_dict, player = player, stat = 'a_freq_123')
|
||||
print "player = ", player, do_stat(stat_dict, player = player, stat = 'a_freq_123_0')
|
||||
print "player = ", player, do_stat(stat_dict, player = player, stat = 'cb_1')
|
||||
print "player = ", player, do_stat(stat_dict, player = player, stat = 'cb_2')
|
||||
print "player = ", player, do_stat(stat_dict, player = player, stat = 'cb_3')
|
||||
print "player = ", player, do_stat(stat_dict, player = player, stat = 'cb_4')
|
||||
print "player = ", player, do_stat(stat_dict, player = player, stat = 'ffreq_1')
|
||||
print "player = ", player, do_stat(stat_dict, player = player, stat = 'ffreq_2')
|
||||
print "player = ", player, do_stat(stat_dict, player = player, stat = 'ffreq_3')
|
||||
print "player = ", player, do_stat(stat_dict, player = player, stat = 'ffreq_4')
|
||||
print "player = ", player, do_stat(stat_dict, player = player, stat = 'cb1')
|
||||
print "player = ", player, do_stat(stat_dict, player = player, stat = 'cb2')
|
||||
print "player = ", player, do_stat(stat_dict, player = player, stat = 'cb3')
|
||||
print "player = ", player, do_stat(stat_dict, player = player, stat = 'cb4')
|
||||
print "player = ", player, do_stat(stat_dict, player = player, stat = 'ffreq1')
|
||||
print "player = ", player, do_stat(stat_dict, player = player, stat = 'ffreq2')
|
||||
print "player = ", player, do_stat(stat_dict, player = player, stat = 'ffreq3')
|
||||
print "player = ", player, do_stat(stat_dict, player = player, stat = 'ffreq4')
|
||||
print "\n"
|
||||
|
||||
print "\n\nLegal stats:"
|
||||
|
|
|
@ -33,12 +33,12 @@ class UltimateBet(HandHistoryConverter):
|
|||
re_Board = re.compile(r"\[(?P<CARDS>.+)\]")
|
||||
# self.re_setHandInfoRegex('.*#(?P<HID>[0-9]+): Table (?P<TABLE>[ a-zA-Z]+) - \$?(?P<SB>[.0-9]+)/\$?(?P<BB>[.0-9]+) - (?P<GAMETYPE>.*) - (?P<HR>[0-9]+):(?P<MIN>[0-9]+) ET - (?P<YEAR>[0-9]+)/(?P<MON>[0-9]+)/(?P<DAY>[0-9]+)Table (?P<TABLE>[ a-zA-Z]+)\nSeat (?P<BUTTON>[0-9]+)')
|
||||
|
||||
def __init__(self, in_path = '-', out_path = '-', follow = False, autostart=True):
|
||||
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="UltimateBet", follow=follow)
|
||||
HandHistoryConverter.__init__(self, in_path, out_path, sitename="UltimateBet", follow=follow, index=index)
|
||||
logging.info("Initialising UltimateBetconverter class")
|
||||
self.filetype = "text"
|
||||
self.codepage = "cp1252"
|
||||
|
|
381
pyfpdb/Win2dayToFpdb.py
Executable file
381
pyfpdb/Win2dayToFpdb.py
Executable file
|
@ -0,0 +1,381 @@
|
|||
#!/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
|
||||
########################################################################
|
||||
|
||||
import sys
|
||||
import datetime
|
||||
from HandHistoryConverter import *
|
||||
|
||||
# Win2day HH Format
|
||||
|
||||
class Win2day(HandHistoryConverter):
|
||||
|
||||
# Static regexes
|
||||
#<HISTORY ID="102271403" SESSION="session31237702.xml" TABLE="Innsbruck 3" GAME="GAME_THM" GAMETYPE="GAMETYPE_REAL" GAMEKIND="GAMEKIND_CASH" TABLECURRENCY="EUR" LIMIT="NL" STAKES="0.25/0.50" DATE="1246909773" WIN="0.00" LOSS="0.50">
|
||||
|
||||
#'^<HISTORY ID="(?P<HID>[0-9]+)" SESSION="session[0-9]+\.xml" TABLE="(?P<TABLE>[- a-zA-Z0-9]+)" GAME="(?P<GAME>[_A-Z]+)" GAMETYPE="[_a-zA-Z]+" GAMEKIND="[_a-zA-Z]+" TABLECURRENCY="(?P<CURRENCY>[A-Z]+)" LIMIT="(?P<LIMIT>NL|PL)" STAKES="(?P<SB>[.0-9]+)/(?P<BB>[.0-9]+)" DATE="(?P<DATETIME>[0-9]+)" WIN="[.0-9]+" LOSS="[.0-9]+">$'
|
||||
re_GameInfo = re.compile('^<HISTORY ID="(?P<HID>[0-9]+)" SESSION="session[0-9]+\.xml" TABLE="(?P<TABLE>[- a-zA-Z0-9]+)" GAME="(?P<GAME>[_A-Z]+)" GAMETYPE="[_a-zA-Z]+" GAMEKIND="[_a-zA-Z]+" TABLECURRENCY="(?P<CURRENCY>[A-Z]+)" LIMIT="(?P<LIMIT>NL|PL)" STAKES="(?P<SB>[.0-9]+)/(?P<BB>[.0-9]+)" DATE="(?P<DATETIME>[0-9]+)" WIN="[.0-9]+" LOSS="[.0-9]+">', re.MULTILINE)
|
||||
re_SplitHands = re.compile('</HISTORY>')
|
||||
re_HandInfo = re.compile("^Table \'(?P<TABLE>[- a-zA-Z]+)\'(?P<TABLEATTRIBUTES>.+?$)?", re.MULTILINE)
|
||||
re_Button = re.compile('<ACTION TYPE="HAND_DEAL" PLAYER="(?P<BUTTON>[^"]+)">\n<CARD LINK="[0-9b]+"></CARD>\n<CARD LINK="[0-9b]+"></CARD></ACTION>\n<ACTION TYPE="ACTION_', re.MULTILINE)
|
||||
#<PLAYER NAME="prato" SEAT="1" AMOUNT="61.29"></PLAYER>
|
||||
re_PlayerInfo = re.compile('^<PLAYER NAME="(?P<PNAME>.*)" SEAT="(?P<SEAT>[0-9]+)" AMOUNT="(?P<CASH>[.0-9]+)"></PLAYER>', re.MULTILINE)
|
||||
re_Card = re.compile('^<CARD LINK="(?P<CARD>[0-9]+)"></CARD>', re.MULTILINE)
|
||||
re_BoardLast = re.compile('^<CARD LINK="(?P<CARD>[0-9]+)"></CARD></ACTION>', re.MULTILINE)
|
||||
|
||||
def __init__(self, in_path = '-', out_path = '-', follow = False, autostart=True, index=0):
|
||||
HandHistoryConverter.__init__(self, in_path, out_path, sitename="Win2day", follow=follow, index=index)
|
||||
logging.info("Initialising Win2day converter class")
|
||||
self.filetype = "text"
|
||||
self.codepage = "cp1252"
|
||||
self.sideID = 4
|
||||
if autostart:
|
||||
self.start()
|
||||
|
||||
|
||||
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)
|
||||
#<ACTION TYPE="HAND_BLINDS" PLAYER="prato" KIND="HAND_SB" VALUE="0.25"></ACTION>
|
||||
|
||||
self.re_PostSB = re.compile(r'^<ACTION TYPE="HAND_BLINDS" PLAYER="%s" KIND="HAND_SB" VALUE="(?P<SB>[.0-9]+)"></ACTION>' % player_re, re.MULTILINE)
|
||||
self.re_PostBB = re.compile(r'^<ACTION TYPE="HAND_BLINDS" PLAYER="%s" KIND="HAND_BB" VALUE="(?P<BB>[.0-9]+)"></ACTION>' % player_re, re.MULTILINE)
|
||||
self.re_Antes = re.compile(r"^%s: posts the ante \$?(?P<ANTE>[.0-9]+)" % player_re, re.MULTILINE)
|
||||
self.re_BringIn = re.compile(r"^%s: brings[- ]in( low|) for \$?(?P<BRINGIN>[.0-9]+)" % player_re, re.MULTILINE)
|
||||
self.re_PostBoth = re.compile(r'^<ACTION TYPE="HAND_BLINDS" PLAYER="%s" KIND="HAND_AB" VALUE="(?P<SBBB>[.0-9]+)"></ACTION>' % player_re, re.MULTILINE)
|
||||
|
||||
#r'<ACTION TYPE="HAND_DEAL" PLAYER="%s">\n<CARD LINK="(?P<CARD1>[0-9]+)"></CARD>\n<CARD LINK="(?P<CARD2>[0-9]+)"></CARD></ACTION>'
|
||||
self.re_HeroCards = re.compile(r'<ACTION TYPE="HAND_DEAL" PLAYER="%s">\n(?P<CARDS><CARD LINK="[0-9]+"></CARD>\n<CARD LINK="[0-9]"></CARD>)</ACTION>' % player_re, re.MULTILINE)
|
||||
|
||||
#'^<ACTION TYPE="(?P<ATYPE>[_A-Z]+)" PLAYER="%s"( VALUE="(?P<BET>[.0-9]+)")?></ACTION>'
|
||||
self.re_Action = re.compile(r'^<ACTION TYPE="(?P<ATYPE>[_A-Z]+)" PLAYER="%s"( VALUE="(?P<BET>[.0-9]+)")?></ACTION>' % player_re, re.MULTILINE)
|
||||
|
||||
self.re_ShowdownAction = re.compile(r'<RESULT PLAYER="%s" WIN="[.0-9]+" HAND="(?P<HAND>\(\$STR_G_FOLD\)|[\$\(\)_ A-Z]+)">\n(?P<CARDS><CARD LINK="[0-9]+"></CARD>\n<CARD LINK="[0-9]+"></CARD>)</RESULT>' % player_re, re.MULTILINE)
|
||||
#<RESULT PLAYER="wig0r" WIN="4.10" HAND="$(STR_G_WIN_TWOPAIR) $(STR_G_CARDS_TENS) $(STR_G_ANDTEXT) $(STR_G_CARDS_EIGHTS)">
|
||||
#
|
||||
self.re_CollectPot = re.compile(r'<RESULT PLAYER="%s" WIN="(?P<POT>[.\d]+)" HAND=".+">' % player_re, re.MULTILINE)
|
||||
self.re_sitsOut = re.compile("^%s sits out" % player_re, re.MULTILINE)
|
||||
self.re_ShownCards = re.compile("^Seat (?P<SEAT>[0-9]+): %s \(.*\) showed \[(?P<CARDS>.*)\].*" % player_re, re.MULTILINE)
|
||||
|
||||
|
||||
def readSupportedGames(self):
|
||||
return [["ring", "hold", "nl"],
|
||||
["ring", "hold", "pl"],
|
||||
["ring", "hold", "fl"],
|
||||
["ring", "stud", "fl"],
|
||||
["ring", "draw", "fl"],
|
||||
["ring", "omaha", "pl"]
|
||||
]
|
||||
|
||||
def determineGameType(self, handText):
|
||||
info = {'type':'ring'}
|
||||
|
||||
m = self.re_GameInfo.search(handText)
|
||||
if not m:
|
||||
print "determineGameType:", handText
|
||||
return None
|
||||
|
||||
mg = m.groupdict()
|
||||
|
||||
# translations from captured groups to our info strings
|
||||
#limits = { 'NL':'nl', 'PL':'pl', 'Limit':'fl' }
|
||||
limits = { 'NL':'nl', 'PL':'pl'}
|
||||
games = { # base, category
|
||||
"GAME_THM" : ('hold','holdem'),
|
||||
# 'Omaha' : ('hold','omahahi'),
|
||||
#'Omaha Hi/Lo' : ('hold','omahahilo'),
|
||||
# 'Razz' : ('stud','razz'),
|
||||
#'7 Card Stud' : ('stud','studhi'),
|
||||
# 'Badugi' : ('draw','badugi')
|
||||
}
|
||||
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']
|
||||
if 'BB' in mg:
|
||||
info['bb'] = mg['BB']
|
||||
if 'CURRENCY' in mg:
|
||||
info['currency'] = mg['CURRENCY']
|
||||
# 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())
|
||||
# TODO: Be less lazy and parse maxseats from the HandInfo regex
|
||||
if m.group('TABLEATTRIBUTES'):
|
||||
m2 = re.search("\s*(\d+)-max", m.group('TABLEATTRIBUTES'))
|
||||
hand.maxseats = int(m2.group(1))
|
||||
m = self.re_GameInfo.search(hand.handText)
|
||||
if m: info.update(m.groupdict())
|
||||
m = self.re_Button.search(hand.handText)
|
||||
if m: info.update(m.groupdict())
|
||||
# TODO : I rather like the idea of just having this dict as hand.info
|
||||
logging.debug("readHandInfo: %s" % info)
|
||||
for key in info:
|
||||
if key == 'DATETIME':
|
||||
# Win2day uses UTC timestamp
|
||||
hand.starttime = datetime.datetime.fromtimestamp(int(info[key]))
|
||||
if key == 'HID':
|
||||
hand.handid = info[key]
|
||||
if key == 'TABLE':
|
||||
hand.tablename = info[key]
|
||||
if key == 'BUTTON':
|
||||
hand.buttonpos = info[key]
|
||||
|
||||
def readButton(self, hand):
|
||||
m = self.re_Button.search(hand.handText)
|
||||
if m:
|
||||
for player in hand.players:
|
||||
if player[1] == m.group('BUTTON'):
|
||||
hand.buttonpos = player[0]
|
||||
break
|
||||
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'), 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.
|
||||
if hand.gametype['base'] in ("hold"):
|
||||
#m = re.search(r"\*\*\* HOLE CARDS \*\*\*(?P<PREFLOP>.+(?=\*\*\* FLOP \*\*\*)|.+)"
|
||||
# r"(\*\*\* FLOP \*\*\*(?P<FLOP> \[\S\S \S\S \S\S\].+(?=\*\*\* TURN \*\*\*)|.+))?"
|
||||
# r"(\*\*\* TURN \*\*\* \[\S\S \S\S \S\S] (?P<TURN>\[\S\S\].+(?=\*\*\* RIVER \*\*\*)|.+))?"
|
||||
# r"(\*\*\* RIVER \*\*\* \[\S\S \S\S \S\S \S\S] (?P<RIVER>\[\S\S\].+))?", hand.handText,re.DOTALL)
|
||||
|
||||
m = re.search('<ACTION TYPE="HAND_BLINDS" PLAYER=".+" KIND="HAND_BB" VALUE="[.0-9]+"></ACTION>(?P<PREFLOP>.+(?=<ACTION TYPE="HAND_BOARD" VALUE="BOARD_FLOP")|.+)'
|
||||
'((?P<FLOP><ACTION TYPE="HAND_BOARD" VALUE="BOARD_FLOP" POT="[.0-9]+">.+(?=<ACTION TYPE="HAND_BOARD" VALUE="BOARD_TURN")|.+))?'
|
||||
'((?P<TURN><ACTION TYPE="HAND_BOARD" VALUE="BOARD_TURN" POT="[.0-9]+">.+(?=<ACTION TYPE="HAND_BOARD" VALUE="BOARD_RIVER")|.+))?'
|
||||
'((?P<RIVER><ACTION TYPE="HAND_BOARD" VALUE="BOARD_RIVER" POT="[.0-9]+">.+(?=<SHOWDOWN NAME="HAND_SHOWDOWN")|.+))?', hand.handText,re.DOTALL)
|
||||
|
||||
hand.addStreets(m)
|
||||
|
||||
def readCommunityCards(self, hand, street): # street has been matched by markStreets, so exists in this hand
|
||||
if street in ('FLOP','TURN','RIVER'): # a list of streets which get dealt community cards (i.e. all but PREFLOP)
|
||||
#print "DEBUG readCommunityCards:", street, hand.streets.group(street)
|
||||
|
||||
boardCards = set([])
|
||||
if street == 'FLOP':
|
||||
m = self.re_Card.findall(hand.streets[street])
|
||||
for card in m:
|
||||
boardCards.add(self.convertWin2dayCards(card))
|
||||
else:
|
||||
m = self.re_BoardLast.search(hand.streets[street])
|
||||
boardCards.add(self.convertWin2dayCards(m.group('CARD')))
|
||||
|
||||
hand.setCommunityCards(street, boardCards)
|
||||
|
||||
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("readBringIn: %s for %s" %(m.group('PNAME'), m.group('BRINGIN')))
|
||||
hand.addBringIn(m.group('PNAME'), m.group('BRINGIN'))
|
||||
|
||||
def readBlinds(self, hand):
|
||||
try:
|
||||
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'))
|
||||
for a in self.re_PostBoth.finditer(hand.handText):
|
||||
hand.addBlind(a.group('PNAME'), 'small & big blinds', a.group('SBBB'))
|
||||
|
||||
def readHeroCards(self, hand):
|
||||
# streets PREFLOP, PREDRAW, and THIRD are special cases beacause
|
||||
# we need to grab hero's cards
|
||||
m = self.re_HeroCards.finditer(hand.streets['PREFLOP'])
|
||||
newcards = []
|
||||
for found in m:
|
||||
hand.hero = found.group('PNAME')
|
||||
for card in self.re_Card.finditer(found.group('CARDS')):
|
||||
print self.convertWin2dayCards(card.group('CARD'))
|
||||
newcards.append(self.convertWin2dayCards(card.group('CARD')))
|
||||
|
||||
#hand.addHoleCards(holeCards, m.group('PNAME'))
|
||||
hand.addHoleCards('PREFLOP', hand.hero, closed=newcards, shown=False, mucked=False, dealt=True)
|
||||
|
||||
def convertWin2dayCards(self, card):
|
||||
card = int(card)
|
||||
retCard = ''
|
||||
cardconvert = { 1:'A',
|
||||
10:'T',
|
||||
11:'J',
|
||||
12:'Q',
|
||||
13:'K'}
|
||||
realNumber = card % 13 + 1
|
||||
if(realNumber in cardconvert):
|
||||
retCard += cardconvert[realNumber]
|
||||
else:
|
||||
retCard += str(realNumber)
|
||||
|
||||
if(card > 38):
|
||||
retCard += 's'
|
||||
elif(card > 25):
|
||||
retCard += 'h'
|
||||
elif(card > 12):
|
||||
retCard += 'c'
|
||||
else:
|
||||
retCard += 'd'
|
||||
|
||||
return(retCard)
|
||||
|
||||
def readDrawCards(self, hand, street):
|
||||
logging.debug("readDrawCards")
|
||||
m = self.re_HeroCards.finditer(hand.streets[street])
|
||||
if m == None:
|
||||
hand.involved = False
|
||||
else:
|
||||
for player in m:
|
||||
hand.hero = player.group('PNAME') # Only really need to do this once
|
||||
newcards = player.group('NEWCARDS')
|
||||
oldcards = player.group('OLDCARDS')
|
||||
if newcards == None:
|
||||
newcards = set()
|
||||
else:
|
||||
newcards = set(newcards.split(' '))
|
||||
if oldcards == None:
|
||||
oldcards = set()
|
||||
else:
|
||||
oldcards = set(oldcards.split(' '))
|
||||
hand.addDrawHoleCards(newcards, oldcards, player.group('PNAME'), street)
|
||||
|
||||
|
||||
def readStudPlayerCards(self, hand, street):
|
||||
# See comments of reference implementation in FullTiltToFpdb.py
|
||||
logging.debug("readStudPlayerCards")
|
||||
m = self.re_HeroCards.finditer(hand.streets[street])
|
||||
for player in m:
|
||||
#~ logging.debug(player.groupdict())
|
||||
(pname, oldcards, newcards) = (player.group('PNAME'), player.group('OLDCARDS'), player.group('NEWCARDS'))
|
||||
if oldcards:
|
||||
oldcards = [c.strip() for c in oldcards.split(' ')]
|
||||
if newcards:
|
||||
newcards = [c.strip() for c in newcards.split(' ')]
|
||||
if street=='ANTES':
|
||||
return
|
||||
elif street=='THIRD':
|
||||
# we'll have observed hero holecards in CARDS and thirdstreet open cards in 'NEWCARDS'
|
||||
# hero: [xx][o]
|
||||
# others: [o]
|
||||
hand.addPlayerCards(player = player.group('PNAME'), street = street, closed = oldcards, open = newcards)
|
||||
elif street in ('FOURTH', 'FIFTH', 'SIXTH'):
|
||||
# 4th:
|
||||
# hero: [xxo] [o]
|
||||
# others: [o] [o]
|
||||
# 5th:
|
||||
# hero: [xxoo] [o]
|
||||
# others: [oo] [o]
|
||||
# 6th:
|
||||
# hero: [xxooo] [o]
|
||||
# others: [ooo] [o]
|
||||
hand.addPlayerCards(player = player.group('PNAME'), street = street, open = newcards)
|
||||
# we may additionally want to check the earlier streets tally with what we have but lets trust it for now.
|
||||
elif street=='SEVENTH' and newcards:
|
||||
# hero: [xxoooo] [x]
|
||||
# others: not reported.
|
||||
hand.addPlayerCards(player = player.group('PNAME'), street = street, closed = newcards)
|
||||
|
||||
def readAction(self, hand, street):
|
||||
m = self.re_Action.finditer(hand.streets[street])
|
||||
for action in m:
|
||||
if action.group('ATYPE') == 'ACTION_RAISE':
|
||||
hand.addRaiseBy( street, action.group('PNAME'), action.group('BET') )
|
||||
elif action.group('ATYPE') == 'ACTION_CALL':
|
||||
hand.addCall( street, action.group('PNAME'), action.group('BET') )
|
||||
elif action.group('ATYPE') == 'ACTION_ALLIN':
|
||||
hand.addRaiseBy( street, action.group('PNAME'), action.group('BET') )
|
||||
elif action.group('ATYPE') == 'ACTION_BET':
|
||||
hand.addBet( street, action.group('PNAME'), action.group('BET') )
|
||||
elif action.group('ATYPE') == 'ACTION_FOLD':
|
||||
hand.addFold( street, action.group('PNAME'))
|
||||
elif action.group('ATYPE') == 'ACTION_CHECK':
|
||||
hand.addCheck( street, action.group('PNAME'))
|
||||
elif action.group('ATYPE') == 'ACTION_DISCARD':
|
||||
hand.addDiscard(street, action.group('PNAME'), action.group('NODISCARDED'), action.group('DISCARDED'))
|
||||
elif action.group('ATYPE') == 'ACTION_STAND':
|
||||
hand.addStandsPat( street, action.group('PNAME'))
|
||||
else:
|
||||
print "DEBUG: unimplemented readAction: '%s' '%s'" %(action.group('PNAME'),action.group('ATYPE'),)
|
||||
|
||||
|
||||
def readShowdownActions(self, hand):
|
||||
for shows in self.re_ShowdownAction.finditer(hand.handText):
|
||||
showdownCards = set([])
|
||||
for card in self.re_Card.finditer(shows.group('CARDS')):
|
||||
#print "DEBUG:", card, card.group('CARD'), self.convertWin2dayCards(card.group('CARD'))
|
||||
showdownCards.add(self.convertWin2dayCards(card.group('CARD')))
|
||||
|
||||
hand.addShownCards(showdownCards, shows.group('PNAME'))
|
||||
|
||||
def readCollectPot(self,hand):
|
||||
for m in self.re_CollectPot.finditer(hand.handText):
|
||||
potcoll = Decimal(m.group('POT'))
|
||||
if potcoll > 0:
|
||||
hand.addCollectPot(player=m.group('PNAME'),pot=potcoll)
|
||||
|
||||
def readShownCards(self,hand):
|
||||
for m in self.re_ShownCards.finditer(hand.handText):
|
||||
if m.group('CARDS') is not None:
|
||||
cards = m.group('CARDS')
|
||||
cards = set(cards.split(' '))
|
||||
hand.addShownCards(cards=cards, player=m.group('PNAME'))
|
||||
|
||||
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 = Win2day(in_path = options.ipath, out_path = options.opath, follow = options.follow)
|
|
@ -17,9 +17,9 @@
|
|||
|
||||
import os
|
||||
import sys
|
||||
import threading
|
||||
import Options
|
||||
import string
|
||||
|
||||
cl_options = string.join(sys.argv[1:])
|
||||
(options, sys.argv) = Options.fpdb_options()
|
||||
|
||||
|
@ -28,10 +28,14 @@ if not options.errorsToConsole:
|
|||
errorFile = open('fpdb-error-log.txt', 'w', 0)
|
||||
sys.stderr = errorFile
|
||||
|
||||
import logging
|
||||
|
||||
import pygtk
|
||||
pygtk.require('2.0')
|
||||
import gtk
|
||||
|
||||
import interlocks
|
||||
|
||||
|
||||
import fpdb_simple
|
||||
import GuiBulkImport
|
||||
|
@ -115,11 +119,13 @@ class fpdb:
|
|||
def dia_create_del_database(self, widget, data=None):
|
||||
print "todo: implement dia_create_del_database"
|
||||
self.obtain_global_lock()
|
||||
self.release_global_lock()
|
||||
#end def dia_create_del_database
|
||||
|
||||
def dia_create_del_user(self, widget, data=None):
|
||||
print "todo: implement dia_create_del_user"
|
||||
self.obtain_global_lock()
|
||||
self.release_global_lock()
|
||||
#end def dia_create_del_user
|
||||
|
||||
def dia_database_stats(self, widget, data=None):
|
||||
|
@ -128,7 +134,7 @@ class fpdb:
|
|||
#end def dia_database_stats
|
||||
|
||||
def dia_database_sessions(self, widget, data=None):
|
||||
new_sessions_thread=GuiSessionViewer.GuiSessionViewer(self.config, self.querydict)
|
||||
new_sessions_thread=GuiSessionViewer.GuiSessionViewer(self.config, self.sql)
|
||||
self.threads.append(new_sessions_thread)
|
||||
sessions_tab=new_sessions_thread.get_vbox()
|
||||
self.add_and_display_tab(sessions_tab, "Sessions")
|
||||
|
@ -136,16 +142,19 @@ class fpdb:
|
|||
def dia_delete_db_parts(self, widget, data=None):
|
||||
print "todo: implement dia_delete_db_parts"
|
||||
self.obtain_global_lock()
|
||||
self.release_global_lock()
|
||||
#end def dia_delete_db_parts
|
||||
|
||||
def dia_edit_profile(self, widget=None, data=None, create_default=False, path=None):
|
||||
print "todo: implement dia_edit_profile"
|
||||
self.obtain_global_lock()
|
||||
self.release_global_lock()
|
||||
#end def dia_edit_profile
|
||||
|
||||
def dia_export_db(self, widget, data=None):
|
||||
print "todo: implement dia_export_db"
|
||||
self.obtain_global_lock()
|
||||
self.release_global_lock()
|
||||
#end def dia_export_db
|
||||
|
||||
def dia_get_db_root_credentials(self):
|
||||
|
@ -171,6 +180,7 @@ class fpdb:
|
|||
def dia_import_db(self, widget, data=None):
|
||||
print "todo: implement dia_import_db"
|
||||
self.obtain_global_lock()
|
||||
self.release_global_lock()
|
||||
#end def dia_import_db
|
||||
|
||||
def dia_licensing(self, widget, data=None):
|
||||
|
@ -179,7 +189,7 @@ class fpdb:
|
|||
|
||||
def dia_load_profile(self, widget, data=None):
|
||||
"""Dialogue to select a file to load a profile from"""
|
||||
if self.obtain_global_lock() == 0: # returns 0 if successful
|
||||
if self.obtain_global_lock(): # returns true if successful
|
||||
#try:
|
||||
# chooser = gtk.FileChooserDialog(title="Please select a profile file to load",
|
||||
# action=gtk.FILE_CHOOSER_ACTION_OPEN,
|
||||
|
@ -194,15 +204,18 @@ class fpdb:
|
|||
# print 'User cancelled loading profile'
|
||||
#except:
|
||||
# pass
|
||||
self.load_profile()
|
||||
try:
|
||||
self.load_profile()
|
||||
except:
|
||||
pass
|
||||
self.release_global_lock()
|
||||
#end def dia_load_profile
|
||||
|
||||
def dia_recreate_tables(self, widget, data=None):
|
||||
"""Dialogue that asks user to confirm that he wants to delete and recreate the tables"""
|
||||
if self.obtain_global_lock() in (0,2): # returns 0 if successful, 2 if Hands table does not exist
|
||||
if self.obtain_global_lock(): # returns true if successful
|
||||
|
||||
lock_released = False
|
||||
#lock_released = False
|
||||
try:
|
||||
dia_confirm = gtk.MessageDialog(parent=None, flags=0, type=gtk.MESSAGE_WARNING,
|
||||
buttons=(gtk.BUTTONS_YES_NO), message_format="Confirm deleting and recreating tables")
|
||||
|
@ -213,27 +226,46 @@ class fpdb:
|
|||
response = dia_confirm.run()
|
||||
dia_confirm.destroy()
|
||||
if response == gtk.RESPONSE_YES:
|
||||
if self.db.fdb.backend == self.fdb_lock.fdb.MYSQL_INNODB:
|
||||
#if self.db.fdb.backend == self.fdb_lock.fdb.MYSQL_INNODB:
|
||||
# mysql requires locks on all tables or none - easier to release this lock
|
||||
# than lock all the other tables
|
||||
# ToDo: lock all other tables so that lock doesn't have to be released
|
||||
self.release_global_lock()
|
||||
lock_released = True
|
||||
self.db.fdb.recreate_tables()
|
||||
else:
|
||||
# self.release_global_lock()
|
||||
# lock_released = True
|
||||
self.db.recreate_tables()
|
||||
#else:
|
||||
# for other dbs use same connection as holds global lock
|
||||
self.fdb_lock.fdb.recreate_tables()
|
||||
# self.fdb_lock.fdb.recreate_tables()
|
||||
elif response == gtk.RESPONSE_NO:
|
||||
print 'User cancelled recreating tables'
|
||||
except:
|
||||
pass
|
||||
if not lock_released:
|
||||
self.release_global_lock()
|
||||
#if not lock_released:
|
||||
self.release_global_lock()
|
||||
#end def dia_recreate_tables
|
||||
|
||||
def dia_recreate_hudcache(self, widget, data=None):
|
||||
if self.obtain_global_lock():
|
||||
try:
|
||||
dia_confirm = gtk.MessageDialog(parent=None, flags=0, type=gtk.MESSAGE_WARNING, buttons=(gtk.BUTTONS_YES_NO), message_format="Confirm recreating HUD cache")
|
||||
diastring = "Please confirm that you want to re-create the HUD cache."
|
||||
dia_confirm.format_secondary_text(diastring)
|
||||
|
||||
response = dia_confirm.run()
|
||||
dia_confirm.destroy()
|
||||
if response == gtk.RESPONSE_YES:
|
||||
self.db.rebuild_hudcache()
|
||||
elif response == gtk.REPSONSE_NO:
|
||||
print 'User cancelled rebuilding hud cache'
|
||||
except:
|
||||
pass
|
||||
self.release_global_lock()
|
||||
|
||||
|
||||
def dia_regression_test(self, widget, data=None):
|
||||
print "todo: implement dia_regression_test"
|
||||
self.obtain_global_lock()
|
||||
self.release_global_lock()
|
||||
#end def dia_regression_test
|
||||
|
||||
def dia_save_profile(self, widget, data=None):
|
||||
|
@ -292,6 +324,7 @@ class fpdb:
|
|||
<menuitem action="createdb"/>
|
||||
<menuitem action="createuser"/>
|
||||
<menuitem action="createtabs"/>
|
||||
<menuitem action="rebuildhudcache"/>
|
||||
<menuitem action="stats"/>
|
||||
<menuitem action="sessions"/>
|
||||
</menu>
|
||||
|
@ -330,6 +363,7 @@ class fpdb:
|
|||
('createdb', None, 'Create or Delete _Database (todo)', None, 'Create or Delete Database', self.dia_create_del_database),
|
||||
('createuser', None, 'Create or Delete _User (todo)', None, 'Create or Delete User', self.dia_create_del_user),
|
||||
('createtabs', None, 'Create or Recreate _Tables', None, 'Create or Recreate Tables ', self.dia_recreate_tables),
|
||||
('rebuildhudcache', None, 'Rebuild HUD Cache', None, 'Rebuild HUD Cache', self.dia_recreate_hudcache),
|
||||
('stats', None, '_Statistics (todo)', None, 'View Database Statistics', self.dia_database_stats),
|
||||
('sessions', None, 'Sessions', None, 'View Sessions', self.dia_database_sessions),
|
||||
('help', None, '_Help'),
|
||||
|
@ -352,6 +386,7 @@ class fpdb:
|
|||
"""Loads profile from the provided path name."""
|
||||
self.config = Configuration.Config(file=options.config, dbname=options.dbname)
|
||||
self.settings = {}
|
||||
self.settings['global_lock'] = self.lock
|
||||
if (os.sep=="/"):
|
||||
self.settings['os']="linuxmac"
|
||||
else:
|
||||
|
@ -395,7 +430,6 @@ class fpdb:
|
|||
self.status_bar.set_text("Status: Connected to %s database named %s on host %s" % (self.db.get_backend_name(),self.db.fdb.database, self.db.fdb.host))
|
||||
|
||||
# Database connected to successfully, load queries to pass on to other classes
|
||||
self.querydict = FpdbSQLQueries.FpdbSQLQueries(self.db.get_backend_name())
|
||||
self.db.connection.rollback()
|
||||
#end def load_profile
|
||||
|
||||
|
@ -404,10 +438,15 @@ class fpdb:
|
|||
#end def not_implemented
|
||||
|
||||
def obtain_global_lock(self):
|
||||
print "\nTaking global lock ..."
|
||||
self.fdb_lock = Database.Database(self.config, sql = self.sql)
|
||||
self.fdb_lock.do_connect(self.config)
|
||||
return self.fdb_lock.fdb.get_global_lock()
|
||||
ret = self.lock.acquire(False) # will return false if lock is already held
|
||||
if ret:
|
||||
print "\nGlobal lock taken ..."
|
||||
else:
|
||||
print "\nFailed to get global lock."
|
||||
return ret
|
||||
# need to release it later:
|
||||
# self.lock.release()
|
||||
|
||||
#end def obtain_global_lock
|
||||
|
||||
def quit(self, widget, data=None):
|
||||
|
@ -418,8 +457,7 @@ class fpdb:
|
|||
#end def quit_cliecked
|
||||
|
||||
def release_global_lock(self):
|
||||
self.fdb_lock.fdb.db.rollback()
|
||||
self.fdb_lock.fdb.disconnect()
|
||||
self.lock.release()
|
||||
print "Global lock released.\n"
|
||||
#end def release_global_lock
|
||||
|
||||
|
@ -438,20 +476,20 @@ class fpdb:
|
|||
def tab_bulk_import(self, widget, data=None):
|
||||
"""opens a tab for bulk importing"""
|
||||
#print "start of tab_bulk_import"
|
||||
new_import_thread=GuiBulkImport.GuiBulkImport(self.settings, self.config)
|
||||
new_import_thread = GuiBulkImport.GuiBulkImport(self.settings, self.config, self.sql)
|
||||
self.threads.append(new_import_thread)
|
||||
bulk_tab=new_import_thread.get_vbox()
|
||||
self.add_and_display_tab(bulk_tab, "Bulk Import")
|
||||
#end def tab_bulk_import
|
||||
|
||||
def tab_player_stats(self, widget, data=None):
|
||||
new_ps_thread=GuiPlayerStats.GuiPlayerStats(self.config, self.querydict, self.window)
|
||||
new_ps_thread=GuiPlayerStats.GuiPlayerStats(self.config, self.sql, self.window)
|
||||
self.threads.append(new_ps_thread)
|
||||
ps_tab=new_ps_thread.get_vbox()
|
||||
self.add_and_display_tab(ps_tab, "Player Stats")
|
||||
|
||||
def tab_positional_stats(self, widget, data=None):
|
||||
new_ps_thread=GuiPositionalStats.GuiPositionalStats(self.config, self.querydict)
|
||||
new_ps_thread = GuiPositionalStats.GuiPositionalStats(self.config, self.sql)
|
||||
self.threads.append(new_ps_thread)
|
||||
ps_tab=new_ps_thread.get_vbox()
|
||||
self.add_and_display_tab(ps_tab, "Positional Stats")
|
||||
|
@ -478,7 +516,7 @@ This program is licensed under the AGPL3, see docs"""+os.sep+"agpl-3.0.txt")
|
|||
def tabGraphViewer(self, widget, data=None):
|
||||
"""opens a graph viewer tab"""
|
||||
#print "start of tabGraphViewer"
|
||||
new_gv_thread = GuiGraphViewer.GuiGraphViewer(self.querydict, self.config)
|
||||
new_gv_thread = GuiGraphViewer.GuiGraphViewer(self.sql, self.config)
|
||||
self.threads.append(new_gv_thread)
|
||||
gv_tab=new_gv_thread.get_vbox()
|
||||
self.add_and_display_tab(gv_tab, "Graphs")
|
||||
|
@ -486,6 +524,8 @@ This program is licensed under the AGPL3, see docs"""+os.sep+"agpl-3.0.txt")
|
|||
|
||||
def __init__(self):
|
||||
self.threads = []
|
||||
# no more than 1 process can this lock at a time:
|
||||
self.lock = interlocks.InterProcessLock(name="fpdb_global_lock")
|
||||
self.db = None
|
||||
self.status_bar = None
|
||||
|
||||
|
|
|
@ -18,124 +18,21 @@
|
|||
import os
|
||||
import re
|
||||
import sys
|
||||
import logging
|
||||
from time import time, strftime
|
||||
|
||||
import fpdb_simple
|
||||
import FpdbSQLQueries
|
||||
|
||||
class fpdb_db:
|
||||
MYSQL_INNODB = 2
|
||||
PGSQL = 3
|
||||
SQLITE = 4
|
||||
def __init__(self):
|
||||
"""Simple constructor, doesnt really do anything"""
|
||||
self.db = None
|
||||
self.cursor = None
|
||||
self.sql = {}
|
||||
self.MYSQL_INNODB = 2
|
||||
self.PGSQL = 3
|
||||
self.SQLITE = 4
|
||||
|
||||
# Data Structures for index and foreign key creation
|
||||
# drop_code is an int with possible values: 0 - don't drop for bulk import
|
||||
# 1 - drop during bulk import
|
||||
# db differences:
|
||||
# - note that mysql automatically creates indexes on constrained columns when
|
||||
# foreign keys are created, while postgres does not. Hence the much longer list
|
||||
# of indexes is required for postgres.
|
||||
# all primary keys are left on all the time
|
||||
#
|
||||
# table column drop_code
|
||||
|
||||
self.indexes = [
|
||||
[ ] # no db with index 0
|
||||
, [ ] # no db with index 1
|
||||
, [ # indexes for mysql (list index 2)
|
||||
{'tab':'Players', 'col':'name', 'drop':0}
|
||||
, {'tab':'Hands', 'col':'siteHandNo', 'drop':0}
|
||||
, {'tab':'Tourneys', 'col':'siteTourneyNo', 'drop':0}
|
||||
]
|
||||
, [ # indexes for postgres (list index 3)
|
||||
{'tab':'Boardcards', 'col':'handId', 'drop':0}
|
||||
, {'tab':'Gametypes', 'col':'siteId', 'drop':0}
|
||||
, {'tab':'Hands', 'col':'gametypeId', 'drop':0} # mct 22/3/09
|
||||
, {'tab':'Hands', 'col':'siteHandNo', 'drop':0}
|
||||
, {'tab':'HandsActions', 'col':'handsPlayerId', 'drop':0}
|
||||
, {'tab':'HandsPlayers', 'col':'handId', 'drop':1}
|
||||
, {'tab':'HandsPlayers', 'col':'playerId', 'drop':1}
|
||||
, {'tab':'HandsPlayers', 'col':'tourneysPlayersId', 'drop':0}
|
||||
, {'tab':'HudCache', 'col':'gametypeId', 'drop':1}
|
||||
, {'tab':'HudCache', 'col':'playerId', 'drop':0}
|
||||
, {'tab':'HudCache', 'col':'tourneyTypeId', 'drop':0}
|
||||
, {'tab':'Players', 'col':'siteId', 'drop':1}
|
||||
, {'tab':'Players', 'col':'name', 'drop':0}
|
||||
, {'tab':'Tourneys', 'col':'tourneyTypeId', 'drop':1}
|
||||
, {'tab':'Tourneys', 'col':'siteTourneyNo', 'drop':0}
|
||||
, {'tab':'TourneysPlayers', 'col':'playerId', 'drop':0}
|
||||
, {'tab':'TourneysPlayers', 'col':'tourneyId', 'drop':0}
|
||||
, {'tab':'TourneyTypes', 'col':'siteId', 'drop':0}
|
||||
]
|
||||
]
|
||||
|
||||
self.foreignKeys = [
|
||||
[ ] # no db with index 0
|
||||
, [ ] # no db with index 1
|
||||
, [ # foreign keys for mysql
|
||||
{'fktab':'Hands', 'fkcol':'gametypeId', 'rtab':'Gametypes', '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':'HandsActions', 'fkcol':'handsPlayerId', 'rtab':'HandsPlayers', 'rcol':'id', 'drop':1}
|
||||
, {'fktab':'HudCache', 'fkcol':'gametypeId', 'rtab':'Gametypes', 'rcol':'id', 'drop':1}
|
||||
, {'fktab':'HudCache', 'fkcol':'playerId', 'rtab':'Players', 'rcol':'id', 'drop':0}
|
||||
, {'fktab':'HudCache', 'fkcol':'tourneyTypeId', 'rtab':'TourneyTypes', 'rcol':'id', 'drop':1}
|
||||
]
|
||||
, [ # foreign keys for postgres
|
||||
{'fktab':'Hands', 'fkcol':'gametypeId', 'rtab':'Gametypes', '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':'HandsActions', 'fkcol':'handsPlayerId', 'rtab':'HandsPlayers', 'rcol':'id', 'drop':1}
|
||||
, {'fktab':'HudCache', 'fkcol':'gametypeId', 'rtab':'Gametypes', 'rcol':'id', 'drop':1}
|
||||
, {'fktab':'HudCache', 'fkcol':'playerId', 'rtab':'Players', 'rcol':'id', 'drop':0}
|
||||
, {'fktab':'HudCache', 'fkcol':'tourneyTypeId', 'rtab':'TourneyTypes', 'rcol':'id', 'drop':1}
|
||||
]
|
||||
]
|
||||
|
||||
|
||||
# MySQL Notes:
|
||||
# "FOREIGN KEY (handId) REFERENCES Hands(id)" - requires index on Hands.id
|
||||
# - creates index handId on <thistable>.handId
|
||||
# alter table t drop foreign key fk
|
||||
# alter table t add foreign key (fkcol) references tab(rcol)
|
||||
# alter table t add constraint c foreign key (fkcol) references tab(rcol)
|
||||
# (fkcol is used for foreigh key name)
|
||||
|
||||
# mysql to list indexes:
|
||||
# SELECT table_name, index_name, non_unique, column_name
|
||||
# FROM INFORMATION_SCHEMA.STATISTICS
|
||||
# WHERE table_name = 'tbl_name'
|
||||
# AND table_schema = 'db_name'
|
||||
# ORDER BY table_name, index_name, seq_in_index
|
||||
#
|
||||
# ALTER TABLE Tourneys ADD INDEX siteTourneyNo(siteTourneyNo)
|
||||
# ALTER TABLE tab DROP INDEX idx
|
||||
|
||||
# mysql to list fks:
|
||||
# SELECT constraint_name, table_name, column_name, referenced_table_name, referenced_column_name
|
||||
# FROM information_schema.KEY_COLUMN_USAGE
|
||||
# WHERE REFERENCED_TABLE_SCHEMA = (your schema name here)
|
||||
# AND REFERENCED_TABLE_NAME is not null
|
||||
# ORDER BY TABLE_NAME, COLUMN_NAME;
|
||||
|
||||
# this may indicate missing object
|
||||
# _mysql_exceptions.OperationalError: (1025, "Error on rename of '.\\fpdb\\hands' to '.\\fpdb\\#sql2-7f0-1b' (errno: 152)")
|
||||
|
||||
|
||||
# PG notes:
|
||||
|
||||
# To add a foreign key constraint to a table:
|
||||
# ALTER TABLE tab ADD CONSTRAINT c FOREIGN KEY (col) REFERENCES t2(col2) MATCH FULL;
|
||||
# ALTER TABLE tab DROP CONSTRAINT zipchk
|
||||
#
|
||||
# Note: index names must be unique across a schema
|
||||
# CREATE INDEX idx ON tab(col)
|
||||
# DROP INDEX idx
|
||||
#end def __init__
|
||||
|
||||
def do_connect(self, config=None):
|
||||
|
@ -146,12 +43,12 @@ class fpdb_db:
|
|||
self.settings = {}
|
||||
self.settings['os'] = "linuxmac" if os.name != "nt" else "windows"
|
||||
|
||||
self.settings.update(config.get_db_parameters())
|
||||
self.connect(self.settings['db-backend'],
|
||||
self.settings['db-host'],
|
||||
self.settings['db-databaseName'],
|
||||
self.settings['db-user'],
|
||||
self.settings['db-password'])
|
||||
db = config.get_db_parameters()
|
||||
self.connect(backend=db['db-backend'],
|
||||
host=db['db-host'],
|
||||
database=db['db-databaseName'],
|
||||
user=db['db-user'],
|
||||
password=db['db-password'])
|
||||
#end def do_connect
|
||||
|
||||
def connect(self, backend=None, host=None, database=None,
|
||||
|
@ -164,13 +61,13 @@ class fpdb_db:
|
|||
self.user=user
|
||||
self.password=password
|
||||
self.database=database
|
||||
if backend==self.MYSQL_INNODB:
|
||||
if backend==fpdb_db.MYSQL_INNODB:
|
||||
import MySQLdb
|
||||
try:
|
||||
self.db = MySQLdb.connect(host = host, user = user, passwd = password, db = database, use_unicode=True)
|
||||
except:
|
||||
raise fpdb_simple.FpdbError("MySQL connection failed")
|
||||
elif backend==self.PGSQL:
|
||||
elif backend==fpdb_db.PGSQL:
|
||||
import psycopg2
|
||||
import psycopg2.extensions
|
||||
psycopg2.extensions.register_type(psycopg2.extensions.UNICODE)
|
||||
|
@ -182,9 +79,7 @@ class fpdb_db:
|
|||
# sqlcoder: This database only connect failed in my windows setup??
|
||||
# Modifed it to try the 4 parameter style if the first connect fails - does this work everywhere?
|
||||
connected = False
|
||||
if self.host == None or self.host == '' \
|
||||
or self.host == "localhost" \
|
||||
or self.host == "127.0.0.1":
|
||||
if self.host == "localhost" or self.host == "127.0.0.1":
|
||||
try:
|
||||
self.db = psycopg2.connect(database = database)
|
||||
connected = True
|
||||
|
@ -203,13 +98,19 @@ class fpdb_db:
|
|||
msg = "PostgreSQL connection to database (%s) user (%s) failed." % (database, user)
|
||||
print msg
|
||||
raise fpdb_simple.FpdbError(msg)
|
||||
elif backend==fpdb_db.SQLITE:
|
||||
logging.info("Connecting to SQLite:%(database)s" % {'database':database})
|
||||
import sqlite3
|
||||
self.db = sqlite3.connect(database,detect_types=sqlite3.PARSE_DECLTYPES)
|
||||
sqlite3.register_converter("bool", lambda x: bool(int(x)))
|
||||
sqlite3.register_adapter(bool, lambda x: "1" if x else "0")
|
||||
|
||||
else:
|
||||
raise fpdb_simple.FpdbError("unrecognised database backend:"+backend)
|
||||
self.cursor=self.db.cursor()
|
||||
self.cursor.execute('SET SESSION TRANSACTION ISOLATION LEVEL READ COMMITTED')
|
||||
self.db.commit()
|
||||
# Set up query dictionary as early in the connection process as we can.
|
||||
self.sql = FpdbSQLQueries.FpdbSQLQueries(self.get_backend_name())
|
||||
self.cursor.execute(self.sql.query['set tx level'])
|
||||
self.wrongDbVersion=False
|
||||
try:
|
||||
self.cursor.execute("SELECT * FROM Settings")
|
||||
|
@ -237,71 +138,6 @@ class fpdb_db:
|
|||
#print "started fpdb_db.reconnect"
|
||||
self.disconnect(due_to_error)
|
||||
self.connect(self.backend, self.host, self.database, self.user, self.password)
|
||||
|
||||
def create_tables(self):
|
||||
#todo: should detect and fail gracefully if tables already exist.
|
||||
self.cursor.execute(self.sql.query['createSettingsTable'])
|
||||
self.cursor.execute(self.sql.query['createSitesTable'])
|
||||
self.cursor.execute(self.sql.query['createGametypesTable'])
|
||||
self.cursor.execute(self.sql.query['createPlayersTable'])
|
||||
self.cursor.execute(self.sql.query['createAutoratesTable'])
|
||||
self.cursor.execute(self.sql.query['createHandsTable'])
|
||||
self.cursor.execute(self.sql.query['createTourneyTypesTable'])
|
||||
self.cursor.execute(self.sql.query['createTourneysTable'])
|
||||
self.cursor.execute(self.sql.query['createTourneysPlayersTable'])
|
||||
self.cursor.execute(self.sql.query['createHandsPlayersTable'])
|
||||
self.cursor.execute(self.sql.query['createHandsActionsTable'])
|
||||
self.cursor.execute(self.sql.query['createHudCacheTable'])
|
||||
#self.cursor.execute(self.sql.query['addTourneyIndex'])
|
||||
#self.cursor.execute(self.sql.query['addHandsIndex'])
|
||||
#self.cursor.execute(self.sql.query['addPlayersIndex'])
|
||||
self.fillDefaultData()
|
||||
self.db.commit()
|
||||
#end def disconnect
|
||||
|
||||
def drop_tables(self):
|
||||
"""Drops the fpdb tables from the current db"""
|
||||
|
||||
if(self.get_backend_name() == 'MySQL InnoDB'):
|
||||
#Databases with FOREIGN KEY support need this switched of before you can drop tables
|
||||
self.drop_referential_integrity()
|
||||
|
||||
# Query the DB to see what tables exist
|
||||
self.cursor.execute(self.sql.query['list_tables'])
|
||||
for table in self.cursor:
|
||||
self.cursor.execute(self.sql.query['drop_table'] + table[0])
|
||||
elif(self.get_backend_name() == 'PostgreSQL'):
|
||||
self.db.commit()# I have no idea why this makes the query work--REB 07OCT2008
|
||||
self.cursor.execute(self.sql.query['list_tables'])
|
||||
tables = self.cursor.fetchall()
|
||||
for table in tables:
|
||||
self.cursor.execute(self.sql.query['drop_table'] + table[0] + ' cascade')
|
||||
elif(self.get_backend_name() == 'SQLite'):
|
||||
#todo: sqlite version here
|
||||
print "Empty function here"
|
||||
|
||||
self.db.commit()
|
||||
#end def drop_tables
|
||||
|
||||
def drop_referential_integrity(self):
|
||||
"""Update all tables to remove foreign keys"""
|
||||
|
||||
self.cursor.execute(self.sql.query['list_tables'])
|
||||
result = self.cursor.fetchall()
|
||||
|
||||
for i in range(len(result)):
|
||||
self.cursor.execute("SHOW CREATE TABLE " + result[i][0])
|
||||
inner = self.cursor.fetchall()
|
||||
|
||||
for j in range(len(inner)):
|
||||
# result[i][0] - Table name
|
||||
# result[i][1] - CREATE TABLE parameters
|
||||
#Searching for CONSTRAINT `tablename_ibfk_1`
|
||||
for m in re.finditer('(ibfk_[0-9]+)', inner[j][1]):
|
||||
key = "`" + inner[j][0] + "_" + m.group() + "`"
|
||||
self.cursor.execute("ALTER TABLE " + inner[j][0] + " DROP FOREIGN KEY " + key)
|
||||
self.db.commit()
|
||||
#end drop_referential_inegrity
|
||||
|
||||
def get_backend_name(self):
|
||||
"""Returns the name of the currently used backend"""
|
||||
|
@ -309,6 +145,8 @@ class fpdb_db:
|
|||
return "MySQL InnoDB"
|
||||
elif self.backend==3:
|
||||
return "PostgreSQL"
|
||||
elif self.backend==4:
|
||||
return "SQLite"
|
||||
else:
|
||||
raise fpdb_simple.FpdbError("invalid backend")
|
||||
#end def get_backend_name
|
||||
|
@ -316,343 +154,108 @@ class fpdb_db:
|
|||
def get_db_info(self):
|
||||
return (self.host, self.database, self.user, self.password)
|
||||
#end def get_db_info
|
||||
|
||||
def fillDefaultData(self):
|
||||
self.cursor.execute("INSERT INTO Settings VALUES (118);")
|
||||
self.cursor.execute("INSERT INTO Sites VALUES (DEFAULT, 'Full Tilt Poker', 'USD');")
|
||||
self.cursor.execute("INSERT INTO Sites VALUES (DEFAULT, 'PokerStars', 'USD');")
|
||||
self.cursor.execute("INSERT INTO Sites VALUES (DEFAULT, 'Everleaf', 'USD');")
|
||||
self.cursor.execute("INSERT INTO TourneyTypes VALUES (DEFAULT, 1, 0, 0, 0, False);")
|
||||
#end def fillDefaultData
|
||||
|
||||
def recreate_tables(self):
|
||||
"""(Re-)creates the tables of the current DB"""
|
||||
|
||||
self.drop_tables()
|
||||
self.create_tables()
|
||||
self.createAllIndexes()
|
||||
self.db.commit()
|
||||
print "Finished recreating tables"
|
||||
#end def recreate_tables
|
||||
|
||||
def prepareBulkImport(self):
|
||||
"""Drop some indexes/foreign keys to prepare for bulk import.
|
||||
Currently keeping the standalone indexes as needed to import quickly"""
|
||||
stime = time()
|
||||
if self.backend == self.PGSQL:
|
||||
self.db.set_isolation_level(0) # allow table/index operations to work
|
||||
for fk in self.foreignKeys[self.backend]:
|
||||
if fk['drop'] == 1:
|
||||
if self.backend == self.MYSQL_INNODB:
|
||||
self.cursor.execute("SELECT constraint_name " +
|
||||
"FROM information_schema.KEY_COLUMN_USAGE " +
|
||||
#"WHERE REFERENCED_TABLE_SCHEMA = 'fpdb'
|
||||
"WHERE 1=1 " +
|
||||
"AND table_name = %s AND column_name = %s " +
|
||||
"AND referenced_table_name = %s " +
|
||||
"AND referenced_column_name = %s ",
|
||||
(fk['fktab'], fk['fkcol'], fk['rtab'], fk['rcol']) )
|
||||
cons = self.cursor.fetchone()
|
||||
#print "preparebulk: cons=", cons
|
||||
if cons:
|
||||
print "dropping mysql fk", cons[0], fk['fktab'], fk['fkcol']
|
||||
try:
|
||||
self.cursor.execute("alter table " + fk['fktab'] + " drop foreign key " + cons[0])
|
||||
except:
|
||||
pass
|
||||
elif self.backend == self.PGSQL:
|
||||
# DON'T FORGET TO RECREATE THEM!!
|
||||
print "dropping pg fk", fk['fktab'], fk['fkcol']
|
||||
try:
|
||||
# try to lock table to see if index drop will work:
|
||||
# hmmm, tested by commenting out rollback in grapher. lock seems to work but
|
||||
# then drop still hangs :-( does work in some tests though??
|
||||
# will leave code here for now pending further tests/enhancement ...
|
||||
self.cursor.execute( "lock table %s in exclusive mode nowait" % (fk['fktab'],) )
|
||||
#print "after lock, status:", self.cursor.statusmessage
|
||||
#print "alter table %s drop constraint %s_%s_fkey" % (fk['fktab'], fk['fktab'], fk['fkcol'])
|
||||
try:
|
||||
self.cursor.execute("alter table %s drop constraint %s_%s_fkey" % (fk['fktab'], fk['fktab'], fk['fkcol']))
|
||||
print "dropped pg fk pg fk %s_%s_fkey, continuing ..." % (fk['fktab'], fk['fkcol'])
|
||||
except:
|
||||
if "does not exist" not in str(sys.exc_value):
|
||||
print "warning: drop pg fk %s_%s_fkey failed: %s, continuing ..." \
|
||||
% (fk['fktab'], fk['fkcol'], str(sys.exc_value).rstrip('\n') )
|
||||
except:
|
||||
print "warning: constraint %s_%s_fkey not dropped: %s, continuing ..." \
|
||||
% (fk['fktab'],fk['fkcol'], str(sys.exc_value).rstrip('\n'))
|
||||
else:
|
||||
print "Only MySQL and Postgres supported so far"
|
||||
return -1
|
||||
|
||||
for idx in self.indexes[self.backend]:
|
||||
if idx['drop'] == 1:
|
||||
if self.backend == self.MYSQL_INNODB:
|
||||
print "dropping mysql index ", idx['tab'], idx['col']
|
||||
try:
|
||||
# apparently nowait is not implemented in mysql so this just hands if there are locks
|
||||
# preventing the index drop :-(
|
||||
self.cursor.execute( "alter table %s drop index %s", (idx['tab'],idx['col']) )
|
||||
except:
|
||||
pass
|
||||
elif self.backend == self.PGSQL:
|
||||
# DON'T FORGET TO RECREATE THEM!!
|
||||
print "dropping pg index ", idx['tab'], idx['col']
|
||||
try:
|
||||
# try to lock table to see if index drop will work:
|
||||
self.cursor.execute( "lock table %s in exclusive mode nowait" % (idx['tab'],) )
|
||||
#print "after lock, status:", self.cursor.statusmessage
|
||||
try:
|
||||
# table locked ok so index drop should work:
|
||||
#print "drop index %s_%s_idx" % (idx['tab'],idx['col'])
|
||||
self.cursor.execute( "drop index if exists %s_%s_idx" % (idx['tab'],idx['col']) )
|
||||
#print "dropped pg index ", idx['tab'], idx['col']
|
||||
except:
|
||||
if "does not exist" not in str(sys.exc_value):
|
||||
print "warning: drop index %s_%s_idx failed: %s, continuing ..." \
|
||||
% (idx['tab'],idx['col'], str(sys.exc_value).rstrip('\n'))
|
||||
except:
|
||||
print "warning: index %s_%s_idx not dropped %s, continuing ..." \
|
||||
% (idx['tab'],idx['col'], str(sys.exc_value).rstrip('\n'))
|
||||
else:
|
||||
print "Error: Only MySQL and Postgres supported so far"
|
||||
return -1
|
||||
|
||||
if self.backend == self.PGSQL:
|
||||
self.db.set_isolation_level(1) # go back to normal isolation level
|
||||
self.db.commit() # seems to clear up errors if there were any in postgres
|
||||
ptime = time() - stime
|
||||
print "prepare import took", ptime, "seconds"
|
||||
#end def prepareBulkImport
|
||||
|
||||
def afterBulkImport(self):
|
||||
"""Re-create any dropped indexes/foreign keys after bulk import"""
|
||||
stime = time()
|
||||
if self.backend == self.PGSQL:
|
||||
self.db.set_isolation_level(0) # allow table/index operations to work
|
||||
for fk in self.foreignKeys[self.backend]:
|
||||
if fk['drop'] == 1:
|
||||
if self.backend == self.MYSQL_INNODB:
|
||||
self.cursor.execute("SELECT constraint_name " +
|
||||
"FROM information_schema.KEY_COLUMN_USAGE " +
|
||||
#"WHERE REFERENCED_TABLE_SCHEMA = 'fpdb'
|
||||
"WHERE 1=1 " +
|
||||
"AND table_name = %s AND column_name = %s " +
|
||||
"AND referenced_table_name = %s " +
|
||||
"AND referenced_column_name = %s ",
|
||||
(fk['fktab'], fk['fkcol'], fk['rtab'], fk['rcol']) )
|
||||
cons = self.cursor.fetchone()
|
||||
print "afterbulk: cons=", cons
|
||||
if cons:
|
||||
pass
|
||||
else:
|
||||
print "creating fk ", fk['fktab'], fk['fkcol'], "->", fk['rtab'], fk['rcol']
|
||||
try:
|
||||
self.cursor.execute("alter table " + fk['fktab'] + " add foreign key ("
|
||||
+ fk['fkcol'] + ") references " + fk['rtab'] + "("
|
||||
+ fk['rcol'] + ")")
|
||||
except:
|
||||
pass
|
||||
elif self.backend == self.PGSQL:
|
||||
print "creating fk ", fk['fktab'], fk['fkcol'], "->", fk['rtab'], fk['rcol']
|
||||
try:
|
||||
self.cursor.execute("alter table " + fk['fktab'] + " add constraint "
|
||||
+ fk['fktab'] + '_' + fk['fkcol'] + '_fkey'
|
||||
+ " foreign key (" + fk['fkcol']
|
||||
+ ") references " + fk['rtab'] + "(" + fk['rcol'] + ")")
|
||||
except:
|
||||
pass
|
||||
else:
|
||||
print "Only MySQL and Postgres supported so far"
|
||||
return -1
|
||||
|
||||
for idx in self.indexes[self.backend]:
|
||||
if idx['drop'] == 1:
|
||||
if self.backend == self.MYSQL_INNODB:
|
||||
print "creating mysql index ", idx['tab'], idx['col']
|
||||
try:
|
||||
self.cursor.execute( "alter table %s add index %s(%s)"
|
||||
, (idx['tab'],idx['col'],idx['col']) )
|
||||
except:
|
||||
pass
|
||||
elif self.backend == self.PGSQL:
|
||||
# pass
|
||||
# mod to use tab_col for index name?
|
||||
print "creating pg index ", idx['tab'], idx['col']
|
||||
try:
|
||||
print "create index %s_%s_idx on %s(%s)" % (idx['tab'], idx['col'], idx['tab'], idx['col'])
|
||||
self.cursor.execute( "create index %s_%s_idx on %s(%s)"
|
||||
% (idx['tab'], idx['col'], idx['tab'], idx['col']) )
|
||||
except:
|
||||
print " ERROR! :-("
|
||||
pass
|
||||
else:
|
||||
print "Only MySQL and Postgres supported so far"
|
||||
return -1
|
||||
|
||||
if self.backend == self.PGSQL:
|
||||
self.db.set_isolation_level(1) # go back to normal isolation level
|
||||
self.db.commit() # seems to clear up errors if there were any in postgres
|
||||
atime = time() - stime
|
||||
print "after import took", atime, "seconds"
|
||||
#end def afterBulkImport
|
||||
|
||||
def createAllIndexes(self):
|
||||
"""Create new indexes"""
|
||||
if self.backend == self.PGSQL:
|
||||
self.db.set_isolation_level(0) # allow table/index operations to work
|
||||
for idx in self.indexes[self.backend]:
|
||||
if self.backend == self.MYSQL_INNODB:
|
||||
print "creating mysql index ", idx['tab'], idx['col']
|
||||
try:
|
||||
self.cursor.execute( "alter table %s add index %s(%s)"
|
||||
, (idx['tab'],idx['col'],idx['col']) )
|
||||
except:
|
||||
pass
|
||||
elif self.backend == self.PGSQL:
|
||||
# mod to use tab_col for index name?
|
||||
print "creating pg index ", idx['tab'], idx['col']
|
||||
try:
|
||||
print "create index %s_%s_idx on %s(%s)" % (idx['tab'], idx['col'], idx['tab'], idx['col'])
|
||||
self.cursor.execute( "create index %s_%s_idx on %s(%s)"
|
||||
% (idx['tab'], idx['col'], idx['tab'], idx['col']) )
|
||||
except:
|
||||
print " ERROR! :-("
|
||||
pass
|
||||
else:
|
||||
print "Only MySQL and Postgres supported so far"
|
||||
return -1
|
||||
if self.backend == self.PGSQL:
|
||||
self.db.set_isolation_level(1) # go back to normal isolation level
|
||||
#end def createAllIndexes
|
||||
|
||||
def dropAllIndexes(self):
|
||||
"""Drop all standalone indexes (i.e. not including primary keys or foreign keys)
|
||||
using list of indexes in indexes data structure"""
|
||||
# maybe upgrade to use data dictionary?? (but take care to exclude PK and FK)
|
||||
if self.backend == self.PGSQL:
|
||||
self.db.set_isolation_level(0) # allow table/index operations to work
|
||||
for idx in self.indexes[self.backend]:
|
||||
if self.backend == self.MYSQL_INNODB:
|
||||
print "dropping mysql index ", idx['tab'], idx['col']
|
||||
try:
|
||||
self.cursor.execute( "alter table %s drop index %s"
|
||||
, (idx['tab'],idx['col']) )
|
||||
except:
|
||||
pass
|
||||
elif self.backend == self.PGSQL:
|
||||
print "dropping pg index ", idx['tab'], idx['col']
|
||||
# mod to use tab_col for index name?
|
||||
try:
|
||||
self.cursor.execute( "drop index %s_%s_idx"
|
||||
% (idx['tab'],idx['col']) )
|
||||
except:
|
||||
pass
|
||||
else:
|
||||
print "Only MySQL and Postgres supported so far"
|
||||
return -1
|
||||
if self.backend == self.PGSQL:
|
||||
self.db.set_isolation_level(1) # go back to normal isolation level
|
||||
#end def dropAllIndexes
|
||||
|
||||
def analyzeDB(self):
|
||||
"""Do whatever the DB can offer to update index/table statistics"""
|
||||
stime = time()
|
||||
if self.backend == self.PGSQL:
|
||||
self.db.set_isolation_level(0) # allow vacuum to work
|
||||
try:
|
||||
self.cursor.execute("vacuum analyze")
|
||||
except:
|
||||
print "Error during vacuum"
|
||||
self.db.set_isolation_level(1) # go back to normal isolation level
|
||||
self.db.commit()
|
||||
atime = time() - stime
|
||||
print "analyze took", atime, "seconds"
|
||||
#end def analyzeDB
|
||||
|
||||
# Currently uses an exclusive lock on the Players table as a global lock
|
||||
# ( Changed because Hands is used in Database.init() )
|
||||
# Return values are Unix style, 0 for success, positive integers for errors
|
||||
# 1 = generic error
|
||||
# 2 = players table does not exist (error message is suppressed)
|
||||
def get_global_lock(self):
|
||||
if self.backend == self.MYSQL_INNODB:
|
||||
try:
|
||||
self.cursor.execute( "lock tables Players write" )
|
||||
except:
|
||||
# Table 'fpdb.players' doesn't exist
|
||||
if str(sys.exc_value).find(".Players' doesn't exist") >= 0:
|
||||
return(2)
|
||||
print "Error! failed to obtain global lock. Close all programs accessing " \
|
||||
+ "database (including fpdb) and try again (%s)." \
|
||||
% ( str(sys.exc_value).rstrip('\n'), )
|
||||
return(1)
|
||||
elif self.backend == self.PGSQL:
|
||||
try:
|
||||
self.db.commit()
|
||||
self.cursor.execute( "lock table Players in exclusive mode nowait" )
|
||||
#print "... after lock table, status =", self.cursor.statusmessage
|
||||
except:
|
||||
# relation "players" does not exist
|
||||
if str(sys.exc_value).find('does not exist') >= 0:
|
||||
return(2)
|
||||
print "Error! failed to obtain global lock. Close all programs accessing " \
|
||||
+ "database (including fpdb) and try again (%s)." \
|
||||
% ( str(sys.exc_value).rstrip('\n'), )
|
||||
return(1)
|
||||
return(0)
|
||||
|
||||
def getLastInsertId(self):
|
||||
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)
|
||||
self.cursor.execute ("SELECT lastval()")
|
||||
row = self.cursor.fetchone()
|
||||
if not row:
|
||||
print "getLastInsertId(%s): problem fetching lastval? row=" % seq, row
|
||||
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:
|
||||
# don't know how to do this in sqlite
|
||||
print "getLastInsertId(): not coded for sqlite yet"
|
||||
ret = -1
|
||||
else:
|
||||
ret = row[0]
|
||||
elif self.backend == self.SQLITE:
|
||||
# don't know how to do this in sqlite
|
||||
print "getLastInsertId(): not coded for sqlite yet"
|
||||
ret = -1
|
||||
else:
|
||||
print "getLastInsertId(): unknown backend ", self.backend
|
||||
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
|
||||
(siteHandNo, gametypeId, handStart, seats, tableName, importTime, maxSeats
|
||||
,boardcard1, boardcard2, boardcard3, boardcard4, boardcard5
|
||||
,playersVpi, playersAtStreet1, playersAtStreet2
|
||||
,playersAtStreet3, playersAtStreet4, playersAtShowdown
|
||||
,street0Raises, street1Raises, street2Raises
|
||||
,street3Raises, street4Raises, street1Pot
|
||||
,street2Pot, street3Pot, street4Pot
|
||||
,showdownPot
|
||||
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['siteHandNo'], gametype_id, p['handStart'], len(names), p['tableName'], datetime.datetime.today(), p['maxSeats']
|
||||
,p['boardcard1'], ['boardcard2'], p['boardcard3'], ['boardcard4'], ['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']
|
||||
)
|
||||
)
|
||||
(%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
|
||||
|
|
|
@ -22,6 +22,7 @@
|
|||
import os # todo: remove this once import_dir is in fpdb_import
|
||||
import sys
|
||||
from time import time, strftime
|
||||
import logging
|
||||
import traceback
|
||||
import math
|
||||
import datetime
|
||||
|
@ -53,14 +54,14 @@ except:
|
|||
|
||||
class Importer:
|
||||
|
||||
def __init__(self, caller, settings, config):
|
||||
def __init__(self, caller, settings, config, sql = None):
|
||||
"""Constructor"""
|
||||
self.settings = settings
|
||||
self.caller = caller
|
||||
self.config = config
|
||||
self.sql = sql
|
||||
|
||||
self.database = None # database will be the main db interface eventually
|
||||
self.fdb = None # fdb may disappear or just hold the simple db connection
|
||||
self.cursor = None
|
||||
self.filelist = {}
|
||||
self.dirlist = {}
|
||||
self.siteIds = {}
|
||||
|
@ -77,10 +78,10 @@ class Importer:
|
|||
self.settings.setdefault("minPrint", 30)
|
||||
self.settings.setdefault("handCount", 0)
|
||||
|
||||
self.database = Database.Database(self.config) # includes .connection and .sql variables
|
||||
self.fdb = fpdb_db.fpdb_db() # sets self.fdb.db self.fdb.cursor and self.fdb.sql
|
||||
self.fdb.do_connect(self.config)
|
||||
self.fdb.db.rollback()
|
||||
self.database = Database.Database(self.config, sql = self.sql) # includes .connection and .sql variables
|
||||
|
||||
self.NEWIMPORT = False
|
||||
self.allow_hudcache_rebuild = False
|
||||
|
||||
#Set functions
|
||||
def setCallHud(self, value):
|
||||
|
@ -119,8 +120,7 @@ class Importer:
|
|||
self.filelist[filename] = [site] + [filter]
|
||||
if site not in self.siteIds:
|
||||
# Get id from Sites table in DB
|
||||
self.fdb.cursor.execute(self.fdb.sql.query['getSiteId'], (site,))
|
||||
result = self.fdb.cursor.fetchall()
|
||||
result = self.database.get_site_id(site)
|
||||
if len(result) == 1:
|
||||
self.siteIds[site] = result[0][0]
|
||||
else:
|
||||
|
@ -165,13 +165,19 @@ class Importer:
|
|||
|
||||
def runImport(self):
|
||||
""""Run full import on self.filelist."""
|
||||
|
||||
start = datetime.datetime.now()
|
||||
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':
|
||||
self.settings['dropIndexes'] = self.calculate_auto2(10.0, 500.0)
|
||||
self.settings['dropIndexes'] = self.calculate_auto2(12.0, 500.0)
|
||||
if self.allow_hudcache_rebuild:
|
||||
self.settings['dropHudCache'] = self.calculate_auto2(25.0, 500.0) # returns "drop"/"don't drop"
|
||||
|
||||
if self.settings['dropIndexes'] == 'drop':
|
||||
self.fdb.prepareBulkImport()
|
||||
#self.settings['updateHudCache'] = self.calculate_auto2(10.0, 500.0)
|
||||
self.database.prepareBulkImport()
|
||||
else:
|
||||
print "No need to drop indexes."
|
||||
#print "dropInd =", self.settings['dropIndexes'], " dropHudCache =", self.settings['dropHudCache']
|
||||
totstored = 0
|
||||
totdups = 0
|
||||
totpartial = 0
|
||||
|
@ -186,8 +192,14 @@ class Importer:
|
|||
toterrors += errors
|
||||
tottime += ttime
|
||||
if self.settings['dropIndexes'] == 'drop':
|
||||
self.fdb.afterBulkImport()
|
||||
self.fdb.analyzeDB()
|
||||
self.database.afterBulkImport()
|
||||
else:
|
||||
print "No need to rebuild indexes."
|
||||
if self.allow_hudcache_rebuild and self.settings['dropHudCache'] == 'drop':
|
||||
self.database.rebuild_hudcache()
|
||||
else:
|
||||
print "No need to rebuild hudcache."
|
||||
self.database.analyzeDB()
|
||||
return (totstored, totdups, totpartial, toterrors, tottime)
|
||||
# else: import threaded
|
||||
|
||||
|
@ -196,7 +208,7 @@ class Importer:
|
|||
if len(self.filelist) == 1: return "don't drop"
|
||||
if 'handsInDB' not in self.settings:
|
||||
try:
|
||||
tmpcursor = self.fdb.db.cursor()
|
||||
tmpcursor = self.database.get_cursor()
|
||||
tmpcursor.execute("Select count(1) from Hands;")
|
||||
self.settings['handsInDB'] = tmpcursor.fetchone()[0]
|
||||
except:
|
||||
|
@ -219,7 +231,7 @@ class Importer:
|
|||
# get number of hands in db
|
||||
if 'handsInDB' not in self.settings:
|
||||
try:
|
||||
tmpcursor = self.fdb.db.cursor()
|
||||
tmpcursor = self.database.get_cursor()
|
||||
tmpcursor.execute("Select count(1) from Hands;")
|
||||
self.settings['handsInDB'] = tmpcursor.fetchone()[0]
|
||||
except:
|
||||
|
@ -234,11 +246,12 @@ class Importer:
|
|||
|
||||
# if hands_in_db is zero or very low, we want to drop indexes, otherwise compare
|
||||
# import size with db size somehow:
|
||||
#print "auto2: handsindb =", self.settings['handsInDB'], "total_size =", total_size, "size_per_hand =", \
|
||||
# size_per_hand, "inc =", increment
|
||||
ret = "don't drop"
|
||||
if self.settings['handsInDB'] < scale * (total_size/size_per_hand) + increment:
|
||||
return "drop"
|
||||
return "don't drop"
|
||||
ret = "drop"
|
||||
#print "auto2: handsindb =", self.settings['handsInDB'], "total_size =", total_size, "size_per_hand =", \
|
||||
# size_per_hand, "inc =", increment, "return:", ret
|
||||
return ret
|
||||
|
||||
#Run import on updated files, then store latest update time.
|
||||
def runUpdated(self):
|
||||
|
@ -282,12 +295,13 @@ class Importer:
|
|||
|
||||
self.addToDirList = {}
|
||||
self.removeFromFileList = {}
|
||||
self.fdb.db.rollback()
|
||||
self.database.rollback()
|
||||
#rulog.writelines(" finished\n")
|
||||
#rulog.close()
|
||||
|
||||
# This is now an internal function that should not be called directly.
|
||||
def import_file_dict(self, file, site, filter):
|
||||
#print "import_file_dict"
|
||||
if os.path.isdir(file):
|
||||
self.addToDirList[file] = [site] + [filter]
|
||||
return
|
||||
|
@ -309,9 +323,17 @@ class Importer:
|
|||
mod = __import__(filter)
|
||||
obj = getattr(mod, filter_name, None)
|
||||
if callable(obj):
|
||||
conv = obj(in_path = file, out_path = out_path)
|
||||
if(conv.getStatus()):
|
||||
conv = obj(in_path = file, out_path = out_path, index = 0) # Index into file 0 until changeover
|
||||
if(conv.getStatus() and self.NEWIMPORT == False):
|
||||
(stored, duplicates, partial, errors, ttime) = self.import_fpdb_file(out_path, site)
|
||||
elif (conv.getStatus() and self.NEWIMPORT == True):
|
||||
#This code doesn't do anything yet
|
||||
handlist = hhc.getProcessedHands()
|
||||
self.pos_in_file[file] = hhc.getLastCharacterRead()
|
||||
|
||||
for hand in handlist:
|
||||
hand.prepInsert()
|
||||
hand.insert()
|
||||
else:
|
||||
# conversion didn't work
|
||||
# TODO: appropriate response?
|
||||
|
@ -325,6 +347,7 @@ class Importer:
|
|||
|
||||
|
||||
def import_fpdb_file(self, file, site):
|
||||
#print "import_fpdb_file"
|
||||
starttime = time()
|
||||
last_read_hand = 0
|
||||
loc = 0
|
||||
|
@ -354,6 +377,8 @@ class Importer:
|
|||
self.pos_in_file[file] = inputFile.tell()
|
||||
inputFile.close()
|
||||
|
||||
#self.database.lock_for_insert() # should be ok when using one thread
|
||||
|
||||
try: # sometimes we seem to be getting an empty self.lines, in which case, we just want to return.
|
||||
firstline = self.lines[0]
|
||||
except:
|
||||
|
@ -395,10 +420,10 @@ class Importer:
|
|||
self.hand=hand
|
||||
|
||||
try:
|
||||
handsId = fpdb_parse_logic.mainParser( self.settings, self.fdb
|
||||
handsId = fpdb_parse_logic.mainParser( self.settings
|
||||
, self.siteIds[site], category, hand
|
||||
, self.config, self.database )
|
||||
self.fdb.db.commit()
|
||||
self.database.commit()
|
||||
|
||||
stored += 1
|
||||
if self.callHud:
|
||||
|
@ -408,23 +433,23 @@ class Importer:
|
|||
self.caller.pipe_to_hud.stdin.write("%s" % (handsId) + os.linesep)
|
||||
except fpdb_simple.DuplicateError:
|
||||
duplicates += 1
|
||||
self.fdb.db.rollback()
|
||||
self.database.rollback()
|
||||
except (ValueError), fe:
|
||||
errors += 1
|
||||
self.printEmailErrorMessage(errors, file, hand)
|
||||
|
||||
if (self.settings['failOnError']):
|
||||
self.fdb.db.commit() #dont remove this, in case hand processing was cancelled.
|
||||
self.database.commit() #dont remove this, in case hand processing was cancelled.
|
||||
raise
|
||||
else:
|
||||
self.fdb.db.rollback()
|
||||
self.database.rollback()
|
||||
except (fpdb_simple.FpdbError), fe:
|
||||
errors += 1
|
||||
self.printEmailErrorMessage(errors, file, hand)
|
||||
self.fdb.db.rollback()
|
||||
self.database.rollback()
|
||||
|
||||
if self.settings['failOnError']:
|
||||
self.fdb.db.commit() #dont remove this, in case hand processing was cancelled.
|
||||
self.database.commit() #dont remove this, in case hand processing was cancelled.
|
||||
raise
|
||||
|
||||
if self.settings['minPrint']:
|
||||
|
@ -451,7 +476,7 @@ class Importer:
|
|||
print "failed to read a single hand from file:", inputFile
|
||||
handsId=0
|
||||
#todo: this will cause return of an unstored hand number if the last hand was error
|
||||
self.fdb.db.commit()
|
||||
self.database.commit()
|
||||
self.handsId=handsId
|
||||
return (stored, duplicates, partial, errors, ttime)
|
||||
|
||||
|
|
|
@ -15,19 +15,25 @@
|
|||
#In the "official" distribution you can find the license in
|
||||
#agpl-3.0.txt in the docs folder of the package.
|
||||
|
||||
#methods that are specific to holdem but not trivial
|
||||
#parses an in-memory fpdb hand history and calls db routine to store it
|
||||
|
||||
import sys
|
||||
|
||||
import fpdb_simple
|
||||
import Database
|
||||
from time import time, strftime
|
||||
|
||||
|
||||
#parses a holdem hand
|
||||
def mainParser(settings, fdb, siteID, category, hand, config, db = None):
|
||||
def mainParser(settings, siteID, category, hand, config, db = None):
|
||||
#print "mainparser"
|
||||
# fdb is not used now - to be removed ...
|
||||
|
||||
t0 = time()
|
||||
#print "mainparser"
|
||||
backend = settings['db-backend']
|
||||
if db == None:
|
||||
#This is redundant - hopefully fdb will be a Database object in an iteration soon
|
||||
db = Database.Database(c = config, sql = None)
|
||||
else:
|
||||
db = db
|
||||
category = fpdb_simple.recogniseCategory(hand[0])
|
||||
|
||||
base = "hold" if category == "holdem" or category == "omahahi" or category == "omahahilo" else "stud"
|
||||
|
@ -50,9 +56,8 @@ def mainParser(settings, fdb, siteID, category, hand, config, db = None):
|
|||
if line[-2:] == "$0": continue
|
||||
smallBlindLine = i
|
||||
break
|
||||
#print "small blind line:",smallBlindLine
|
||||
|
||||
gametypeID = fpdb_simple.recogniseGametypeID(backend, fdb.db, fdb.cursor, hand[0], hand[smallBlindLine], siteID, category, isTourney)
|
||||
gametypeID = fpdb_simple.recogniseGametypeID(backend, db, db.get_cursor(), hand[0], hand[smallBlindLine], siteID, category, isTourney)
|
||||
if isTourney:
|
||||
siteTourneyNo = fpdb_simple.parseTourneyNo(hand[0])
|
||||
buyin = fpdb_simple.parseBuyin(hand[0])
|
||||
|
@ -63,9 +68,20 @@ def mainParser(settings, fdb, siteID, category, hand, config, db = None):
|
|||
tourneyStartTime= handStartTime #todo: read tourney start time
|
||||
rebuyOrAddon = fpdb_simple.isRebuyOrAddon(hand[0])
|
||||
|
||||
tourneyTypeId = fpdb_simple.recogniseTourneyTypeId(fdb.cursor, siteID, buyin, fee, knockout, rebuyOrAddon)
|
||||
tourneyTypeId = fpdb_simple.recogniseTourneyTypeId(db.get_cursor(), siteID, buyin, fee, knockout, rebuyOrAddon)
|
||||
else:
|
||||
siteTourneyNo = -1
|
||||
buyin = -1
|
||||
fee = -1
|
||||
entries = -1
|
||||
prizepool = -1
|
||||
knockout = 0
|
||||
tourneyStartTime= None
|
||||
rebuyOrAddon = -1
|
||||
|
||||
fpdb_simple.isAlreadyInDB(fdb.cursor, gametypeID, siteHandNo)
|
||||
tourneyTypeId = 1
|
||||
|
||||
fpdb_simple.isAlreadyInDB(db.get_cursor(), gametypeID, siteHandNo)
|
||||
|
||||
hand = fpdb_simple.filterCrap(hand, isTourney)
|
||||
|
||||
|
@ -79,7 +95,7 @@ def mainParser(settings, fdb, siteID, category, hand, config, db = None):
|
|||
seatLines.append(line)
|
||||
|
||||
names = fpdb_simple.parseNames(seatLines)
|
||||
playerIDs = fpdb_simple.recognisePlayerIDs(fdb.cursor, names, siteID)
|
||||
playerIDs = fpdb_simple.recognisePlayerIDs(db.get_cursor(), names, siteID) # inserts players as needed
|
||||
tmp = fpdb_simple.parseCashesAndSeatNos(seatLines)
|
||||
startCashes = tmp['startCashes']
|
||||
seatNos = tmp['seatNos']
|
||||
|
@ -126,8 +142,9 @@ def mainParser(settings, fdb, siteID, category, hand, config, db = None):
|
|||
fpdb_simple.convertBlindBet(actionTypes, actionAmounts)
|
||||
fpdb_simple.checkPositions(positions)
|
||||
|
||||
fdb.cursor.execute("SELECT limitType FROM Gametypes WHERE id=%s",(gametypeID, ))
|
||||
limit_type = fdb.cursor.fetchone()[0]
|
||||
c = db.get_cursor()
|
||||
c.execute("SELECT limitType FROM Gametypes WHERE id=%s",(gametypeID, ))
|
||||
limit_type = c.fetchone()[0]
|
||||
fpdb_simple.convert3B4B(category, limit_type, actionTypes, actionAmounts)
|
||||
|
||||
totalWinnings = sum(winnings)
|
||||
|
@ -143,49 +160,27 @@ def mainParser(settings, fdb, siteID, category, hand, config, db = None):
|
|||
, allIns, actionTypeByNo, winnings, totalWinnings, None
|
||||
, actionTypes, actionAmounts, antes)
|
||||
|
||||
if isTourney:
|
||||
ranks = map(lambda x: 0, names) # create an array of 0's equal to the length of names
|
||||
payin_amounts = fpdb_simple.calcPayin(len(names), buyin, fee)
|
||||
|
||||
if base == "hold":
|
||||
result = db.tourney_holdem_omaha(
|
||||
config, settings, fdb.db, fdb.cursor, base, category, siteTourneyNo, buyin
|
||||
, fee, knockout, entries, prizepool, tourneyStartTime
|
||||
, payin_amounts, ranks, tourneyTypeId, siteID, siteHandNo
|
||||
, gametypeID, handStartTime, names, playerIDs, startCashes
|
||||
, positions, cardValues, cardSuits, boardValues, boardSuits
|
||||
, winnings, rakes, actionTypes, allIns, actionAmounts
|
||||
, actionNos, hudImportData, maxSeats, tableName, seatNos)
|
||||
elif base == "stud":
|
||||
result = db.tourney_stud(
|
||||
config, settings, fdb.db, fdb.cursor, base, category, siteTourneyNo
|
||||
, buyin, fee, knockout, entries, prizepool, tourneyStartTime
|
||||
, payin_amounts, ranks, tourneyTypeId, siteID, siteHandNo
|
||||
, gametypeID, handStartTime, names, playerIDs, startCashes
|
||||
, antes, cardValues, cardSuits, winnings, rakes, actionTypes
|
||||
, allIns, actionAmounts, actionNos, hudImportData, maxSeats
|
||||
, tableName, seatNos)
|
||||
else:
|
||||
raise fpdb_simple.FpdbError("unrecognised category")
|
||||
else:
|
||||
if base == "hold":
|
||||
result = db.ring_holdem_omaha(
|
||||
config, settings, fdb.db, fdb.cursor, base, category, siteHandNo
|
||||
, gametypeID, handStartTime, names, playerIDs
|
||||
, startCashes, positions, cardValues, cardSuits
|
||||
, boardValues, boardSuits, winnings, rakes
|
||||
, actionTypes, allIns, actionAmounts, actionNos
|
||||
, hudImportData, maxSeats, tableName, seatNos)
|
||||
elif base == "stud":
|
||||
result = db.ring_stud(
|
||||
config, settings, fdb.db, fdb.cursor, base, category, siteHandNo, gametypeID
|
||||
, handStartTime, names, playerIDs, startCashes, antes
|
||||
, cardValues, cardSuits, winnings, rakes, actionTypes, allIns
|
||||
, actionAmounts, actionNos, hudImportData, maxSeats, tableName
|
||||
, seatNos)
|
||||
else:
|
||||
raise fpdb_simple.FpdbError ("unrecognised category")
|
||||
fdb.db.commit()
|
||||
#print "parse: hand data prepared" # only reads up to here apart from inserting new players
|
||||
try:
|
||||
db.commit() # need to commit new players as different db connection used
|
||||
# for other writes. maybe this will change maybe not ...
|
||||
except:
|
||||
print "parse: error during commit: " + str(sys.exc_value)
|
||||
|
||||
|
||||
# save data structures in a HandToWrite instance and then insert into database:
|
||||
htw = Database.HandToWrite()
|
||||
htw.set_all( config, settings, base, category, siteTourneyNo, buyin
|
||||
, fee, knockout, entries, prizepool, tourneyStartTime
|
||||
, isTourney, tourneyTypeId, siteID, siteHandNo
|
||||
, gametypeID, handStartTime, names, playerIDs, startCashes
|
||||
, positions, antes, cardValues, cardSuits, boardValues, boardSuits
|
||||
, winnings, rakes, actionTypes, allIns, actionAmounts
|
||||
, actionNos, hudImportData, maxSeats, tableName, seatNos)
|
||||
result = db.store_the_hand(htw)
|
||||
|
||||
t9 = time()
|
||||
#print "parse and save=(%4.3f)" % (t9-t0)
|
||||
return result
|
||||
#end def mainParser
|
||||
|
||||
|
|
|
@ -37,9 +37,6 @@ MYSQL_INNODB = 2
|
|||
PGSQL = 3
|
||||
SQLITE = 4
|
||||
|
||||
# config while trying out new hudcache mechanism
|
||||
use_date_in_hudcache = True
|
||||
|
||||
class DuplicateError(Exception):
|
||||
def __init__(self, value):
|
||||
self.value = value
|
||||
|
@ -986,7 +983,7 @@ def recogniseGametypeID(backend, db, cursor, topline, smallBlindLine, site_id, c
|
|||
#AND limitType=%s AND smallBlind=%s AND bigBlind=%s", (site_id, type, category, limit_type, small_bet, big_bet))
|
||||
|
||||
#result=(db.insert_id(),)
|
||||
result=(getLastInsertId(backend,db,cursor),)
|
||||
result=(db.get_last_insert_id(),)
|
||||
|
||||
return result[0]
|
||||
#end def recogniseGametypeID
|
||||
|
@ -1122,282 +1119,6 @@ def splitRake(winnings, rakes, totalRake):
|
|||
rakes[i]=totalRake*winPortion
|
||||
#end def splitRake
|
||||
|
||||
def storeActions(cursor, handsPlayersIds, actionTypes, allIns, actionAmounts, actionNos):
|
||||
#stores into table hands_actions
|
||||
#print "start of storeActions, actionNos:",actionNos
|
||||
#print " action_amounts:",action_amounts
|
||||
inserts = []
|
||||
for i in xrange(len(actionTypes)): #iterate through streets
|
||||
for j in xrange(len(actionTypes[i])): #iterate through names
|
||||
for k in xrange(len(actionTypes[i][j])): #iterate through individual actions of that player on that street
|
||||
# Add inserts into a list and let
|
||||
inserts = inserts + [(handsPlayersIds[j], i, actionNos[i][j][k], actionTypes[i][j][k], allIns[i][j][k], actionAmounts[i][j][k])]
|
||||
|
||||
cursor.executemany("INSERT INTO HandsActions (handsPlayerId, street, actionNo, action, allIn, amount) VALUES (%s, %s, %s, %s, %s, %s)", inserts)
|
||||
#end def storeActions
|
||||
|
||||
def storeHands(backend, conn, cursor, site_hand_no, gametype_id
|
||||
,hand_start_time, names, tableName, maxSeats, hudCache,
|
||||
board_values, board_suits):
|
||||
cards = [Card.cardFromValueSuit(v,s) for v,s in zip(board_values,board_suits)]
|
||||
#stores into table hands:
|
||||
cursor.execute ("""INSERT INTO Hands
|
||||
(siteHandNo, gametypeId, handStart, seats, tableName, importTime, maxSeats
|
||||
,boardcard1,boardcard2,boardcard3,boardcard4,boardcard5
|
||||
,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, %s, %s, %s, %s, %s)
|
||||
"""
|
||||
, (site_hand_no, gametype_id, hand_start_time, len(names), tableName, datetime.datetime.today(), maxSeats
|
||||
,cards[0], cards[1], cards[2], cards[3], cards[4]
|
||||
,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 def storeHands
|
||||
|
||||
def store_hands_players_holdem_omaha(backend, conn, cursor, category, hands_id, player_ids, start_cashes
|
||||
,positions, card_values, card_suits, winnings, rakes, seatNos, hudCache):
|
||||
result=[]
|
||||
|
||||
# postgres (and others?) needs the booleans converted to ints before saving:
|
||||
# (or we could just save them as boolean ... but then we can't sum them so easily in sql ???)
|
||||
# NO - storing booleans for now so don't need this
|
||||
#hudCacheInt = {}
|
||||
#for k,v in hudCache.iteritems():
|
||||
# if k in ('wonWhenSeenStreet1', 'wonAtSD', 'totalProfit'):
|
||||
# hudCacheInt[k] = v
|
||||
# else:
|
||||
# hudCacheInt[k] = map(lambda x: 1 if x else 0, v)
|
||||
|
||||
if (category=="holdem"):
|
||||
for i in xrange(len(player_ids)):
|
||||
startCards = Card.twoStartCards(card_values[i][0], card_suits[i][0], card_values[i][1], card_suits[i][1])
|
||||
card1 = Card.cardFromValueSuit(card_values[i][0], card_suits[i][0])
|
||||
card2 = Card.cardFromValueSuit(card_values[i][1], card_suits[i][1])
|
||||
cursor.execute ("""
|
||||
INSERT INTO HandsPlayers
|
||||
(handId, playerId, startCash, position, tourneyTypeId,
|
||||
card1, card2, startCards, winnings, rake, seatNo, totalProfit,
|
||||
street0VPI, street0Aggr, street0_3BChance, street0_3BDone,
|
||||
street1Seen, street2Seen, street3Seen, street4Seen, sawShowdown,
|
||||
street1Aggr, street2Aggr, street3Aggr, street4Aggr,
|
||||
otherRaisedStreet1, otherRaisedStreet2, otherRaisedStreet3, otherRaisedStreet4,
|
||||
foldToOtherRaisedStreet1, foldToOtherRaisedStreet2, foldToOtherRaisedStreet3, foldToOtherRaisedStreet4,
|
||||
wonWhenSeenStreet1, wonAtSD,
|
||||
stealAttemptChance, stealAttempted, foldBbToStealChance, foldedBbToSteal, foldSbToStealChance, foldedSbToSteal,
|
||||
street1CBChance, street1CBDone, street2CBChance, street2CBDone,
|
||||
street3CBChance, street3CBDone, street4CBChance, street4CBDone,
|
||||
foldToStreet1CBChance, foldToStreet1CBDone, foldToStreet2CBChance, foldToStreet2CBDone,
|
||||
foldToStreet3CBChance, foldToStreet3CBDone, foldToStreet4CBChance, foldToStreet4CBDone,
|
||||
street1CheckCallRaiseChance, street1CheckCallRaiseDone, street2CheckCallRaiseChance, street2CheckCallRaiseDone,
|
||||
street3CheckCallRaiseChance, street3CheckCallRaiseDone, street4CheckCallRaiseChance, street4CheckCallRaiseDone,
|
||||
street0Calls, street1Calls, street2Calls, street3Calls, street4Calls,
|
||||
street0Bets, street1Bets, street2Bets, street3Bets, street4Bets
|
||||
)
|
||||
VALUES (%s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s,
|
||||
%s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s,
|
||||
%s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s,
|
||||
%s, %s, %s, %s, %s, %s, %s, %s)""",
|
||||
(hands_id, player_ids[i], start_cashes[i], positions[i], 1, # tourneytypeid
|
||||
card1, card2, startCards,
|
||||
winnings[i], rakes[i], seatNos[i], hudCache['totalProfit'][i],
|
||||
hudCache['street0VPI'][i], hudCache['street0Aggr'][i],
|
||||
hudCache['street0_3BChance'][i], hudCache['street0_3BDone'][i],
|
||||
hudCache['street1Seen'][i], hudCache['street2Seen'][i], hudCache['street3Seen'][i],
|
||||
hudCache['street4Seen'][i], hudCache['sawShowdown'][i],
|
||||
hudCache['street1Aggr'][i], hudCache['street2Aggr'][i], hudCache['street3Aggr'][i], hudCache['street4Aggr'][i],
|
||||
hudCache['otherRaisedStreet1'][i], hudCache['otherRaisedStreet2'][i],
|
||||
hudCache['otherRaisedStreet3'][i], hudCache['otherRaisedStreet4'][i],
|
||||
hudCache['foldToOtherRaisedStreet1'][i], hudCache['foldToOtherRaisedStreet2'][i],
|
||||
hudCache['foldToOtherRaisedStreet3'][i], hudCache['foldToOtherRaisedStreet4'][i],
|
||||
hudCache['wonWhenSeenStreet1'][i], hudCache['wonAtSD'][i],
|
||||
hudCache['stealAttemptChance'][i], hudCache['stealAttempted'][i], hudCache['foldBbToStealChance'][i],
|
||||
hudCache['foldedBbToSteal'][i], hudCache['foldSbToStealChance'][i], hudCache['foldedSbToSteal'][i],
|
||||
hudCache['street1CBChance'][i], hudCache['street1CBDone'][i], hudCache['street2CBChance'][i], hudCache['street2CBDone'][i],
|
||||
hudCache['street3CBChance'][i], hudCache['street3CBDone'][i], hudCache['street4CBChance'][i], hudCache['street4CBDone'][i],
|
||||
hudCache['foldToStreet1CBChance'][i], hudCache['foldToStreet1CBDone'][i],
|
||||
hudCache['foldToStreet2CBChance'][i], hudCache['foldToStreet2CBDone'][i],
|
||||
hudCache['foldToStreet3CBChance'][i], hudCache['foldToStreet3CBDone'][i],
|
||||
hudCache['foldToStreet4CBChance'][i], hudCache['foldToStreet4CBDone'][i],
|
||||
hudCache['street1CheckCallRaiseChance'][i], hudCache['street1CheckCallRaiseDone'][i],
|
||||
hudCache['street2CheckCallRaiseChance'][i], hudCache['street2CheckCallRaiseDone'][i],
|
||||
hudCache['street3CheckCallRaiseChance'][i], hudCache['street3CheckCallRaiseDone'][i],
|
||||
hudCache['street4CheckCallRaiseChance'][i], hudCache['street4CheckCallRaiseDone'][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]
|
||||
) )
|
||||
#cursor.execute("SELECT id FROM HandsPlayers WHERE handId=%s AND playerId=%s", (hands_id, player_ids[i]))
|
||||
#result.append(cursor.fetchall()[0][0])
|
||||
result.append( getLastInsertId(backend, conn, cursor) )
|
||||
elif (category=="omahahi" or category=="omahahilo"):
|
||||
for i in xrange(len(player_ids)):
|
||||
startCards = Card.fourStartCards(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])
|
||||
card1 = Card.cardFromValueSuit(card_values[i][0], card_suits[i][0])
|
||||
card2 = Card.cardFromValueSuit(card_values[i][1], card_suits[i][1])
|
||||
card3 = Card.cardFromValueSuit(card_values[i][2], card_suits[i][2])
|
||||
card4 = Card.cardFromValueSuit(card_values[i][3], card_suits[i][3])
|
||||
cursor.execute ("""INSERT INTO HandsPlayers
|
||||
(handId, playerId, startCash, position, tourneyTypeId,
|
||||
card1, card2, card3, card4, winnings, rake, seatNo, totalProfit,
|
||||
street0VPI, street0Aggr, street0_3BChance, street0_3BDone,
|
||||
street1Seen, street2Seen, street3Seen, street4Seen, sawShowdown,
|
||||
street1Aggr, street2Aggr, street3Aggr, street4Aggr,
|
||||
otherRaisedStreet1, otherRaisedStreet2, otherRaisedStreet3, otherRaisedStreet4,
|
||||
foldToOtherRaisedStreet1, foldToOtherRaisedStreet2, foldToOtherRaisedStreet3, foldToOtherRaisedStreet4,
|
||||
wonWhenSeenStreet1, wonAtSD,
|
||||
stealAttemptChance, stealAttempted, foldBbToStealChance, foldedBbToSteal, foldSbToStealChance, foldedSbToSteal,
|
||||
street1CBChance, street1CBDone, street2CBChance, street2CBDone,
|
||||
street3CBChance, street3CBDone, street4CBChance, street4CBDone,
|
||||
foldToStreet1CBChance, foldToStreet1CBDone, foldToStreet2CBChance, foldToStreet2CBDone,
|
||||
foldToStreet3CBChance, foldToStreet3CBDone, foldToStreet4CBChance, foldToStreet4CBDone,
|
||||
street1CheckCallRaiseChance, street1CheckCallRaiseDone, street2CheckCallRaiseChance, street2CheckCallRaiseDone,
|
||||
street3CheckCallRaiseChance, street3CheckCallRaiseDone, street4CheckCallRaiseChance, street4CheckCallRaiseDone,
|
||||
street0Calls, street1Calls, street2Calls, street3Calls, street4Calls,
|
||||
street0Bets, street1Bets, street2Bets, street3Bets, street4Bets
|
||||
)
|
||||
VALUES (%s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s,
|
||||
%s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s,
|
||||
%s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s,
|
||||
%s, %s, %s, %s, %s, %s, %s, %s)""",
|
||||
(hands_id, player_ids[i], start_cashes[i], positions[i], 1, # tourneytypeid
|
||||
card1, card2, card3, card4,
|
||||
winnings[i], rakes[i], seatNos[i], hudCache['totalProfit'][i],
|
||||
hudCache['street0VPI'][i], hudCache['street0Aggr'][i],
|
||||
hudCache['street0_3BChance'][i], hudCache['street0_3BDone'][i],
|
||||
hudCache['street1Seen'][i], hudCache['street2Seen'][i], hudCache['street3Seen'][i],
|
||||
hudCache['street4Seen'][i], hudCache['sawShowdown'][i],
|
||||
hudCache['street1Aggr'][i], hudCache['street2Aggr'][i], hudCache['street3Aggr'][i], hudCache['street4Aggr'][i],
|
||||
hudCache['otherRaisedStreet1'][i], hudCache['otherRaisedStreet2'][i],
|
||||
hudCache['otherRaisedStreet3'][i], hudCache['otherRaisedStreet4'][i],
|
||||
hudCache['foldToOtherRaisedStreet1'][i], hudCache['foldToOtherRaisedStreet2'][i],
|
||||
hudCache['foldToOtherRaisedStreet3'][i], hudCache['foldToOtherRaisedStreet4'][i],
|
||||
hudCache['wonWhenSeenStreet1'][i], hudCache['wonAtSD'][i],
|
||||
hudCache['stealAttemptChance'][i], hudCache['stealAttempted'][i], hudCache['foldBbToStealChance'][i],
|
||||
hudCache['foldedBbToSteal'][i], hudCache['foldSbToStealChance'][i], hudCache['foldedSbToSteal'][i],
|
||||
hudCache['street1CBChance'][i], hudCache['street1CBDone'][i], hudCache['street2CBChance'][i], hudCache['street2CBDone'][i],
|
||||
hudCache['street3CBChance'][i], hudCache['street3CBDone'][i], hudCache['street4CBChance'][i], hudCache['street4CBDone'][i],
|
||||
hudCache['foldToStreet1CBChance'][i], hudCache['foldToStreet1CBDone'][i],
|
||||
hudCache['foldToStreet2CBChance'][i], hudCache['foldToStreet2CBDone'][i],
|
||||
hudCache['foldToStreet3CBChance'][i], hudCache['foldToStreet3CBDone'][i],
|
||||
hudCache['foldToStreet4CBChance'][i], hudCache['foldToStreet4CBDone'][i],
|
||||
hudCache['street1CheckCallRaiseChance'][i], hudCache['street1CheckCallRaiseDone'][i],
|
||||
hudCache['street2CheckCallRaiseChance'][i], hudCache['street2CheckCallRaiseDone'][i],
|
||||
hudCache['street3CheckCallRaiseChance'][i], hudCache['street3CheckCallRaiseDone'][i],
|
||||
hudCache['street4CheckCallRaiseChance'][i], hudCache['street4CheckCallRaiseDone'][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]
|
||||
) )
|
||||
#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( getLastInsertId(backend, conn, cursor) )
|
||||
else:
|
||||
raise FpdbError("invalid category")
|
||||
return result
|
||||
#end def store_hands_players_holdem_omaha
|
||||
|
||||
def store_hands_players_stud(backend, conn, cursor, hands_id, player_ids, start_cashes, antes,
|
||||
card_values, card_suits, winnings, rakes, seatNos):
|
||||
#stores hands_players rows for stud/razz games. returns an array of the resulting IDs
|
||||
result=[]
|
||||
#print "before inserts in store_hands_players_stud, antes:", antes
|
||||
for i in xrange(len(player_ids)):
|
||||
card1 = Card.cardFromValueSuit(card_values[i][0], card_suits[i][0])
|
||||
card2 = Card.cardFromValueSuit(card_values[i][1], card_suits[i][1])
|
||||
card3 = Card.cardFromValueSuit(card_values[i][2], card_suits[i][2])
|
||||
card4 = Card.cardFromValueSuit(card_values[i][3], card_suits[i][3])
|
||||
card5 = Card.cardFromValueSuit(card_values[i][4], card_suits[i][4])
|
||||
card6 = Card.cardFromValueSuit(card_values[i][5], card_suits[i][5])
|
||||
card7 = Card.cardFromValueSuit(card_values[i][6], card_suits[i][6])
|
||||
|
||||
cursor.execute ("""INSERT INTO HandsPlayers
|
||||
(handId, playerId, startCash, ante, tourneyTypeId,
|
||||
card1, card2,
|
||||
card3, card4,
|
||||
card5, card6,
|
||||
card7, winnings, rake, seatNo)
|
||||
VALUES (%s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s)""",
|
||||
(hands_id, player_ids[i], start_cashes[i], antes[i], 1,
|
||||
card1, card2,
|
||||
card3, card4,
|
||||
card5, card6,
|
||||
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]))
|
||||
#result.append(cursor.fetchall()[0][0])
|
||||
result.append( getLastInsertId(backend, conn, cursor) )
|
||||
return result
|
||||
#end def store_hands_players_stud
|
||||
|
||||
def store_hands_players_holdem_omaha_tourney(backend, conn, cursor, category, hands_id, player_ids
|
||||
,start_cashes, positions, card_values, card_suits
|
||||
, winnings, rakes, seatNos, tourneys_players_ids):
|
||||
#stores hands_players for tourney holdem/omaha hands
|
||||
result=[]
|
||||
for i in xrange(len(player_ids)):
|
||||
if len(card_values[0])==2:
|
||||
cursor.execute ("""INSERT INTO HandsPlayers
|
||||
(handId, playerId, startCash, position,
|
||||
card1Value, card1Suit, card2Value, card2Suit,
|
||||
winnings, rake, tourneysPlayersId, seatNo)
|
||||
VALUES (%s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s)""",
|
||||
(hands_id, player_ids[i], start_cashes[i], positions[i],
|
||||
card_values[i][0], card_suits[i][0], card_values[i][1], card_suits[i][1],
|
||||
winnings[i], rakes[i], tourneys_players_ids[i], seatNos[i]))
|
||||
elif len(card_values[0])==4:
|
||||
cursor.execute ("""INSERT INTO HandsPlayers
|
||||
(handId, playerId, startCash, position,
|
||||
card1Value, card1Suit, card2Value, card2Suit,
|
||||
card3Value, card3Suit, card4Value, card4Suit,
|
||||
winnings, rake, tourneysPlayersId, seatNo)
|
||||
VALUES (%s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s)""",
|
||||
(hands_id, player_ids[i], start_cashes[i], positions[i],
|
||||
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],
|
||||
winnings[i], rakes[i], tourneys_players_ids[i], seatNos[i]))
|
||||
else:
|
||||
raise FpdbError ("invalid card_values length:"+str(len(card_values[0])))
|
||||
#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( getLastInsertId(backend, conn, cursor) )
|
||||
|
||||
return result
|
||||
#end def store_hands_players_holdem_omaha_tourney
|
||||
|
||||
def store_hands_players_stud_tourney(backend, conn, cursor, hands_id, player_ids, start_cashes,
|
||||
antes, card_values, card_suits, winnings, rakes, seatNos, tourneys_players_ids):
|
||||
#stores hands_players for tourney stud/razz hands
|
||||
result=[]
|
||||
for i in xrange(len(player_ids)):
|
||||
cursor.execute ("""INSERT INTO HandsPlayers
|
||||
(handId, playerId, startCash, ante,
|
||||
card1Value, card1Suit, card2Value, card2Suit,
|
||||
card3Value, card3Suit, card4Value, card4Suit,
|
||||
card5Value, card5Suit, card6Value, card6Suit,
|
||||
card7Value, card7Suit, winnings, rake, tourneysPlayersId, seatNo)
|
||||
VALUES (%s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s,
|
||||
%s, %s, %s, %s, %s, %s)""",
|
||||
(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][2], card_suits[i][2], card_values[i][3], card_suits[i][3],
|
||||
card_values[i][4], card_suits[i][4], card_values[i][5], card_suits[i][5],
|
||||
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]))
|
||||
#result.append(cursor.fetchall()[0][0])
|
||||
result.append( getLastInsertId(backend, conn, cursor) )
|
||||
return result
|
||||
#end def store_hands_players_stud_tourney
|
||||
|
||||
def generateHudCacheData(player_ids, base, category, action_types, allIns, actionTypeByNo
|
||||
,winnings, totalWinnings, positions, actionTypes, actionAmounts, antes):
|
||||
"""calculates data for the HUD during import. IMPORTANT: if you change this method make
|
||||
|
@ -2105,230 +1826,3 @@ def generateFoldToCB(street, playerIDs, didStreetCB, streetCBDone, foldToStreetC
|
|||
if action[1]=="fold":
|
||||
foldToStreetCBDone[player]=True
|
||||
#end def generateFoldToCB
|
||||
|
||||
def storeHudCache(backend, cursor, base, category, gametypeId, hand_start_time, playerIds, hudImportData):
|
||||
"""Modified version aiming for more speed ..."""
|
||||
# if (category=="holdem" or category=="omahahi" or category=="omahahilo"):
|
||||
if use_date_in_hudcache:
|
||||
#print "key =", "d%02d%02d%02d " % (hand_start_time.year-2000, hand_start_time.month, hand_start_time.day)
|
||||
styleKey = "d%02d%02d%02d" % (hand_start_time.year-2000, hand_start_time.month, hand_start_time.day)
|
||||
else:
|
||||
# hard-code styleKey as 'A000000' (all-time cache, no key) for now
|
||||
styleKey = 'A000000'
|
||||
|
||||
#print "storeHudCache2, len(playerIds)=", len(playerIds), " len(vpip)=" \
|
||||
#, len(hudImportData['street0VPI']), " len(totprof)=", len(hudImportData['totalProfit'])
|
||||
for player in xrange(len(playerIds)):
|
||||
|
||||
# Set up a clean row
|
||||
row=[]
|
||||
row.append(0)#blank for id
|
||||
row.append(gametypeId)
|
||||
row.append(playerIds[player])
|
||||
row.append(len(playerIds))#seats
|
||||
for i in xrange(len(hudImportData)+2):
|
||||
row.append(0)
|
||||
|
||||
if base=="hold":
|
||||
row[4]=hudImportData['position'][player]
|
||||
else:
|
||||
row[4]=0
|
||||
row[5]=1 #tourneysGametypeId
|
||||
row[6]+=1 #HDs
|
||||
if hudImportData['street0VPI'][player]: row[7]+=1
|
||||
if hudImportData['street0Aggr'][player]: row[8]+=1
|
||||
if hudImportData['street0_3BChance'][player]: row[9]+=1
|
||||
if hudImportData['street0_3BDone'][player]: row[10]+=1
|
||||
if hudImportData['street1Seen'][player]: row[11]+=1
|
||||
if hudImportData['street2Seen'][player]: row[12]+=1
|
||||
if hudImportData['street3Seen'][player]: row[13]+=1
|
||||
if hudImportData['street4Seen'][player]: row[14]+=1
|
||||
if hudImportData['sawShowdown'][player]: row[15]+=1
|
||||
if hudImportData['street1Aggr'][player]: row[16]+=1
|
||||
if hudImportData['street2Aggr'][player]: row[17]+=1
|
||||
if hudImportData['street3Aggr'][player]: row[18]+=1
|
||||
if hudImportData['street4Aggr'][player]: row[19]+=1
|
||||
if hudImportData['otherRaisedStreet1'][player]: row[20]+=1
|
||||
if hudImportData['otherRaisedStreet2'][player]: row[21]+=1
|
||||
if hudImportData['otherRaisedStreet3'][player]: row[22]+=1
|
||||
if hudImportData['otherRaisedStreet4'][player]: row[23]+=1
|
||||
if hudImportData['foldToOtherRaisedStreet1'][player]: row[24]+=1
|
||||
if hudImportData['foldToOtherRaisedStreet2'][player]: row[25]+=1
|
||||
if hudImportData['foldToOtherRaisedStreet3'][player]: row[26]+=1
|
||||
if hudImportData['foldToOtherRaisedStreet4'][player]: row[27]+=1
|
||||
if hudImportData['wonWhenSeenStreet1'][player]!=0.0: row[28]+=hudImportData['wonWhenSeenStreet1'][player]
|
||||
if hudImportData['wonAtSD'][player]!=0.0: row[29]+=hudImportData['wonAtSD'][player]
|
||||
if hudImportData['stealAttemptChance'][player]: row[30]+=1
|
||||
if hudImportData['stealAttempted'][player]: row[31]+=1
|
||||
if hudImportData['foldBbToStealChance'][player]: row[32]+=1
|
||||
if hudImportData['foldedBbToSteal'][player]: row[33]+=1
|
||||
if hudImportData['foldSbToStealChance'][player]: row[34]+=1
|
||||
if hudImportData['foldedSbToSteal'][player]: row[35]+=1
|
||||
|
||||
if hudImportData['street1CBChance'][player]: row[36]+=1
|
||||
if hudImportData['street1CBDone'][player]: row[37]+=1
|
||||
if hudImportData['street2CBChance'][player]: row[38]+=1
|
||||
if hudImportData['street2CBDone'][player]: row[39]+=1
|
||||
if hudImportData['street3CBChance'][player]: row[40]+=1
|
||||
if hudImportData['street3CBDone'][player]: row[41]+=1
|
||||
if hudImportData['street4CBChance'][player]: row[42]+=1
|
||||
if hudImportData['street4CBDone'][player]: row[43]+=1
|
||||
|
||||
if hudImportData['foldToStreet1CBChance'][player]: row[44]+=1
|
||||
if hudImportData['foldToStreet1CBDone'][player]: row[45]+=1
|
||||
if hudImportData['foldToStreet2CBChance'][player]: row[46]+=1
|
||||
if hudImportData['foldToStreet2CBDone'][player]: row[47]+=1
|
||||
if hudImportData['foldToStreet3CBChance'][player]: row[48]+=1
|
||||
if hudImportData['foldToStreet3CBDone'][player]: row[49]+=1
|
||||
if hudImportData['foldToStreet4CBChance'][player]: row[50]+=1
|
||||
if hudImportData['foldToStreet4CBDone'][player]: row[51]+=1
|
||||
|
||||
#print "player=", player
|
||||
#print "len(totalProfit)=", len(hudImportData['totalProfit'])
|
||||
if hudImportData['totalProfit'][player]:
|
||||
row[52]+=hudImportData['totalProfit'][player]
|
||||
|
||||
if hudImportData['street1CheckCallRaiseChance'][player]: row[53]+=1
|
||||
if hudImportData['street1CheckCallRaiseDone'][player]: row[54]+=1
|
||||
if hudImportData['street2CheckCallRaiseChance'][player]: row[55]+=1
|
||||
if hudImportData['street2CheckCallRaiseDone'][player]: row[56]+=1
|
||||
if hudImportData['street3CheckCallRaiseChance'][player]: row[57]+=1
|
||||
if hudImportData['street3CheckCallRaiseDone'][player]: row[58]+=1
|
||||
if hudImportData['street4CheckCallRaiseChance'][player]: row[59]+=1
|
||||
if hudImportData['street4CheckCallRaiseDone'][player]: row[60]+=1
|
||||
|
||||
# Try to do the update first:
|
||||
num = cursor.execute("""UPDATE HudCache
|
||||
SET HDs=HDs+%s, street0VPI=street0VPI+%s, street0Aggr=street0Aggr+%s,
|
||||
street0_3BChance=street0_3BChance+%s, street0_3BDone=street0_3BDone+%s,
|
||||
street1Seen=street1Seen+%s, street2Seen=street2Seen+%s, street3Seen=street3Seen+%s,
|
||||
street4Seen=street4Seen+%s, sawShowdown=sawShowdown+%s,
|
||||
street1Aggr=street1Aggr+%s, street2Aggr=street2Aggr+%s, street3Aggr=street3Aggr+%s,
|
||||
street4Aggr=street4Aggr+%s, otherRaisedStreet1=otherRaisedStreet1+%s,
|
||||
otherRaisedStreet2=otherRaisedStreet2+%s, otherRaisedStreet3=otherRaisedStreet3+%s,
|
||||
otherRaisedStreet4=otherRaisedStreet4+%s,
|
||||
foldToOtherRaisedStreet1=foldToOtherRaisedStreet1+%s, foldToOtherRaisedStreet2=foldToOtherRaisedStreet2+%s,
|
||||
foldToOtherRaisedStreet3=foldToOtherRaisedStreet3+%s, foldToOtherRaisedStreet4=foldToOtherRaisedStreet4+%s,
|
||||
wonWhenSeenStreet1=wonWhenSeenStreet1+%s, wonAtSD=wonAtSD+%s, stealAttemptChance=stealAttemptChance+%s,
|
||||
stealAttempted=stealAttempted+%s, foldBbToStealChance=foldBbToStealChance+%s,
|
||||
foldedBbToSteal=foldedBbToSteal+%s,
|
||||
foldSbToStealChance=foldSbToStealChance+%s, foldedSbToSteal=foldedSbToSteal+%s,
|
||||
street1CBChance=street1CBChance+%s, street1CBDone=street1CBDone+%s, street2CBChance=street2CBChance+%s,
|
||||
street2CBDone=street2CBDone+%s, street3CBChance=street3CBChance+%s,
|
||||
street3CBDone=street3CBDone+%s, street4CBChance=street4CBChance+%s, street4CBDone=street4CBDone+%s,
|
||||
foldToStreet1CBChance=foldToStreet1CBChance+%s, foldToStreet1CBDone=foldToStreet1CBDone+%s,
|
||||
foldToStreet2CBChance=foldToStreet2CBChance+%s, foldToStreet2CBDone=foldToStreet2CBDone+%s,
|
||||
foldToStreet3CBChance=foldToStreet3CBChance+%s,
|
||||
foldToStreet3CBDone=foldToStreet3CBDone+%s, foldToStreet4CBChance=foldToStreet4CBChance+%s,
|
||||
foldToStreet4CBDone=foldToStreet4CBDone+%s, totalProfit=totalProfit+%s,
|
||||
street1CheckCallRaiseChance=street1CheckCallRaiseChance+%s,
|
||||
street1CheckCallRaiseDone=street1CheckCallRaiseDone+%s, street2CheckCallRaiseChance=street2CheckCallRaiseChance+%s,
|
||||
street2CheckCallRaiseDone=street2CheckCallRaiseDone+%s, street3CheckCallRaiseChance=street3CheckCallRaiseChance+%s,
|
||||
street3CheckCallRaiseDone=street3CheckCallRaiseDone+%s, street4CheckCallRaiseChance=street4CheckCallRaiseChance+%s,
|
||||
street4CheckCallRaiseDone=street4CheckCallRaiseDone+%s
|
||||
WHERE gametypeId+0=%s
|
||||
AND playerId=%s
|
||||
AND activeSeats=%s
|
||||
AND position=%s
|
||||
AND tourneyTypeId+0=%s
|
||||
AND styleKey=%s
|
||||
""", (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[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[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[1], row[2], row[3], str(row[4]), row[5], styleKey))
|
||||
# Test statusmessage to see if update worked, do insert if not
|
||||
#print "storehud2, upd num =", num
|
||||
if ( (backend == PGSQL and cursor.statusmessage != "UPDATE 1")
|
||||
or (backend == MYSQL_INNODB and num == 0) ):
|
||||
#print "playerid before insert:",row[2]," num = ", num
|
||||
cursor.execute("""INSERT INTO HudCache
|
||||
(gametypeId, playerId, activeSeats, position, tourneyTypeId, styleKey,
|
||||
HDs, street0VPI, street0Aggr, street0_3BChance, street0_3BDone,
|
||||
street1Seen, street2Seen, street3Seen, street4Seen, sawShowdown,
|
||||
street1Aggr, street2Aggr, street3Aggr, street4Aggr, otherRaisedStreet1,
|
||||
otherRaisedStreet2, otherRaisedStreet3, otherRaisedStreet4, foldToOtherRaisedStreet1, foldToOtherRaisedStreet2,
|
||||
foldToOtherRaisedStreet3, foldToOtherRaisedStreet4, wonWhenSeenStreet1, wonAtSD, 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)
|
||||
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)"""
|
||||
, (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[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[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]) )
|
||||
#print "hopefully inserted hud data line: ", cursor.statusmessage
|
||||
# message seems to be "INSERT 0 1"
|
||||
else:
|
||||
#print "updated(2) hud data line"
|
||||
pass
|
||||
# else:
|
||||
# print "todo: implement storeHudCache for stud base"
|
||||
#end def storeHudCache2
|
||||
|
||||
def store_tourneys(cursor, tourneyTypeId, siteTourneyNo, entries, prizepool, startTime):
|
||||
cursor.execute("SELECT id FROM Tourneys WHERE siteTourneyNo=%s AND tourneyTypeId+0=%s", (siteTourneyNo, tourneyTypeId))
|
||||
tmp=cursor.fetchone()
|
||||
#print "tried SELECTing tourneys.id, result:",tmp
|
||||
|
||||
try:
|
||||
len(tmp)
|
||||
except TypeError:#means we have to create new one
|
||||
cursor.execute("""INSERT INTO Tourneys
|
||||
(tourneyTypeId, siteTourneyNo, entries, prizepool, startTime)
|
||||
VALUES (%s, %s, %s, %s, %s)""", (tourneyTypeId, siteTourneyNo, entries, prizepool, startTime))
|
||||
cursor.execute("SELECT id FROM Tourneys WHERE siteTourneyNo=%s AND tourneyTypeId+0=%s", (siteTourneyNo, tourneyTypeId))
|
||||
tmp=cursor.fetchone()
|
||||
#print "created new tourneys.id:",tmp
|
||||
return tmp[0]
|
||||
#end def store_tourneys
|
||||
|
||||
def store_tourneys_players(cursor, tourney_id, player_ids, payin_amounts, ranks, winnings):
|
||||
result=[]
|
||||
#print "in store_tourneys_players. tourney_id:",tourney_id
|
||||
#print "player_ids:",player_ids
|
||||
#print "payin_amounts:",payin_amounts
|
||||
#print "ranks:",ranks
|
||||
#print "winnings:",winnings
|
||||
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]))
|
||||
tmp=cursor.fetchone()
|
||||
#print "tried SELECTing tourneys_players.id:",tmp
|
||||
|
||||
try:
|
||||
len(tmp)
|
||||
except TypeError:
|
||||
cursor.execute("""INSERT INTO TourneysPlayers
|
||||
(tourneyId, playerId, payinAmount, rank, winnings) VALUES (%s, %s, %s, %s, %s)""",
|
||||
(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",
|
||||
(tourney_id, player_ids[i]))
|
||||
tmp=cursor.fetchone()
|
||||
#print "created new tourneys_players.id:",tmp
|
||||
result.append(tmp[0])
|
||||
return result
|
||||
#end def store_tourneys_players
|
||||
|
|
271
pyfpdb/interlocks.py
Executable file
271
pyfpdb/interlocks.py
Executable file
|
@ -0,0 +1,271 @@
|
|||
|
||||
# Code from http://ender.snowburst.org:4747/~jjohns/interlocks.py
|
||||
# Thanks JJ!
|
||||
|
||||
import sys
|
||||
import os, os.path
|
||||
import subprocess
|
||||
import time
|
||||
import signal
|
||||
import base64
|
||||
|
||||
InterProcessLock = None
|
||||
|
||||
"""
|
||||
Just use me like a thread lock. acquire() / release() / locked()
|
||||
|
||||
Differences compared to thread locks:
|
||||
1. By default, acquire()'s wait parameter is false.
|
||||
2. When acquire fails, SingleInstanceError is thrown instead of simply returning false.
|
||||
3. acquire() can take a 3rd parameter retry_time, which, if wait is True, tells the locking
|
||||
mechanism how long to sleep between retrying the lock. Has no effect for unix/InterProcessLockFcntl.
|
||||
|
||||
Differences in fpdb version to JJ's original:
|
||||
1. Changed acquire() to return false like other locks
|
||||
2. Made acquire fail if same process already has the lock
|
||||
"""
|
||||
|
||||
class SingleInstanceError(RuntimeError):
|
||||
"Thrown when you try to acquire an InterProcessLock and another version of the process is already running."
|
||||
|
||||
class InterProcessLockBase:
|
||||
def __init__(self, name=None ):
|
||||
self._has_lock = False
|
||||
if not name:
|
||||
name = sys.argv[0]
|
||||
self.name = name
|
||||
|
||||
def getHashedName(self):
|
||||
return base64.b64encode(self.name).replace('=','')
|
||||
|
||||
def acquire_impl(self, wait): abstract
|
||||
|
||||
def acquire(self, wait=False, retry_time=1):
|
||||
if self._has_lock: # make sure 2nd acquire in same process fails
|
||||
return False
|
||||
while not self._has_lock:
|
||||
try:
|
||||
self.acquire_impl(wait)
|
||||
self._has_lock = True
|
||||
#print 'i have the lock'
|
||||
except SingleInstanceError:
|
||||
if not wait:
|
||||
# raise # change back to normal acquire functionality, sorry JJ!
|
||||
return False
|
||||
time.sleep(retry_time)
|
||||
return True
|
||||
|
||||
def release(self):
|
||||
self.release_impl()
|
||||
self._has_lock = False
|
||||
|
||||
def locked(self):
|
||||
if self._has_lock:
|
||||
return True
|
||||
try:
|
||||
self.acquire()
|
||||
self.release()
|
||||
return False
|
||||
except SingleInstanceError:
|
||||
return True
|
||||
|
||||
LOCK_FILE_DIRECTORY = '/tmp'
|
||||
|
||||
class InterProcessLockFcntl(InterProcessLockBase):
|
||||
def __init__(self, name=None):
|
||||
InterProcessLockBase.__init__(self, name)
|
||||
self.lockfd = 0
|
||||
self.lock_file_name = os.path.join(LOCK_FILE_DIRECTORY, self.getHashedName() + '.lck')
|
||||
assert(os.path.isdir(LOCK_FILE_DIRECTORY))
|
||||
|
||||
# This is the suggested way to get a safe file name, but I like having a descriptively named lock file.
|
||||
def getHashedName(self):
|
||||
import re
|
||||
bad_filename_character_re = re.compile(r'/\?<>\\\:;\*\|\'\"\^=\.\[\]')
|
||||
return bad_filename_character_re.sub('_',self.name)
|
||||
|
||||
def acquire_impl(self, wait):
|
||||
self.lockfd = open(self.lock_file_name, 'w')
|
||||
fcntrl_options = fcntl.LOCK_EX
|
||||
if not wait:
|
||||
fcntrl_options |= fcntl.LOCK_NB
|
||||
try:
|
||||
fcntl.flock(self.lockfd, fcntrl_options)
|
||||
except IOError:
|
||||
self.lockfd.close()
|
||||
self.lockfd = 0
|
||||
raise SingleInstanceError('Could not acquire exclusive lock on '+self.lock_file_name)
|
||||
|
||||
def release_impl(self):
|
||||
fcntl.lockf(self.lockfd, fcntl.LOCK_UN)
|
||||
self.lockfd.close()
|
||||
self.lockfd = 0
|
||||
try:
|
||||
os.unlink(self.lock_file_name)
|
||||
except IOError:
|
||||
# We don't care about the existence of the file too much here. It's the flock() we care about,
|
||||
# And that should just go away magically.
|
||||
pass
|
||||
|
||||
class InterProcessLockWin32(InterProcessLockBase):
|
||||
def __init__(self, name=None):
|
||||
InterProcessLockBase.__init__(self, name)
|
||||
self.mutex = None
|
||||
|
||||
def acquire_impl(self,wait):
|
||||
self.mutex = win32event.CreateMutex(None, 0, self.getHashedName())
|
||||
if win32api.GetLastError() == winerror.ERROR_ALREADY_EXISTS:
|
||||
self.mutex.Close()
|
||||
self.mutex = None
|
||||
raise SingleInstanceError('Could not acquire exclusive lock on ' + self.name)
|
||||
|
||||
def release_impl(self):
|
||||
self.mutex.Close()
|
||||
|
||||
class InterProcessLockSocket(InterProcessLockBase):
|
||||
def __init__(self, name=None):
|
||||
InterProcessLockBase.__init__(self, name)
|
||||
self.socket = None
|
||||
self.portno = 65530 - abs(self.getHashedName().__hash__()) % 32749
|
||||
|
||||
def acquire_impl(self, wait):
|
||||
self.socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
|
||||
try:
|
||||
self.socket.bind(('127.0.0.1', self.portno))
|
||||
except socket.error:
|
||||
self.socket.close()
|
||||
self.socket = None
|
||||
raise SingleInstanceError('Could not acquire exclusive lock on ' + self.name)
|
||||
|
||||
def release_impl(self):
|
||||
self.socket.close()
|
||||
self.socket = None
|
||||
|
||||
# Set InterProcessLock to the correct type given the sysem parameters available
|
||||
try:
|
||||
import fcntl
|
||||
InterProcessLock = InterProcessLockFcntl
|
||||
except ImportError:
|
||||
try:
|
||||
import win32event
|
||||
import win32api
|
||||
import winerror
|
||||
InterProcessLock = InterProcessLockWin32
|
||||
except ImportError:
|
||||
import socket
|
||||
InterProcessLock = InterProcessLockSocket
|
||||
|
||||
def test_construct():
|
||||
"""
|
||||
# Making the name of the test unique so it can be executed my multiple users on the same machine.
|
||||
>>> test_name = 'InterProcessLockTest' +str(os.getpid()) + str(time.time())
|
||||
|
||||
>>> lock1 = InterProcessLock(name=test_name)
|
||||
>>> lock1.acquire()
|
||||
|
||||
>>> lock2 = InterProcessLock(name=test_name)
|
||||
>>> lock3 = InterProcessLock(name=test_name)
|
||||
|
||||
# Since lock1 is locked, other attempts to acquire it fail.
|
||||
>>> lock2.acquire()
|
||||
Traceback (most recent call last):
|
||||
...
|
||||
SingleInstanceError: Could not acquire exclusive lock on /tmp/test.lck
|
||||
|
||||
>>> lock3.acquire()
|
||||
Traceback (most recent call last):
|
||||
...
|
||||
SingleInstanceError: Could not acquire exclusive lock on /tmp/test.lck
|
||||
|
||||
# Release the lock and let lock2 have it.
|
||||
>>> lock1.release()
|
||||
>>> lock2.acquire()
|
||||
|
||||
>>> lock3.acquire()
|
||||
Traceback (most recent call last):
|
||||
...
|
||||
SingleInstanceError: Could not acquire exclusive lock on /tmp/test.lck
|
||||
|
||||
# Release it and give it back to lock1
|
||||
>>> lock2.release()
|
||||
>>> lock1.acquire()
|
||||
|
||||
>>> lock2.acquire()
|
||||
Traceback (most recent call last):
|
||||
...
|
||||
SingleInstanceError: Could not acquire exclusive lock on /tmp/test.lck
|
||||
|
||||
# Test lock status
|
||||
>>> lock2.locked()
|
||||
True
|
||||
>>> lock3.locked()
|
||||
True
|
||||
>>> lock1.locked()
|
||||
True
|
||||
|
||||
>>> lock1.release()
|
||||
|
||||
>>> lock2.locked()
|
||||
False
|
||||
>>> lock3.locked()
|
||||
False
|
||||
>>> lock1.locked()
|
||||
False
|
||||
|
||||
>>> if os.name == 'posix':
|
||||
... def os_independent_kill(pid):
|
||||
... import signal
|
||||
... os.kill(pid, signal.SIGKILL)
|
||||
... else:
|
||||
... assert(os.name == 'nt')
|
||||
... def os_independent_kill(pid):
|
||||
... ''' http://www.python.org/doc/faq/windows/#how-do-i-emulate-os-kill-in-windows '''
|
||||
... import win32api
|
||||
... import win32con
|
||||
... import pywintypes
|
||||
... handle = win32api.OpenProcess(win32con.PROCESS_TERMINATE , pywintypes.FALSE, pid)
|
||||
... return (0 != win32api.TerminateProcess(handle, 0))
|
||||
|
||||
# Test to acquire the lock in another process.
|
||||
>>> def execute(cmd):
|
||||
... cmd = 'import time;' + cmd + 'time.sleep(10);'
|
||||
... process = subprocess.Popen([sys.executable, '-c', cmd])
|
||||
... pid = process.pid
|
||||
... time.sleep(2) # quick hack, but we test synchronization in the end
|
||||
... return pid
|
||||
|
||||
>>> pid = execute('import interlocks;a=interlocks.InterProcessLock(name=\\''+test_name+ '\\');a.acquire();')
|
||||
|
||||
>>> lock1.acquire()
|
||||
Traceback (most recent call last):
|
||||
...
|
||||
SingleInstanceError: Could not acquire exclusive lock on /tmp/test.lck
|
||||
|
||||
>>> os_independent_kill(pid)
|
||||
|
||||
>>> time.sleep(1)
|
||||
|
||||
>>> lock1.acquire()
|
||||
>>> lock1.release()
|
||||
|
||||
# Testing wait
|
||||
|
||||
>>> pid = execute('import interlocks;a=interlocks.InterProcessLock(name=\\''+test_name+ '\\');a.acquire();')
|
||||
|
||||
>>> lock1.acquire()
|
||||
Traceback (most recent call last):
|
||||
...
|
||||
SingleInstanceError: Could not acquire exclusive lock on /tmp/test.lck
|
||||
|
||||
>>> os_independent_kill(pid)
|
||||
|
||||
>>> lock1.acquire(True)
|
||||
>>> lock1.release()
|
||||
|
||||
"""
|
||||
|
||||
pass
|
||||
|
||||
if __name__=='__main__':
|
||||
import doctest
|
||||
doctest.testmod(optionflags=doctest.IGNORE_EXCEPTION_DETAIL)
|
Loading…
Reference in New Issue
Block a user