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

Conflicts:
	pyfpdb/Configuration.py
	pyfpdb/SQL.py

note:hopefully got the merge right
This commit is contained in:
fpdb-mme 2009-11-04 18:34:28 +01:00
commit 6d54da1c49
11 changed files with 491 additions and 189 deletions

View File

@ -3,3 +3,4 @@
# When installed into .../fpdb/ the script gets mode 644 # When installed into .../fpdb/ the script gets mode 644
# Note: "dh_fixperms -Xfpdb.py" did not work, hence this hack # Note: "dh_fixperms -Xfpdb.py" did not work, hence this hack
chmod 755 /usr/bin/fpdb chmod 755 /usr/bin/fpdb
chmod 755 /usr/share/pyshared/fpdb/HUD_main.py

View File

@ -157,8 +157,8 @@ class Site:
if self.use_frames == "": self.use_frames = False if self.use_frames == "": self.use_frames = False
if self.font == "": self.font = "Sans" if self.font == "": self.font = "Sans"
if self.hudbgcolor == "": self.hudbgcolor = "000000" if self.hudbgcolor == "": self.hudbgcolor = "#000000"
if self.hudfgcolor == "": self.hudfgcolor = "FFFFFF" if self.hudfgcolor == "": self.hudfgcolor = "#FFFFFF"
def __str__(self): def __str__(self):
temp = "Site = " + self.site_name + "\n" temp = "Site = " + self.site_name + "\n"

View File

@ -1144,6 +1144,7 @@ class Database:
c.execute("INSERT INTO Sites (name,currency) VALUES ('Betfair', 'USD')") c.execute("INSERT INTO Sites (name,currency) VALUES ('Betfair', 'USD')")
c.execute("INSERT INTO Sites (name,currency) VALUES ('Absolute', 'USD')") c.execute("INSERT INTO Sites (name,currency) VALUES ('Absolute', 'USD')")
c.execute("INSERT INTO Sites (name,currency) VALUES ('PartyPoker', 'USD')") c.execute("INSERT INTO Sites (name,currency) VALUES ('PartyPoker', 'USD')")
c.execute("INSERT INTO Sites (name,currency) VALUES ('Partouche', 'EUR')")
if self.backend == self.SQLITE: if self.backend == self.SQLITE:
c.execute("INSERT INTO TourneyTypes (id, siteId, buyin, fee) VALUES (NULL, 1, 0, 0);") c.execute("INSERT INTO TourneyTypes (id, siteId, buyin, fee) VALUES (NULL, 1, 0, 0);")
elif self.backend == self.PGSQL: elif self.backend == self.PGSQL:
@ -1263,63 +1264,6 @@ class Database:
print "Error during fdb.lock_for_insert:", str(sys.exc_value) print "Error during fdb.lock_for_insert:", str(sys.exc_value)
#end def lock_for_insert #end def lock_for_insert
def getGameTypeId(self, siteid, game):
c = self.get_cursor()
#FIXME: Fixed for NL at the moment
c.execute(self.sql.query['getGametypeNL'], (siteid, game['type'], game['category'], game['limitType'],
int(Decimal(game['sb'])*100), int(Decimal(game['bb'])*100)))
tmp = c.fetchone()
if (tmp == None):
hilo = "h"
if game['category'] in ['studhilo', 'omahahilo']:
hilo = "s"
elif game['category'] in ['razz','27_3draw','badugi']:
hilo = "l"
tmp = self.insertGameTypes( (siteid, game['type'], game['base'], game['category'], game['limitType'], hilo,
int(Decimal(game['sb'])*100), int(Decimal(game['bb'])*100), 0, 0) )
return tmp[0]
def getSqlPlayerIDs(self, pnames, siteid):
result = {}
if(self.pcache == None):
self.pcache = LambdaDict(lambda key:self.insertPlayer(key, siteid))
for player in pnames:
result[player] = self.pcache[player]
# NOTE: Using the LambdaDict does the same thing as:
#if player in self.pcache:
# #print "DEBUG: cachehit"
# pass
#else:
# self.pcache[player] = self.insertPlayer(player, siteid)
#result[player] = self.pcache[player]
return result
def insertPlayer(self, name, site_id):
result = None
c = self.get_cursor()
q = "SELECT name, id FROM Players WHERE siteid=%s and name=%s"
q = q.replace('%s', self.sql.query['placeholder'])
#print "DEBUG: name: %s site: %s" %(name, site_id)
c.execute (q, (site_id, name))
tmp = c.fetchone()
if (tmp == None): #new player
c.execute ("INSERT INTO Players (name, siteId) VALUES (%s, %s)".replace('%s',self.sql.query['placeholder'])
,(name, site_id))
#Get last id might be faster here.
#c.execute ("SELECT id FROM Players WHERE name=%s", (name,))
tmp = [self.get_last_insert_id(c)]
return tmp[0]
def insertGameTypes(self, row):
c = self.get_cursor()
c.execute( self.sql.query['insertGameTypes'], row )
return [self.get_last_insert_id(c)]
def store_the_hand(self, h): def store_the_hand(self, h):
"""Take a HandToWrite object and store it in the db""" """Take a HandToWrite object and store it in the db"""
@ -1667,6 +1611,64 @@ class Database:
# street4CheckCallRaiseChance, # street4CheckCallRaiseChance,
# street4CheckCallRaiseDone) # street4CheckCallRaiseDone)
def getGameTypeId(self, siteid, game):
c = self.get_cursor()
#FIXME: Fixed for NL at the moment
c.execute(self.sql.query['getGametypeNL'], (siteid, game['type'], game['category'], game['limitType'],
int(Decimal(game['sb'])*100), int(Decimal(game['bb'])*100)))
tmp = c.fetchone()
if (tmp == None):
hilo = "h"
if game['category'] in ['studhilo', 'omahahilo']:
hilo = "s"
elif game['category'] in ['razz','27_3draw','badugi']:
hilo = "l"
tmp = self.insertGameTypes( (siteid, game['type'], game['base'], game['category'], game['limitType'], hilo,
int(Decimal(game['sb'])*100), int(Decimal(game['bb'])*100), 0, 0) )
return tmp[0]
def getSqlPlayerIDs(self, pnames, siteid):
result = {}
if(self.pcache == None):
self.pcache = LambdaDict(lambda key:self.insertPlayer(key, siteid))
for player in pnames:
result[player] = self.pcache[player]
# NOTE: Using the LambdaDict does the same thing as:
#if player in self.pcache:
# #print "DEBUG: cachehit"
# pass
#else:
# self.pcache[player] = self.insertPlayer(player, siteid)
#result[player] = self.pcache[player]
return result
def insertPlayer(self, name, site_id):
result = None
c = self.get_cursor()
q = "SELECT name, id FROM Players WHERE siteid=%s and name=%s"
q = q.replace('%s', self.sql.query['placeholder'])
#print "DEBUG: name: %s site: %s" %(name, site_id)
c.execute (q, (site_id, name))
tmp = c.fetchone()
if (tmp == None): #new player
c.execute ("INSERT INTO Players (name, siteId) VALUES (%s, %s)".replace('%s',self.sql.query['placeholder'])
,(name, site_id))
#Get last id might be faster here.
#c.execute ("SELECT id FROM Players WHERE name=%s", (name,))
tmp = [self.get_last_insert_id(c)]
return tmp[0]
def insertGameTypes(self, row):
c = self.get_cursor()
c.execute( self.sql.query['insertGameTypes'], row )
return [self.get_last_insert_id(c)]
################################# #################################
# Finish of NEWIMPORT CODE # Finish of NEWIMPORT CODE

