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_PlayerInfo = re.compile("Seat (?P<SEAT>[0-9]+): (?P<PNAME>.*)\s\(\s(\$(?P<CASH>[.0-9]+)) \)")
|
||||||
re_Board = re.compile(ur"\[ (?P<CARDS>.+) \]")
|
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)
|
in_path (default '-' = sys.stdin)
|
||||||
out_path (default '-' = sys.stdout)
|
out_path (default '-' = sys.stdout)
|
||||||
follow : whether to tail -f the input"""
|
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")
|
logging.info("Initialising Betfair converter class")
|
||||||
self.filetype = "text"
|
self.filetype = "text"
|
||||||
self.codepage = "cp1252"
|
self.codepage = "cp1252"
|
||||||
|
|
|
@ -24,25 +24,37 @@ def twoStartCards(value1, suit1, value2, suit2):
|
||||||
(y+2) represents rank of second card (2=2 .. 14=Ace)
|
(y+2) represents rank of second card (2=2 .. 14=Ace)
|
||||||
If x > y then pair is suited, if x < y then unsuited"""
|
If x > y then pair is suited, if x < y then unsuited"""
|
||||||
if value1 < 2 or value2 < 2:
|
if value1 < 2 or value2 < 2:
|
||||||
return(0)
|
ret = 0
|
||||||
if (suit1 == suit2 and value1 < value2) or (suit1 != suit2 and value2 > value1):
|
if value1 == value2: # pairs
|
||||||
return(13 * (value2-2) + (value1-1))
|
ret = (13 * (value2-2) + (value2-1) )
|
||||||
|
elif suit1 == suit2:
|
||||||
|
if value1 > value2:
|
||||||
|
ret = 13 * (value1-2) + (value2-1)
|
||||||
else:
|
else:
|
||||||
return(13 * (value1-2) + (value2-1))
|
ret = 13 * (value2-2) + (value1-1)
|
||||||
|
else:
|
||||||
|
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):
|
def twoStartCardString(card):
|
||||||
""" Function to convert an int representing 2 holdem hole cards (as created by twoStartCards)
|
""" Function to convert an int representing 2 holdem hole cards (as created by twoStartCards)
|
||||||
into a string like AQo """
|
into a string like AQo """
|
||||||
if card <= 0:
|
ret = 'xx'
|
||||||
return 'xx'
|
if card > 0:
|
||||||
else:
|
|
||||||
card -= 1
|
card -= 1
|
||||||
s = ('2', '3', '4', '5', '6', '7', '8', '9', 'T', 'J', 'Q', 'K', 'A')
|
s = ('2', '3', '4', '5', '6', '7', '8', '9', 'T', 'J', 'Q', 'K', 'A')
|
||||||
x = card / 13
|
x = card / 13
|
||||||
y = card - 13 * x
|
y = card - 13 * x
|
||||||
if x == y: return(s[x] + s[y])
|
if x == y: ret = s[x] + s[y]
|
||||||
elif x > y: return(s[x] + s[y] + 's')
|
elif x > y: ret = s[x] + s[y] + 's'
|
||||||
else: return(s[y] + s[x] + 'o')
|
else: ret = s[y] + s[x] + 'o'
|
||||||
|
# print "twoStartCardString(", card ,") = " + ret
|
||||||
|
return ret
|
||||||
|
|
||||||
def fourStartCards(value1, suit1, value2, suit2, value3, suit3, value4, suit4):
|
def fourStartCards(value1, suit1, value2, suit2, value3, suit3, value4, suit4):
|
||||||
""" Function to convert 4 value,suit pairs into a Omaha style starting hand,
|
""" 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'
|
, '2s', '3s', '4s', '5s', '6s', '7s', '8s', '9s', 'Ts', 'Js', 'Qs', 'Ks', 'As'
|
||||||
][card] )
|
][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
|
db['db-backend'] = 2
|
||||||
elif string.lower(self.supported_databases[name].db_server) == 'postgresql':
|
elif string.lower(self.supported_databases[name].db_server) == 'postgresql':
|
||||||
db['db-backend'] = 3
|
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
|
else: db['db-backend'] = None # this is big trouble
|
||||||
return db
|
return db
|
||||||
|
|
||||||
|
|
1434
pyfpdb/Database.py
1434
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>.+) \]")
|
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)
|
in_path (default '-' = sys.stdin)
|
||||||
out_path (default '-' = sys.stdout)
|
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)
|
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..."""
|
debugging: if False, pass on partially supported game types. If true, have a go and error..."""
|
||||||
print "DEBUG: XXXXXXXXXXXXXXX"
|
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")
|
logging.info("Initialising Everleaf converter class")
|
||||||
self.filetype = "text"
|
self.filetype = "text"
|
||||||
self.codepage = "cp1252"
|
self.codepage = "cp1252"
|
||||||
|
@ -237,11 +237,14 @@ or None if we fail to get the info """
|
||||||
# Also works with Omaha hands.
|
# Also works with Omaha hands.
|
||||||
cards = m.group('CARDS')
|
cards = m.group('CARDS')
|
||||||
cards = [card.strip() for card in cards.split(',')]
|
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:
|
else:
|
||||||
#Not involved in hand
|
#Not involved in hand
|
||||||
hand.involved = False
|
hand.involved = False
|
||||||
|
|
||||||
|
|
||||||
def readStudPlayerCards(self, hand, street):
|
def readStudPlayerCards(self, hand, street):
|
||||||
# lol. see Plymouth.txt
|
# lol. see Plymouth.txt
|
||||||
logging.warning("Everleaf readStudPlayerCards is only a stub.")
|
logging.warning("Everleaf readStudPlayerCards is only a stub.")
|
||||||
|
@ -292,7 +295,8 @@ or None if we fail to get the info """
|
||||||
cards = cards.split(', ')
|
cards = cards.split(', ')
|
||||||
player = m.group('PNAME')
|
player = m.group('PNAME')
|
||||||
logging.debug("readShownCards %s cards=%s" % (player, cards))
|
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 *
|
from HandHistoryConverter import *
|
||||||
|
|
||||||
# Fulltilt HH Format converter
|
# Fulltilt HH Format converter
|
||||||
|
# TODO: cat tourno and table to make table name for tournaments
|
||||||
|
|
||||||
class Fulltilt(HandHistoryConverter):
|
class Fulltilt(HandHistoryConverter):
|
||||||
|
|
||||||
# Static regexes
|
# 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_SplitHands = re.compile(r"\n\n+")
|
||||||
re_TailSplitHands = 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_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>.+)\]")
|
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.
|
# 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)
|
in_path (default '-' = sys.stdin)
|
||||||
out_path (default '-' = sys.stdout)
|
out_path (default '-' = sys.stdout)
|
||||||
follow : whether to tail -f the input"""
|
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")
|
logging.info("Initialising Fulltilt converter class")
|
||||||
self.filetype = "text"
|
self.filetype = "text"
|
||||||
self.codepage = "cp1252"
|
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_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_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_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_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_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_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)
|
self.re_ShownCards = re.compile(r"^Seat (?P<SEAT>[0-9]+): %s \(.*\) showed \[(?P<CARDS>.*)\].*" % player_re, re.MULTILINE)
|
||||||
|
|
||||||
|
|
||||||
def readSupportedGames(self):
|
def readSupportedGames(self):
|
||||||
return [["ring", "hold", "nl"],
|
return [["ring", "hold", "nl"],
|
||||||
["ring", "hold", "pl"],
|
["ring", "hold", "pl"],
|
||||||
["ring", "hold", "fl"],
|
["ring", "hold", "fl"],
|
||||||
|
|
||||||
["ring", "stud", "fl"],
|
["ring", "stud", "fl"],
|
||||||
["ring", "omaha", "pl"]
|
|
||||||
|
["tour", "hold", "nl"],
|
||||||
|
["tour", "hold", "pl"],
|
||||||
|
["tour", "hold", "fl"],
|
||||||
|
|
||||||
|
["tour", "stud", "fl"],
|
||||||
]
|
]
|
||||||
|
|
||||||
def determineGameType(self, handText):
|
def determineGameType(self, handText):
|
||||||
|
@ -88,7 +117,6 @@ follow : whether to tail -f the input"""
|
||||||
m = self.re_GameInfo.search(handText)
|
m = self.re_GameInfo.search(handText)
|
||||||
if not m:
|
if not m:
|
||||||
return None
|
return None
|
||||||
|
|
||||||
mg = m.groupdict()
|
mg = m.groupdict()
|
||||||
|
|
||||||
# translations from captured groups to our info strings
|
# translations from captured groups to our info strings
|
||||||
|
@ -96,39 +124,41 @@ follow : whether to tail -f the input"""
|
||||||
games = { # base, category
|
games = { # base, category
|
||||||
"Hold'em" : ('hold','holdem'),
|
"Hold'em" : ('hold','holdem'),
|
||||||
'Omaha Hi' : ('hold','omahahi'),
|
'Omaha Hi' : ('hold','omahahi'),
|
||||||
|
'Omaha H/L' : ('hold','omahahilo'),
|
||||||
'Razz' : ('stud','razz'),
|
'Razz' : ('stud','razz'),
|
||||||
'7 Card Stud' : ('stud','studhi')
|
'Stud Hi' : ('stud','studhi'),
|
||||||
|
'Stud H/L' : ('stud','studhilo')
|
||||||
}
|
}
|
||||||
currencies = { u' €':'EUR', '$':'USD', '':'T$' }
|
currencies = { u' €':'EUR', '$':'USD', '':'T$' }
|
||||||
if 'LIMIT' in mg:
|
|
||||||
info['limitType'] = limits[mg['LIMIT']]
|
info['limitType'] = limits[mg['LIMIT']]
|
||||||
if 'GAME' in mg:
|
|
||||||
(info['base'], info['category']) = games[mg['GAME']]
|
|
||||||
if 'SB' in mg:
|
|
||||||
info['sb'] = mg['SB']
|
info['sb'] = mg['SB']
|
||||||
if 'BB' in mg:
|
|
||||||
info['bb'] = mg['BB']
|
info['bb'] = mg['BB']
|
||||||
if 'CURRENCY' in mg:
|
if mg['GAME'] != None:
|
||||||
|
(info['base'], info['category']) = games[mg['GAME']]
|
||||||
|
if mg['CURRENCY'] != None:
|
||||||
info['currency'] = currencies[mg['CURRENCY']]
|
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.
|
# NB: SB, BB must be interpreted as blinds or bets depending on limit type.
|
||||||
|
|
||||||
return info
|
return info
|
||||||
|
|
||||||
def readHandInfo(self, hand):
|
def readHandInfo(self, hand):
|
||||||
m = self.re_HandInfo.search(hand.handText,re.DOTALL)
|
m = self.re_HandInfo.search(hand.handText,re.DOTALL)
|
||||||
|
|
||||||
if(m == None):
|
if(m == None):
|
||||||
logging.info("Didn't match re_HandInfo")
|
logging.info("Didn't match re_HandInfo")
|
||||||
logging.info(hand.handText)
|
logging.info(hand.handText)
|
||||||
return None
|
return None
|
||||||
|
|
||||||
hand.handid = m.group('HID')
|
hand.handid = m.group('HID')
|
||||||
hand.tablename = m.group('TABLE')
|
hand.tablename = m.group('TABLE')
|
||||||
hand.starttime = datetime.datetime.strptime(m.group('DATETIME'), "%H:%M:%S ET - %Y/%m/%d")
|
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'):
|
if m.group('TABLEATTRIBUTES'):
|
||||||
m2 = re.search("(deep )?(\d+)( max)?", m.group('TABLEATTRIBUTES'))
|
m2 = self.re_Max.search(m.group('TABLEATTRIBUTES'))
|
||||||
hand.maxseats = int(m2.group(2))
|
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.
|
# These work, but the info is already in the Hand class - should be used for tourneys though.
|
||||||
# m.group('SB')
|
# m.group('SB')
|
||||||
# m.group('BB')
|
# m.group('BB')
|
||||||
|
@ -190,6 +220,7 @@ follow : whether to tail -f the input"""
|
||||||
m = self.re_Antes.finditer(hand.handText)
|
m = self.re_Antes.finditer(hand.handText)
|
||||||
for player in m:
|
for player in m:
|
||||||
logging.debug("hand.addAnte(%s,%s)" %(player.group('PNAME'), player.group('ANTE')))
|
logging.debug("hand.addAnte(%s,%s)" %(player.group('PNAME'), player.group('ANTE')))
|
||||||
|
# if player.group() !=
|
||||||
hand.addAnte(player.group('PNAME'), player.group('ANTE'))
|
hand.addAnte(player.group('PNAME'), player.group('ANTE'))
|
||||||
|
|
||||||
def readBringIn(self, hand):
|
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')))
|
logging.debug("Player bringing in: %s for %s" %(m.group('PNAME'), m.group('BRINGIN')))
|
||||||
hand.addBringIn(m.group('PNAME'), m.group('BRINGIN'))
|
hand.addBringIn(m.group('PNAME'), m.group('BRINGIN'))
|
||||||
else:
|
else:
|
||||||
logging.warning("No bringin found")
|
logging.warning("No bringin found, handid =%s" % hand.handid)
|
||||||
|
|
||||||
def readButton(self, hand):
|
def readButton(self, hand):
|
||||||
hand.buttonpos = int(self.re_Button.search(hand.handText).group('BUTTON'))
|
hand.buttonpos = int(self.re_Button.search(hand.handText).group('BUTTON'))
|
||||||
|
|
||||||
def readHeroCards(self, hand):
|
def readHeroCards(self, hand):
|
||||||
m = self.re_HeroCards.search(hand.handText)
|
# streets PREFLOP, PREDRAW, and THIRD are special cases beacause
|
||||||
if(m == None):
|
# we need to grab hero's cards
|
||||||
#Not involved in hand
|
for street in ('PREFLOP', 'DEAL'):
|
||||||
hand.involved = False
|
if street in hand.streets.keys():
|
||||||
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'))
|
|
||||||
|
|
||||||
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])
|
m = self.re_HeroCards.finditer(hand.streets[street])
|
||||||
for player in m:
|
for found in m:
|
||||||
logging.debug(player.groupdict())
|
# if m == None:
|
||||||
(pname, oldcards, newcards) = (player.group('PNAME'), player.group('OLDCARDS'), player.group('NEWCARDS'))
|
# hand.involved = False
|
||||||
if oldcards:
|
# else:
|
||||||
oldcards = [c.strip() for c in oldcards.split(' ')]
|
hand.hero = found.group('PNAME')
|
||||||
if newcards:
|
newcards = found.group('NEWCARDS').split(' ')
|
||||||
newcards = [c.strip() for c in newcards.split(' ')]
|
hand.addHoleCards(street, hand.hero, closed=newcards, shown=False, mucked=False, dealt=True)
|
||||||
# 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.
|
for street, text in hand.streets.iteritems():
|
||||||
# (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)
|
if not text or street in ('PREFLOP', 'DEAL'): continue # already done these
|
||||||
# so call addPlayerCards with the appropriate information.
|
m = self.re_HeroCards.finditer(hand.streets[street])
|
||||||
# I favour (2) here but I'm afraid it is rather stud7-specific.
|
for found in m:
|
||||||
# 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'
|
player = found.group('PNAME')
|
||||||
if street=='ANTES':
|
if found.group('NEWCARDS') == None:
|
||||||
return
|
newcards = []
|
||||||
elif street=='THIRD':
|
else:
|
||||||
# we'll have observed hero holecards in CARDS and thirdstreet open cards in 'NEWCARDS'
|
newcards = found.group('NEWCARDS').split(' ')
|
||||||
# hero: [xx][o]
|
if found.group('OLDCARDS') == None:
|
||||||
# others: [o]
|
oldcards = []
|
||||||
hand.addPlayerCards(player = player.group('PNAME'), street = street, closed = oldcards, open = newcards)
|
else:
|
||||||
elif street in ('FOURTH', 'FIFTH', 'SIXTH'):
|
oldcards = found.group('OLDCARDS').split(' ')
|
||||||
# 4th:
|
|
||||||
# hero: [xxo] [o]
|
if street == 'THIRD' and len(oldcards) == 2: # hero in stud game
|
||||||
# others: [o] [o]
|
hand.hero = player
|
||||||
# 5th:
|
hand.dealt.add(player) # need this for stud??
|
||||||
# hero: [xxoo] [o]
|
hand.addHoleCards(street, player, closed=oldcards, open=newcards, shown=False, mucked=False, dealt=False)
|
||||||
# others: [oo] [o]
|
else:
|
||||||
# 6th:
|
hand.addHoleCards(street, player, open=newcards, closed=oldcards, shown=False, mucked=False, dealt=False)
|
||||||
# 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):
|
def readAction(self, hand, street):
|
||||||
m = self.re_Action.finditer(hand.streets[street])
|
m = self.re_Action.finditer(hand.streets[street])
|
||||||
|
@ -308,6 +306,29 @@ follow : whether to tail -f the input"""
|
||||||
cards = cards.split(' ')
|
cards = cards.split(' ')
|
||||||
hand.addShownCards(cards=cards, player=m.group('PNAME'))
|
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__":
|
if __name__ == "__main__":
|
||||||
parser = OptionParser()
|
parser = OptionParser()
|
||||||
|
|
|
@ -154,6 +154,12 @@ class GuiAutoImport (threading.Thread):
|
||||||
# results to the same pipe. This means that self.path should be a a list of dirs
|
# results to the same pipe. This means that self.path should be a a list of dirs
|
||||||
# to watch.
|
# to watch.
|
||||||
if widget.get_active(): # toggled on
|
if widget.get_active(): # toggled on
|
||||||
|
# - 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
|
self.doAutoImportBool = True
|
||||||
widget.set_label(u' _Stop Autoimport ')
|
widget.set_label(u' _Stop Autoimport ')
|
||||||
if self.pipe_to_hud is None:
|
if self.pipe_to_hud is None:
|
||||||
|
@ -176,9 +182,12 @@ class GuiAutoImport (threading.Thread):
|
||||||
|
|
||||||
interval=int(self.intervalEntry.get_text())
|
interval=int(self.intervalEntry.get_text())
|
||||||
gobject.timeout_add(interval*1000, self.do_import)
|
gobject.timeout_add(interval*1000, self.do_import)
|
||||||
|
else:
|
||||||
|
print "auto-import aborted - global lock not available"
|
||||||
else: # toggled off
|
else: # toggled off
|
||||||
|
self.settings['global_lock'].release()
|
||||||
self.doAutoImportBool = False # do_import will return this and stop the gobject callback timer
|
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:
|
if self.pipe_to_hud.poll() is not None:
|
||||||
print "HUD already terminated"
|
print "HUD already terminated"
|
||||||
else:
|
else:
|
||||||
|
@ -187,8 +196,6 @@ class GuiAutoImport (threading.Thread):
|
||||||
self.pipe_to_hud = None
|
self.pipe_to_hud = None
|
||||||
self.startButton.set_label(u' _Start Autoimport ')
|
self.startButton.set_label(u' _Start Autoimport ')
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
#end def GuiAutoImport.startClicked
|
#end def GuiAutoImport.startClicked
|
||||||
|
|
||||||
def get_vbox(self):
|
def get_vbox(self):
|
||||||
|
|
|
@ -34,6 +34,7 @@ import Configuration
|
||||||
|
|
||||||
class GuiBulkImport():
|
class GuiBulkImport():
|
||||||
|
|
||||||
|
# not used
|
||||||
def import_dir(self):
|
def import_dir(self):
|
||||||
"""imports a directory, non-recursive. todo: move this to fpdb_import so CLI can use it"""
|
"""imports a directory, non-recursive. todo: move this to fpdb_import so CLI can use it"""
|
||||||
|
|
||||||
|
@ -49,6 +50,11 @@ class GuiBulkImport():
|
||||||
self.importer.RunImportThreaded()
|
self.importer.RunImportThreaded()
|
||||||
|
|
||||||
def load_clicked(self, widget, data=None):
|
def load_clicked(self, widget, data=None):
|
||||||
|
# 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
|
# get the dir to import from the chooser
|
||||||
self.inputFile = self.chooser.get_filename()
|
self.inputFile = self.chooser.get_filename()
|
||||||
|
|
||||||
|
@ -75,21 +81,26 @@ class GuiBulkImport():
|
||||||
ttime = time() - starttime
|
ttime = time() - starttime
|
||||||
if ttime == 0:
|
if ttime == 0:
|
||||||
ttime = 1
|
ttime = 1
|
||||||
print 'GuiBulkImport.import_dir done: Stored: %d \tDuplicates: %d \tPartial: %d \tErrors: %d in %s seconds - %d/sec'\
|
print 'GuiBulkImport.load done: Stored: %d \tDuplicates: %d \tPartial: %d \tErrors: %d in %s seconds - %d/sec'\
|
||||||
% (stored, dups, partial, errs, ttime, stored / ttime)
|
% (stored, dups, partial, errs, ttime, stored / ttime)
|
||||||
self.importer.clearFileList()
|
self.importer.clearFileList()
|
||||||
|
|
||||||
self.lab_info.set_text("Import finished")
|
self.lab_info.set_text("Import finished")
|
||||||
|
except:
|
||||||
|
print "bulkimport.loadclicked error: "+str(sys.exc_value)
|
||||||
|
pass
|
||||||
|
self.settings['global_lock'].release()
|
||||||
|
else:
|
||||||
|
print "bulk-import aborted - global lock not available"
|
||||||
|
|
||||||
def get_vbox(self):
|
def get_vbox(self):
|
||||||
"""returns the vbox of this thread"""
|
"""returns the vbox of this thread"""
|
||||||
return self.vbox
|
return self.vbox
|
||||||
|
|
||||||
def __init__(self, settings, config):
|
def __init__(self, settings, config, sql = None):
|
||||||
self.settings = settings
|
self.settings = settings
|
||||||
self.config = config
|
self.config = config
|
||||||
self.importer = fpdb_import.Importer(self, self.settings,
|
self.importer = fpdb_import.Importer(self, self.settings, config, sql)
|
||||||
config)
|
|
||||||
|
|
||||||
self.vbox = gtk.VBox(False, 0)
|
self.vbox = gtk.VBox(False, 0)
|
||||||
self.vbox.show()
|
self.vbox.show()
|
||||||
|
@ -196,10 +207,11 @@ class GuiBulkImport():
|
||||||
self.load_button.show()
|
self.load_button.show()
|
||||||
|
|
||||||
# see how many hands are in the db and adjust accordingly
|
# 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")
|
tcursor.execute("Select count(1) from Hands")
|
||||||
row = tcursor.fetchone()
|
row = tcursor.fetchone()
|
||||||
tcursor.close()
|
tcursor.close()
|
||||||
|
self.importer.database.rollback()
|
||||||
self.n_hands_in_db = row[0]
|
self.n_hands_in_db = row[0]
|
||||||
if self.n_hands_in_db == 0:
|
if self.n_hands_in_db == 0:
|
||||||
self.cb_dropindexes.set_active(2)
|
self.cb_dropindexes.set_active(2)
|
||||||
|
@ -252,7 +264,8 @@ def main(argv=None):
|
||||||
else:
|
else:
|
||||||
#Do something useful
|
#Do something useful
|
||||||
importer = fpdb_import.Importer(False,settings, config)
|
importer = fpdb_import.Importer(False,settings, config)
|
||||||
importer.setDropIndexes("auto")
|
# importer.setDropIndexes("auto")
|
||||||
|
importer.setDropIndexes("don't drop")
|
||||||
importer.setFailOnError(options.failOnError)
|
importer.setFailOnError(options.failOnError)
|
||||||
importer.addBulkImportImportFileOrDir(os.path.expanduser(options.filename), site=options.filtername)
|
importer.addBulkImportImportFileOrDir(os.path.expanduser(options.filename), site=options.filtername)
|
||||||
importer.setCallHud(False)
|
importer.setCallHud(False)
|
||||||
|
|
|
@ -38,20 +38,19 @@ except:
|
||||||
and HUD are NOT affected by this problem."""
|
and HUD are NOT affected by this problem."""
|
||||||
|
|
||||||
import fpdb_import
|
import fpdb_import
|
||||||
import fpdb_db
|
import Database
|
||||||
import Filters
|
import Filters
|
||||||
|
|
||||||
class GuiGraphViewer (threading.Thread):
|
class GuiGraphViewer (threading.Thread):
|
||||||
|
|
||||||
def __init__(self, querylist, config, debug=True):
|
def __init__(self, querylist, config, debug=True):
|
||||||
"""Constructor for GraphViewer"""
|
"""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.sql = querylist
|
||||||
self.conf = config
|
self.conf = config
|
||||||
|
self.debug = debug
|
||||||
|
#print "start of GraphViewer constructor"
|
||||||
|
self.db = Database.Database(self.conf, sql=self.sql)
|
||||||
|
|
||||||
|
|
||||||
filters_display = { "Heroes" : True,
|
filters_display = { "Heroes" : True,
|
||||||
"Sites" : True,
|
"Sites" : True,
|
||||||
|
@ -63,7 +62,7 @@ class GuiGraphViewer (threading.Thread):
|
||||||
"Button2" : True
|
"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.registerButton1Name("Refresh Graph")
|
||||||
self.filters.registerButton1Callback(self.generateGraph)
|
self.filters.registerButton1Callback(self.generateGraph)
|
||||||
self.filters.registerButton2Name("Export to File")
|
self.filters.registerButton2Name("Export to File")
|
||||||
|
@ -90,7 +89,7 @@ class GuiGraphViewer (threading.Thread):
|
||||||
self.canvas = None
|
self.canvas = None
|
||||||
|
|
||||||
|
|
||||||
self.db.db.rollback()
|
self.db.rollback()
|
||||||
|
|
||||||
#################################
|
#################################
|
||||||
#
|
#
|
||||||
|
@ -126,7 +125,7 @@ class GuiGraphViewer (threading.Thread):
|
||||||
#end def get_vbox
|
#end def get_vbox
|
||||||
|
|
||||||
def clearGraphData(self):
|
def clearGraphData(self):
|
||||||
self.fig.clf()
|
self.fig.clear()
|
||||||
if self.canvas is not None:
|
if self.canvas is not None:
|
||||||
self.canvas.destroy()
|
self.canvas.destroy()
|
||||||
|
|
||||||
|
@ -154,7 +153,7 @@ class GuiGraphViewer (threading.Thread):
|
||||||
if not sitenos:
|
if not sitenos:
|
||||||
#Should probably pop up here.
|
#Should probably pop up here.
|
||||||
print "No sites selected - defaulting to PokerStars"
|
print "No sites selected - defaulting to PokerStars"
|
||||||
sitenos = [2]
|
return
|
||||||
|
|
||||||
if not playerids:
|
if not playerids:
|
||||||
print "No player ids found"
|
print "No player ids found"
|
||||||
|
@ -197,6 +196,7 @@ class GuiGraphViewer (threading.Thread):
|
||||||
|
|
||||||
self.graphBox.add(self.canvas)
|
self.graphBox.add(self.canvas)
|
||||||
self.canvas.show()
|
self.canvas.show()
|
||||||
|
self.canvas.draw()
|
||||||
#self.exportButton.set_sensitive(True)
|
#self.exportButton.set_sensitive(True)
|
||||||
#end of def showClicked
|
#end of def showClicked
|
||||||
|
|
||||||
|
@ -205,7 +205,7 @@ class GuiGraphViewer (threading.Thread):
|
||||||
# print "DEBUG: getRingProfitGraph"
|
# print "DEBUG: getRingProfitGraph"
|
||||||
start_date, end_date = self.filters.getDates()
|
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.
|
# and turn it into a tuple readale by sql.
|
||||||
# [5L] into (5) not (5,) and [5L, 2829L] into (5, 2829)
|
# [5L] into (5) not (5,) and [5L, 2829L] into (5, 2829)
|
||||||
nametest = str(tuple(names))
|
nametest = str(tuple(names))
|
||||||
|
@ -229,7 +229,7 @@ class GuiGraphViewer (threading.Thread):
|
||||||
self.db.cursor.execute(tmp)
|
self.db.cursor.execute(tmp)
|
||||||
#returns (HandId,Winnings,Costs,Profit)
|
#returns (HandId,Winnings,Costs,Profit)
|
||||||
winnings = self.db.cursor.fetchall()
|
winnings = self.db.cursor.fetchall()
|
||||||
self.db.db.rollback()
|
self.db.rollback()
|
||||||
|
|
||||||
if(winnings == ()):
|
if(winnings == ()):
|
||||||
return None
|
return None
|
||||||
|
|
|
@ -20,34 +20,35 @@ import pygtk
|
||||||
pygtk.require('2.0')
|
pygtk.require('2.0')
|
||||||
import gtk
|
import gtk
|
||||||
import os
|
import os
|
||||||
|
import sys
|
||||||
from time import time, strftime
|
from time import time, strftime
|
||||||
|
|
||||||
import Card
|
import Card
|
||||||
import fpdb_import
|
import fpdb_import
|
||||||
|
import Database
|
||||||
import fpdb_db
|
import fpdb_db
|
||||||
import Filters
|
import Filters
|
||||||
import FpdbSQLQueries
|
|
||||||
|
|
||||||
class GuiPlayerStats (threading.Thread):
|
class GuiPlayerStats (threading.Thread):
|
||||||
def __init__(self, config, querylist, mainwin, debug=True):
|
def __init__(self, config, querylist, mainwin, debug=True):
|
||||||
self.debug = debug
|
self.debug = debug
|
||||||
self.conf = config
|
self.conf = config
|
||||||
self.main_window = mainwin
|
self.main_window = mainwin
|
||||||
|
self.sql = querylist
|
||||||
|
|
||||||
self.MYSQL_INNODB = 2
|
self.MYSQL_INNODB = 2
|
||||||
self.PGSQL = 3
|
self.PGSQL = 3
|
||||||
self.SQLITE = 4
|
self.SQLITE = 4
|
||||||
|
|
||||||
# create new db connection to avoid conflicts with other threads
|
# create new db connection to avoid conflicts with other threads
|
||||||
self.db = fpdb_db.fpdb_db()
|
self.db = Database.Database(self.conf, sql=self.sql)
|
||||||
self.db.do_connect(self.conf)
|
|
||||||
self.cursor = self.db.cursor
|
self.cursor = self.db.cursor
|
||||||
self.sql = querylist
|
|
||||||
|
|
||||||
settings = {}
|
settings = {}
|
||||||
settings.update(config.get_db_parameters())
|
settings.update(self.conf.get_db_parameters())
|
||||||
settings.update(config.get_tv_parameters())
|
settings.update(self.conf.get_tv_parameters())
|
||||||
settings.update(config.get_import_parameters())
|
settings.update(self.conf.get_import_parameters())
|
||||||
settings.update(config.get_default_paths())
|
settings.update(self.conf.get_default_paths())
|
||||||
|
|
||||||
# text used on screen stored here so that it can be configured
|
# text used on screen stored here so that it can be configured
|
||||||
self.filterText = {'handhead':'Hand Breakdown for all levels listed above'
|
self.filterText = {'handhead':'Hand Breakdown for all levels listed above'
|
||||||
|
@ -66,7 +67,7 @@ class GuiPlayerStats (threading.Thread):
|
||||||
"Button2" : True
|
"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.registerButton1Name("_Filters")
|
||||||
self.filters.registerButton1Callback(self.showDetailFilter)
|
self.filters.registerButton1Callback(self.showDetailFilter)
|
||||||
self.filters.registerButton2Name("_Refresh")
|
self.filters.registerButton2Name("_Refresh")
|
||||||
|
@ -216,7 +217,7 @@ class GuiPlayerStats (threading.Thread):
|
||||||
flags = [True]
|
flags = [True]
|
||||||
self.addTable(vbox1, 'playerDetailedStats', flags, playerids, sitenos, limits, seats, groups, dates)
|
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)
|
print "Stats page displayed in %4.2f seconds" % (time() - starttime)
|
||||||
#end def fillStatsFrame(self, vbox):
|
#end def fillStatsFrame(self, vbox):
|
||||||
|
|
||||||
|
@ -280,8 +281,10 @@ class GuiPlayerStats (threading.Thread):
|
||||||
if column[colalias] == 'plposition':
|
if column[colalias] == 'plposition':
|
||||||
if value == 'B':
|
if value == 'B':
|
||||||
value = 'BB'
|
value = 'BB'
|
||||||
if value == 'S':
|
elif value == 'S':
|
||||||
value = 'SB'
|
value = 'SB'
|
||||||
|
elif value == '0':
|
||||||
|
value = 'Btn'
|
||||||
else:
|
else:
|
||||||
if column[colalias] == 'game':
|
if column[colalias] == 'game':
|
||||||
if holecards:
|
if holecards:
|
||||||
|
@ -379,7 +382,8 @@ class GuiPlayerStats (threading.Thread):
|
||||||
|
|
||||||
# Group by position?
|
# Group by position?
|
||||||
if groups['posn']:
|
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
|
# set flag in self.columns to show posn column
|
||||||
[x for x in self.columns if x[0] == 'plposition'][0][1] = True
|
[x for x in self.columns if x[0] == 'plposition'][0][1] = True
|
||||||
else:
|
else:
|
||||||
|
|
|
@ -23,7 +23,7 @@ import os
|
||||||
from time import time, strftime
|
from time import time, strftime
|
||||||
|
|
||||||
import fpdb_import
|
import fpdb_import
|
||||||
import fpdb_db
|
import Database
|
||||||
import Filters
|
import Filters
|
||||||
import FpdbSQLQueries
|
import FpdbSQLQueries
|
||||||
|
|
||||||
|
@ -31,21 +31,20 @@ class GuiPositionalStats (threading.Thread):
|
||||||
def __init__(self, config, querylist, debug=True):
|
def __init__(self, config, querylist, debug=True):
|
||||||
self.debug = debug
|
self.debug = debug
|
||||||
self.conf = config
|
self.conf = config
|
||||||
|
self.sql = querylist
|
||||||
self.MYSQL_INNODB = 2
|
self.MYSQL_INNODB = 2
|
||||||
self.PGSQL = 3
|
self.PGSQL = 3
|
||||||
self.SQLITE = 4
|
self.SQLITE = 4
|
||||||
|
|
||||||
# create new db connection to avoid conflicts with other threads
|
# create new db connection to avoid conflicts with other threads
|
||||||
self.db = fpdb_db.fpdb_db()
|
self.db = Database.Database(self.conf, sql=self.sql)
|
||||||
self.db.do_connect(self.conf)
|
|
||||||
self.cursor = self.db.cursor
|
self.cursor = self.db.cursor
|
||||||
self.sql = querylist
|
|
||||||
|
|
||||||
settings = {}
|
settings = {}
|
||||||
settings.update(config.get_db_parameters())
|
settings.update(self.conf.get_db_parameters())
|
||||||
settings.update(config.get_tv_parameters())
|
settings.update(self.conf.get_tv_parameters())
|
||||||
settings.update(config.get_import_parameters())
|
settings.update(self.conf.get_import_parameters())
|
||||||
settings.update(config.get_default_paths())
|
settings.update(self.conf.get_default_paths())
|
||||||
|
|
||||||
filters_display = { "Heroes" : True,
|
filters_display = { "Heroes" : True,
|
||||||
"Sites" : True,
|
"Sites" : True,
|
||||||
|
@ -59,7 +58,7 @@ class GuiPositionalStats (threading.Thread):
|
||||||
"Button2" : False
|
"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.registerButton1Name("Refresh")
|
||||||
self.filters.registerButton1Callback(self.refreshStats)
|
self.filters.registerButton1Callback(self.refreshStats)
|
||||||
|
|
||||||
|
@ -319,7 +318,7 @@ class GuiPositionalStats (threading.Thread):
|
||||||
row = row + 1
|
row = row + 1
|
||||||
vbox.show_all()
|
vbox.show_all()
|
||||||
|
|
||||||
self.db.db.rollback()
|
self.db.rollback()
|
||||||
print "Positional Stats page displayed in %4.2f seconds" % (time() - starttime)
|
print "Positional Stats page displayed in %4.2f seconds" % (time() - starttime)
|
||||||
#end def fillStatsFrame(self, vbox):
|
#end def fillStatsFrame(self, vbox):
|
||||||
|
|
||||||
|
|
|
@ -25,7 +25,7 @@ from numpy import diff, nonzero
|
||||||
|
|
||||||
import Card
|
import Card
|
||||||
import fpdb_import
|
import fpdb_import
|
||||||
import fpdb_db
|
import Database
|
||||||
import Filters
|
import Filters
|
||||||
import FpdbSQLQueries
|
import FpdbSQLQueries
|
||||||
|
|
||||||
|
@ -33,21 +33,20 @@ class GuiSessionViewer (threading.Thread):
|
||||||
def __init__(self, config, querylist, debug=True):
|
def __init__(self, config, querylist, debug=True):
|
||||||
self.debug = debug
|
self.debug = debug
|
||||||
self.conf = config
|
self.conf = config
|
||||||
|
self.sql = querylist
|
||||||
self.MYSQL_INNODB = 2
|
self.MYSQL_INNODB = 2
|
||||||
self.PGSQL = 3
|
self.PGSQL = 3
|
||||||
self.SQLITE = 4
|
self.SQLITE = 4
|
||||||
|
|
||||||
# create new db connection to avoid conflicts with other threads
|
# create new db connection to avoid conflicts with other threads
|
||||||
self.db = fpdb_db.fpdb_db()
|
self.db = Database.Database(self.conf, sql=self.sql)
|
||||||
self.db.do_connect(self.conf)
|
|
||||||
self.cursor = self.db.cursor
|
self.cursor = self.db.cursor
|
||||||
self.sql = querylist
|
|
||||||
|
|
||||||
settings = {}
|
settings = {}
|
||||||
settings.update(config.get_db_parameters())
|
settings.update(self.conf.get_db_parameters())
|
||||||
settings.update(config.get_tv_parameters())
|
settings.update(self.conf.get_tv_parameters())
|
||||||
settings.update(config.get_import_parameters())
|
settings.update(self.conf.get_import_parameters())
|
||||||
settings.update(config.get_default_paths())
|
settings.update(self.conf.get_default_paths())
|
||||||
|
|
||||||
# text used on screen stored here so that it can be configured
|
# text used on screen stored here so that it can be configured
|
||||||
self.filterText = {'handhead':'Hand Breakdown for all levels listed above'
|
self.filterText = {'handhead':'Hand Breakdown for all levels listed above'
|
||||||
|
@ -66,7 +65,7 @@ class GuiSessionViewer (threading.Thread):
|
||||||
"Button2" : True
|
"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.registerButton2Name("_Refresh")
|
||||||
self.filters.registerButton2Callback(self.refreshStats)
|
self.filters.registerButton2Callback(self.refreshStats)
|
||||||
|
|
||||||
|
@ -195,7 +194,7 @@ class GuiSessionViewer (threading.Thread):
|
||||||
flags = [True]
|
flags = [True]
|
||||||
self.addTable(vbox1, 'playerDetailedStats', flags, playerids, sitenos, limits, seats)
|
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)
|
print "Stats page displayed in %4.2f seconds" % (time() - starttime)
|
||||||
#end def fillStatsFrame(self, vbox):
|
#end def fillStatsFrame(self, vbox):
|
||||||
|
|
||||||
|
|
|
@ -159,6 +159,50 @@
|
||||||
<location seat="9" x="70" y="53"> </location>
|
<location seat="9" x="70" y="53"> </location>
|
||||||
</layout>
|
</layout>
|
||||||
</site>
|
</site>
|
||||||
|
|
||||||
|
<site enabled="False"
|
||||||
|
site_name="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_sites>
|
||||||
|
|
||||||
<supported_games>
|
<supported_games>
|
||||||
|
@ -292,6 +336,7 @@
|
||||||
<hhc site="PokerStars" converter="PokerStarsToFpdb"/>
|
<hhc site="PokerStars" converter="PokerStarsToFpdb"/>
|
||||||
<hhc site="Full Tilt Poker" converter="FulltiltToFpdb"/>
|
<hhc site="Full Tilt Poker" converter="FulltiltToFpdb"/>
|
||||||
<hhc site="Everleaf" converter="EverleafToFpdb"/>
|
<hhc site="Everleaf" converter="EverleafToFpdb"/>
|
||||||
|
<hhc site="Win2day" converter="Win2dayToFpdb"/>
|
||||||
</hhcs>
|
</hhcs>
|
||||||
|
|
||||||
<supported_databases>
|
<supported_databases>
|
||||||
|
@ -300,4 +345,3 @@
|
||||||
|
|
||||||
</FreePokerToolsConfig>
|
</FreePokerToolsConfig>
|
||||||
|
|
||||||
|
|
||||||
|
|
348
pyfpdb/Hand.py
348
pyfpdb/Hand.py
|
@ -32,14 +32,14 @@ import pprint
|
||||||
import DerivedStats
|
import DerivedStats
|
||||||
import Card
|
import Card
|
||||||
|
|
||||||
class Hand:
|
class Hand(object):
|
||||||
|
|
||||||
###############################################################3
|
###############################################################3
|
||||||
# Class Variables
|
# Class Variables
|
||||||
UPS = {'a':'A', 't':'T', 'j':'J', 'q':'Q', 'k':'K', 'S':'s', 'C':'c', 'H':'h', 'D':'d'}
|
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'}
|
LCS = {'H':'h', 'D':'d', 'C':'c', 'S':'s'}
|
||||||
SYMBOL = {'USD': '$', 'EUR': u'E', 'T$': '', 'play': ''}
|
SYMBOL = {'USD': '$', 'EUR': u'$', 'T$': '', 'play': ''}
|
||||||
MS = {'horse' : 'HORSE', '8game' : '8-Game', 'hose' : 'HOSE'}
|
MS = {'horse' : 'HORSE', '8game' : '8-Game', 'hose' : 'HOSE', 'ha': 'HA'}
|
||||||
|
|
||||||
|
|
||||||
def __init__(self, sitename, gametype, handText, builtFrom = "HHC"):
|
def __init__(self, sitename, gametype, handText, builtFrom = "HHC"):
|
||||||
|
@ -51,7 +51,7 @@ class Hand:
|
||||||
self.handid = 0
|
self.handid = 0
|
||||||
self.tablename = ""
|
self.tablename = ""
|
||||||
self.hero = ""
|
self.hero = ""
|
||||||
self.maxseats = 10
|
self.maxseats = None
|
||||||
self.counted_seats = 0
|
self.counted_seats = 0
|
||||||
self.buttonpos = 0
|
self.buttonpos = 0
|
||||||
self.tourNo = None
|
self.tourNo = None
|
||||||
|
@ -81,7 +81,6 @@ class Hand:
|
||||||
self.holecards[street] = {} # dict from player names to holecards
|
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
|
self.discards[street] = {} # dict from player names to dicts by street ... of tuples ... of discarded holecards
|
||||||
# Collections indexed by player names
|
# Collections indexed by player names
|
||||||
# self.holecards = {} # dict from player names to dicts by street ... of tuples ... of holecards
|
|
||||||
self.stacks = {}
|
self.stacks = {}
|
||||||
self.collected = [] #list of ?
|
self.collected = [] #list of ?
|
||||||
self.collectees = {} # dict from player names to amounts collected (?)
|
self.collectees = {} # dict from player names to amounts collected (?)
|
||||||
|
@ -92,12 +91,14 @@ class Hand:
|
||||||
self.shown = set() # cards were shown
|
self.shown = set() # cards were shown
|
||||||
self.mucked = set() # cards were mucked at showdown
|
self.mucked = set() # cards were mucked at showdown
|
||||||
|
|
||||||
# self.action = []
|
|
||||||
# Things to do with money
|
# Things to do with money
|
||||||
self.pot = Pot()
|
self.pot = Pot()
|
||||||
self.totalpot = None
|
self.totalpot = None
|
||||||
self.totalcollected = None
|
self.totalcollected = None
|
||||||
self.rake = 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):
|
def __str__(self):
|
||||||
vars = ( ("BB", self.bb),
|
vars = ( ("BB", self.bb),
|
||||||
|
@ -171,6 +172,9 @@ dealt whether they were seen in a 'dealt to' line
|
||||||
|
|
||||||
self.holecards[street][player] = [open, closed]
|
self.holecards[street][player] = [open, closed]
|
||||||
|
|
||||||
|
def prepInsert(self, db):
|
||||||
|
pass
|
||||||
|
|
||||||
def insert(self, db):
|
def insert(self, db):
|
||||||
""" Function to insert Hand into database
|
""" Function to insert Hand into database
|
||||||
Should not commit, and do minimal selects. Callers may want to cache commits
|
Should not commit, and do minimal selects. Callers may want to cache commits
|
||||||
|
@ -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."""
|
If a player has None chips he won't be added."""
|
||||||
logging.debug("addPlayer: %s %s (%s)" % (seat, name, chips))
|
logging.debug("addPlayer: %s %s (%s)" % (seat, name, chips))
|
||||||
if chips is not None:
|
if chips is not None:
|
||||||
|
chips = re.sub(u',', u'', chips) #some sites have commas
|
||||||
self.players.append([seat, name, chips])
|
self.players.append([seat, name, chips])
|
||||||
self.stacks[name] = Decimal(chips)
|
self.stacks[name] = Decimal(chips)
|
||||||
self.pot.addPlayer(name)
|
self.pot.addPlayer(name)
|
||||||
|
@ -297,6 +302,7 @@ If a player has None chips he won't be added."""
|
||||||
def addAnte(self, player, ante):
|
def addAnte(self, player, ante):
|
||||||
logging.debug("%s %s antes %s" % ('ANTES', player, ante))
|
logging.debug("%s %s antes %s" % ('ANTES', player, ante))
|
||||||
if player is not None:
|
if player is not None:
|
||||||
|
ante = re.sub(u',', u'', ante) #some sites have commas
|
||||||
self.bets['ANTES'][player].append(Decimal(ante))
|
self.bets['ANTES'][player].append(Decimal(ante))
|
||||||
self.stacks[player] -= Decimal(ante)
|
self.stacks[player] -= Decimal(ante)
|
||||||
act = (player, 'posts', "ante", ante, self.stacks[player]==0)
|
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))
|
logging.debug("addBlind: %s posts %s, %s" % (player, blindtype, amount))
|
||||||
if player is not None:
|
if player is not None:
|
||||||
|
amount = re.sub(u',', u'', amount) #some sites have commas
|
||||||
self.bets['PREFLOP'][player].append(Decimal(amount))
|
self.bets['PREFLOP'][player].append(Decimal(amount))
|
||||||
self.stacks[player] -= Decimal(amount)
|
self.stacks[player] -= Decimal(amount)
|
||||||
#print "DEBUG %s posts, stack %s" % (player, self.stacks[player])
|
#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):
|
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))
|
logging.debug("%s %s calls %s" %(street, player, amount))
|
||||||
# Potentially calculate the amount of the call if not supplied
|
# Potentially calculate the amount of the call if not supplied
|
||||||
# corner cases include if player would be all in
|
# 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)
|
# then: C = Bp - Bc (amount to call)
|
||||||
# Rt = Bp + Rb (raise to)
|
# Rt = Bp + Rb (raise to)
|
||||||
#
|
#
|
||||||
|
amountBy = re.sub(u',', u'', amountBy) #some sites have commas
|
||||||
self.checkPlayerExists(player)
|
self.checkPlayerExists(player)
|
||||||
Rb = Decimal(amountBy)
|
Rb = Decimal(amountBy)
|
||||||
Bp = self.lastBet[street]
|
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". """
|
For sites which by "raises x" mean "calls and raises putting a total of x in the por". """
|
||||||
self.checkPlayerExists(player)
|
self.checkPlayerExists(player)
|
||||||
|
amount = re.sub(u',', u'', amount) #some sites have commas
|
||||||
CRb = Decimal(amount)
|
CRb = Decimal(amount)
|
||||||
Bp = self.lastBet[street]
|
Bp = self.lastBet[street]
|
||||||
Bc = reduce(operator.add, self.bets[street][player], 0)
|
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
|
#CG - No idea if this function has been test/verified
|
||||||
self.checkPlayerExists(player)
|
self.checkPlayerExists(player)
|
||||||
|
amountTo = re.sub(u',', u'', amountTo) #some sites have commas
|
||||||
Bp = self.lastBet[street]
|
Bp = self.lastBet[street]
|
||||||
Bc = reduce(operator.add, self.bets[street][player], 0)
|
Bc = reduce(operator.add, self.bets[street][player], 0)
|
||||||
Rt = Decimal(amountTo)
|
Rt = Decimal(amountTo)
|
||||||
|
@ -411,6 +423,7 @@ Add a raise on [street] by [player] to [amountTo]
|
||||||
|
|
||||||
def addBet(self, street, player, amount):
|
def addBet(self, street, player, amount):
|
||||||
logging.debug("%s %s bets %s" %(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.checkPlayerExists(player)
|
||||||
self.bets[street][player].append(Decimal(amount))
|
self.bets[street][player].append(Decimal(amount))
|
||||||
self.stacks[player] -= 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':
|
elif act[1] == 'checks':
|
||||||
return ("%s: checks " %(act[0]))
|
return ("%s: checks " %(act[0]))
|
||||||
elif act[1] == 'calls':
|
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':
|
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':
|
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':
|
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':
|
elif act[1] == 'posts':
|
||||||
if(act[2] == "small blind"):
|
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"):
|
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"):
|
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':
|
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':
|
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 ''))
|
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':
|
elif act[1] == 'stands pat':
|
||||||
return ("%s: stands pat" %(act[0]))
|
return ("%s: stands pat" %(act[0]))
|
||||||
|
|
||||||
def getStakesAsString(self):
|
def getStakesAsString(self):
|
||||||
retstring = "%s%s/%s%s" % (self.SYMBOL[self.gametype['currency']], self.sb, self.SYMBOL[self.gametype['currency']], self.bb)
|
"""Return a string of the stakes of the current hand."""
|
||||||
return retstring
|
return "%s%s/%s%s" % (self.sym, self.sb, self.sym, self.bb)
|
||||||
|
|
||||||
def writeGameLine(self):
|
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')))
|
"""Return the first HH line for the current hand."""
|
||||||
game_string = "PokerStars Game #%s: " % self.handid
|
gs = "PokerStars Game #%s: " % self.handid
|
||||||
if self.tourNo != None:
|
|
||||||
game_string = game_string + "Tournament #%s, %s %s - Level %s (%s) - " % (self.tourNo,
|
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())
|
self.buyin, self.getGameTypeAsString(), self.level, self.getStakesAsString())
|
||||||
elif self.mixed != None:
|
elif self.mixed != None: # all other mixed games
|
||||||
game_string = game_string + " %s (%s, %s) - " % (self.MS[self.mixed],
|
gs = gs + " %s (%s, %s) - " % (self.MS[self.mixed],
|
||||||
self.getGameTypeAsString(), self.getStakesAsString())
|
self.getGameTypeAsString(), self.getStakesAsString())
|
||||||
else:
|
else: # non-mixed cash games
|
||||||
game_string = game_string + " %s (%s) - " % (self.getGameTypeAsString(), self.getStakesAsString())
|
gs = gs + " %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
|
return gs + datetime.datetime.strftime(self.starttime,'%Y/%m/%d %H:%M:%S ET')
|
||||||
|
|
||||||
|
|
||||||
def writeTableLine(self):
|
def writeTableLine(self):
|
||||||
table_string = "Table \'%s\' %s-max" % (self.tablename, self.maxseats)
|
table_string = "Table \'%s\' %s-max" % (self.tablename, self.maxseats)
|
||||||
if self.gametype['currency'] == 'play':
|
if self.gametype['currency'] == 'play':
|
||||||
table_string = table_string + " (Play Money)"
|
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
|
table_string = table_string + " Seat #%s is the button" % self.buttonpos
|
||||||
return table_string
|
return table_string
|
||||||
|
|
||||||
|
|
||||||
|
def writeHand(self, fh=sys.__stdout__):
|
||||||
|
# PokerStars format.
|
||||||
|
print >>fh, self.writeGameLine()
|
||||||
|
print >>fh, self.writeTableLine()
|
||||||
|
|
||||||
|
|
||||||
class HoldemOmahaHand(Hand):
|
class HoldemOmahaHand(Hand):
|
||||||
def __init__(self, hhc, sitename, gametype, handText, builtFrom = "HHC", handid=None):
|
def __init__(self, hhc, sitename, gametype, handText, builtFrom = "HHC", handid=None):
|
||||||
if gametype['base'] != 'hold':
|
if gametype['base'] != 'hold':
|
||||||
|
@ -608,6 +630,9 @@ class HoldemOmahaHand(Hand):
|
||||||
hhc.readShownCards(self)
|
hhc.readShownCards(self)
|
||||||
self.totalPot() # finalise it (total the pot)
|
self.totalPot() # finalise it (total the pot)
|
||||||
hhc.getRake(self)
|
hhc.getRake(self)
|
||||||
|
if self.maxseats == None:
|
||||||
|
self.maxseats = hhc.guessMaxSeats(self)
|
||||||
|
hhc.readOther(self)
|
||||||
elif builtFrom == "DB":
|
elif builtFrom == "DB":
|
||||||
if handid is not None:
|
if handid is not None:
|
||||||
self.select(handid) # Will need a handId
|
self.select(handid) # Will need a handId
|
||||||
|
@ -635,8 +660,8 @@ class HoldemOmahaHand(Hand):
|
||||||
def render_stack(context,data):
|
def render_stack(context,data):
|
||||||
pat = context.tag.patternGenerator('list_item')
|
pat = context.tag.patternGenerator('list_item')
|
||||||
for player in data:
|
for player in data:
|
||||||
x = "Seat %s: %s ($%s in chips) " %(player[0], player[1],
|
x = "Seat %s: %s (%s%s in chips) " %(player[0], player[1],
|
||||||
player[2])
|
self.sym, player[2])
|
||||||
context.tag[ pat().fillSlots('playerStack', x)]
|
context.tag[ pat().fillSlots('playerStack', x)]
|
||||||
return context.tag
|
return context.tag
|
||||||
|
|
||||||
|
@ -723,11 +748,7 @@ class HoldemOmahaHand(Hand):
|
||||||
|
|
||||||
def writeHand(self, fh=sys.__stdout__):
|
def writeHand(self, fh=sys.__stdout__):
|
||||||
# PokerStars format.
|
# 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')))
|
super(HoldemOmahaHand, self).writeHand(fh)
|
||||||
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))
|
|
||||||
|
|
||||||
players_who_act_preflop = set(([x[0] for x in self.actions['PREFLOP']]+[x[0] for x in self.actions['BLINDSANTES']]))
|
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'])
|
logging.debug(self.actions['PREFLOP'])
|
||||||
|
@ -793,16 +814,16 @@ class HoldemOmahaHand(Hand):
|
||||||
# Immediately before the summary.
|
# Immediately before the summary.
|
||||||
# The current importer uses those lines for importing winning rather than the summary
|
# The current importer uses those lines for importing winning rather than the summary
|
||||||
for name in self.pot.returned:
|
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:
|
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, ("*** SUMMARY ***")
|
||||||
print >>fh, "%s | Rake $%.2f" % (self.pot, self.rake)
|
print >>fh, "%s | Rake %s%.2f" % (self.pot, self.sym, self.rake)
|
||||||
|
|
||||||
board = []
|
board = []
|
||||||
for s in self.board.values():
|
for street in ["FLOP", "TURN", "RIVER"]:
|
||||||
board += s
|
board += self.board[street]
|
||||||
if board: # sometimes hand ends preflop without a board
|
if board: # sometimes hand ends preflop without a board
|
||||||
print >>fh, ("Board [%s]" % (" ".join(board)))
|
print >>fh, ("Board [%s]" % (" ".join(board)))
|
||||||
|
|
||||||
|
@ -810,9 +831,9 @@ class HoldemOmahaHand(Hand):
|
||||||
seatnum = player[0]
|
seatnum = player[0]
|
||||||
name = player[1]
|
name = player[1]
|
||||||
if name in self.collectees and name in self.shown:
|
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:
|
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:
|
#~ elif name in self.shown:
|
||||||
#~ print >>fh, _("Seat %d: %s showed [%s]" % (seatnum, name, " ".join(self.holecards[name]['PREFLOP'])))
|
#~ print >>fh, _("Seat %d: %s showed [%s]" % (seatnum, name, " ".join(self.holecards[name]['PREFLOP'])))
|
||||||
elif name in self.folded:
|
elif name in self.folded:
|
||||||
|
@ -852,13 +873,14 @@ class DrawHand(Hand):
|
||||||
# Read actions in street order
|
# Read actions in street order
|
||||||
for street in self.streetList:
|
for street in self.streetList:
|
||||||
if self.streets[street]:
|
if self.streets[street]:
|
||||||
# hhc.readCommunityCards(self, street)
|
|
||||||
# hhc.readDrawCards(self, street)
|
|
||||||
hhc.readAction(self, street)
|
hhc.readAction(self, street)
|
||||||
hhc.readCollectPot(self)
|
hhc.readCollectPot(self)
|
||||||
hhc.readShownCards(self)
|
hhc.readShownCards(self)
|
||||||
self.totalPot() # finalise it (total the pot)
|
self.totalPot() # finalise it (total the pot)
|
||||||
hhc.getRake(self)
|
hhc.getRake(self)
|
||||||
|
if self.maxseats == None:
|
||||||
|
self.maxseats = hhc.guessMaxSeats(self)
|
||||||
|
hhc.readOther(self)
|
||||||
elif builtFrom == "DB":
|
elif builtFrom == "DB":
|
||||||
self.select("dummy") # Will need a handId
|
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)
|
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):
|
def discardDrawHoleCards(self, cards, player, street):
|
||||||
logging.debug("discardDrawHoleCards '%s' '%s' '%s'" % (cards, player, street))
|
logging.debug("discardDrawHoleCards '%s' '%s' '%s'" % (cards, player, street))
|
||||||
self.discards[street][player] = set([cards])
|
self.discards[street][player] = set([cards])
|
||||||
|
@ -928,64 +935,19 @@ class DrawHand(Hand):
|
||||||
self.actions[street].append(act)
|
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__):
|
def writeHand(self, fh=sys.__stdout__):
|
||||||
# PokerStars format.
|
# 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)))
|
super(DrawHand, self).writeHand(fh)
|
||||||
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()
|
|
||||||
|
|
||||||
players_who_act_ondeal = set(([x[0] for x in self.actions['DEAL']]+[x[0] for x in self.actions['BLINDSANTES']]))
|
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]:
|
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
|
#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:
|
if 'BLINDSANTES' in self.actions:
|
||||||
for act in self.actions['BLINDSANTES']:
|
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:
|
if 'DEAL' in self.actions:
|
||||||
print >>fh, _("*** DEALING HANDS ***")
|
print >>fh, _("*** DEALING HANDS ***")
|
||||||
|
@ -1038,12 +1000,12 @@ class DrawHand(Hand):
|
||||||
# Immediately before the summary.
|
# Immediately before the summary.
|
||||||
# The current importer uses those lines for importing winning rather than the summary
|
# The current importer uses those lines for importing winning rather than the summary
|
||||||
for name in self.pot.returned:
|
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:
|
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, _("*** 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"
|
print >>fh, "\n\n"
|
||||||
|
|
||||||
|
|
||||||
|
@ -1058,7 +1020,7 @@ class StudHand(Hand):
|
||||||
self.actionStreets = ['ANTES','THIRD','FOURTH','FIFTH','SIXTH','SEVENTH']
|
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.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)
|
Hand.__init__(self, sitename, gametype, handText)
|
||||||
self.sb = gametype['sb']
|
self.sb = gametype['sb']
|
||||||
self.bb = gametype['bb']
|
self.bb = gametype['bb']
|
||||||
|
@ -1073,18 +1035,20 @@ class StudHand(Hand):
|
||||||
hhc.readAntes(self)
|
hhc.readAntes(self)
|
||||||
hhc.readBringIn(self)
|
hhc.readBringIn(self)
|
||||||
hhc.readHeroCards(self)
|
hhc.readHeroCards(self)
|
||||||
#hhc.readShowdownActions(self) # not done yet
|
|
||||||
# Read actions in street order
|
# 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]:
|
if self.streets[street]:
|
||||||
logging.debug(street)
|
logging.debug(street)
|
||||||
logging.debug(self.streets[street])
|
logging.debug(self.streets[street])
|
||||||
# hhc.readStudPlayerCards(self, street)
|
|
||||||
hhc.readAction(self, street)
|
hhc.readAction(self, street)
|
||||||
hhc.readCollectPot(self)
|
hhc.readCollectPot(self)
|
||||||
hhc.readShownCards(self) # not done yet
|
hhc.readShownCards(self) # not done yet
|
||||||
self.totalPot() # finalise it (total the pot)
|
self.totalPot() # finalise it (total the pot)
|
||||||
hhc.getRake(self)
|
hhc.getRake(self)
|
||||||
|
if self.maxseats == None:
|
||||||
|
self.maxseats = hhc.guessMaxSeats(self)
|
||||||
|
hhc.readOther(self)
|
||||||
elif builtFrom == "DB":
|
elif builtFrom == "DB":
|
||||||
self.select("dummy") # Will need a handId
|
self.select("dummy") # Will need a handId
|
||||||
|
|
||||||
|
@ -1093,11 +1057,10 @@ class StudHand(Hand):
|
||||||
if shown: self.shown.add(player)
|
if shown: self.shown.add(player)
|
||||||
if mucked: self.mucked.add(player)
|
if mucked: self.mucked.add(player)
|
||||||
else:
|
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('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('FOURTH', player, open=[cards[3]], closed=[cards[2]], shown=shown, mucked=mucked)
|
||||||
self.addHoleCards('FIFTH', player, open=[cards[4]], closed=[], 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=[], 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)
|
self.addHoleCards('SEVENTH', player, open=[], closed=[cards[6]], shown=shown, mucked=mucked)
|
||||||
|
|
||||||
|
|
||||||
|
@ -1113,46 +1076,9 @@ closed likewise, but known only to player
|
||||||
try:
|
try:
|
||||||
self.checkPlayerExists(player)
|
self.checkPlayerExists(player)
|
||||||
self.holecards[street][player] = (open, closed)
|
self.holecards[street][player] = (open, closed)
|
||||||
# cards = set([self.card(c) for c in cards])
|
|
||||||
# self.holecards[player].update(cards)
|
|
||||||
except FpdbParseError, e:
|
except FpdbParseError, e:
|
||||||
print "[ERROR] Tried to add holecards for unknown player: %s" % (player,)
|
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):
|
# TODO: def addComplete(self, player, amount):
|
||||||
def addComplete(self, street, player, amountTo):
|
def addComplete(self, street, player, amountTo):
|
||||||
# assert street=='THIRD'
|
# assert street=='THIRD'
|
||||||
|
@ -1161,6 +1087,7 @@ closed likewise, but known only to player
|
||||||
Add a complete on [street] by [player] to [amountTo]
|
Add a complete on [street] by [player] to [amountTo]
|
||||||
"""
|
"""
|
||||||
logging.debug("%s %s completes %s" % (street, player, amountTo))
|
logging.debug("%s %s completes %s" % (street, player, amountTo))
|
||||||
|
amountTo = re.sub(u',', u'', amountTo) #some sites have commas
|
||||||
self.checkPlayerExists(player)
|
self.checkPlayerExists(player)
|
||||||
Bp = self.lastBet['THIRD']
|
Bp = self.lastBet['THIRD']
|
||||||
Bc = reduce(operator.add, self.bets[street][player], 0)
|
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__):
|
def writeHand(self, fh=sys.__stdout__):
|
||||||
# PokerStars format.
|
# 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:
|
super(StudHand, self).writeHand(fh)
|
||||||
# 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))
|
|
||||||
|
|
||||||
players_who_post_antes = set([x[0] for x in self.actions['ANTES']])
|
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]:
|
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
|
#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:
|
if 'ANTES' in self.actions:
|
||||||
for act in self.actions['ANTES']:
|
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:
|
if 'THIRD' in self.actions:
|
||||||
dealt = 0
|
dealt = 0
|
||||||
|
@ -1218,7 +1137,8 @@ Add a complete on [street] by [player] to [amountTo]
|
||||||
dealt+=1
|
dealt+=1
|
||||||
if dealt==1:
|
if dealt==1:
|
||||||
print >>fh, _("*** 3RD STREET ***")
|
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']:
|
for act in self.actions['THIRD']:
|
||||||
#FIXME: Need some logic here for bringin vs completes
|
#FIXME: Need some logic here for bringin vs completes
|
||||||
print >>fh, self.actionString(act)
|
print >>fh, self.actionString(act)
|
||||||
|
@ -1228,15 +1148,10 @@ Add a complete on [street] by [player] to [amountTo]
|
||||||
#~ print >>fh, _("*** 4TH STREET ***")
|
#~ print >>fh, _("*** 4TH STREET ***")
|
||||||
for player in [x[1] for x in self.players if x[1] in players_who_post_antes]:
|
for player in [x[1] for x in self.players if x[1] in players_who_post_antes]:
|
||||||
if player in self.holecards['FOURTH']:
|
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
|
dealt+=1
|
||||||
if dealt==1:
|
if dealt==1:
|
||||||
print >>fh, _("*** 4TH STREET ***")
|
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']:
|
for act in self.actions['FOURTH']:
|
||||||
print >>fh, self.actionString(act)
|
print >>fh, self.actionString(act)
|
||||||
|
|
||||||
|
@ -1245,16 +1160,10 @@ Add a complete on [street] by [player] to [amountTo]
|
||||||
#~ print >>fh, _("*** 5TH STREET ***")
|
#~ print >>fh, _("*** 5TH STREET ***")
|
||||||
for player in [x[1] for x in self.players if x[1] in players_who_post_antes]:
|
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):
|
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
|
dealt+=1
|
||||||
if dealt==1:
|
if dealt==1:
|
||||||
print >>fh, _("*** 5TH STREET ***")
|
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']:
|
for act in self.actions['FIFTH']:
|
||||||
print >>fh, self.actionString(act)
|
print >>fh, self.actionString(act)
|
||||||
|
|
||||||
|
@ -1263,16 +1172,10 @@ Add a complete on [street] by [player] to [amountTo]
|
||||||
#~ print >>fh, _("*** 6TH STREET ***")
|
#~ print >>fh, _("*** 6TH STREET ***")
|
||||||
for player in [x[1] for x in self.players if x[1] in players_who_post_antes]:
|
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):
|
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
|
dealt += 1
|
||||||
if dealt == 1:
|
if dealt == 1:
|
||||||
print >>fh, _("*** 6TH STREET ***")
|
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']:
|
for act in self.actions['SIXTH']:
|
||||||
print >>fh, self.actionString(act)
|
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.
|
# 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
|
# 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.
|
# 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]:
|
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):
|
if self.holecards['SEVENTH'].has_key(player):
|
||||||
old = []
|
if self.writeHoleCards('SEVENTH', player):
|
||||||
for street in ('THIRD','FOURTH','FIFTH','SIXTH'):
|
print >>fh, self.writeHoleCards('SEVENTH', player)
|
||||||
(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 "")
|
|
||||||
for act in self.actions['SEVENTH']:
|
for act in self.actions['SEVENTH']:
|
||||||
print >>fh, self.actionString(act)
|
print >>fh, self.actionString(act)
|
||||||
|
|
||||||
|
@ -1310,13 +1207,13 @@ Add a complete on [street] by [player] to [amountTo]
|
||||||
# Immediately before the summary.
|
# Immediately before the summary.
|
||||||
# The current importer uses those lines for importing winning rather than the summary
|
# The current importer uses those lines for importing winning rather than the summary
|
||||||
for name in self.pot.returned:
|
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:
|
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, _("*** SUMMARY ***")
|
||||||
print >>fh, "%s | Rake $%.2f" % (self.pot, self.rake)
|
print >>fh, "%s | Rake %s%.2f" % (self.pot, self.sym, self.rake)
|
||||||
#print >>fh, _("Total pot $%s | Rake $%.2f" % (self.totalpot, self.rake)) # TODO: side pots
|
# TODO: side pots
|
||||||
|
|
||||||
board = []
|
board = []
|
||||||
for s in self.board.values():
|
for s in self.board.values():
|
||||||
|
@ -1328,9 +1225,9 @@ Add a complete on [street] by [player] to [amountTo]
|
||||||
seatnum = player[0]
|
seatnum = player[0]
|
||||||
name = player[1]
|
name = player[1]
|
||||||
if name in self.collectees and name in self.shown:
|
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:
|
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:
|
elif name in self.shown:
|
||||||
print >>fh, _("Seat %d: %s showed [%s]" % (seatnum, name, self.join_holecards(name)))
|
print >>fh, _("Seat %d: %s showed [%s]" % (seatnum, name, self.join_holecards(name)))
|
||||||
elif name in self.mucked:
|
elif name in self.mucked:
|
||||||
|
@ -1343,10 +1240,29 @@ Add a complete on [street] by [player] to [amountTo]
|
||||||
print >>fh, "\n\n"
|
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):
|
def join_holecards(self, player):
|
||||||
holecards = []
|
holecards = []
|
||||||
for street in self.holeStreets:
|
for street in self.holeStreets:
|
||||||
if self.holecards[street].has_key(player):
|
if self.holecards[street].has_key(player):
|
||||||
|
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]
|
holecards = holecards + self.holecards[street][player][0]
|
||||||
return " ".join(holecards)
|
return " ".join(holecards)
|
||||||
|
|
||||||
|
@ -1358,6 +1274,10 @@ class Pot(object):
|
||||||
self.committed = {}
|
self.committed = {}
|
||||||
self.total = None
|
self.total = None
|
||||||
self.returned = {}
|
self.returned = {}
|
||||||
|
self.sym = u'$' # this is the default currency symbol
|
||||||
|
|
||||||
|
def setSym(self, sym):
|
||||||
|
self.sym = sym
|
||||||
|
|
||||||
def addPlayer(self,player):
|
def addPlayer(self,player):
|
||||||
self.committed[player] = Decimal(0)
|
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
|
# Total pot $124.30 Main pot $98.90. Side pot $23.40. | Rake $2
|
||||||
|
|
||||||
def __str__(self):
|
def __str__(self):
|
||||||
|
if self.sym is None:
|
||||||
|
self.sym = "C"
|
||||||
if self.total is None:
|
if self.total is None:
|
||||||
print "call Pot.end() before printing pot total"
|
print "call Pot.end() before printing pot total"
|
||||||
# NB if I'm sure end() is idempotent, call it here.
|
# NB if I'm sure end() is idempotent, call it here.
|
||||||
raise FpdbParseError
|
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])
|
||||||
|
|
||||||
|
return ret + ''.join([ (" Side pot %s%.2f." % (self.sym, self.pots[x]) ) for x in xrange(1, len(self.pots)) ])
|
||||||
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
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
def assemble(cnxn, handid):
|
def assemble(cnxn, handid):
|
||||||
c = cnxn.cursor()
|
c = cnxn.cursor()
|
||||||
|
|
|
@ -28,91 +28,54 @@ import codecs
|
||||||
from decimal import Decimal
|
from decimal import Decimal
|
||||||
import operator
|
import operator
|
||||||
from xml.dom.minidom import Node
|
from xml.dom.minidom import Node
|
||||||
# from pokereval import PokerEval
|
|
||||||
import time
|
import time
|
||||||
import datetime
|
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
|
import gettext
|
||||||
gettext.install('myapplication')
|
gettext.install('fpdb')
|
||||||
|
|
||||||
class HandHistoryConverter():
|
class HandHistoryConverter():
|
||||||
|
|
||||||
READ_CHUNK_SIZE = 10000 # bytes to read at a time from file (in tail mode)
|
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):
|
def __init__(self, in_path = '-', out_path = '-', sitename = None, follow=False, index=0):
|
||||||
logging.info("HandHistory init called")
|
logging.info("HandHistory init")
|
||||||
|
|
||||||
# default filetype and codepage. Subclasses should set these properly.
|
# default filetype and codepage. Subclasses should set these properly.
|
||||||
self.filetype = "text"
|
self.filetype = "text"
|
||||||
self.codepage = "utf8"
|
self.codepage = "utf8"
|
||||||
|
self.index = 0
|
||||||
|
|
||||||
self.in_path = in_path
|
self.in_path = in_path
|
||||||
self.out_path = out_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
|
self.out_fh = sys.stdout
|
||||||
else:
|
else:
|
||||||
# TODO: out_path should be sanity checked before opening. Perhaps in fpdb_import?
|
# TODO: out_path should be sanity checked.
|
||||||
# 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')
|
||||||
self.out_fh = open(self.out_path, 'w') # doomswitch is now on :|
|
|
||||||
self.sitename = sitename
|
self.sitename = sitename
|
||||||
self.follow = follow
|
self.follow = follow
|
||||||
self.compiledPlayers = set()
|
self.compiledPlayers = set()
|
||||||
self.maxseats = 10
|
self.maxseats = 10
|
||||||
|
|
||||||
def __str__(self):
|
def __str__(self):
|
||||||
#TODO : I got rid of most of the hhdir stuff.
|
return """
|
||||||
tmp = "HandHistoryConverter: '%s'\n" % (self.sitename)
|
HandHistoryConverter: '%(sitename)s'
|
||||||
#tmp = tmp + "\thhbase: '%s'\n" % (self.hhbase)
|
filetype: '%(filetype)s'
|
||||||
#tmp = tmp + "\thhdir: '%s'\n" % (self.hhdir)
|
in_path: '%(in_path)s'
|
||||||
tmp = tmp + "\tfiletype: '%s'\n" % (self.filetype)
|
out_path: '%(out_path)s'
|
||||||
tmp = tmp + "\tinfile: '%s'\n" % (self.in_path)
|
""" % { 'sitename':self.sitename, 'filetype':self.filetype, 'in_path':self.in_path, 'out_path':self.out_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
|
|
||||||
|
|
||||||
def start(self):
|
def start(self):
|
||||||
"""process a hand at a time from the input specified by in_path.
|
"""process a hand at a time from the input specified by in_path.
|
||||||
If in follow mode, wait for more data to turn up.
|
If in follow mode, wait for more data to turn up.
|
||||||
Otherwise, finish at eof...
|
Otherwise, finish at eof.
|
||||||
|
|
||||||
"""
|
"""
|
||||||
starttime = time.time()
|
starttime = time.time()
|
||||||
|
@ -129,7 +92,7 @@ Otherwise, finish at eof...
|
||||||
handsList = self.allHandsAsList()
|
handsList = self.allHandsAsList()
|
||||||
logging.info("Parsing %d hands" % len(handsList))
|
logging.info("Parsing %d hands" % len(handsList))
|
||||||
for handText in handsList:
|
for handText in handsList:
|
||||||
self.processHand(handText)
|
self.processedHands.append(self.processHand(handText))
|
||||||
numHands= len(handsList)
|
numHands= len(handsList)
|
||||||
endtime = time.time()
|
endtime = time.time()
|
||||||
print "read %d hands in %.3f seconds" % (numHands, endtime - starttime)
|
print "read %d hands in %.3f seconds" % (numHands, endtime - starttime)
|
||||||
|
@ -213,6 +176,7 @@ which it expects to find at self.re_TailSplitHands -- see for e.g. Everleaf.py.
|
||||||
def processHand(self, handText):
|
def processHand(self, handText):
|
||||||
gametype = self.determineGameType(handText)
|
gametype = self.determineGameType(handText)
|
||||||
logging.debug("gametype %s" % gametype)
|
logging.debug("gametype %s" % gametype)
|
||||||
|
hand = None
|
||||||
if gametype is None:
|
if gametype is None:
|
||||||
l = None
|
l = None
|
||||||
gametype = "unmatched"
|
gametype = "unmatched"
|
||||||
|
@ -224,9 +188,7 @@ which it expects to find at self.re_TailSplitHands -- see for e.g. Everleaf.py.
|
||||||
base = gametype['base']
|
base = gametype['base']
|
||||||
limit = gametype['limitType']
|
limit = gametype['limitType']
|
||||||
l = [type] + [base] + [limit]
|
l = [type] + [base] + [limit]
|
||||||
hand = None
|
|
||||||
if l in self.readSupportedGames():
|
if l in self.readSupportedGames():
|
||||||
hand = None
|
|
||||||
if gametype['base'] == 'hold':
|
if gametype['base'] == 'hold':
|
||||||
logging.debug("hand = Hand.HoldemOmahaHand(self, self.sitename, gametype, handtext)")
|
logging.debug("hand = Hand.HoldemOmahaHand(self, self.sitename, gametype, handtext)")
|
||||||
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:
|
if hand:
|
||||||
# print hand
|
# print hand
|
||||||
hand.writeHand(self.out_fh)
|
hand.writeHand(self.out_fh)
|
||||||
|
return hand
|
||||||
else:
|
else:
|
||||||
logging.info("Unsupported game type: %s" % gametype)
|
logging.info("Unsupported game type: %s" % gametype)
|
||||||
# TODO: pity we don't know the HID at this stage. Log the entire hand?
|
# TODO: pity we don't know the HID at this stage. Log the entire hand?
|
||||||
|
@ -307,6 +270,11 @@ or None if we fail to get the info """
|
||||||
def readCollectPot(self, hand): abstract
|
def readCollectPot(self, hand): abstract
|
||||||
def readShownCards(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
|
# 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.
|
# an inheriting class can calculate it for the specific site if need be.
|
||||||
def getRake(self, hand):
|
def getRake(self, hand):
|
||||||
|
@ -350,6 +318,7 @@ or None if we fail to get the info """
|
||||||
self.filetype = filetype
|
self.filetype = filetype
|
||||||
self.codepage = codepage
|
self.codepage = codepage
|
||||||
|
|
||||||
|
#This function doesn't appear to be used
|
||||||
def splitFileIntoHands(self):
|
def splitFileIntoHands(self):
|
||||||
hands = []
|
hands = []
|
||||||
self.obs = self.obs.strip()
|
self.obs = self.obs.strip()
|
||||||
|
@ -371,7 +340,9 @@ or None if we fail to get the info """
|
||||||
else:
|
else:
|
||||||
logging.debug("Opening %s with %s" % (self.in_path, self.codepage))
|
logging.debug("Opening %s with %s" % (self.in_path, self.codepage))
|
||||||
in_fh = codecs.open(self.in_path, 'r', self.codepage)
|
in_fh = codecs.open(self.in_path, 'r', self.codepage)
|
||||||
|
in_fh.seek(self.index)
|
||||||
self.obs = in_fh.read()
|
self.obs = in_fh.read()
|
||||||
|
self.index = in_fh.tell()
|
||||||
in_fh.close()
|
in_fh.close()
|
||||||
elif(self.filetype == "xml"):
|
elif(self.filetype == "xml"):
|
||||||
try:
|
try:
|
||||||
|
@ -380,10 +351,39 @@ or None if we fail to get the info """
|
||||||
except:
|
except:
|
||||||
traceback.print_exc(file=sys.stderr)
|
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):
|
def getStatus(self):
|
||||||
#TODO: Return a status of true if file processed ok
|
#TODO: Return a status of true if file processed ok
|
||||||
return True
|
return True
|
||||||
|
|
||||||
|
def getProcessedHands(self):
|
||||||
|
return self.processedHands
|
||||||
|
|
||||||
def getProcessedFile(self):
|
def getProcessedFile(self):
|
||||||
return self.out_path
|
return self.out_path
|
||||||
|
|
||||||
|
def getLastCharacterRead(self):
|
||||||
|
return self.index
|
||||||
|
|
|
@ -235,12 +235,8 @@ class Hud:
|
||||||
# does the user have a fav_seat?
|
# does the user have a fav_seat?
|
||||||
if int(config.supported_sites[self.table.site].layout[self.max].fav_seat) > 0:
|
if int(config.supported_sites[self.table.site].layout[self.max].fav_seat) > 0:
|
||||||
try:
|
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
|
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)
|
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):
|
for i in xrange(0, self.max + 1):
|
||||||
j = actual_seat + i
|
j = actual_seat + i
|
||||||
if j > self.max:
|
if j > self.max:
|
||||||
|
@ -273,7 +269,6 @@ class Hud:
|
||||||
self.cards = cards
|
self.cards = cards
|
||||||
sys.stderr.write("------------------------------------------------------------\nCreating hud from hand %s\n" % hand)
|
sys.stderr.write("------------------------------------------------------------\nCreating hud from hand %s\n" % hand)
|
||||||
adj = self.adj_seats(hand, config)
|
adj = self.adj_seats(hand, config)
|
||||||
sys.stderr.write("adj = %s\n" % adj)
|
|
||||||
loc = self.config.get_locations(self.table.site, self.max)
|
loc = self.config.get_locations(self.table.site, self.max)
|
||||||
|
|
||||||
# create the stat windows
|
# create the stat windows
|
||||||
|
@ -282,7 +277,6 @@ class Hud:
|
||||||
if i in self.stat_windows:
|
if i in self.stat_windows:
|
||||||
self.stat_windows[i].relocate(x, y)
|
self.stat_windows[i].relocate(x, y)
|
||||||
else:
|
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],
|
self.stat_windows[i] = Stat_Window(game = config.supported_games[self.poker_game],
|
||||||
parent = self,
|
parent = self,
|
||||||
table = self.table,
|
table = self.table,
|
||||||
|
|
|
@ -294,6 +294,7 @@ class Stud_cards:
|
||||||
def update_gui(self, new_hand_id):
|
def update_gui(self, new_hand_id):
|
||||||
self.clear()
|
self.clear()
|
||||||
for c, cards in self.parent.hud.cards.iteritems():
|
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))
|
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]),
|
for i in ((0, cards[0]), (1, cards[1]), (2, cards[2]), (3, cards[3]),
|
||||||
(4, cards[4]), (5, cards[5]), (6, cards[6])):
|
(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':
|
if n_cards > 0 and i != 'common':
|
||||||
n_sd = n_sd + 1
|
n_sd = n_sd + 1
|
||||||
if n_sd < 2:
|
if n_sd < 2:
|
||||||
print "skipping, n_sd =", n_sd
|
|
||||||
return
|
return
|
||||||
|
|
||||||
super(Flop_Mucked, self).update_gui(new_hand_id)
|
super(Flop_Mucked, self).update_gui(new_hand_id)
|
||||||
|
|
|
@ -55,12 +55,12 @@ class PokerStars(HandHistoryConverter):
|
||||||
|
|
||||||
mixes = { 'HORSE': 'horse', '8-Game': '8game', 'HOSE': 'hose'}
|
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)
|
in_path (default '-' = sys.stdin)
|
||||||
out_path (default '-' = sys.stdout)
|
out_path (default '-' = sys.stdout)
|
||||||
follow : whether to tail -f the input"""
|
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")
|
logging.info("Initialising PokerStars converter class")
|
||||||
self.filetype = "text"
|
self.filetype = "text"
|
||||||
self.codepage = "cp1252"
|
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)
|
hand.addHoleCards(street, hand.hero, closed=newcards, shown=False, mucked=False, dealt=True)
|
||||||
|
|
||||||
for street, text in hand.streets.iteritems():
|
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])
|
m = self.re_HeroCards.finditer(hand.streets[street])
|
||||||
for found in m:
|
for found in m:
|
||||||
player = found.group('PNAME')
|
player = found.group('PNAME')
|
||||||
|
@ -398,7 +398,7 @@ follow : whether to tail -f the input"""
|
||||||
|
|
||||||
|
|
||||||
def readShowdownActions(self, hand):
|
def readShowdownActions(self, hand):
|
||||||
# TODO: pick up mucks also
|
# TODO: pick up mucks also??
|
||||||
for shows in self.re_ShowdownAction.finditer(hand.handText):
|
for shows in self.re_ShowdownAction.finditer(hand.handText):
|
||||||
cards = shows.group('CARDS').split(' ')
|
cards = shows.group('CARDS').split(' ')
|
||||||
hand.addShownCards(cards, shows.group('PNAME'))
|
hand.addShownCards(cards, shows.group('PNAME'))
|
||||||
|
@ -421,7 +421,7 @@ follow : whether to tail -f the input"""
|
||||||
|
|
||||||
if __name__ == "__main__":
|
if __name__ == "__main__":
|
||||||
parser = OptionParser()
|
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("-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("-f", "--follow", dest="follow", help="follow (tail -f) the input", action="store_true", default=False)
|
||||||
parser.add_option("-q", "--quiet",
|
parser.add_option("-q", "--quiet",
|
||||||
|
|
1842
pyfpdb/SQL.py
1842
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:
|
# 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)
|
# 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
|
# 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
|
# those raw stats to get stats to present to the HUD. If you need more
|
||||||
|
@ -50,16 +52,34 @@
|
||||||
# pyGTK modules
|
# pyGTK modules
|
||||||
import pygtk
|
import pygtk
|
||||||
import gtk
|
import gtk
|
||||||
|
import re
|
||||||
|
|
||||||
# FreePokerTools modules
|
# FreePokerTools modules
|
||||||
import Configuration
|
import Configuration
|
||||||
import Database
|
import Database
|
||||||
|
|
||||||
|
|
||||||
|
re_Places = re.compile("_[0-9]$")
|
||||||
|
re_Percent = re.compile("%$")
|
||||||
|
|
||||||
|
|
||||||
def do_tip(widget, tip):
|
def do_tip(widget, tip):
|
||||||
widget.set_tooltip_text(tip)
|
widget.set_tooltip_text(tip)
|
||||||
|
|
||||||
def do_stat(stat_dict, player = 24, stat = 'vpip'):
|
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:
|
# OK, for reference the tuple returned by the stat is:
|
||||||
# 0 - The stat, raw, no formating, eg 0.33333333
|
# 0 - The stat, raw, no formating, eg 0.33333333
|
||||||
|
@ -108,26 +128,6 @@ def vpip(stat_dict, player):
|
||||||
'Voluntarily Put In Pot %'
|
'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):
|
def pfr(stat_dict, player):
|
||||||
""" Preflop (3rd street) raise."""
|
""" Preflop (3rd street) raise."""
|
||||||
stat = 0.0
|
stat = 0.0
|
||||||
|
@ -149,27 +149,6 @@ def pfr(stat_dict, player):
|
||||||
'Pre-Flop Raise %'
|
'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):
|
def wtsd(stat_dict, player):
|
||||||
""" Went to SD when saw flop/4th."""
|
""" Went to SD when saw flop/4th."""
|
||||||
stat = 0.0
|
stat = 0.0
|
||||||
|
@ -191,27 +170,6 @@ def wtsd(stat_dict, player):
|
||||||
'% went to showdown'
|
'% 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):
|
def wmsd(stat_dict, player):
|
||||||
""" Won $ at showdown."""
|
""" Won $ at showdown."""
|
||||||
stat = 0.0
|
stat = 0.0
|
||||||
|
@ -233,28 +191,7 @@ def wmsd(stat_dict, player):
|
||||||
'% won money at showdown'
|
'% won money at showdown'
|
||||||
)
|
)
|
||||||
|
|
||||||
def wmsd_0(stat_dict, player):
|
def profit100(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):
|
|
||||||
""" Profit won per 100 hands (no decimal places)."""
|
""" Profit won per 100 hands (no decimal places)."""
|
||||||
stat = 0.0
|
stat = 0.0
|
||||||
try:
|
try:
|
||||||
|
@ -356,27 +293,6 @@ def steal(stat_dict, player):
|
||||||
except:
|
except:
|
||||||
return (stat, 'NA', 'st=NA', 'steal=NA', '(0/0)', '% steal attempted')
|
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):
|
def f_SB_steal(stat_dict, player):
|
||||||
""" Folded SB to steal."""
|
""" Folded SB to steal."""
|
||||||
stat = 0.0
|
stat = 0.0
|
||||||
|
@ -417,27 +333,7 @@ def f_BB_steal(stat_dict, player):
|
||||||
'(0/0)',
|
'(0/0)',
|
||||||
'% folded BB to steal')
|
'% folded BB to steal')
|
||||||
|
|
||||||
def f_BB_steal_0(stat_dict, player):
|
def three_B(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):
|
|
||||||
""" Three bet preflop/3rd."""
|
""" Three bet preflop/3rd."""
|
||||||
stat = 0.0
|
stat = 0.0
|
||||||
try:
|
try:
|
||||||
|
@ -479,7 +375,7 @@ def WMsF(stat_dict, player):
|
||||||
'% won$/saw flop/4th'
|
'% won$/saw flop/4th'
|
||||||
)
|
)
|
||||||
|
|
||||||
def a_freq_1(stat_dict, player):
|
def a_freq1(stat_dict, player):
|
||||||
""" Flop/4th aggression frequency."""
|
""" Flop/4th aggression frequency."""
|
||||||
stat = 0.0
|
stat = 0.0
|
||||||
try:
|
try:
|
||||||
|
@ -500,7 +396,7 @@ def a_freq_1(stat_dict, player):
|
||||||
'Aggression Freq flop/4th'
|
'Aggression Freq flop/4th'
|
||||||
)
|
)
|
||||||
|
|
||||||
def a_freq_2(stat_dict, player):
|
def a_freq2(stat_dict, player):
|
||||||
""" Turn/5th aggression frequency."""
|
""" Turn/5th aggression frequency."""
|
||||||
stat = 0.0
|
stat = 0.0
|
||||||
try:
|
try:
|
||||||
|
@ -521,7 +417,7 @@ def a_freq_2(stat_dict, player):
|
||||||
'Aggression Freq turn/5th'
|
'Aggression Freq turn/5th'
|
||||||
)
|
)
|
||||||
|
|
||||||
def a_freq_3(stat_dict, player):
|
def a_freq3(stat_dict, player):
|
||||||
""" River/6th aggression frequency."""
|
""" River/6th aggression frequency."""
|
||||||
stat = 0.0
|
stat = 0.0
|
||||||
try:
|
try:
|
||||||
|
@ -542,7 +438,7 @@ def a_freq_3(stat_dict, player):
|
||||||
'Aggression Freq river/6th'
|
'Aggression Freq river/6th'
|
||||||
)
|
)
|
||||||
|
|
||||||
def a_freq_4(stat_dict, player):
|
def a_freq4(stat_dict, player):
|
||||||
""" 7th street aggression frequency."""
|
""" 7th street aggression frequency."""
|
||||||
stat = 0.0
|
stat = 0.0
|
||||||
try:
|
try:
|
||||||
|
@ -591,34 +487,7 @@ def a_freq_123(stat_dict, player):
|
||||||
'Post-Flop Aggression Freq'
|
'Post-Flop Aggression Freq'
|
||||||
)
|
)
|
||||||
|
|
||||||
def a_freq_123_0(stat_dict, player):
|
def cb1(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):
|
|
||||||
""" Flop continuation bet."""
|
""" Flop continuation bet."""
|
||||||
stat = 0.0
|
stat = 0.0
|
||||||
try:
|
try:
|
||||||
|
@ -639,7 +508,7 @@ def cb_1(stat_dict, player):
|
||||||
'% continuation bet flop/4th'
|
'% continuation bet flop/4th'
|
||||||
)
|
)
|
||||||
|
|
||||||
def cb_2(stat_dict, player):
|
def cb2(stat_dict, player):
|
||||||
""" Turn continuation bet."""
|
""" Turn continuation bet."""
|
||||||
stat = 0.0
|
stat = 0.0
|
||||||
try:
|
try:
|
||||||
|
@ -660,7 +529,7 @@ def cb_2(stat_dict, player):
|
||||||
'% continuation bet turn/5th'
|
'% continuation bet turn/5th'
|
||||||
)
|
)
|
||||||
|
|
||||||
def cb_3(stat_dict, player):
|
def cb3(stat_dict, player):
|
||||||
""" River continuation bet."""
|
""" River continuation bet."""
|
||||||
stat = 0.0
|
stat = 0.0
|
||||||
try:
|
try:
|
||||||
|
@ -681,7 +550,7 @@ def cb_3(stat_dict, player):
|
||||||
'% continuation bet river/6th'
|
'% continuation bet river/6th'
|
||||||
)
|
)
|
||||||
|
|
||||||
def cb_4(stat_dict, player):
|
def cb4(stat_dict, player):
|
||||||
""" 7th street continuation bet."""
|
""" 7th street continuation bet."""
|
||||||
stat = 0.0
|
stat = 0.0
|
||||||
try:
|
try:
|
||||||
|
@ -702,7 +571,7 @@ def cb_4(stat_dict, player):
|
||||||
'% continuation bet 7th'
|
'% continuation bet 7th'
|
||||||
)
|
)
|
||||||
|
|
||||||
def ffreq_1(stat_dict, player):
|
def ffreq1(stat_dict, player):
|
||||||
""" Flop/4th fold frequency."""
|
""" Flop/4th fold frequency."""
|
||||||
stat = 0.0
|
stat = 0.0
|
||||||
try:
|
try:
|
||||||
|
@ -723,7 +592,7 @@ def ffreq_1(stat_dict, player):
|
||||||
'% fold frequency flop/4th'
|
'% fold frequency flop/4th'
|
||||||
)
|
)
|
||||||
|
|
||||||
def ffreq_2(stat_dict, player):
|
def ffreq2(stat_dict, player):
|
||||||
""" Turn/5th fold frequency."""
|
""" Turn/5th fold frequency."""
|
||||||
stat = 0.0
|
stat = 0.0
|
||||||
try:
|
try:
|
||||||
|
@ -744,7 +613,7 @@ def ffreq_2(stat_dict, player):
|
||||||
'% fold frequency turn/5th'
|
'% fold frequency turn/5th'
|
||||||
)
|
)
|
||||||
|
|
||||||
def ffreq_3(stat_dict, player):
|
def ffreq3(stat_dict, player):
|
||||||
""" River/6th fold frequency."""
|
""" River/6th fold frequency."""
|
||||||
stat = 0.0
|
stat = 0.0
|
||||||
try:
|
try:
|
||||||
|
@ -765,7 +634,7 @@ def ffreq_3(stat_dict, player):
|
||||||
'% fold frequency river/6th'
|
'% fold frequency river/6th'
|
||||||
)
|
)
|
||||||
|
|
||||||
def ffreq_4(stat_dict, player):
|
def ffreq4(stat_dict, player):
|
||||||
""" 7th fold frequency."""
|
""" 7th fold frequency."""
|
||||||
stat = 0.0
|
stat = 0.0
|
||||||
try:
|
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 = 'fold_f')
|
||||||
print "player = ", player, do_stat(stat_dict, player = player, stat = 'wmsd')
|
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 = '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_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 = '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 = 'three_B_0')
|
||||||
print "player = ", player, do_stat(stat_dict, player = player, stat = 'wmsf')
|
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_freq1')
|
||||||
print "player = ", player, do_stat(stat_dict, player = player, stat = 'a_freq_2')
|
print "player = ", player, do_stat(stat_dict, player = player, stat = 'a_freq2')
|
||||||
print "player = ", player, do_stat(stat_dict, player = player, stat = 'a_freq_3')
|
print "player = ", player, do_stat(stat_dict, player = player, stat = 'a_freq3')
|
||||||
print "player = ", player, do_stat(stat_dict, player = player, stat = 'a_freq_4')
|
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')
|
||||||
print "player = ", player, do_stat(stat_dict, player = player, stat = 'a_freq_123_0')
|
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 = 'cb1')
|
||||||
print "player = ", player, do_stat(stat_dict, player = player, stat = 'cb_2')
|
print "player = ", player, do_stat(stat_dict, player = player, stat = 'cb2')
|
||||||
print "player = ", player, do_stat(stat_dict, player = player, stat = 'cb_3')
|
print "player = ", player, do_stat(stat_dict, player = player, stat = 'cb3')
|
||||||
print "player = ", player, do_stat(stat_dict, player = player, stat = 'cb_4')
|
print "player = ", player, do_stat(stat_dict, player = player, stat = 'cb4')
|
||||||
print "player = ", player, do_stat(stat_dict, player = player, stat = 'ffreq_1')
|
print "player = ", player, do_stat(stat_dict, player = player, stat = 'ffreq1')
|
||||||
print "player = ", player, do_stat(stat_dict, player = player, stat = 'ffreq_2')
|
print "player = ", player, do_stat(stat_dict, player = player, stat = 'ffreq2')
|
||||||
print "player = ", player, do_stat(stat_dict, player = player, stat = 'ffreq_3')
|
print "player = ", player, do_stat(stat_dict, player = player, stat = 'ffreq3')
|
||||||
print "player = ", player, do_stat(stat_dict, player = player, stat = 'ffreq_4')
|
print "player = ", player, do_stat(stat_dict, player = player, stat = 'ffreq4')
|
||||||
print "\n"
|
print "\n"
|
||||||
|
|
||||||
print "\n\nLegal stats:"
|
print "\n\nLegal stats:"
|
||||||
|
|
|
@ -33,12 +33,12 @@ class UltimateBet(HandHistoryConverter):
|
||||||
re_Board = re.compile(r"\[(?P<CARDS>.+)\]")
|
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]+)')
|
# 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)
|
in_path (default '-' = sys.stdin)
|
||||||
out_path (default '-' = sys.stdout)
|
out_path (default '-' = sys.stdout)
|
||||||
follow : whether to tail -f the input"""
|
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")
|
logging.info("Initialising UltimateBetconverter class")
|
||||||
self.filetype = "text"
|
self.filetype = "text"
|
||||||
self.codepage = "cp1252"
|
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 os
|
||||||
import sys
|
import sys
|
||||||
|
import threading
|
||||||
import Options
|
import Options
|
||||||
import string
|
import string
|
||||||
|
|
||||||
cl_options = string.join(sys.argv[1:])
|
cl_options = string.join(sys.argv[1:])
|
||||||
(options, sys.argv) = Options.fpdb_options()
|
(options, sys.argv) = Options.fpdb_options()
|
||||||
|
|
||||||
|
@ -28,10 +28,14 @@ if not options.errorsToConsole:
|
||||||
errorFile = open('fpdb-error-log.txt', 'w', 0)
|
errorFile = open('fpdb-error-log.txt', 'w', 0)
|
||||||
sys.stderr = errorFile
|
sys.stderr = errorFile
|
||||||
|
|
||||||
|
import logging
|
||||||
|
|
||||||
import pygtk
|
import pygtk
|
||||||
pygtk.require('2.0')
|
pygtk.require('2.0')
|
||||||
import gtk
|
import gtk
|
||||||
|
|
||||||
|
import interlocks
|
||||||
|
|
||||||
|
|
||||||
import fpdb_simple
|
import fpdb_simple
|
||||||
import GuiBulkImport
|
import GuiBulkImport
|
||||||
|
@ -115,11 +119,13 @@ class fpdb:
|
||||||
def dia_create_del_database(self, widget, data=None):
|
def dia_create_del_database(self, widget, data=None):
|
||||||
print "todo: implement dia_create_del_database"
|
print "todo: implement dia_create_del_database"
|
||||||
self.obtain_global_lock()
|
self.obtain_global_lock()
|
||||||
|
self.release_global_lock()
|
||||||
#end def dia_create_del_database
|
#end def dia_create_del_database
|
||||||
|
|
||||||
def dia_create_del_user(self, widget, data=None):
|
def dia_create_del_user(self, widget, data=None):
|
||||||
print "todo: implement dia_create_del_user"
|
print "todo: implement dia_create_del_user"
|
||||||
self.obtain_global_lock()
|
self.obtain_global_lock()
|
||||||
|
self.release_global_lock()
|
||||||
#end def dia_create_del_user
|
#end def dia_create_del_user
|
||||||
|
|
||||||
def dia_database_stats(self, widget, data=None):
|
def dia_database_stats(self, widget, data=None):
|
||||||
|
@ -128,7 +134,7 @@ class fpdb:
|
||||||
#end def dia_database_stats
|
#end def dia_database_stats
|
||||||
|
|
||||||
def dia_database_sessions(self, widget, data=None):
|
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)
|
self.threads.append(new_sessions_thread)
|
||||||
sessions_tab=new_sessions_thread.get_vbox()
|
sessions_tab=new_sessions_thread.get_vbox()
|
||||||
self.add_and_display_tab(sessions_tab, "Sessions")
|
self.add_and_display_tab(sessions_tab, "Sessions")
|
||||||
|
@ -136,16 +142,19 @@ class fpdb:
|
||||||
def dia_delete_db_parts(self, widget, data=None):
|
def dia_delete_db_parts(self, widget, data=None):
|
||||||
print "todo: implement dia_delete_db_parts"
|
print "todo: implement dia_delete_db_parts"
|
||||||
self.obtain_global_lock()
|
self.obtain_global_lock()
|
||||||
|
self.release_global_lock()
|
||||||
#end def dia_delete_db_parts
|
#end def dia_delete_db_parts
|
||||||
|
|
||||||
def dia_edit_profile(self, widget=None, data=None, create_default=False, path=None):
|
def dia_edit_profile(self, widget=None, data=None, create_default=False, path=None):
|
||||||
print "todo: implement dia_edit_profile"
|
print "todo: implement dia_edit_profile"
|
||||||
self.obtain_global_lock()
|
self.obtain_global_lock()
|
||||||
|
self.release_global_lock()
|
||||||
#end def dia_edit_profile
|
#end def dia_edit_profile
|
||||||
|
|
||||||
def dia_export_db(self, widget, data=None):
|
def dia_export_db(self, widget, data=None):
|
||||||
print "todo: implement dia_export_db"
|
print "todo: implement dia_export_db"
|
||||||
self.obtain_global_lock()
|
self.obtain_global_lock()
|
||||||
|
self.release_global_lock()
|
||||||
#end def dia_export_db
|
#end def dia_export_db
|
||||||
|
|
||||||
def dia_get_db_root_credentials(self):
|
def dia_get_db_root_credentials(self):
|
||||||
|
@ -171,6 +180,7 @@ class fpdb:
|
||||||
def dia_import_db(self, widget, data=None):
|
def dia_import_db(self, widget, data=None):
|
||||||
print "todo: implement dia_import_db"
|
print "todo: implement dia_import_db"
|
||||||
self.obtain_global_lock()
|
self.obtain_global_lock()
|
||||||
|
self.release_global_lock()
|
||||||
#end def dia_import_db
|
#end def dia_import_db
|
||||||
|
|
||||||
def dia_licensing(self, widget, data=None):
|
def dia_licensing(self, widget, data=None):
|
||||||
|
@ -179,7 +189,7 @@ class fpdb:
|
||||||
|
|
||||||
def dia_load_profile(self, widget, data=None):
|
def dia_load_profile(self, widget, data=None):
|
||||||
"""Dialogue to select a file to load a profile from"""
|
"""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:
|
#try:
|
||||||
# chooser = gtk.FileChooserDialog(title="Please select a profile file to load",
|
# chooser = gtk.FileChooserDialog(title="Please select a profile file to load",
|
||||||
# action=gtk.FILE_CHOOSER_ACTION_OPEN,
|
# action=gtk.FILE_CHOOSER_ACTION_OPEN,
|
||||||
|
@ -194,15 +204,18 @@ class fpdb:
|
||||||
# print 'User cancelled loading profile'
|
# print 'User cancelled loading profile'
|
||||||
#except:
|
#except:
|
||||||
# pass
|
# pass
|
||||||
|
try:
|
||||||
self.load_profile()
|
self.load_profile()
|
||||||
|
except:
|
||||||
|
pass
|
||||||
self.release_global_lock()
|
self.release_global_lock()
|
||||||
#end def dia_load_profile
|
#end def dia_load_profile
|
||||||
|
|
||||||
def dia_recreate_tables(self, widget, data=None):
|
def dia_recreate_tables(self, widget, data=None):
|
||||||
"""Dialogue that asks user to confirm that he wants to delete and recreate the tables"""
|
"""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:
|
try:
|
||||||
dia_confirm = gtk.MessageDialog(parent=None, flags=0, type=gtk.MESSAGE_WARNING,
|
dia_confirm = gtk.MessageDialog(parent=None, flags=0, type=gtk.MESSAGE_WARNING,
|
||||||
buttons=(gtk.BUTTONS_YES_NO), message_format="Confirm deleting and recreating tables")
|
buttons=(gtk.BUTTONS_YES_NO), message_format="Confirm deleting and recreating tables")
|
||||||
|
@ -213,27 +226,46 @@ class fpdb:
|
||||||
response = dia_confirm.run()
|
response = dia_confirm.run()
|
||||||
dia_confirm.destroy()
|
dia_confirm.destroy()
|
||||||
if response == gtk.RESPONSE_YES:
|
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
|
# mysql requires locks on all tables or none - easier to release this lock
|
||||||
# than lock all the other tables
|
# than lock all the other tables
|
||||||
# ToDo: lock all other tables so that lock doesn't have to be released
|
# ToDo: lock all other tables so that lock doesn't have to be released
|
||||||
self.release_global_lock()
|
# self.release_global_lock()
|
||||||
lock_released = True
|
# lock_released = True
|
||||||
self.db.fdb.recreate_tables()
|
self.db.recreate_tables()
|
||||||
else:
|
#else:
|
||||||
# for other dbs use same connection as holds global lock
|
# 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:
|
elif response == gtk.RESPONSE_NO:
|
||||||
print 'User cancelled recreating tables'
|
print 'User cancelled recreating tables'
|
||||||
except:
|
except:
|
||||||
pass
|
pass
|
||||||
if not lock_released:
|
#if not lock_released:
|
||||||
self.release_global_lock()
|
self.release_global_lock()
|
||||||
#end def dia_recreate_tables
|
#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):
|
def dia_regression_test(self, widget, data=None):
|
||||||
print "todo: implement dia_regression_test"
|
print "todo: implement dia_regression_test"
|
||||||
self.obtain_global_lock()
|
self.obtain_global_lock()
|
||||||
|
self.release_global_lock()
|
||||||
#end def dia_regression_test
|
#end def dia_regression_test
|
||||||
|
|
||||||
def dia_save_profile(self, widget, data=None):
|
def dia_save_profile(self, widget, data=None):
|
||||||
|
@ -292,6 +324,7 @@ class fpdb:
|
||||||
<menuitem action="createdb"/>
|
<menuitem action="createdb"/>
|
||||||
<menuitem action="createuser"/>
|
<menuitem action="createuser"/>
|
||||||
<menuitem action="createtabs"/>
|
<menuitem action="createtabs"/>
|
||||||
|
<menuitem action="rebuildhudcache"/>
|
||||||
<menuitem action="stats"/>
|
<menuitem action="stats"/>
|
||||||
<menuitem action="sessions"/>
|
<menuitem action="sessions"/>
|
||||||
</menu>
|
</menu>
|
||||||
|
@ -330,6 +363,7 @@ class fpdb:
|
||||||
('createdb', None, 'Create or Delete _Database (todo)', None, 'Create or Delete Database', self.dia_create_del_database),
|
('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),
|
('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),
|
('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),
|
('stats', None, '_Statistics (todo)', None, 'View Database Statistics', self.dia_database_stats),
|
||||||
('sessions', None, 'Sessions', None, 'View Sessions', self.dia_database_sessions),
|
('sessions', None, 'Sessions', None, 'View Sessions', self.dia_database_sessions),
|
||||||
('help', None, '_Help'),
|
('help', None, '_Help'),
|
||||||
|
@ -352,6 +386,7 @@ class fpdb:
|
||||||
"""Loads profile from the provided path name."""
|
"""Loads profile from the provided path name."""
|
||||||
self.config = Configuration.Config(file=options.config, dbname=options.dbname)
|
self.config = Configuration.Config(file=options.config, dbname=options.dbname)
|
||||||
self.settings = {}
|
self.settings = {}
|
||||||
|
self.settings['global_lock'] = self.lock
|
||||||
if (os.sep=="/"):
|
if (os.sep=="/"):
|
||||||
self.settings['os']="linuxmac"
|
self.settings['os']="linuxmac"
|
||||||
else:
|
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))
|
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
|
# 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()
|
self.db.connection.rollback()
|
||||||
#end def load_profile
|
#end def load_profile
|
||||||
|
|
||||||
|
@ -404,10 +438,15 @@ class fpdb:
|
||||||
#end def not_implemented
|
#end def not_implemented
|
||||||
|
|
||||||
def obtain_global_lock(self):
|
def obtain_global_lock(self):
|
||||||
print "\nTaking global lock ..."
|
ret = self.lock.acquire(False) # will return false if lock is already held
|
||||||
self.fdb_lock = Database.Database(self.config, sql = self.sql)
|
if ret:
|
||||||
self.fdb_lock.do_connect(self.config)
|
print "\nGlobal lock taken ..."
|
||||||
return self.fdb_lock.fdb.get_global_lock()
|
else:
|
||||||
|
print "\nFailed to get global lock."
|
||||||
|
return ret
|
||||||
|
# need to release it later:
|
||||||
|
# self.lock.release()
|
||||||
|
|
||||||
#end def obtain_global_lock
|
#end def obtain_global_lock
|
||||||
|
|
||||||
def quit(self, widget, data=None):
|
def quit(self, widget, data=None):
|
||||||
|
@ -418,8 +457,7 @@ class fpdb:
|
||||||
#end def quit_cliecked
|
#end def quit_cliecked
|
||||||
|
|
||||||
def release_global_lock(self):
|
def release_global_lock(self):
|
||||||
self.fdb_lock.fdb.db.rollback()
|
self.lock.release()
|
||||||
self.fdb_lock.fdb.disconnect()
|
|
||||||
print "Global lock released.\n"
|
print "Global lock released.\n"
|
||||||
#end def release_global_lock
|
#end def release_global_lock
|
||||||
|
|
||||||
|
@ -438,20 +476,20 @@ class fpdb:
|
||||||
def tab_bulk_import(self, widget, data=None):
|
def tab_bulk_import(self, widget, data=None):
|
||||||
"""opens a tab for bulk importing"""
|
"""opens a tab for bulk importing"""
|
||||||
#print "start of tab_bulk_import"
|
#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)
|
self.threads.append(new_import_thread)
|
||||||
bulk_tab=new_import_thread.get_vbox()
|
bulk_tab=new_import_thread.get_vbox()
|
||||||
self.add_and_display_tab(bulk_tab, "Bulk Import")
|
self.add_and_display_tab(bulk_tab, "Bulk Import")
|
||||||
#end def tab_bulk_import
|
#end def tab_bulk_import
|
||||||
|
|
||||||
def tab_player_stats(self, widget, data=None):
|
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)
|
self.threads.append(new_ps_thread)
|
||||||
ps_tab=new_ps_thread.get_vbox()
|
ps_tab=new_ps_thread.get_vbox()
|
||||||
self.add_and_display_tab(ps_tab, "Player Stats")
|
self.add_and_display_tab(ps_tab, "Player Stats")
|
||||||
|
|
||||||
def tab_positional_stats(self, widget, data=None):
|
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)
|
self.threads.append(new_ps_thread)
|
||||||
ps_tab=new_ps_thread.get_vbox()
|
ps_tab=new_ps_thread.get_vbox()
|
||||||
self.add_and_display_tab(ps_tab, "Positional Stats")
|
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):
|
def tabGraphViewer(self, widget, data=None):
|
||||||
"""opens a graph viewer tab"""
|
"""opens a graph viewer tab"""
|
||||||
#print "start of tabGraphViewer"
|
#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)
|
self.threads.append(new_gv_thread)
|
||||||
gv_tab=new_gv_thread.get_vbox()
|
gv_tab=new_gv_thread.get_vbox()
|
||||||
self.add_and_display_tab(gv_tab, "Graphs")
|
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):
|
def __init__(self):
|
||||||
self.threads = []
|
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.db = None
|
||||||
self.status_bar = None
|
self.status_bar = None
|
||||||
|
|
||||||
|
|
|
@ -18,124 +18,21 @@
|
||||||
import os
|
import os
|
||||||
import re
|
import re
|
||||||
import sys
|
import sys
|
||||||
|
import logging
|
||||||
from time import time, strftime
|
from time import time, strftime
|
||||||
|
|
||||||
import fpdb_simple
|
import fpdb_simple
|
||||||
import FpdbSQLQueries
|
import FpdbSQLQueries
|
||||||
|
|
||||||
class fpdb_db:
|
class fpdb_db:
|
||||||
|
MYSQL_INNODB = 2
|
||||||
|
PGSQL = 3
|
||||||
|
SQLITE = 4
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
"""Simple constructor, doesnt really do anything"""
|
"""Simple constructor, doesnt really do anything"""
|
||||||
self.db = None
|
self.db = None
|
||||||
self.cursor = None
|
self.cursor = None
|
||||||
self.sql = {}
|
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__
|
#end def __init__
|
||||||
|
|
||||||
def do_connect(self, config=None):
|
def do_connect(self, config=None):
|
||||||
|
@ -146,12 +43,12 @@ class fpdb_db:
|
||||||
self.settings = {}
|
self.settings = {}
|
||||||
self.settings['os'] = "linuxmac" if os.name != "nt" else "windows"
|
self.settings['os'] = "linuxmac" if os.name != "nt" else "windows"
|
||||||
|
|
||||||
self.settings.update(config.get_db_parameters())
|
db = config.get_db_parameters()
|
||||||
self.connect(self.settings['db-backend'],
|
self.connect(backend=db['db-backend'],
|
||||||
self.settings['db-host'],
|
host=db['db-host'],
|
||||||
self.settings['db-databaseName'],
|
database=db['db-databaseName'],
|
||||||
self.settings['db-user'],
|
user=db['db-user'],
|
||||||
self.settings['db-password'])
|
password=db['db-password'])
|
||||||
#end def do_connect
|
#end def do_connect
|
||||||
|
|
||||||
def connect(self, backend=None, host=None, database=None,
|
def connect(self, backend=None, host=None, database=None,
|
||||||
|
@ -164,13 +61,13 @@ class fpdb_db:
|
||||||
self.user=user
|
self.user=user
|
||||||
self.password=password
|
self.password=password
|
||||||
self.database=database
|
self.database=database
|
||||||
if backend==self.MYSQL_INNODB:
|
if backend==fpdb_db.MYSQL_INNODB:
|
||||||
import MySQLdb
|
import MySQLdb
|
||||||
try:
|
try:
|
||||||
self.db = MySQLdb.connect(host = host, user = user, passwd = password, db = database, use_unicode=True)
|
self.db = MySQLdb.connect(host = host, user = user, passwd = password, db = database, use_unicode=True)
|
||||||
except:
|
except:
|
||||||
raise fpdb_simple.FpdbError("MySQL connection failed")
|
raise fpdb_simple.FpdbError("MySQL connection failed")
|
||||||
elif backend==self.PGSQL:
|
elif backend==fpdb_db.PGSQL:
|
||||||
import psycopg2
|
import psycopg2
|
||||||
import psycopg2.extensions
|
import psycopg2.extensions
|
||||||
psycopg2.extensions.register_type(psycopg2.extensions.UNICODE)
|
psycopg2.extensions.register_type(psycopg2.extensions.UNICODE)
|
||||||
|
@ -182,9 +79,7 @@ class fpdb_db:
|
||||||
# sqlcoder: This database only connect failed in my windows setup??
|
# 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?
|
# Modifed it to try the 4 parameter style if the first connect fails - does this work everywhere?
|
||||||
connected = False
|
connected = False
|
||||||
if self.host == None or self.host == '' \
|
if self.host == "localhost" or self.host == "127.0.0.1":
|
||||||
or self.host == "localhost" \
|
|
||||||
or self.host == "127.0.0.1":
|
|
||||||
try:
|
try:
|
||||||
self.db = psycopg2.connect(database = database)
|
self.db = psycopg2.connect(database = database)
|
||||||
connected = True
|
connected = True
|
||||||
|
@ -203,13 +98,19 @@ class fpdb_db:
|
||||||
msg = "PostgreSQL connection to database (%s) user (%s) failed." % (database, user)
|
msg = "PostgreSQL connection to database (%s) user (%s) failed." % (database, user)
|
||||||
print msg
|
print msg
|
||||||
raise fpdb_simple.FpdbError(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:
|
else:
|
||||||
raise fpdb_simple.FpdbError("unrecognised database backend:"+backend)
|
raise fpdb_simple.FpdbError("unrecognised database backend:"+backend)
|
||||||
self.cursor=self.db.cursor()
|
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.
|
# Set up query dictionary as early in the connection process as we can.
|
||||||
self.sql = FpdbSQLQueries.FpdbSQLQueries(self.get_backend_name())
|
self.sql = FpdbSQLQueries.FpdbSQLQueries(self.get_backend_name())
|
||||||
|
self.cursor.execute(self.sql.query['set tx level'])
|
||||||
self.wrongDbVersion=False
|
self.wrongDbVersion=False
|
||||||
try:
|
try:
|
||||||
self.cursor.execute("SELECT * FROM Settings")
|
self.cursor.execute("SELECT * FROM Settings")
|
||||||
|
@ -238,77 +139,14 @@ class fpdb_db:
|
||||||
self.disconnect(due_to_error)
|
self.disconnect(due_to_error)
|
||||||
self.connect(self.backend, self.host, self.database, self.user, self.password)
|
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):
|
def get_backend_name(self):
|
||||||
"""Returns the name of the currently used backend"""
|
"""Returns the name of the currently used backend"""
|
||||||
if self.backend==2:
|
if self.backend==2:
|
||||||
return "MySQL InnoDB"
|
return "MySQL InnoDB"
|
||||||
elif self.backend==3:
|
elif self.backend==3:
|
||||||
return "PostgreSQL"
|
return "PostgreSQL"
|
||||||
|
elif self.backend==4:
|
||||||
|
return "SQLite"
|
||||||
else:
|
else:
|
||||||
raise fpdb_simple.FpdbError("invalid backend")
|
raise fpdb_simple.FpdbError("invalid backend")
|
||||||
#end def get_backend_name
|
#end def get_backend_name
|
||||||
|
@ -317,292 +155,8 @@ class fpdb_db:
|
||||||
return (self.host, self.database, self.user, self.password)
|
return (self.host, self.database, self.user, self.password)
|
||||||
#end def get_db_info
|
#end def get_db_info
|
||||||
|
|
||||||
def 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):
|
def getLastInsertId(self):
|
||||||
|
try:
|
||||||
if self.backend == self.MYSQL_INNODB:
|
if self.backend == self.MYSQL_INNODB:
|
||||||
ret = self.db.insert_id()
|
ret = self.db.insert_id()
|
||||||
if ret < 1 or ret > 999999999:
|
if ret < 1 or ret > 999999999:
|
||||||
|
@ -614,44 +168,93 @@ class fpdb_db:
|
||||||
# lastval() - still needs sequences set up?
|
# lastval() - still needs sequences set up?
|
||||||
# insert ... returning is useful syntax (but postgres specific?)
|
# insert ... returning is useful syntax (but postgres specific?)
|
||||||
# see rules (fancy trigger type things)
|
# see rules (fancy trigger type things)
|
||||||
self.cursor.execute ("SELECT lastval()")
|
c = self.db.cursor()
|
||||||
row = self.cursor.fetchone()
|
ret = c.execute ("SELECT lastval()")
|
||||||
|
row = c.fetchone()
|
||||||
if not row:
|
if not row:
|
||||||
print "getLastInsertId(%s): problem fetching lastval? row=" % seq, row
|
print "getLastInsertId(%s): problem fetching lastval? row=" % seq, row
|
||||||
ret = -1
|
ret = -1
|
||||||
else:
|
else:
|
||||||
ret = row[0]
|
ret = row[0]
|
||||||
elif self.backend == self.SQLITE:
|
elif self.backend == fpdb_db.SQLITE:
|
||||||
# don't know how to do this in sqlite
|
# don't know how to do this in sqlite
|
||||||
print "getLastInsertId(): not coded for sqlite yet"
|
print "getLastInsertId(): not coded for sqlite yet"
|
||||||
ret = -1
|
ret = -1
|
||||||
else:
|
else:
|
||||||
print "getLastInsertId(): unknown backend ", self.backend
|
print "getLastInsertId(): unknown backend ", self.backend
|
||||||
ret = -1
|
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
|
return ret
|
||||||
|
|
||||||
def storeHand(self, p):
|
def storeHand(self, p):
|
||||||
#stores into table hands:
|
#stores into table hands:
|
||||||
self.cursor.execute ("""INSERT INTO Hands
|
self.cursor.execute ("""INSERT INTO Hands (
|
||||||
(siteHandNo, gametypeId, handStart, seats, tableName, importTime, maxSeats
|
tablename,
|
||||||
,boardcard1, boardcard2, boardcard3, boardcard4, boardcard5
|
sitehandno,
|
||||||
,playersVpi, playersAtStreet1, playersAtStreet2
|
gametypeid,
|
||||||
,playersAtStreet3, playersAtStreet4, playersAtShowdown
|
handstart,
|
||||||
,street0Raises, street1Raises, street2Raises
|
importtime,
|
||||||
,street3Raises, street4Raises, street1Pot
|
seats,
|
||||||
,street2Pot, street3Pot, street4Pot
|
maxseats,
|
||||||
,showdownPot
|
boardcard1,
|
||||||
|
boardcard2,
|
||||||
|
boardcard3,
|
||||||
|
boardcard4,
|
||||||
|
boardcard5,
|
||||||
|
-- texture,
|
||||||
|
playersVpi,
|
||||||
|
playersAtStreet1,
|
||||||
|
playersAtStreet2,
|
||||||
|
playersAtStreet3,
|
||||||
|
playersAtStreet4,
|
||||||
|
playersAtShowdown,
|
||||||
|
street0Raises,
|
||||||
|
street1Raises,
|
||||||
|
street2Raises,
|
||||||
|
street3Raises,
|
||||||
|
street4Raises,
|
||||||
|
-- street1Pot,
|
||||||
|
-- street2Pot,
|
||||||
|
-- street3Pot,
|
||||||
|
-- street4Pot,
|
||||||
|
-- showdownPot
|
||||||
)
|
)
|
||||||
VALUES
|
VALUES
|
||||||
(%s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s)"""
|
(%s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s,
|
||||||
,(p['siteHandNo'], gametype_id, p['handStart'], len(names), p['tableName'], datetime.datetime.today(), p['maxSeats']
|
%s, %s, %s, %s, %s, %s, %s)""",
|
||||||
,p['boardcard1'], ['boardcard2'], p['boardcard3'], ['boardcard4'], ['boardcard5']
|
(
|
||||||
,hudCache['playersVpi'], hudCache['playersAtStreet1'], hudCache['playersAtStreet2']
|
p['tablename'],
|
||||||
,hudCache['playersAtStreet3'], hudCache['playersAtStreet4'], hudCache['playersAtShowdown']
|
p['sitehandno'],
|
||||||
,hudCache['street0Raises'], hudCache['street1Raises'], hudCache['street2Raises']
|
p['gametypeid'],
|
||||||
,hudCache['street3Raises'], hudCache['street4Raises'], hudCache['street1Pot']
|
p['handStart'],
|
||||||
,hudCache['street2Pot'], hudCache['street3Pot'], hudCache['street4Pot']
|
datetime.datetime.today(),
|
||||||
,hudCache['showdownPot']
|
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)
|
#return getLastInsertId(backend, conn, cursor)
|
||||||
|
|
|
@ -22,6 +22,7 @@
|
||||||
import os # todo: remove this once import_dir is in fpdb_import
|
import os # todo: remove this once import_dir is in fpdb_import
|
||||||
import sys
|
import sys
|
||||||
from time import time, strftime
|
from time import time, strftime
|
||||||
|
import logging
|
||||||
import traceback
|
import traceback
|
||||||
import math
|
import math
|
||||||
import datetime
|
import datetime
|
||||||
|
@ -53,14 +54,14 @@ except:
|
||||||
|
|
||||||
class Importer:
|
class Importer:
|
||||||
|
|
||||||
def __init__(self, caller, settings, config):
|
def __init__(self, caller, settings, config, sql = None):
|
||||||
"""Constructor"""
|
"""Constructor"""
|
||||||
self.settings = settings
|
self.settings = settings
|
||||||
self.caller = caller
|
self.caller = caller
|
||||||
self.config = config
|
self.config = config
|
||||||
|
self.sql = sql
|
||||||
|
|
||||||
self.database = None # database will be the main db interface eventually
|
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.filelist = {}
|
||||||
self.dirlist = {}
|
self.dirlist = {}
|
||||||
self.siteIds = {}
|
self.siteIds = {}
|
||||||
|
@ -77,10 +78,10 @@ class Importer:
|
||||||
self.settings.setdefault("minPrint", 30)
|
self.settings.setdefault("minPrint", 30)
|
||||||
self.settings.setdefault("handCount", 0)
|
self.settings.setdefault("handCount", 0)
|
||||||
|
|
||||||
self.database = Database.Database(self.config) # includes .connection and .sql variables
|
self.database = Database.Database(self.config, sql = self.sql) # 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.NEWIMPORT = False
|
||||||
self.fdb.db.rollback()
|
self.allow_hudcache_rebuild = False
|
||||||
|
|
||||||
#Set functions
|
#Set functions
|
||||||
def setCallHud(self, value):
|
def setCallHud(self, value):
|
||||||
|
@ -119,8 +120,7 @@ class Importer:
|
||||||
self.filelist[filename] = [site] + [filter]
|
self.filelist[filename] = [site] + [filter]
|
||||||
if site not in self.siteIds:
|
if site not in self.siteIds:
|
||||||
# Get id from Sites table in DB
|
# Get id from Sites table in DB
|
||||||
self.fdb.cursor.execute(self.fdb.sql.query['getSiteId'], (site,))
|
result = self.database.get_site_id(site)
|
||||||
result = self.fdb.cursor.fetchall()
|
|
||||||
if len(result) == 1:
|
if len(result) == 1:
|
||||||
self.siteIds[site] = result[0][0]
|
self.siteIds[site] = result[0][0]
|
||||||
else:
|
else:
|
||||||
|
@ -165,13 +165,19 @@ class Importer:
|
||||||
|
|
||||||
def runImport(self):
|
def runImport(self):
|
||||||
""""Run full import on self.filelist."""
|
""""Run full import on self.filelist."""
|
||||||
|
|
||||||
start = datetime.datetime.now()
|
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':
|
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':
|
if self.settings['dropIndexes'] == 'drop':
|
||||||
self.fdb.prepareBulkImport()
|
self.database.prepareBulkImport()
|
||||||
#self.settings['updateHudCache'] = self.calculate_auto2(10.0, 500.0)
|
else:
|
||||||
|
print "No need to drop indexes."
|
||||||
|
#print "dropInd =", self.settings['dropIndexes'], " dropHudCache =", self.settings['dropHudCache']
|
||||||
totstored = 0
|
totstored = 0
|
||||||
totdups = 0
|
totdups = 0
|
||||||
totpartial = 0
|
totpartial = 0
|
||||||
|
@ -186,8 +192,14 @@ class Importer:
|
||||||
toterrors += errors
|
toterrors += errors
|
||||||
tottime += ttime
|
tottime += ttime
|
||||||
if self.settings['dropIndexes'] == 'drop':
|
if self.settings['dropIndexes'] == 'drop':
|
||||||
self.fdb.afterBulkImport()
|
self.database.afterBulkImport()
|
||||||
self.fdb.analyzeDB()
|
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)
|
return (totstored, totdups, totpartial, toterrors, tottime)
|
||||||
# else: import threaded
|
# else: import threaded
|
||||||
|
|
||||||
|
@ -196,7 +208,7 @@ class Importer:
|
||||||
if len(self.filelist) == 1: return "don't drop"
|
if len(self.filelist) == 1: return "don't drop"
|
||||||
if 'handsInDB' not in self.settings:
|
if 'handsInDB' not in self.settings:
|
||||||
try:
|
try:
|
||||||
tmpcursor = self.fdb.db.cursor()
|
tmpcursor = self.database.get_cursor()
|
||||||
tmpcursor.execute("Select count(1) from Hands;")
|
tmpcursor.execute("Select count(1) from Hands;")
|
||||||
self.settings['handsInDB'] = tmpcursor.fetchone()[0]
|
self.settings['handsInDB'] = tmpcursor.fetchone()[0]
|
||||||
except:
|
except:
|
||||||
|
@ -219,7 +231,7 @@ class Importer:
|
||||||
# get number of hands in db
|
# get number of hands in db
|
||||||
if 'handsInDB' not in self.settings:
|
if 'handsInDB' not in self.settings:
|
||||||
try:
|
try:
|
||||||
tmpcursor = self.fdb.db.cursor()
|
tmpcursor = self.database.get_cursor()
|
||||||
tmpcursor.execute("Select count(1) from Hands;")
|
tmpcursor.execute("Select count(1) from Hands;")
|
||||||
self.settings['handsInDB'] = tmpcursor.fetchone()[0]
|
self.settings['handsInDB'] = tmpcursor.fetchone()[0]
|
||||||
except:
|
except:
|
||||||
|
@ -234,11 +246,12 @@ class Importer:
|
||||||
|
|
||||||
# if hands_in_db is zero or very low, we want to drop indexes, otherwise compare
|
# if hands_in_db is zero or very low, we want to drop indexes, otherwise compare
|
||||||
# import size with db size somehow:
|
# import size with db size somehow:
|
||||||
#print "auto2: handsindb =", self.settings['handsInDB'], "total_size =", total_size, "size_per_hand =", \
|
ret = "don't drop"
|
||||||
# size_per_hand, "inc =", increment
|
|
||||||
if self.settings['handsInDB'] < scale * (total_size/size_per_hand) + increment:
|
if self.settings['handsInDB'] < scale * (total_size/size_per_hand) + increment:
|
||||||
return "drop"
|
ret = "drop"
|
||||||
return "don't 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.
|
#Run import on updated files, then store latest update time.
|
||||||
def runUpdated(self):
|
def runUpdated(self):
|
||||||
|
@ -282,12 +295,13 @@ class Importer:
|
||||||
|
|
||||||
self.addToDirList = {}
|
self.addToDirList = {}
|
||||||
self.removeFromFileList = {}
|
self.removeFromFileList = {}
|
||||||
self.fdb.db.rollback()
|
self.database.rollback()
|
||||||
#rulog.writelines(" finished\n")
|
#rulog.writelines(" finished\n")
|
||||||
#rulog.close()
|
#rulog.close()
|
||||||
|
|
||||||
# This is now an internal function that should not be called directly.
|
# This is now an internal function that should not be called directly.
|
||||||
def import_file_dict(self, file, site, filter):
|
def import_file_dict(self, file, site, filter):
|
||||||
|
#print "import_file_dict"
|
||||||
if os.path.isdir(file):
|
if os.path.isdir(file):
|
||||||
self.addToDirList[file] = [site] + [filter]
|
self.addToDirList[file] = [site] + [filter]
|
||||||
return
|
return
|
||||||
|
@ -309,9 +323,17 @@ class Importer:
|
||||||
mod = __import__(filter)
|
mod = __import__(filter)
|
||||||
obj = getattr(mod, filter_name, None)
|
obj = getattr(mod, filter_name, None)
|
||||||
if callable(obj):
|
if callable(obj):
|
||||||
conv = obj(in_path = file, out_path = out_path)
|
conv = obj(in_path = file, out_path = out_path, index = 0) # Index into file 0 until changeover
|
||||||
if(conv.getStatus()):
|
if(conv.getStatus() and self.NEWIMPORT == False):
|
||||||
(stored, duplicates, partial, errors, ttime) = self.import_fpdb_file(out_path, site)
|
(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:
|
else:
|
||||||
# conversion didn't work
|
# conversion didn't work
|
||||||
# TODO: appropriate response?
|
# TODO: appropriate response?
|
||||||
|
@ -325,6 +347,7 @@ class Importer:
|
||||||
|
|
||||||
|
|
||||||
def import_fpdb_file(self, file, site):
|
def import_fpdb_file(self, file, site):
|
||||||
|
#print "import_fpdb_file"
|
||||||
starttime = time()
|
starttime = time()
|
||||||
last_read_hand = 0
|
last_read_hand = 0
|
||||||
loc = 0
|
loc = 0
|
||||||
|
@ -354,6 +377,8 @@ class Importer:
|
||||||
self.pos_in_file[file] = inputFile.tell()
|
self.pos_in_file[file] = inputFile.tell()
|
||||||
inputFile.close()
|
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.
|
try: # sometimes we seem to be getting an empty self.lines, in which case, we just want to return.
|
||||||
firstline = self.lines[0]
|
firstline = self.lines[0]
|
||||||
except:
|
except:
|
||||||
|
@ -395,10 +420,10 @@ class Importer:
|
||||||
self.hand=hand
|
self.hand=hand
|
||||||
|
|
||||||
try:
|
try:
|
||||||
handsId = fpdb_parse_logic.mainParser( self.settings, self.fdb
|
handsId = fpdb_parse_logic.mainParser( self.settings
|
||||||
, self.siteIds[site], category, hand
|
, self.siteIds[site], category, hand
|
||||||
, self.config, self.database )
|
, self.config, self.database )
|
||||||
self.fdb.db.commit()
|
self.database.commit()
|
||||||
|
|
||||||
stored += 1
|
stored += 1
|
||||||
if self.callHud:
|
if self.callHud:
|
||||||
|
@ -408,23 +433,23 @@ class Importer:
|
||||||
self.caller.pipe_to_hud.stdin.write("%s" % (handsId) + os.linesep)
|
self.caller.pipe_to_hud.stdin.write("%s" % (handsId) + os.linesep)
|
||||||
except fpdb_simple.DuplicateError:
|
except fpdb_simple.DuplicateError:
|
||||||
duplicates += 1
|
duplicates += 1
|
||||||
self.fdb.db.rollback()
|
self.database.rollback()
|
||||||
except (ValueError), fe:
|
except (ValueError), fe:
|
||||||
errors += 1
|
errors += 1
|
||||||
self.printEmailErrorMessage(errors, file, hand)
|
self.printEmailErrorMessage(errors, file, hand)
|
||||||
|
|
||||||
if (self.settings['failOnError']):
|
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
|
raise
|
||||||
else:
|
else:
|
||||||
self.fdb.db.rollback()
|
self.database.rollback()
|
||||||
except (fpdb_simple.FpdbError), fe:
|
except (fpdb_simple.FpdbError), fe:
|
||||||
errors += 1
|
errors += 1
|
||||||
self.printEmailErrorMessage(errors, file, hand)
|
self.printEmailErrorMessage(errors, file, hand)
|
||||||
self.fdb.db.rollback()
|
self.database.rollback()
|
||||||
|
|
||||||
if self.settings['failOnError']:
|
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
|
raise
|
||||||
|
|
||||||
if self.settings['minPrint']:
|
if self.settings['minPrint']:
|
||||||
|
@ -451,7 +476,7 @@ class Importer:
|
||||||
print "failed to read a single hand from file:", inputFile
|
print "failed to read a single hand from file:", inputFile
|
||||||
handsId=0
|
handsId=0
|
||||||
#todo: this will cause return of an unstored hand number if the last hand was error
|
#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
|
self.handsId=handsId
|
||||||
return (stored, duplicates, partial, errors, ttime)
|
return (stored, duplicates, partial, errors, ttime)
|
||||||
|
|
||||||
|
|
|
@ -15,19 +15,25 @@
|
||||||
#In the "official" distribution you can find the license in
|
#In the "official" distribution you can find the license in
|
||||||
#agpl-3.0.txt in the docs folder of the package.
|
#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 fpdb_simple
|
||||||
import Database
|
import Database
|
||||||
|
from time import time, strftime
|
||||||
|
|
||||||
|
|
||||||
#parses a holdem hand
|
#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']
|
backend = settings['db-backend']
|
||||||
if db == None:
|
if db == None:
|
||||||
#This is redundant - hopefully fdb will be a Database object in an iteration soon
|
|
||||||
db = Database.Database(c = config, sql = None)
|
db = Database.Database(c = config, sql = None)
|
||||||
else:
|
|
||||||
db = db
|
|
||||||
category = fpdb_simple.recogniseCategory(hand[0])
|
category = fpdb_simple.recogniseCategory(hand[0])
|
||||||
|
|
||||||
base = "hold" if category == "holdem" or category == "omahahi" or category == "omahahilo" else "stud"
|
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
|
if line[-2:] == "$0": continue
|
||||||
smallBlindLine = i
|
smallBlindLine = i
|
||||||
break
|
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:
|
if isTourney:
|
||||||
siteTourneyNo = fpdb_simple.parseTourneyNo(hand[0])
|
siteTourneyNo = fpdb_simple.parseTourneyNo(hand[0])
|
||||||
buyin = fpdb_simple.parseBuyin(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
|
tourneyStartTime= handStartTime #todo: read tourney start time
|
||||||
rebuyOrAddon = fpdb_simple.isRebuyOrAddon(hand[0])
|
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)
|
hand = fpdb_simple.filterCrap(hand, isTourney)
|
||||||
|
|
||||||
|
@ -79,7 +95,7 @@ def mainParser(settings, fdb, siteID, category, hand, config, db = None):
|
||||||
seatLines.append(line)
|
seatLines.append(line)
|
||||||
|
|
||||||
names = fpdb_simple.parseNames(seatLines)
|
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)
|
tmp = fpdb_simple.parseCashesAndSeatNos(seatLines)
|
||||||
startCashes = tmp['startCashes']
|
startCashes = tmp['startCashes']
|
||||||
seatNos = tmp['seatNos']
|
seatNos = tmp['seatNos']
|
||||||
|
@ -126,8 +142,9 @@ def mainParser(settings, fdb, siteID, category, hand, config, db = None):
|
||||||
fpdb_simple.convertBlindBet(actionTypes, actionAmounts)
|
fpdb_simple.convertBlindBet(actionTypes, actionAmounts)
|
||||||
fpdb_simple.checkPositions(positions)
|
fpdb_simple.checkPositions(positions)
|
||||||
|
|
||||||
fdb.cursor.execute("SELECT limitType FROM Gametypes WHERE id=%s",(gametypeID, ))
|
c = db.get_cursor()
|
||||||
limit_type = fdb.cursor.fetchone()[0]
|
c.execute("SELECT limitType FROM Gametypes WHERE id=%s",(gametypeID, ))
|
||||||
|
limit_type = c.fetchone()[0]
|
||||||
fpdb_simple.convert3B4B(category, limit_type, actionTypes, actionAmounts)
|
fpdb_simple.convert3B4B(category, limit_type, actionTypes, actionAmounts)
|
||||||
|
|
||||||
totalWinnings = sum(winnings)
|
totalWinnings = sum(winnings)
|
||||||
|
@ -143,49 +160,27 @@ def mainParser(settings, fdb, siteID, category, hand, config, db = None):
|
||||||
, allIns, actionTypeByNo, winnings, totalWinnings, None
|
, allIns, actionTypeByNo, winnings, totalWinnings, None
|
||||||
, actionTypes, actionAmounts, antes)
|
, actionTypes, actionAmounts, antes)
|
||||||
|
|
||||||
if isTourney:
|
#print "parse: hand data prepared" # only reads up to here apart from inserting new players
|
||||||
ranks = map(lambda x: 0, names) # create an array of 0's equal to the length of names
|
try:
|
||||||
payin_amounts = fpdb_simple.calcPayin(len(names), buyin, fee)
|
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)
|
||||||
|
|
||||||
if base == "hold":
|
|
||||||
result = db.tourney_holdem_omaha(
|
# save data structures in a HandToWrite instance and then insert into database:
|
||||||
config, settings, fdb.db, fdb.cursor, base, category, siteTourneyNo, buyin
|
htw = Database.HandToWrite()
|
||||||
|
htw.set_all( config, settings, base, category, siteTourneyNo, buyin
|
||||||
, fee, knockout, entries, prizepool, tourneyStartTime
|
, fee, knockout, entries, prizepool, tourneyStartTime
|
||||||
, payin_amounts, ranks, tourneyTypeId, siteID, siteHandNo
|
, isTourney, tourneyTypeId, siteID, siteHandNo
|
||||||
, gametypeID, handStartTime, names, playerIDs, startCashes
|
, gametypeID, handStartTime, names, playerIDs, startCashes
|
||||||
, positions, cardValues, cardSuits, boardValues, boardSuits
|
, positions, antes, cardValues, cardSuits, boardValues, boardSuits
|
||||||
, winnings, rakes, actionTypes, allIns, actionAmounts
|
, winnings, rakes, actionTypes, allIns, actionAmounts
|
||||||
, actionNos, hudImportData, maxSeats, tableName, seatNos)
|
, actionNos, hudImportData, maxSeats, tableName, seatNos)
|
||||||
elif base == "stud":
|
result = db.store_the_hand(htw)
|
||||||
result = db.tourney_stud(
|
|
||||||
config, settings, fdb.db, fdb.cursor, base, category, siteTourneyNo
|
t9 = time()
|
||||||
, buyin, fee, knockout, entries, prizepool, tourneyStartTime
|
#print "parse and save=(%4.3f)" % (t9-t0)
|
||||||
, 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()
|
|
||||||
return result
|
return result
|
||||||
#end def mainParser
|
#end def mainParser
|
||||||
|
|
||||||
|
|
|
@ -37,9 +37,6 @@ MYSQL_INNODB = 2
|
||||||
PGSQL = 3
|
PGSQL = 3
|
||||||
SQLITE = 4
|
SQLITE = 4
|
||||||
|
|
||||||
# config while trying out new hudcache mechanism
|
|
||||||
use_date_in_hudcache = True
|
|
||||||
|
|
||||||
class DuplicateError(Exception):
|
class DuplicateError(Exception):
|
||||||
def __init__(self, value):
|
def __init__(self, value):
|
||||||
self.value = 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))
|
#AND limitType=%s AND smallBlind=%s AND bigBlind=%s", (site_id, type, category, limit_type, small_bet, big_bet))
|
||||||
|
|
||||||
#result=(db.insert_id(),)
|
#result=(db.insert_id(),)
|
||||||
result=(getLastInsertId(backend,db,cursor),)
|
result=(db.get_last_insert_id(),)
|
||||||
|
|
||||||
return result[0]
|
return result[0]
|
||||||
#end def recogniseGametypeID
|
#end def recogniseGametypeID
|
||||||
|
@ -1122,282 +1119,6 @@ def splitRake(winnings, rakes, totalRake):
|
||||||
rakes[i]=totalRake*winPortion
|
rakes[i]=totalRake*winPortion
|
||||||
#end def splitRake
|
#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
|
def generateHudCacheData(player_ids, base, category, action_types, allIns, actionTypeByNo
|
||||||
,winnings, totalWinnings, positions, actionTypes, actionAmounts, antes):
|
,winnings, totalWinnings, positions, actionTypes, actionAmounts, antes):
|
||||||
"""calculates data for the HUD during import. IMPORTANT: if you change this method make
|
"""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":
|
if action[1]=="fold":
|
||||||
foldToStreetCBDone[player]=True
|
foldToStreetCBDone[player]=True
|
||||||
#end def generateFoldToCB
|
#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