View File

@ -20,6 +20,7 @@ import pygtk
pygtk.require('2.0') pygtk.require('2.0')
import gtk import gtk
import os import os
import sys
import traceback import traceback
from time import * from time import *
#import pokereval #import pokereval
@ -32,7 +33,7 @@ try:
from matplotlib.backends.backend_gtkagg import NavigationToolbar2GTKAgg as NavigationToolbar from matplotlib.backends.backend_gtkagg import NavigationToolbar2GTKAgg as NavigationToolbar
from numpy import arange, cumsum from numpy import arange, cumsum
from pylab import * from pylab import *
except ImportError as inst: except ImportError, inst:
print """Failed to load libs for graphing, graphing will not function. Please in print """Failed to load libs for graphing, graphing will not function. Please in
stall numpy and matplotlib if you want to use graphs.""" stall numpy and matplotlib if you want to use graphs."""
print """This is of no consequence for other parts of the program, e.g. import print """This is of no consequence for other parts of the program, e.g. import

View File

@ -37,7 +37,7 @@ try:
# from matplotlib.dates import DateFormatter, WeekdayLocator, HourLocator, \ # from matplotlib.dates import DateFormatter, WeekdayLocator, HourLocator, \
# DayLocator, MONDAY, timezone # DayLocator, MONDAY, timezone
except ImportError as inst: except ImportError, inst:
print """Failed to load numpy in Session Viewer""" print """Failed to load numpy in Session Viewer"""
print """This is of no consequence as the page is broken and only of interest to developers.""" print """This is of no consequence as the page is broken and only of interest to developers."""
print "ImportError: %s" % inst.args print "ImportError: %s" % inst.args
@ -248,6 +248,8 @@ class GuiSessionViewer (threading.Thread):
nametest = nametest.replace("L", "") nametest = nametest.replace("L", "")
nametest = nametest.replace(",)",")") nametest = nametest.replace(",)",")")
q = q.replace("<player_test>", nametest) q = q.replace("<player_test>", nametest)
q = q.replace("<ampersand_s>", "%s")
self.db.cursor.execute(q) self.db.cursor.execute(q)
THRESHOLD = 1800 THRESHOLD = 1800
hands = self.db.cursor.fetchall() hands = self.db.cursor.fetchall()

View File

@ -4,7 +4,6 @@
<import callFpdbHud = "True" interval = "10" fastStoreHudCache="False" hhArchiveBase="~/.fpdb/HandHistories/" saveActions="True"></import> <import callFpdbHud = "True" interval = "10" fastStoreHudCache="False" hhArchiveBase="~/.fpdb/HandHistories/" saveActions="True"></import>
<!-- These values need some explaining <!-- These values need some explaining
aggregate_ring_game_stats : aggregate_ring_game_stats :
@ -567,6 +566,7 @@ Left-Drag to Move"
<hhc site="Absolute" converter="AbsoluteToFpdb"/> <hhc site="Absolute" converter="AbsoluteToFpdb"/>
<hhc site="PartyPoker" converter="PartyPokerToFpdb"/> <hhc site="PartyPoker" converter="PartyPokerToFpdb"/>
<hhc site="Betfair" converter="BetfairToFpdb"/> <hhc site="Betfair" converter="BetfairToFpdb"/>
<hhc site="Partouche" converter="PartoucheToFpdb"/>
</hhcs> </hhcs>
<supported_databases> <supported_databases>

View File

@ -189,7 +189,6 @@ class HUD_main(object):
# be passed to HUDs for use in the gui thread. HUD objects should not # be passed to HUDs for use in the gui thread. HUD objects should not
# need their own access to the database, but should open their own # need their own access to the database, but should open their own
# if it is required. # if it is required.
try:
self.db_connection = Database.Database(self.config) self.db_connection = Database.Database(self.config)
tourny_finder = re.compile('(\d+) (\d+)') tourny_finder = re.compile('(\d+) (\d+)')
@ -279,9 +278,6 @@ class HUD_main(object):
else: else:
self.create_HUD(new_hand_id, tablewindow, temp_key, max, poker_game, type, stat_dict, cards) self.create_HUD(new_hand_id, tablewindow, temp_key, max, poker_game, type, stat_dict, cards)
self.db_connection.connection.rollback() self.db_connection.connection.rollback()
except:
err = traceback.extract_tb(sys.exc_info()[2])[-1]
print "***Error: "+err[2]+"("+str(err[1])+"): "+str(sys.exc_info()[1])
if __name__== "__main__": if __name__== "__main__":

View File

@ -28,11 +28,12 @@ from HandHistoryConverter import *
class PartyPokerParseError(FpdbParseError): class PartyPokerParseError(FpdbParseError):
"Usage: raise PartyPokerParseError(<msg>[, hh=<hh>][, hid=<hid>])" "Usage: raise PartyPokerParseError(<msg>[, hh=<hh>][, hid=<hid>])"
def __init__(self, msg='', hh=None, hid=None): def __init__(self, msg='', hh=None, hid=None):
if hh is not None: if hh is not None:
msg += "\n\nHand history attached below:\n" + self.wrapHh(hh) msg += "\n\nHand history attached below:\n" + self.wrapHh(hh)
return super(PartyPokerParseError, self).__init__(hid=hid) return super(PartyPokerParseError, self).__init__(msg, hid=hid)
#return super(PartyPokerParseError, self).__init__(msg, hid=hid)
def wrapHh(self, hh): def wrapHh(self, hh):
return ("%(DELIMETER)s\n%(HH)s\n%(DELIMETER)s") % \ return ("%(DELIMETER)s\n%(HH)s\n%(DELIMETER)s") % \
{'DELIMETER': '#'*50, 'HH': hh} {'DELIMETER': '#'*50, 'HH': hh}
@ -93,7 +94,7 @@ class PartyPoker(HandHistoryConverter):
""", """,
re.MULTILINE|re.VERBOSE) re.MULTILINE|re.VERBOSE)
re_TotalPlayers = re.compile("^Total\s+number\s+of\s+players\s*:\s*(?P<MAXSEATS>\d+)", re.MULTILINE) # re_TotalPlayers = re.compile("^Total\s+number\s+of\s+players\s*:\s*(?P<MAXSEATS>\d+)", re.MULTILINE)
re_SplitHands = re.compile('\x00+') re_SplitHands = re.compile('\x00+')
re_TailSplitHands = re.compile('(\x00+)') re_TailSplitHands = re.compile('(\x00+)')
lineSplitter = '\n' lineSplitter = '\n'
@ -229,7 +230,6 @@ class PartyPoker(HandHistoryConverter):
"Unknown game type '%s'" % mg['GAME'], "Unknown game type '%s'" % mg['GAME'],
hh = handText) hh = handText)
if 'TOURNO' in mg: if 'TOURNO' in mg:
info['type'] = 'tour' info['type'] = 'tour'
else: else:
@ -237,15 +237,12 @@ class PartyPoker(HandHistoryConverter):
if info['type'] == 'ring': if info['type'] == 'ring':
info['sb'], info['bb'] = ringBlinds(mg['RINGLIMIT']) info['sb'], info['bb'] = ringBlinds(mg['RINGLIMIT'])
# FIXME: there are only $ and play money availible for cash
# to be honest, party doesn't save play money hh
info['currency'] = currencies[mg['CURRENCY']] info['currency'] = currencies[mg['CURRENCY']]
else: else:
info['sb'] = clearMoneyString(mg['SB']) info['sb'] = clearMoneyString(mg['SB'])
info['bb'] = clearMoneyString(mg['BB']) info['bb'] = clearMoneyString(mg['BB'])
info['currency'] = 'T$' info['currency'] = 'T$'
# NB: SB, BB must be interpreted as blinds or bets depending on limit type.
return info return info
@ -269,8 +266,8 @@ class PartyPoker(HandHistoryConverter):
hh=hand.handText, hid = info['HID']) hh=hand.handText, hid = info['HID'])
m = self.re_TotalPlayers.search(hand.handText) # m = self.re_TotalPlayers.search(hand.handText)
if m: info.update(m.groupdict()) # if m: info.update(m.groupdict())
# FIXME: it's dirty hack # FIXME: it's dirty hack
@ -318,7 +315,7 @@ class PartyPoker(HandHistoryConverter):
hand.tourNo = info[key] hand.tourNo = info[key]
if key == 'BUYIN': if key == 'BUYIN':
# FIXME: it's dirty hack T_T # FIXME: it's dirty hack T_T
# code below assumes that rake is equal to zero # code below assumes that tournament rake is equal to zero
cur = info[key][0] if info[key][0] not in '0123456789' else '' cur = info[key][0] if info[key][0] not in '0123456789' else ''
hand.buyin = info[key] + '+%s0' % cur hand.buyin = info[key] + '+%s0' % cur
if key == 'LEVEL': if key == 'LEVEL':
@ -474,11 +471,9 @@ class PartyPoker(HandHistoryConverter):
if m.group('CARDS') is not None: if m.group('CARDS') is not None:
cards = renderCards(m.group('CARDS')) cards = renderCards(m.group('CARDS'))
(shown, mucked) = (False, False) mucked = m.group('SHOWED') != "show"
if m.group('SHOWED') == "show": shown = True
else: mucked = True
hand.addShownCards(cards=cards, player=m.group('PNAME'), shown=shown, mucked=mucked) hand.addShownCards(cards=cards, player=m.group('PNAME'), shown=True, mucked=mucked)
def ringBlinds(ringLimit): def ringBlinds(ringLimit):
"Returns blinds for current limit in cash games" "Returns blinds for current limit in cash games"

View File

@ -1645,15 +1645,6 @@ class Sql:
where Id = %s where Id = %s
""" """
self.query['get_action_from_hand'] = """
SELECT street, Players.name, HandsActions.action, HandsActions.amount, actionno
FROM Players, HandsActions, HandsPlayers
WHERE HandsPlayers.handid = %s
AND HandsPlayers.playerid = Players.id
AND HandsActions.handsPlayerId = HandsPlayers.id
ORDER BY street, actionno
"""
if db_server == 'mysql': if db_server == 'mysql':
self.query['get_hand_1day_ago'] = """ self.query['get_hand_1day_ago'] = """
select coalesce(max(id),0) select coalesce(max(id),0)
@ -1890,6 +1881,272 @@ class Sql:
,maxbigblind desc ,maxbigblind desc
,s.name ,s.name
""" """
elif db_server == 'sqlite':
self.query['playerDetailedStats'] = """
select <hgameTypeId> AS hgametypeid
,gt.base
,gt.category AS category
,upper(gt.limitType) AS limittype
,s.name AS name
,min(gt.bigBlind) AS minbigblind
,max(gt.bigBlind) AS maxbigblind
/*,<hcgametypeId> AS gtid*/
,<position> AS plposition
,count(1) AS n
,100.0*sum(cast(hp.street0VPI as <signed>integer))/count(1) AS vpip
,100.0*sum(cast(hp.street0Aggr as <signed>integer))/count(1) AS pfr
,case when sum(cast(hp.street0_3Bchance as <signed>integer)) = 0 then -999
else 100.0*sum(cast(hp.street0_3Bdone as <signed>integer))/sum(cast(hp.street0_3Bchance as <signed>integer))
end AS pf3
,case when sum(cast(hp.stealattemptchance as <signed>integer)) = 0 then -999
else 100.0*sum(cast(hp.stealattempted as <signed>integer))/sum(cast(hp.stealattemptchance as <signed>integer))
end AS steals
,100.0*sum(cast(hp.street1Seen as <signed>integer))/count(1) AS saw_f
,100.0*sum(cast(hp.sawShowdown as <signed>integer))/count(1) AS sawsd
,case when sum(cast(hp.street1Seen as <signed>integer)) = 0 then -999
else 100.0*sum(cast(hp.sawShowdown as <signed>integer))/sum(cast(hp.street1Seen as <signed>integer))
end AS wtsdwsf
,case when sum(cast(hp.sawShowdown as <signed>integer)) = 0 then -999
else 100.0*sum(cast(hp.wonAtSD as <signed>integer))/sum(cast(hp.sawShowdown as <signed>integer))
end AS wmsd
,case when sum(cast(hp.street1Seen as <signed>integer)) = 0 then -999
else 100.0*sum(cast(hp.street1Aggr as <signed>integer))/sum(cast(hp.street1Seen as <signed>integer))
end AS flafq
,case when sum(cast(hp.street2Seen as <signed>integer)) = 0 then -999
else 100.0*sum(cast(hp.street2Aggr as <signed>integer))/sum(cast(hp.street2Seen as <signed>integer))
end AS tuafq
,case when sum(cast(hp.street3Seen as <signed>integer)) = 0 then -999
else 100.0*sum(cast(hp.street3Aggr as <signed>integer))/sum(cast(hp.street3Seen as <signed>integer))
end AS rvafq
,case when sum(cast(hp.street1Seen as <signed>integer))+sum(cast(hp.street2Seen as <signed>integer))+sum(cast(hp.street3Seen as <signed>integer)) = 0 then -999
else 100.0*(sum(cast(hp.street1Aggr as <signed>integer))+sum(cast(hp.street2Aggr as <signed>integer))+sum(cast(hp.street3Aggr as <signed>integer)))
/(sum(cast(hp.street1Seen as <signed>integer))+sum(cast(hp.street2Seen as <signed>integer))+sum(cast(hp.street3Seen as <signed>integer)))
end AS pofafq
,sum(hp.totalProfit)/100.0 AS net
,sum(hp.rake)/100.0 AS rake
,100.0*avg(hp.totalProfit/(gt.bigBlind+0.0)) AS bbper100
,avg(hp.totalProfit)/100.0 AS profitperhand
,100.0*avg((hp.totalProfit+hp.rake)/(gt.bigBlind+0.0)) AS bb100xr
,avg((hp.totalProfit+hp.rake)/100.0) AS profhndxr
,avg(h.seats+0.0) AS avgseats
/*,variance(hp.totalProfit/100.0) AS variance*/
,0.0 AS variance
from HandsPlayers hp
inner join Hands h on (h.id = hp.handId)
inner join Gametypes gt on (gt.Id = h.gameTypeId)
inner join Sites s on (s.Id = gt.siteId)
where hp.playerId in <player_test>
/*and hp.tourneysPlayersId IS NULL*/
and h.seats <seats_test>
<flagtest>
<gtbigBlind_test>
and to_char(h.handStart, 'YYYY-MM-DD') <datestest>
group by hgameTypeId
,hp.playerId
,gt.base
,gt.category
<groupbyseats>
,plposition
,upper(gt.limitType)
,s.name
order by hp.playerId
,gt.base
,gt.category
<orderbyseats>
,case <position> when 'B' then 'B'
when 'S' then 'S'
when '0' then 'Y'
else 'Z'||<position>
end
<orderbyhgameTypeId>
,upper(gt.limitType) desc
,maxbigblind desc
,s.name
"""
if db_server == 'mysql':
self.query['playerStats'] = """
SELECT
concat(upper(stats.limitType), ' '
,concat(upper(substring(stats.category,1,1)),substring(stats.category,2) ), ' '
,stats.name, ' '
,cast(stats.bigBlindDesc as char)
) AS Game
,stats.n
,stats.vpip
,stats.pfr
,stats.pf3
,stats.steals
,stats.saw_f
,stats.sawsd
,stats.wtsdwsf
,stats.wmsd
,stats.FlAFq
,stats.TuAFq
,stats.RvAFq
,stats.PoFAFq
,stats.Net
,stats.BBper100
,stats.Profitperhand
,case when hprof2.variance = -999 then '-'
else format(hprof2.variance, 2)
end AS Variance
,stats.AvgSeats
FROM
(select /* stats from hudcache */
gt.base
,gt.category
,upper(gt.limitType) as limitType
,s.name
,<selectgt.bigBlind> AS bigBlindDesc
,<hcgametypeId> AS gtId
,sum(HDs) AS n
,format(100.0*sum(street0VPI)/sum(HDs),1) AS vpip
,format(100.0*sum(street0Aggr)/sum(HDs),1) AS pfr
,case when sum(street0_3Bchance) = 0 then '0'
else format(100.0*sum(street0_3Bdone)/sum(street0_3Bchance),1)
end AS pf3
,case when sum(stealattemptchance) = 0 then '-'
else format(100.0*sum(stealattempted)/sum(stealattemptchance),1)
end AS steals
,format(100.0*sum(street1Seen)/sum(HDs),1) AS saw_f
,format(100.0*sum(sawShowdown)/sum(HDs),1) AS sawsd
,case when sum(street1Seen) = 0 then '-'
else format(100.0*sum(sawShowdown)/sum(street1Seen),1)
end AS wtsdwsf
,case when sum(sawShowdown) = 0 then '-'
else format(100.0*sum(wonAtSD)/sum(sawShowdown),1)
end AS wmsd
,case when sum(street1Seen) = 0 then '-'
else format(100.0*sum(street1Aggr)/sum(street1Seen),1)
end AS FlAFq
,case when sum(street2Seen) = 0 then '-'
else format(100.0*sum(street2Aggr)/sum(street2Seen),1)
end AS TuAFq
,case when sum(street3Seen) = 0 then '-'
else format(100.0*sum(street3Aggr)/sum(street3Seen),1)
end AS RvAFq
,case when sum(street1Seen)+sum(street2Seen)+sum(street3Seen) = 0 then '-'
else format(100.0*(sum(street1Aggr)+sum(street2Aggr)+sum(street3Aggr))
/(sum(street1Seen)+sum(street2Seen)+sum(street3Seen)),1)
end AS PoFAFq
,format(sum(totalProfit)/100.0,2) AS Net
,format((sum(totalProfit/(gt.bigBlind+0.0))) / (sum(HDs)/100.0),2)
AS BBper100
,format( (sum(totalProfit)/100.0) / sum(HDs), 4) AS Profitperhand
,format( sum(activeSeats*HDs)/(sum(HDs)+0.0), 2) AS AvgSeats
from Gametypes gt
inner join Sites s on s.Id = gt.siteId
inner join HudCache hc on hc.gameTypeId = gt.Id
where hc.playerId in <player_test>
and <gtbigBlind_test>
and hc.activeSeats <seats_test>
and concat( '20', substring(hc.styleKey,2,2), '-', substring(hc.styleKey,4,2), '-'
, substring(hc.styleKey,6,2) ) <datestest>
group by gt.base
,gt.category
<groupbyseats>
,plposition
,upper(gt.limitType)
,s.name
having 1 = 1 <havingclause>
order by pname
,gt.base
,gt.category
<orderbyseats>
,case <position> when 'B' then 'B'
when 'S' then 'S'
else concat('Z', <position>)
end
<orderbyhgameTypeId>
,upper(gt.limitType) desc
,maxbigblind desc
,s.name
"""
elif db_server == 'postgresql':
self.query['playerDetailedStats'] = """
select <hgameTypeId> AS hgametypeid
,<playerName> AS pname
,gt.base
,gt.category
,upper(gt.limitType) AS limittype
,s.name
,min(gt.bigBlind) AS minbigblind
,max(gt.bigBlind) AS maxbigblind
/*,<hcgametypeId> AS gtid*/
,<position> AS plposition
,count(1) AS n
,100.0*sum(cast(hp.street0VPI as <signed>integer))/count(1) AS vpip
,100.0*sum(cast(hp.street0Aggr as <signed>integer))/count(1) AS pfr
,case when sum(cast(hp.street0_3Bchance as <signed>integer)) = 0 then -999
else 100.0*sum(cast(hp.street0_3Bdone as <signed>integer))/sum(cast(hp.street0_3Bchance as <signed>integer))
end AS pf3
,case when sum(cast(hp.stealattemptchance as <signed>integer)) = 0 then -999
else 100.0*sum(cast(hp.stealattempted as <signed>integer))/sum(cast(hp.stealattemptchance as <signed>integer))
end AS steals
,100.0*sum(cast(hp.street1Seen as <signed>integer))/count(1) AS saw_f
,100.0*sum(cast(hp.sawShowdown as <signed>integer))/count(1) AS sawsd
,case when sum(cast(hp.street1Seen as <signed>integer)) = 0 then -999
else 100.0*sum(cast(hp.sawShowdown as <signed>integer))/sum(cast(hp.street1Seen as <signed>integer))
end AS wtsdwsf
,case when sum(cast(hp.sawShowdown as <signed>integer)) = 0 then -999
else 100.0*sum(cast(hp.wonAtSD as <signed>integer))/sum(cast(hp.sawShowdown as <signed>integer))
end AS wmsd
,case when sum(cast(hp.street1Seen as <signed>integer)) = 0 then -999
else 100.0*sum(cast(hp.street1Aggr as <signed>integer))/sum(cast(hp.street1Seen as <signed>integer))
end AS flafq
,case when sum(cast(hp.street2Seen as <signed>integer)) = 0 then -999
else 100.0*sum(cast(hp.street2Aggr as <signed>integer))/sum(cast(hp.street2Seen as <signed>integer))
end AS tuafq
,case when sum(cast(hp.street3Seen as <signed>integer)) = 0 then -999
else 100.0*sum(cast(hp.street3Aggr as <signed>integer))/sum(cast(hp.street3Seen as <signed>integer))
end AS rvafq
,case when sum(cast(hp.street1Seen as <signed>integer))+sum(cast(hp.street2Seen as <signed>integer))+sum(cast(hp.street3Seen as <signed>integer)) = 0 then -999
else 100.0*(sum(cast(hp.street1Aggr as <signed>integer))+sum(cast(hp.street2Aggr as <signed>integer))+sum(cast(hp.street3Aggr as <signed>integer)))
/(sum(cast(hp.street1Seen as <signed>integer))+sum(cast(hp.street2Seen as <signed>integer))+sum(cast(hp.street3Seen as <signed>integer)))
end AS pofafq
,sum(hp.totalProfit)/100.0 AS net
,sum(hp.rake)/100.0 AS rake
,100.0*avg(hp.totalProfit/(gt.bigBlind+0.0)) AS bbper100
,avg(hp.totalProfit)/100.0 AS profitperhand
,100.0*avg((hp.totalProfit+hp.rake)/(gt.bigBlind+0.0)) AS bb100xr
,avg((hp.totalProfit+hp.rake)/100.0) AS profhndxr
,avg(h.seats+0.0) AS avgseats
,variance(hp.totalProfit/100.0) AS variance
from HandsPlayers hp
inner join Hands h on (h.id = hp.handId)
inner join Gametypes gt on (gt.Id = h.gameTypeId)
inner join Sites s on (s.Id = gt.siteId)
inner join Players p on (p.Id = hp.playerId)
where hp.playerId in <player_test>
/*and hp.tourneysPlayersId IS NULL*/
and h.seats <seats_test>
<flagtest>
<gtbigBlind_test>
and to_char(h.handStart, 'YYYY-MM-DD') <datestest>
group by hgameTypeId
,pname
,gt.base
,gt.category
<groupbyseats>
,plposition
,upper(gt.limitType)
,s.name
having 1 = 1 <havingclause>
order by pname
,gt.base
,gt.category
<orderbyseats>
,case <position> when 'B' then 'B'
when 'S' then 'S'
when '0' then 'Y'
else 'Z'||<position>
end
<orderbyhgameTypeId>
,upper(gt.limitType) desc
,maxbigblind desc
,s.name
"""
elif db_server == 'sqlite': elif db_server == 'sqlite':
self.query['playerDetailedStats'] = """ self.query['playerDetailedStats'] = """
select <hgameTypeId> AS hgametypeid select <hgameTypeId> AS hgametypeid
@ -2474,6 +2731,25 @@ class Sql:
GROUP BY h.handStart, hp.handId, hp.totalProfit GROUP BY h.handStart, hp.handId, hp.totalProfit
ORDER BY h.handStart""" ORDER BY h.handStart"""
####################################
# Session stats query
####################################
if db_server == 'mysql':
self.query['sessionStats'] = """
SELECT UNIX_TIMESTAMP(h.handStart) as time, hp.handId, hp.startCash, hp.winnings, hp.totalProfit
FROM HandsPlayers hp
INNER JOIN Players pl ON (pl.id = hp.playerId)
INNER JOIN Hands h ON (h.id = hp.handId)
INNER JOIN Gametypes gt ON (gt.id = h.gametypeId)
WHERE pl.id in <player_test>
AND pl.siteId in <site_test>
AND h.handStart > '<startdate_test>'
AND h.handStart < '<enddate_test>'
<limit_test>
AND hp.tourneysPlayersId IS NULL
GROUP BY h.handStart, hp.handId, hp.totalProfit
ORDER BY h.handStart"""
#################################### ####################################
# Session stats query # Session stats query
#################################### ####################################
@ -2500,7 +2776,17 @@ class Sql:
AND h.handStart <datestest> AND h.handStart <datestest>
ORDER by time""" ORDER by time"""
elif db_server == 'sqlite': elif db_server == 'sqlite':
self.query['sessionStats'] = """ """ self.query['sessionStats'] = """
SELECT STRFTIME('<ampersand_s>', h.handStart) as time, hp.handId, hp.startCash, hp.winnings, hp.totalProfit
FROM HandsPlayers hp
INNER JOIN Hands h on (h.id = hp.handId)
INNER JOIN Gametypes gt on (gt.Id = h.gameTypeId)
INNER JOIN Sites s on (s.Id = gt.siteId)
INNER JOIN Players p on (p.Id = hp.playerId)
WHERE hp.playerId in <player_test>
AND h.handStart <datestest>
ORDER by time"""
#################################### ####################################
# Queries to rebuild/modify hudcache # Queries to rebuild/modify hudcache
@ -2656,6 +2942,7 @@ class Sql:
,hc_position ,hc_position
,hp.tourneyTypeId ,hp.tourneyTypeId
,date_format(h.handStart, 'd%y%m%d') ,date_format(h.handStart, 'd%y%m%d')
>>>>>>> 28ca49d592c8e706ad6ee58dd26655bcc33fc5fb:pyfpdb/SQL.py
""" """
elif db_server == 'postgresql': elif db_server == 'postgresql':
self.query['rebuildHudCache'] = """ self.query['rebuildHudCache'] = """

View File

@ -238,7 +238,8 @@ def discover_nt_by_name(c, tablename):
try: try:
# maybe it's better to make global titles[hwnd] decoding? # maybe it's better to make global titles[hwnd] decoding?
# this can blow up in XP on some windows, eg firefox displaying http://docs.python.org/tutorial/classes.html # this can blow up in XP on some windows, eg firefox displaying http://docs.python.org/tutorial/classes.html
if not tablename.lower() in titles[hwnd].decode(LOCALE_ENCODING).lower(): continue if not tablename.lower() in titles[hwnd].decode(LOCALE_ENCODING).lower():
continue
except: except:
continue continue
if 'History for table:' in titles[hwnd]: continue # Everleaf Network HH viewer window if 'History for table:' in titles[hwnd]: continue # Everleaf Network HH viewer window
@ -246,8 +247,8 @@ def discover_nt_by_name(c, tablename):
if 'Chat:' in titles[hwnd]: continue # Some sites (FTP? PS? Others?) have seperable or seperately constructed chat windows if 'Chat:' in titles[hwnd]: continue # Some sites (FTP? PS? Others?) have seperable or seperately constructed chat windows
if ' - Table ' in titles[hwnd]: continue # Absolute table Chat window.. sigh. TODO: Can we tell what site we're trying to discover for somehow in here, so i can limit this check just to AP searches? if ' - Table ' in titles[hwnd]: continue # Absolute table Chat window.. sigh. TODO: Can we tell what site we're trying to discover for somehow in here, so i can limit this check just to AP searches?
temp = decode_windows(c, titles[hwnd], hwnd) temp = decode_windows(c, titles[hwnd], hwnd)
#print "attach to window", temp print "attach to window", temp
return decode_windows(c, titles[hwnd], hwnd) return temp
return None return None
def discover_nt_tournament(c, tour_number, tab_number): def discover_nt_tournament(c, tour_number, tab_number):
@ -257,9 +258,12 @@ def discover_nt_tournament(c, tour_number, tab_number):
titles ={} titles ={}
win32gui.EnumWindows(win_enum_handler, titles) win32gui.EnumWindows(win_enum_handler, titles)
for hwnd in titles: for hwnd in titles:
if 'Chat:' in titles[hwnd]: continue # Some sites (FTP? PS? Others?) have seperable or seperately constructed chat windows # Some sites (FTP? PS? Others?) have seperable or seperately constructed chat windows
if 'History for table:' in titles[hwnd]: continue # Everleaf Network HH viewer window if 'Chat:' in titles[hwnd]: continue
if 'HUD:' in titles[hwnd]: continue # FPDB HUD window # Everleaf Network HH viewer window
if 'History for table:' in titles[hwnd]: continue
# FPDB HUD window
if 'HUD:' in titles[hwnd]: continue
if re.search(search_string, titles[hwnd]): if re.search(search_string, titles[hwnd]):
return decode_windows(c, titles[hwnd], hwnd) return decode_windows(c, titles[hwnd], hwnd)
@ -268,18 +272,30 @@ def discover_nt_tournament(c, tour_number, tab_number):
def get_nt_exe(hwnd): def get_nt_exe(hwnd):
"""Finds the name of the executable that the given window handle belongs to.""" """Finds the name of the executable that the given window handle belongs to."""
# Request privileges to enable "debug process", so we can later use PROCESS_VM_READ, retardedly required to GetModuleFileNameEx() # Request privileges to enable "debug process", so we can later use
# PROCESS_VM_READ, retardedly required to GetModuleFileNameEx()
priv_flags = win32security.TOKEN_ADJUST_PRIVILEGES | win32security.TOKEN_QUERY priv_flags = win32security.TOKEN_ADJUST_PRIVILEGES | win32security.TOKEN_QUERY
hToken = win32security.OpenProcessToken (win32api.GetCurrentProcess(), priv_flags) hToken = win32security.OpenProcessToken (win32api.GetCurrentProcess(),
priv_flags)
# enable "debug process" # enable "debug process"
privilege_id = win32security.LookupPrivilegeValue (None, win32security.SE_DEBUG_NAME) privilege_id = win32security.LookupPrivilegeValue(None,
old_privs = win32security.AdjustTokenPrivileges (hToken, 0, [(privilege_id, win32security.SE_PRIVILEGE_ENABLED)]) win32security.SE_DEBUG_NAME)
old_privs = win32security.AdjustTokenPrivileges(hToken, 0,
[(privilege_id,
win32security.SE_PRIVILEGE_ENABLED)])
# Open the process, and query it's filename # Open the process, and query it's filename
processid = win32process.GetWindowThreadProcessId(hwnd) processid = win32process.GetWindowThreadProcessId(hwnd)
pshandle = win32api.OpenProcess(win32con.PROCESS_QUERY_INFORMATION | win32con.PROCESS_VM_READ, False, processid[1]) pshandle = win32api.OpenProcess(win32con.PROCESS_QUERY_INFORMATION |
win32con.PROCESS_VM_READ, False,
processid[1])
try:
exename = win32process.GetModuleFileNameEx(pshandle, 0) exename = win32process.GetModuleFileNameEx(pshandle, 0)
except pywintypes.error:
# insert code to call GetProcessImageName if we can find it..
# returning None from here will hopefully break all following code
exename = None
finally:
# clean up # clean up
win32api.CloseHandle(pshandle) win32api.CloseHandle(pshandle)
win32api.CloseHandle(hToken) win32api.CloseHandle(hToken)
@ -305,6 +321,8 @@ def decode_windows(c, title, hwnd):
info['width'] = int( width ) - 2*b_width info['width'] = int( width ) - 2*b_width
info['height'] = int( height ) - b_width - tb_height info['height'] = int( height ) - b_width - tb_height
info['exe'] = get_nt_exe(hwnd) info['exe'] = get_nt_exe(hwnd)
print "get_nt_exe returned ", info['exe']
# TODO: 'width' here is all sorts of screwed up.
title_bits = re.split(' - ', info['title']) title_bits = re.split(' - ', info['title'])
info['name'] = title_bits[0] info['name'] = title_bits[0]

View File

@ -78,7 +78,7 @@ class fpdb_db:
if use_pool: if use_pool:
MySQLdb = pool.manage(MySQLdb, pool_size=5) MySQLdb = pool.manage(MySQLdb, pool_size=5)
# 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)
#TODO: Add port option #TODO: Add port option
# except: # except:
# raise FpdbMySQLFailedError("MySQL connection failed") # raise FpdbMySQLFailedError("MySQL connection failed")