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

This commit is contained in:
Eric Blade 2010-01-22 00:30:07 -05:00
commit 9be7f308a6
25 changed files with 1586 additions and 3410 deletions

116
pyfpdb/AlchemyFacilities.py Normal file
View File

@ -0,0 +1,116 @@
# -*- coding: utf-8 -*-
from decimal import Decimal
from sqlalchemy import types
from sqlalchemy.orm.exc import NoResultFound
from sqlalchemy.exc import IntegrityError
import Card
class CardColumn(types.TypeDecorator):
"""Stores cards as smallints
Automatically converts values like '9h' to smallint
>>> CardColumn().process_bind_param( 'Td', '' )
22
>>> CardColumn().process_bind_param( u'Td', '' )
22
>>> CardColumn().process_bind_param( 22, '' )
22
>>> CardColumn().process_result_value( 22, '' )
'Td'
"""
impl = types.SmallInteger
def process_bind_param(self, value, dialect):
if value is None or isinstance(value, int):
return value
elif isinstance(value, basestring) and len(value) == 2:
return Card.encodeCard(str(value))
else:
raise Exception, "Incorrect card value: " + repr(value)
def process_result_value(self, value, dialect):
return Card.valueSuitFromCard( value )
class MoneyColumn(types.TypeDecorator):
"""Stores money: bets, pots, etc
Understands:
Decimal as real amount
int as amount mupliplied by 100
string as decimal
Returns Decimal
>>> MoneyColumn().process_bind_param( 230, '' )
230
>>> MoneyColumn().process_bind_param( Decimal('2.30'), '' )
230
>>> MoneyColumn().process_bind_param( '2.30', '' )
230
>>> MoneyColumn().process_result_value( 230, '' )
Decimal('2.3')
"""
impl = types.Integer
def process_bind_param(self, value, dialect):
if value is None or isinstance(value, int):
return value
elif isinstance(value, basestring) or isinstance(value, Decimal):
return int(Decimal(value)*100)
else:
raise Exception, "Incorrect amount:" + repr(value)
def process_result_value(self, value, dialect):
if value is None:
return None
return Decimal(value)/100
class BigIntColumn(types.TypeDecorator, types.Integer):
"""Representing db-independent big integer """
# Integer inheritance required for auto_increment flag
impl = types.Integer
def load_dialect_impl(self, dialect):
from sqlalchemy import databases
if dialect.name == 'mysql':
return databases.mysql.MSBigInteger()
elif dialect.name == 'postgres':
return databases.mysql.PGBigInteger()
return types.Integer()
class MappedBase(object):
"""Provide dummy contrcutor"""
def __init__(self, **kwargs):
for k, v in kwargs.iteritems():
setattr(self, k, v)
def get_columns_names(self):
return [i.name for i in self._sa_class_manager.mapper.c]
def get_or_create(klass, session, **kwargs):
"""
Looks up an object with the given kwargs, creating one if necessary.
Returns a tuple of (object, created), where created is a boolean
specifying whether an object was created.
"""
assert kwargs, \
'get_or_create() must be passed at least one keyword argument'
try:
return session.query(klass).filter_by(**kwargs).one(), False
except NoResultFound:
try:
obj = klass(**kwargs)
session.add(obj)
session.flush()
return obj, True
except IntegrityError:
return session.query(klass).filter_by(**kwargs).one(), False

464
pyfpdb/AlchemyMappings.py Normal file
View File

@ -0,0 +1,464 @@
# -*- coding: utf-8 -*-
"""@package AlchemyMappings
This package contains all classes to be mapped and mappers themselves
"""
import logging
import re
from decimal import Decimal
from sqlalchemy.orm import mapper, relation, reconstructor
from sqlalchemy.sql import select
from collections import defaultdict
from AlchemyTables import *
from AlchemyFacilities import get_or_create, MappedBase
from DerivedStats import DerivedStats
from Exceptions import IncompleteHandError, FpdbError
class Player(MappedBase):
"""Class reflecting Players db table"""
@staticmethod
def get_or_create(session, siteId, name):
return get_or_create(Player, session, siteId=siteId, name=name)[0]
def __str__(self):
return '<Player "%s" on %s>' % (self.name, self.site and self.site.name)
class Gametype(MappedBase):
"""Class reflecting Gametypes db table"""
@staticmethod
def get_or_create(session, siteId, gametype):
map = zip(
['type', 'base', 'category', 'limitType', 'smallBlind', 'bigBlind', 'smallBet', 'bigBet'],
['type', 'base', 'category', 'limitType', 'sb', 'bb', 'dummy', 'dummy', ])
gametype = dict([(new, gametype.get(old)) for new, old in map ])
hilo = "h"
if gametype['category'] in ('studhilo', 'omahahilo'):
hilo = "s"
elif gametype['category'] in ('razz','27_3draw','badugi'):
hilo = "l"
gametype['hiLo'] = hilo
for f in ['smallBlind', 'bigBlind', 'smallBet', 'bigBet']:
if gametype[f] is None:
gametype[f] = 0
gametype[f] = int(Decimal(gametype[f])*100)
gametype['siteId'] = siteId
return get_or_create(Gametype, session, **gametype)[0]
class HandActions(object):
"""Class reflecting HandsActions db table"""
def initFromImportedHand(self, hand, actions):
self.hand = hand
self.actions = {}
for street, street_actions in actions.iteritems():
self.actions[street] = []
for v in street_actions:
hp = hand.handplayers_by_name[v[0]]
self.actions[street].append({'street': street, 'pid': hp.id, 'seat': hp.seatNo, 'action':v})
@property
def flat_actions(self):
actions = []
for street in self.hand.allStreets:
actions += self.actions[street]
return actions
class HandInternal(DerivedStats):
"""Class reflecting Hands db table"""
def parseImportedHandStep1(self, hand):
"""Extracts values to insert into from hand returned by HHC. No db is needed he"""
hand.players = hand.getAlivePlayers()
# also save some data for step2. Those fields aren't in Hands table
self.siteId = hand.siteId
self.gametype_dict = hand.gametype
self.attachHandPlayers(hand)
self.attachActions(hand)
self.assembleHands(hand)
self.assembleHandsPlayers(hand)
def parseImportedHandStep2(self, session):
"""Fetching ids for gametypes and players"""
gametype = Gametype.get_or_create(session, self.siteId, self.gametype_dict)
self.gametypeId = gametype.id
for hp in self.handPlayers:
hp.playerId = Player.get_or_create(session, self.siteId, hp.name).id
def getPlayerByName(self, name):
if not hasattr(self, 'handplayers_by_name'):
self.handplayers_by_name = {}
for hp in self.handPlayers:
pname = getattr(hp, 'name', None) or hp.player.name
self.handplayers_by_name[pname] = hp
return self.handplayers_by_name[name]
def attachHandPlayers(self, hand):
"""Fill HandInternal.handPlayers list. Create self.handplayers_by_name"""
hand.noSb = getattr(hand, 'noSb', None)
if hand.noSb is None and self.gametype_dict['base']=='hold':
saw_sb = False
for action in hand.actions[hand.actionStreets[0]]: # blindsantes
if action[1] == 'posts' and action[2] == 'small blind' and action[0] is not None:
saw_sb = True
hand.noSb = saw_sb
self.handplayers_by_name = {}
for seat, name, chips in hand.players:
p = HandPlayer(hand = self, imported_hand=hand, seatNo=seat,
name=name, startCash=chips)
self.handplayers_by_name[name] = p
def attachActions(self, hand):
"""Create HandActions object"""
a = HandActions()
a.initFromImportedHand(self, hand.actions)
def parseImportedTournament(self, hand, session):
"""Fetching tourney, its type and players
Must be called after Step2
"""
if self.gametype_dict['type'] != 'tour': return
# check for consistense
for i in ('buyin', 'tourNo'):
if not hasattr(hand, i):
raise IncompleteHandError(
"Field '%s' required for tournaments" % i, self.id, hand )
# repair old-style buyin value
m = re.match('\$(\d+)\+\$(\d+)', hand.buyin)
if m is not None:
hand.buyin, self.fee = m.groups()
# fetch tourney type
tour_type_hand2db = {
'buyin': 'buyin',
'fee': 'fee',
'speed': 'speed',
'maxSeats': 'maxseats',
'knockout': 'isKO',
'rebuyOrAddon': 'isRebuy',
'headsUp': 'isHU',
'shootout': 'isShootout',
'matrix': 'isMatrix',
'sng': 'isSNG',
}
tour_type_index = dict([
( i_db, getattr(hand, i_hand, None) )
for i_db, i_hand in tour_type_hand2db.iteritems()
])
tour_type_index['siteId'] = self.siteId
tour_type = TourneyType.get_or_create(session, **tour_type_index)
# fetch and update tourney
tour = Tourney.get_or_create(session, hand.tourNo, tour_type.id)
cols = tour.get_columns_names()
for col in cols:
hand_val = getattr(hand, col, None)
if col in ('id', 'tourneyTypeId', 'comment', 'commentTs') or hand_val is None:
continue
db_val = getattr(tour, col, None)
if db_val is None:
setattr(tour, col, hand_val)
elif col == 'koBounty':
setattr(tour, col, max(db_val, hand_val))
elif col == 'tourStartTime' and hand.handStart:
setattr(tour, col, min(db_val, hand.handStart))
if tour.entries is None and tour_type.sng:
tour.entries = tour_type.maxSeats
# fetch and update tourney players
for hp in self.handPlayers:
tp = TourneyPlayer.get_or_create(session, tour.id, hp.playerId)
# FIXME: other TourneysPlayers should be added here
session.flush()
def isDuplicate(self, session):
"""Checks if current hand already exists in db
siteHandNo ans gameTypeId have to be setted
"""
return session.query(HandInternal).filter_by(
siteHandNo=self.siteHandNo, gametypeId=self.gametypeId).count()!=0
def __str__(self):
s = list()
for i in self._sa_class_manager.mapper.c:
s.append('%25s %s' % (i, getattr(self, i.name)))
s+=['', '']
for i,p in enumerate(self.handPlayers):
s.append('%d. %s' % (i, p.name or '???'))
s.append(str(p))
return '\n'.join(s)
@property
def boardcards(self):
cards = []
for i in range(5):
cards.append(getattr(self, 'boardcard%d' % (i+1), None))
return filter(bool, cards)
@property
def HandClass(self):
"""Return HoldemOmahaHand or something like this"""
import Hand
if self.gametype.base == 'hold':
return Hand.HoldemOmahaHand
elif self.gametype.base == 'draw':
return Hand.DrawHand
elif self.gametype.base == 'stud':
return Hand.StudHand
raise Exception("Unknow gametype.base: '%s'" % self.gametype.base)
@property
def allStreets(self):
return self.HandClass.allStreets
@property
def actionStreets(self):
return self.HandClass.actionStreets
class HandPlayer(MappedBase):
"""Class reflecting HandsPlayers db table"""
def __init__(self, **kwargs):
if 'imported_hand' in kwargs and 'seatNo' in kwargs:
imported_hand = kwargs.pop('imported_hand')
self.position = self.getPosition(imported_hand, kwargs['seatNo'])
super(HandPlayer, self).__init__(**kwargs)
@reconstructor
def init_on_load(self):
self.name = self.player.name
@staticmethod
def getPosition(hand, seat):
"""Returns position value like 'B', 'S', '0', '1', ...
>>> class A(object): pass
...
>>> A.noSb = False
>>> A.maxseats = 6
>>> A.buttonpos = 2
>>> A.gametype = {'base': 'hold'}
>>> A.players = [(i, None, None) for i in (2, 4, 5, 6)]
>>> HandPlayer.getPosition(A, 6) # cut off
'1'
>>> HandPlayer.getPosition(A, 2) # button
'0'
>>> HandPlayer.getPosition(A, 4) # SB
'S'
>>> HandPlayer.getPosition(A, 5) # BB
'B'
>>> A.noSb = True
>>> HandPlayer.getPosition(A, 5) # MP3
'2'
>>> HandPlayer.getPosition(A, 6) # cut off
'1'
>>> HandPlayer.getPosition(A, 2) # button
'0'
>>> HandPlayer.getPosition(A, 4) # BB
'B'
"""
from itertools import chain
if hand.gametype['base'] == 'stud':
# FIXME: i've never played stud so plz check & del comment \\grindi
bringin = None
for action in chain(*[self.actions[street] for street in hand.allStreets]):
if action[1]=='bringin':
bringin = action[0]
break
if bringin is None:
raise Exception, "Cannot find bringin"
# name -> seat
bringin = int(filter(lambda p: p[1]==bringin, bringin)[0])
seat = (int(seat) - int(bringin))%int(hand.maxseats)
return str(seat)
else:
seats_occupied = sorted([seat_ for seat_, name, chips in hand.players], key=int)
if hand.buttonpos not in seats_occupied:
# i.e. something like
# Seat 3: PlayerX ($0), is sitting out
# The button is in seat #3
hand.buttonpos = max(seats_occupied,
key = lambda s: int(s)
if int(s) <= int(hand.buttonpos)
else int(s) - int(hand.maxseats)
)
seats_occupied = sorted(seats_occupied,
key = lambda seat_: (
- seats_occupied.index(seat_)
+ seats_occupied.index(hand.buttonpos)
+ 2) % len(seats_occupied)
)
# now (if SB presents) seats_occupied contains seats in order: BB, SB, BU, CO, MP3, ...
if hand.noSb:
# fix order in the case nosb
seats_occupied = seats_occupied[1:] + seats_occupied[0:1]
seats_occupied.insert(1, -1)
seat = seats_occupied.index(seat)
if seat == 0:
return 'B'
elif seat == 1:
return 'S'
else:
return str(seat-2)
@property
def cards(self):
cards = []
for i in range(7):
cards.append(getattr(self, 'card%d' % (i+1), None))
return filter(bool, cards)
def __str__(self):
s = list()
for i in self._sa_class_manager.mapper.c:
s.append('%45s %s' % (i, getattr(self, i.name)))
return '\n'.join(s)
class Site(object):
"""Class reflecting Players db table"""
INITIAL_DATA = [
(1 , 'Full Tilt Poker','USD'),
(2 , 'PokerStars', 'USD'),
(3 , 'Everleaf', 'USD'),
(4 , 'Win2day', 'USD'),
(5 , 'OnGame', 'USD'),
(6 , 'UltimateBet', 'USD'),
(7 , 'Betfair', 'USD'),
(8 , 'Absolute', 'USD'),
(9 , 'PartyPoker', 'USD'),
(10, 'Partouche', 'EUR'),
]
INITIAL_DATA_KEYS = ('id', 'name', 'currency')
INITIAL_DATA_DICTS = [ dict(zip(INITIAL_DATA_KEYS, datum)) for datum in INITIAL_DATA ]
@classmethod
def insert_initial(cls, connection):
connection.execute(sites_table.insert(), cls.INITIAL_DATA_DICTS)
class Tourney(MappedBase):
"""Class reflecting Tourneys db table"""
@classmethod
def get_or_create(cls, session, siteTourneyNo, tourneyTypeId):
"""Fetch tourney by index or creates one if none. """
return get_or_create(cls, session, siteTourneyNo=siteTourneyNo,
tourneyTypeId=tourneyTypeId)[0]
class TourneyType(MappedBase):
"""Class reflecting TourneysType db table"""
@classmethod
def get_or_create(cls, session, **kwargs):
"""Fetch tourney type by index or creates one if none
Required kwargs:
buyin fee speed maxSeats knockout
rebuyOrAddon headsUp shootout matrix sng
"""
return get_or_create(cls, session, **kwargs)[0]
class TourneyPlayer(MappedBase):
"""Class reflecting TourneysPlayers db table"""
@classmethod
def get_or_create(cls, session, tourneyId, playerId):
"""Fetch tourney player by index or creates one if none """
return get_or_create(cls, session, tourneyId=tourneyId, playerId=playerId)
class Version(object):
"""Provides read/write access for version var"""
CURRENT_VERSION = 120 # db version for current release
# 119 - first alchemy version
# 120 - add m_factor
conn = None
ver = None
def __init__(self, connection=None):
if self.__class__.conn is None:
self.__class__.conn = connection
@classmethod
def is_wrong(cls):
return cls.get() != cls.CURRENT_VERSION
@classmethod
def get(cls):
if cls.ver is None:
try:
cls.ver = cls.conn.execute(select(['version'], settings_table)).fetchone()[0]
except:
return None
return cls.ver
@classmethod
def set(cls, value):
if cls.conn.execute(settings_table.select()).rowcount==0:
cls.conn.execute(settings_table.insert(), version=value)
else:
cls.conn.execute(settings_table.update().values(version=value))
cls.ver = value
@classmethod
def set_initial(cls):
cls.set(cls.CURRENT_VERSION)
mapper (Gametype, gametypes_table, properties={
'hands': relation(HandInternal, backref='gametype'),
})
mapper (Player, players_table, properties={
'playerHands': relation(HandPlayer, backref='player'),
'playerTourney': relation(TourneyPlayer, backref='player'),
})
mapper (Site, sites_table, properties={
'gametypes': relation(Gametype, backref = 'site'),
'players': relation(Player, backref = 'site'),
'tourneyTypes': relation(TourneyType, backref = 'site'),
})
mapper (HandActions, hands_actions_table, properties={})
mapper (HandInternal, hands_table, properties={
'handPlayers': relation(HandPlayer, backref='hand'),
'actions_all': relation(HandActions, backref='hand', uselist=False),
})
mapper (HandPlayer, hands_players_table, properties={})
mapper (Tourney, tourneys_table)
mapper (TourneyType, tourney_types_table, properties={
'tourneys': relation(Tourney, backref='type'),
})
mapper (TourneyPlayer, tourneys_players_table)
class LambdaKeyDict(defaultdict):
"""Operates like defaultdict but passes key argument to the factory function"""
def __missing__(key):
return self.default_factory(key)

438
pyfpdb/AlchemyTables.py Normal file
View File

@ -0,0 +1,438 @@
# -*- coding: utf-8 -*-
"""@package AlchemyTables
Contains all sqlalchemy tables
"""
from sqlalchemy import Table, Float, Column, Integer, String, MetaData, \
ForeignKey, Boolean, SmallInteger, DateTime, Text, Index, CHAR, \
PickleType, Unicode
from AlchemyFacilities import CardColumn, MoneyColumn, BigIntColumn
metadata = MetaData()
autorates_table = Table('Autorates', metadata,
Column('id', Integer, primary_key=True, nullable=False),
Column('playerId', Integer, ForeignKey("Players.id"), nullable=False),
Column('gametypeId', SmallInteger, ForeignKey("Gametypes.id"), nullable=False),
Column('description', String(50), nullable=False),
Column('shortDesc', CHAR(8), nullable=False),
Column('ratingTime', DateTime, nullable=False),
Column('handCount', Integer, nullable=False),
mysql_charset='utf8',
mysql_engine='InnoDB',
)
gametypes_table = Table('Gametypes', metadata,
Column('id', SmallInteger, primary_key=True),
Column('siteId', SmallInteger, ForeignKey("Sites.id"), nullable=False), # SMALLINT
Column('type', String(4), nullable=False), # char(4) NOT NULL
Column('base', String(4), nullable=False), # char(4) NOT NULL
Column('category', String(9), nullable=False), # varchar(9) NOT NULL
Column('limitType', CHAR(2), nullable=False), # char(2) NOT NULL
Column('hiLo', CHAR(1), nullable=False), # char(1) NOT NULL
Column('smallBlind', Integer(3)), # int
Column('bigBlind', Integer(3)), # int
Column('smallBet', Integer(3), nullable=False), # int NOT NULL
Column('bigBet', Integer(3), nullable=False), # int NOT NULL
mysql_charset='utf8',
mysql_engine='InnoDB',
)
hands_table = Table('Hands', metadata,
Column('id', BigIntColumn, primary_key=True),
Column('tableName', String(30), nullable=False),
Column('siteHandNo', BigIntColumn, nullable=False),
Column('gametypeId', SmallInteger, ForeignKey('Gametypes.id'), nullable=False),
Column('handStart', DateTime, nullable=False),
Column('importTime', DateTime, nullable=False),
Column('seats', SmallInteger, nullable=False),
Column('maxSeats', SmallInteger, nullable=False),
Column('boardcard1', CardColumn),
Column('boardcard2', CardColumn),
Column('boardcard3', CardColumn),
Column('boardcard4', CardColumn),
Column('boardcard5', CardColumn),
Column('texture', SmallInteger),
Column('playersVpi', SmallInteger, nullable=False),
Column('playersAtStreet1', SmallInteger, nullable=False, default=0),
Column('playersAtStreet2', SmallInteger, nullable=False, default=0),
Column('playersAtStreet3', SmallInteger, nullable=False, default=0),
Column('playersAtStreet4', SmallInteger, nullable=False, default=0),
Column('playersAtShowdown',SmallInteger, nullable=False),
Column('street0Raises', SmallInteger, nullable=False),
Column('street1Raises', SmallInteger, nullable=False),
Column('street2Raises', SmallInteger, nullable=False),
Column('street3Raises', SmallInteger, nullable=False),
Column('street4Raises', SmallInteger, nullable=False),
Column('street1Pot', MoneyColumn),
Column('street2Pot', MoneyColumn),
Column('street3Pot', MoneyColumn),
Column('street4Pot', MoneyColumn),
Column('showdownPot', MoneyColumn),
Column('comment', Text),
Column('commentTs', DateTime),
mysql_charset='utf8',
mysql_engine='InnoDB',
)
Index('siteHandNo', hands_table.c.siteHandNo, hands_table.c.gametypeId, unique=True)
hands_actions_table = Table('HandsActions', metadata,
Column('id', BigIntColumn, primary_key=True, nullable=False),
Column('handId', BigIntColumn, ForeignKey("Hands.id"), nullable=False),
Column('actions', PickleType, nullable=False),
mysql_charset='utf8',
mysql_engine='InnoDB',
)
hands_players_table = Table('HandsPlayers', metadata,
Column('id', BigIntColumn, primary_key=True),
Column('handId', BigIntColumn, ForeignKey("Hands.id"), nullable=False),
Column('playerId', Integer, ForeignKey("Players.id"), nullable=False),
Column('startCash', MoneyColumn),
Column('position', CHAR(1)), #CHAR(1)
Column('seatNo', SmallInteger, nullable=False), #SMALLINT NOT NULL
Column('card1', CardColumn), #smallint NOT NULL,
Column('card2', CardColumn), #smallint NOT NULL
Column('card3', CardColumn), #smallint
Column('card4', CardColumn), #smallint
Column('card5', CardColumn), #smallint
Column('card6', CardColumn), #smallint
Column('card7', CardColumn), #smallint
Column('startCards', SmallInteger), #smallint
Column('m_factor', Integer), # null for ring games
Column('ante', MoneyColumn), #INT
Column('winnings', MoneyColumn, nullable=False, default=0), #int NOT NULL
Column('rake', MoneyColumn, nullable=False, default=0), #int NOT NULL
Column('totalProfit', MoneyColumn), #INT
Column('comment', Text), #text
Column('commentTs', DateTime), #DATETIME
Column('tourneysPlayersId', BigIntColumn, ForeignKey("TourneysPlayers.id"),), #BIGINT UNSIGNED
Column('tourneyTypeId', Integer, ForeignKey("TourneyTypes.id"),), #SMALLINT UNSIGNED
Column('wonWhenSeenStreet1',Float), #FLOAT
Column('wonWhenSeenStreet2',Float), #FLOAT
Column('wonWhenSeenStreet3',Float), #FLOAT
Column('wonWhenSeenStreet4',Float), #FLOAT
Column('wonAtSD', Float), #FLOAT
Column('street0VPI', Boolean), #BOOLEAN
Column('street0Aggr', Boolean), #BOOLEAN
Column('street0_3BChance', Boolean), #BOOLEAN
Column('street0_3BDone', Boolean), #BOOLEAN
Column('street0_4BChance', Boolean), #BOOLEAN
Column('street0_4BDone', Boolean), #BOOLEAN
Column('other3BStreet0', Boolean), #BOOLEAN
Column('other4BStreet0', Boolean), #BOOLEAN
Column('street1Seen', Boolean), #BOOLEAN
Column('street2Seen', Boolean), #BOOLEAN
Column('street3Seen', Boolean), #BOOLEAN
Column('street4Seen', Boolean), #BOOLEAN
Column('sawShowdown', Boolean), #BOOLEAN
Column('street1Aggr', Boolean), #BOOLEAN
Column('street2Aggr', Boolean), #BOOLEAN
Column('street3Aggr', Boolean), #BOOLEAN
Column('street4Aggr', Boolean), #BOOLEAN
Column('otherRaisedStreet0',Boolean), #BOOLEAN
Column('otherRaisedStreet1',Boolean), #BOOLEAN
Column('otherRaisedStreet2',Boolean), #BOOLEAN
Column('otherRaisedStreet3',Boolean), #BOOLEAN
Column('otherRaisedStreet4',Boolean), #BOOLEAN
Column('foldToOtherRaisedStreet0', Boolean), #BOOLEAN
Column('foldToOtherRaisedStreet1', Boolean), #BOOLEAN
Column('foldToOtherRaisedStreet2', Boolean), #BOOLEAN
Column('foldToOtherRaisedStreet3', Boolean), #BOOLEAN
Column('foldToOtherRaisedStreet4', Boolean), #BOOLEAN
Column('stealAttemptChance', Boolean), #BOOLEAN
Column('stealAttempted', Boolean), #BOOLEAN
Column('foldBbToStealChance', Boolean), #BOOLEAN
Column('foldedBbToSteal', Boolean), #BOOLEAN
Column('foldSbToStealChance', Boolean), #BOOLEAN
Column('foldedSbToSteal', Boolean), #BOOLEAN
Column('street1CBChance', Boolean), #BOOLEAN
Column('street1CBDone', Boolean), #BOOLEAN
Column('street2CBChance', Boolean), #BOOLEAN
Column('street2CBDone', Boolean), #BOOLEAN
Column('street3CBChance', Boolean), #BOOLEAN
Column('street3CBDone', Boolean), #BOOLEAN
Column('street4CBChance', Boolean), #BOOLEAN
Column('street4CBDone', Boolean), #BOOLEAN
Column('foldToStreet1CBChance', Boolean), #BOOLEAN
Column('foldToStreet1CBDone', Boolean), #BOOLEAN
Column('foldToStreet2CBChance', Boolean), #BOOLEAN
Column('foldToStreet2CBDone', Boolean), #BOOLEAN
Column('foldToStreet3CBChance', Boolean), #BOOLEAN
Column('foldToStreet3CBDone', Boolean), #BOOLEAN
Column('foldToStreet4CBChance', Boolean), #BOOLEAN
Column('foldToStreet4CBDone', Boolean), #BOOLEAN
Column('street1CheckCallRaiseChance',Boolean), #BOOLEAN
Column('street1CheckCallRaiseDone', Boolean), #BOOLEAN
Column('street2CheckCallRaiseChance',Boolean), #BOOLEAN
Column('street2CheckCallRaiseDone', Boolean), #BOOLEAN
Column('street3CheckCallRaiseChance',Boolean), #BOOLEAN
Column('street3CheckCallRaiseDone', Boolean), #BOOLEAN
Column('street4CheckCallRaiseChance',Boolean), #BOOLEAN
Column('street4CheckCallRaiseDone', Boolean), #BOOLEAN
Column('street0Calls', SmallInteger), #TINYINT
Column('street1Calls', SmallInteger), #TINYINT
Column('street2Calls', SmallInteger), #TINYINT
Column('street3Calls', SmallInteger), #TINYINT
Column('street4Calls', SmallInteger), #TINYINT
Column('street0Bets', SmallInteger), #TINYINT
Column('street1Bets', SmallInteger), #TINYINT
Column('street2Bets', SmallInteger), #TINYINT
Column('street3Bets', SmallInteger), #TINYINT
Column('street4Bets', SmallInteger), #TINYINT
Column('street0Raises', SmallInteger), #TINYINT
Column('street1Raises', SmallInteger), #TINYINT
Column('street2Raises', SmallInteger), #TINYINT
Column('street3Raises', SmallInteger), #TINYINT
Column('street4Raises', SmallInteger), #TINYINT
Column('actionString', String(15)), #VARCHAR(15)
mysql_charset='utf8',
mysql_engine='InnoDB',
)
hud_cache_table = Table('HudCache', metadata,
Column('id', BigIntColumn, primary_key=True),
Column('gametypeId', SmallInteger, ForeignKey("Gametypes.id"), nullable=False), # SMALLINT
Column('playerId', Integer, ForeignKey("Players.id"), nullable=False), # SMALLINT
Column('activeSeats', SmallInteger, nullable=False), # SMALLINT NOT NULL
Column('position', CHAR(1)), # CHAR(1)
Column('tourneyTypeId', Integer, ForeignKey("TourneyTypes.id") ), # SMALLINT
Column('styleKey', CHAR(7), nullable=False), # CHAR(7) NOT NULL
Column('m_factor', Integer),
Column('HDs', Integer, nullable=False), # INT NOT NULL
Column('wonWhenSeenStreet1', Float), # FLOAT
Column('wonWhenSeenStreet2', Float), # FLOAT
Column('wonWhenSeenStreet3', Float), # FLOAT
Column('wonWhenSeenStreet4', Float), # FLOAT
Column('wonAtSD', Float), # FLOAT
Column('street0VPI', Integer), # INT
Column('street0Aggr', Integer), # INT
Column('street0_3BChance', Integer), # INT
Column('street0_3BDone', Integer), # INT
Column('street0_4BChance', Integer), # INT
Column('street0_4BDone', Integer), # INT
Column('other3BStreet0', Integer), # INT
Column('other4BStreet0', Integer), # INT
Column('street1Seen', Integer), # INT
Column('street2Seen', Integer), # INT
Column('street3Seen', Integer), # INT
Column('street4Seen', Integer), # INT
Column('sawShowdown', Integer), # INT
Column('street1Aggr', Integer), # INT
Column('street2Aggr', Integer), # INT
Column('street3Aggr', Integer), # INT
Column('street4Aggr', Integer), # INT
Column('otherRaisedStreet0', Integer), # INT
Column('otherRaisedStreet1', Integer), # INT
Column('otherRaisedStreet2', Integer), # INT
Column('otherRaisedStreet3', Integer), # INT
Column('otherRaisedStreet4', Integer), # INT
Column('foldToOtherRaisedStreet0', Integer), # INT
Column('foldToOtherRaisedStreet1', Integer), # INT
Column('foldToOtherRaisedStreet2', Integer), # INT
Column('foldToOtherRaisedStreet3', Integer), # INT
Column('foldToOtherRaisedStreet4', Integer), # INT
Column('stealAttemptChance', Integer), # INT
Column('stealAttempted', Integer), # INT
Column('foldBbToStealChance', Integer), # INT
Column('foldedBbToSteal', Integer), # INT
Column('foldSbToStealChance', Integer), # INT
Column('foldedSbToSteal', Integer), # INT
Column('street1CBChance', Integer), # INT
Column('street1CBDone', Integer), # INT
Column('street2CBChance', Integer), # INT
Column('street2CBDone', Integer), # INT
Column('street3CBChance', Integer), # INT
Column('street3CBDone', Integer), # INT
Column('street4CBChance', Integer), # INT
Column('street4CBDone', Integer), # INT
Column('foldToStreet1CBChance', Integer), # INT
Column('foldToStreet1CBDone', Integer), # INT
Column('foldToStreet2CBChance', Integer), # INT
Column('foldToStreet2CBDone', Integer), # INT
Column('foldToStreet3CBChance', Integer), # INT
Column('foldToStreet3CBDone', Integer), # INT
Column('foldToStreet4CBChance', Integer), # INT
Column('foldToStreet4CBDone', Integer), # INT
Column('totalProfit', Integer), # INT
Column('street1CheckCallRaiseChance', Integer), # INT
Column('street1CheckCallRaiseDone', Integer), # INT
Column('street2CheckCallRaiseChance', Integer), # INT
Column('street2CheckCallRaiseDone', Integer), # INT
Column('street3CheckCallRaiseChance', Integer), # INT
Column('street3CheckCallRaiseDone', Integer), # INT
Column('street4CheckCallRaiseChance', Integer), # INT
Column('street4CheckCallRaiseDone', Integer), # INT
Column('street0Calls', Integer), # INT
Column('street1Calls', Integer), # INT
Column('street2Calls', Integer), # INT
Column('street3Calls', Integer), # INT
Column('street4Calls', Integer), # INT
Column('street0Bets', Integer), # INT
Column('street1Bets', Integer), # INT
Column('street2Bets', Integer), # INT
Column('street3Bets', Integer), # INT
Column('street4Bets', Integer), # INT
Column('street0Raises', Integer), # INT
Column('street1Raises', Integer), # INT
Column('street2Raises', Integer), # INT
Column('street3Raises', Integer), # INT
Column('street4Raises', Integer), # INT
mysql_charset='utf8',
mysql_engine='InnoDB',
)
players_table = Table('Players', metadata,
Column('id', Integer, primary_key=True),
Column('name', Unicode(32), nullable=False), # VARCHAR(32) CHARACTER SET utf8 NOT NULL
Column('siteId', SmallInteger, ForeignKey("Sites.id"), nullable=False), # SMALLINT
Column('comment', Text), # text
Column('commentTs', DateTime), # DATETIME
mysql_charset='utf8',
mysql_engine='InnoDB',
)
Index('name', players_table.c.name, players_table.c.siteId, unique=True)
settings_table = Table('Settings', metadata,
Column('version', SmallInteger, nullable=False),
mysql_charset='utf8',
mysql_engine='InnoDB',
)
sites_table = Table('Sites', metadata,
Column('id', SmallInteger, primary_key=True),
Column('name', String(32), nullable=False), # varchar(32) NOT NULL
Column('currency', String(3), nullable=False), # char(3) NOT NULL
mysql_charset='utf8',
mysql_engine='InnoDB',
)
tourneys_table = Table('Tourneys', metadata,
Column('id', Integer, primary_key=True),
Column('tourneyTypeId', Integer, ForeignKey("TourneyTypes.id"), nullable=False, default=1),
Column('siteTourneyNo', BigIntColumn, nullable=False), # BIGINT NOT NULL
Column('entries', Integer), # INT NOT NULL
Column('prizepool', Integer), # INT NOT NULL
Column('tourStartTime', DateTime), # DATETIME NOT NULL
Column('tourEndTime', DateTime), # DATETIME
Column('buyinChips', Integer), # INT
Column('tourneyName', String(40)), # varchar(40)
# Mask use : 1=Positionnal Winnings|2=Match1|4=Match2|...|pow(2,n)=Matchn
Column('matrixIdProcessed',SmallInteger, default=0), # TINYINT UNSIGNED DEFAULT 0
Column('rebuyChips', Integer, default=0), # INT DEFAULT 0
Column('addonChips', Integer, default=0), # INT DEFAULT 0
Column('rebuyAmount', MoneyColumn, default=0), # INT DEFAULT 0
Column('addonAmount', MoneyColumn, default=0), # INT DEFAULT 0
Column('totalRebuys', Integer, default=0), # INT DEFAULT 0
Column('totalAddons', Integer, default=0), # INT DEFAULT 0
Column('koBounty', Integer, default=0), # INT DEFAULT 0
Column('comment', Text), # TEXT
Column('commentTs', DateTime), # DATETIME
mysql_charset='utf8',
mysql_engine='InnoDB',
)
Index('siteTourneyNo', tourneys_table.c.siteTourneyNo, tourneys_table.c.tourneyTypeId, unique=True)
tourney_types_table = Table('TourneyTypes', metadata,
Column('id', Integer, primary_key=True),
Column('siteId', SmallInteger, ForeignKey("Sites.id"), nullable=False),
Column('buyin', Integer, nullable=False), # INT NOT NULL
Column('fee', Integer, nullable=False, default=0), # INT NOT NULL
Column('maxSeats', Boolean, nullable=False, default=-1), # INT NOT NULL DEFAULT -1
Column('knockout', Boolean, nullable=False, default=False), # BOOLEAN NOT NULL DEFAULT False
Column('rebuyOrAddon', Boolean, nullable=False, default=False), # BOOLEAN NOT NULL DEFAULT False
Column('speed', String(10)), # varchar(10)
Column('headsUp', Boolean, nullable=False, default=False), # BOOLEAN NOT NULL DEFAULT False
Column('shootout', Boolean, nullable=False, default=False), # BOOLEAN NOT NULL DEFAULT False
Column('matrix', Boolean, nullable=False, default=False), # BOOLEAN NOT NULL DEFAULT False
Column('sng', Boolean, nullable=False, default=False), # BOOLEAN NOT NULL DEFAULT False
mysql_charset='utf8',
mysql_engine='InnoDB',
)
Index('tourneyTypes_all',
tourney_types_table.c.siteId, tourney_types_table.c.buyin, tourney_types_table.c.fee,
tourney_types_table.c.maxSeats, tourney_types_table.c.knockout, tourney_types_table.c.rebuyOrAddon,
tourney_types_table.c.speed, tourney_types_table.c.headsUp, tourney_types_table.c.shootout,
tourney_types_table.c.matrix, tourney_types_table.c.sng)
tourneys_players_table = Table('TourneysPlayers', metadata,
Column('id', BigIntColumn, primary_key=True),
Column('tourneyId', Integer, ForeignKey("Tourneys.id"), nullable=False),
Column('playerId', Integer, ForeignKey("Players.id"), nullable=False),
Column('payinAmount', Integer), # INT NOT NULL
Column('rank', Integer), # INT NOT NULL
Column('winnings', Integer), # INT NOT NULL
Column('nbRebuys', Integer, default=0), # INT DEFAULT 0
Column('nbAddons', Integer, default=0), # INT DEFAULT 0
Column('nbKO', Integer, default=0), # INT DEFAULT 0
Column('comment', Text), # TEXT
Column('commentTs', DateTime), # DATETIME
mysql_charset='utf8',
mysql_engine='InnoDB',
)
Index('tourneyId', tourneys_players_table.c.tourneyId, tourneys_players_table.c.playerId, unique=True)
def sss():
"Debug function. Returns (config, sql, db)"
import Configuration, SQL, Database, os
class Dummy(object):
pass
self = Dummy()
self.config = Configuration.Config()
self.settings = {}
if (os.sep=="/"):
self.settings['os']="linuxmac"
else:
self.settings['os']="windows"
self.settings.update(self.config.get_db_parameters())
self.settings.update(self.config.get_tv_parameters())
self.settings.update(self.config.get_import_parameters())
self.settings.update(self.config.get_default_paths())
self.sql = SQL.Sql( db_server = self.settings['db-server'])
self.db = Database.Database(self.config, sql = self.sql)
return self.config, self.sql, self.db

View File

@ -39,23 +39,36 @@ def calcStartCards(hand, player):
def twoStartCards(value1, suit1, value2, suit2):
""" Function to convert 2 value,suit pairs into a Holdem style starting hand e.g. AQo
Hand is stored as an int 13 * x + y where (x+2) represents rank of 1st card and
Incoming values should be ints 2-14 (2,3,...K,A), suits are 'd'/'h'/'c'/'s'
Hand is stored as an int 13 * x + y + 1 where (x+2) represents rank of 1st card and
(y+2) represents rank of second card (2=2 .. 14=Ace)
If x > y then pair is suited, if x < y then unsuited"""
if value1 < 2 or value2 < 2:
If x > y then pair is suited, if x < y then unsuited
Examples:
0 Unknown / Illegal cards
1 22
2 32o
3 42o
...
14 32s
15 33
16 42o
...
170 AA
"""
if value1 is None or value1 < 2 or value1 > 14 or value2 is None or value2 < 2 or value2 > 14:
ret = 0
if value1 == value2: # pairs
ret = (13 * (value2-2) + (value2-2) )
elif value1 == value2: # pairs
ret = (13 * (value2-2) + (value2-2) ) + 1
elif suit1 == suit2:
if value1 > value2:
ret = 13 * (value1-2) + (value2-2)
ret = 13 * (value1-2) + (value2-2) + 1
else:
ret = 13 * (value2-2) + (value1-2)
ret = 13 * (value2-2) + (value1-2) + 1
else:
if value1 > value2:
ret = 13 * (value2-2) + (value1-2)
ret = 13 * (value2-2) + (value1-2) + 1
else:
ret = 13 * (value1-2) + (value2-2)
ret = 13 * (value1-2) + (value2-2) + 1
# print "twoStartCards(", value1, suit1, value2, suit2, ")=", ret
return ret
@ -66,8 +79,8 @@ def twoStartCardString(card):
ret = 'xx'
if card > 0:
s = ('2', '3', '4', '5', '6', '7', '8', '9', 'T', 'J', 'Q', 'K', 'A')
x = card / 13
y = card - 13 * x
x = (card-1) / 13
y = (card-1) - 13 * x
if x == y: ret = s[x] + s[y]
elif x > y: ret = s[x] + s[y] + 's'
else: ret = s[y] + s[x] + 'o'

View File

@ -1,66 +0,0 @@
#!/usr/bin/python
#Copyright 2008 Steffen Jobbagy-Felso
#This program is free software: you can redistribute it and/or modify
#it under the terms of the GNU Affero General Public License as published by
#the Free Software Foundation, version 3 of the License.
#
#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 Affero General Public License
#along with this program. If not, see <http://www.gnu.org/licenses/>.
#In the "official" distribution you can find the license in
#agpl-3.0.txt in the docs folder of the package.
import os
import sys
import fpdb_simple
from optparse import OptionParser
try:
import MySQLdb
except:
diaSQLLibMissing = gtk.Dialog(title="Fatal Error - SQL interface library missing", parent=None, flags=0, buttons=(gtk.STOCK_QUIT,gtk.RESPONSE_OK))
print "Please note that the CLI importer only works with MySQL, if you use PostgreSQL this error is expected."
import fpdb_import
import fpdb_db
if __name__ == "__main__":
#process CLI parameters
parser = OptionParser()
parser.add_option("-c", "--handCount", default="0", type="int",
help="Number of hands to import (default 0 means unlimited)")
parser.add_option("-d", "--database", default="fpdb", help="The MySQL database to use (default fpdb)")
parser.add_option("-e", "--errorFile", default="failed.txt",
help="File to store failed hands into. (default: failed.txt) Not implemented.")
parser.add_option("-f", "--inputFile", "--file", "--inputfile", default="stdin",
help="The file you want to import (remember to use quotes if necessary)")
parser.add_option("-m", "--minPrint", "--status", default="50", type="int",
help="How often to print a one-line status report (0 means never, default is 50)")
parser.add_option("-p", "--password", help="The password for the MySQL user")
parser.add_option("-q", "--quiet", action="store_true",
help="If this is passed it doesn't print a total at the end nor the opening line. Note that this purposely does NOT change --minPrint")
parser.add_option("-s", "--server", default="localhost",
help="Hostname/IP of the MySQL server (default localhost)")
parser.add_option("-u", "--user", default="fpdb", help="The MySQL username (default fpdb)")
parser.add_option("-x", "--failOnError", action="store_true",
help="If this option is passed it quits when it encounters any error")
(options, argv) = parser.parse_args()
settings={'callFpdbHud':False, 'db-backend':2}
settings['db-host']=options.server
settings['db-user']=options.user
settings['db-password']=options.password
settings['db-databaseName']=options.database
settings['handCount']=options.handCount
settings['failOnError']=options.failOnError
importer = fpdb_import.Importer(options, settings)
importer.addImportFile(options.inputFile)
importer.runImport()

View File

@ -31,6 +31,7 @@ import inspect
import string
import traceback
import shutil
import locale
import xml.dom.minidom
from xml.dom.minidom import Node
@ -125,7 +126,8 @@ DATABASE_TYPES = (
DATABASE_TYPE_MYSQL,
)
NEWIMPORT = False
NEWIMPORT = True
LOCALE_ENCODING = locale.getdefaultlocale()[1]
########################################################################
def string_to_bool(string, default=True):

File diff suppressed because it is too large Load Diff

View File

@ -48,18 +48,11 @@ class DerivedStats():
self.handsplayers[player[1]]['sawShowdown'] = False
self.handsplayers[player[1]]['wonAtSD'] = 0.0
self.handsplayers[player[1]]['startCards'] = 0
for i in range(5):
self.handsplayers[player[1]]['street%dCalls' % i] = 0
self.handsplayers[player[1]]['street%dBets' % i] = 0
for i in range(1,5):
self.handsplayers[player[1]]['street%dCBChance' %i] = False
self.handsplayers[player[1]]['street%dCBDone' %i] = False
#FIXME - Everything below this point is incomplete.
self.handsplayers[player[1]]['position'] = 2
self.handsplayers[player[1]]['tourneyTypeId'] = 1
self.handsplayers[player[1]]['street0_3BChance'] = False
self.handsplayers[player[1]]['street0_3BDone'] = False
self.handsplayers[player[1]]['street0_4BChance'] = False
self.handsplayers[player[1]]['street0_4BDone'] = False
self.handsplayers[player[1]]['stealAttemptChance'] = False
self.handsplayers[player[1]]['stealAttempted'] = False
self.handsplayers[player[1]]['foldBbToStealChance'] = False
@ -67,13 +60,22 @@ class DerivedStats():
self.handsplayers[player[1]]['foldSbToStealChance'] = False
self.handsplayers[player[1]]['foldedSbToSteal'] = False
self.handsplayers[player[1]]['foldedBbToSteal'] = False
for i in range(5):
self.handsplayers[player[1]]['street%dCalls' % i] = 0
self.handsplayers[player[1]]['street%dBets' % i] = 0
for i in range(1,5):
self.handsplayers[player[1]]['street%dCBChance' %i] = False
self.handsplayers[player[1]]['street%dCBDone' %i] = False
self.handsplayers[player[1]]['street%dCheckCallRaiseChance' %i] = False
self.handsplayers[player[1]]['street%dCheckCallRaiseDone' %i] = False
#FIXME - Everything below this point is incomplete.
self.handsplayers[player[1]]['tourneyTypeId'] = 1
for i in range(1,5):
self.handsplayers[player[1]]['otherRaisedStreet%d' %i] = False
self.handsplayers[player[1]]['foldToOtherRaisedStreet%d' %i] = False
self.handsplayers[player[1]]['foldToStreet%dCBChance' %i] = False
self.handsplayers[player[1]]['foldToStreet%dCBDone' %i] = False
self.handsplayers[player[1]]['street%dCheckCallRaiseChance' %i] = False
self.handsplayers[player[1]]['street%dCheckCallRaiseDone' %i] = False
self.assembleHands(self.hand)
self.assembleHandsPlayers(self.hand)
@ -174,33 +176,47 @@ class DerivedStats():
self.handsplayers[player[1]]['card%s' % (i+1)] = Card.encodeCard(card)
self.handsplayers[player[1]]['startCards'] = Card.calcStartCards(hand, player[1])
# position,
#Stud 3rd street card test
# denny501: brings in for $0.02
# s0rrow: calls $0.02
# TomSludge: folds
# Soroka69: calls $0.02
# rdiezchang: calls $0.02 (Seat 8)
# u.pressure: folds (Seat 1)
# 123smoothie: calls $0.02
# gashpor: calls $0.02
self.setPositions(hand)
self.calcCheckCallRaise(hand)
self.calc34BetStreet0(hand)
self.calcSteals(hand)
# Additional stats
# 3betSB, 3betBB
# Squeeze, Ratchet?
def getPosition(hand, seat):
"""Returns position value like 'B', 'S', 0, 1, ..."""
# Flop/Draw games with blinds
# Need a better system???
# -2 BB - B (all)
# -1 SB - S (all)
# 0 Button
# 1 Cutoff
# 2 Hijack
def setPositions(self, hand):
"""Sets the position for each player in HandsPlayers
any blinds are negative values, and the last person to act on the
first betting round is 0
NOTE: HU, both values are negative for non-stud games
NOTE2: I've never seen a HU stud match"""
# The position calculation must be done differently for Stud and other games as
# Stud the 'blind' acts first - in all other games they act last.
#
#This function is going to get it wrong when there in situations where there
# is no small blind. I can live with that.
positions = [7, 6, 5, 4, 3, 2, 1, 0, 'S', 'B']
actions = hand.actions[hand.holeStreets[0]]
players = self.pfbao(actions)
seats = len(players)
map = []
if hand.gametype['base'] == 'stud':
# Could posibly change this to be either -2 or -1 depending if they complete or bring-in
# First player to act is -1, last player is 0 for 6 players it should look like:
# ['S', 4, 3, 2, 1, 0]
map = positions[-seats-1:-1] # Copy required positions from postions array anding in -1
map = map[-1:] + map[0:-1] # and move the -1 to the start of that array
else:
# For 6 players is should look like:
# [3, 2, 1, 0, 'S', 'B']
map = positions[-seats:] # Copy required positions from array ending in -2
for i, player in enumerate(players):
self.handsplayers[player]['position'] = map[i]
def assembleHudCache(self, hand):
# No real work to be done - HandsPlayers data already contains the correct info
pass
def vpip(self, hand):
@ -262,13 +278,59 @@ class DerivedStats():
for (i, street) in enumerate(hand.actionStreets[1:]):
self.hands['street%dRaises' % i] = len(filter( lambda action: action[1] in ('raises','bets'), hand.actions[street]))
def calcCBets(self, hand):
# Continuation Bet chance, action:
# Had the last bet (initiative) on previous street, got called, close street action
# Then no bets before the player with initiatives first action on current street
# ie. if player on street-1 had initiative
# and no donkbets occurred
def calcSteals(self, hand):
"""Fills stealAttempt(Chance|ed, fold(Bb|Sb)ToSteal(Chance|)
Steal attemp - open raise on positions 2 1 0 S - i.e. MP3, CO, BU, SB
Fold to steal - folding blind after steal attemp wo any other callers or raisers
"""
steal_attemp = False
steal_positions = ('2', '1', '0', 'S')
if hand.gametype['base'] == 'stud':
steal_positions = ('2', '1', '0')
for action in hand.actions[hand.actionStreets[1]]:
pname, act = action[0], action[1]
#print action[0], hp.position, steal_attemp, act
if self.handsplayers[pname]['position'] == 'B':
#NOTE: Stud games will never hit this section
self.handsplayers[pname]['foldBbToStealChance'] = steal_attemp
self.handsplayers[pname]['foldBbToSteal'] = self.handsplayers[pname]['foldBbToStealChance'] and act == 'folds'
break
elif self.handsplayers[pname]['position'] == 'S':
self.handsplayers[pname]['foldSbToStealChance'] = steal_attemp
self.handsplayers[pname]['foldSbToSteal'] = self.handsplayers[pname]['foldSbToStealChance'] and act == 'folds'
if steal_attemp and act != 'folds':
break
if self.handsplayers[pname]['position'] in steal_positions and not steal_attemp:
self.handsplayers[pname]['stealAttemptChance'] = True
if act in ('bets', 'raises'):
self.handsplayers[pname]['stealAttempted'] = True
steal_attemp = True
def calc34BetStreet0(self, hand):
"""Fills street0_(3|4)B(Chance|Done), other(3|4)BStreet0"""
bet_level = 1 # bet_level after 3-bet is equal to 3
for action in hand.actions[hand.actionStreets[1]]:
# FIXME: fill other(3|4)BStreet0 - i have no idea what does it mean
pname, aggr = action[0], action[1] in ('raises', 'bets')
self.handsplayers[pname]['street0_3BChance'] = bet_level == 2
self.handsplayers[pname]['street0_4BChance'] = bet_level == 3
self.handsplayers[pname]['street0_3BDone'] = aggr and (self.handsplayers[pname]['street0_3BChance'])
self.handsplayers[pname]['street0_4BDone'] = aggr and (self.handsplayers[pname]['street0_4BChance'])
if aggr:
bet_level += 1
def calcCBets(self, hand):
"""Fill streetXCBChance, streetXCBDone, foldToStreetXCBDone, foldToStreetXCBChance
Continuation Bet chance, action:
Had the last bet (initiative) on previous street, got called, close street action
Then no bets before the player with initiatives first action on current street
ie. if player on street-1 had initiative and no donkbets occurred
"""
# XXX: enumerate(list, start=x) is python 2.6 syntax; 'start'
# came there
#for i, street in enumerate(hand.actionStreets[2:], start=1):
@ -280,6 +342,29 @@ class DerivedStats():
if chance == True:
self.handsplayers[name]['street%dCBDone' % (i+1)] = self.betStreet(hand.actionStreets[i+2], name)
def calcCheckCallRaise(self, hand):
"""Fill streetXCheckCallRaiseChance, streetXCheckCallRaiseDone
streetXCheckCallRaiseChance = got raise/bet after check
streetXCheckCallRaiseDone = checked. got raise/bet. didn't fold
CG: CheckCall would be a much better name for this.
"""
#for i, street in enumerate(hand.actionStreets[2:], start=1):
for i, street in enumerate(hand.actionStreets[2:]):
actions = hand.actions[hand.actionStreets[i+1]]
checkers = set()
initial_raiser = None
for action in actions:
pname, act = action[0], action[1]
if act in ('bets', 'raises') and initial_raiser is None:
initial_raiser = pname
elif act == 'checks' and initial_raiser is None:
checkers.add(pname)
elif initial_raiser is not None and pname in checkers:
self.handsplayers[pname]['street%dCheckCallRaiseChance' % (i+1)] = True
self.handsplayers[pname]['street%dCheckCallRaiseDone' % (i+1)] = act!='folds'
def seen(self, hand, i):
pas = set()
for act in hand.actions[hand.actionStreets[i+1]]:
@ -293,11 +378,13 @@ class DerivedStats():
def aggr(self, hand, i):
aggrers = set()
for act in hand.actions[hand.actionStreets[i]]:
if act[1] in ('completes', 'raises'):
# Growl - actionStreets contains 'BLINDSANTES', which isn't actually an action street
for act in hand.actions[hand.actionStreets[i+1]]:
if act[1] in ('completes', 'bets', 'raises'):
aggrers.add(act[0])
for player in hand.players:
#print "DEBUG: actionStreet[%s]: %s" %(hand.actionStreets[i+1], i)
if player[1] in aggrers:
self.handsplayers[player[1]]['street%sAggr' % i] = True
else:
@ -333,6 +420,44 @@ class DerivedStats():
players.add(action[0])
return players
def pfbao(self, actions, f=None, l=None, unique=True):
"""Helper method. Returns set of PlayersFilteredByActionsOrdered
f - forbidden actions
l - limited to actions
"""
# Note, this is an adaptation of function 5 from:
# http://www.peterbe.com/plog/uniqifiers-benchmark
seen = {}
players = []
for action in actions:
if l is not None and action[1] not in l: continue
if f is not None and action[1] in f: continue
if action[0] in seen and unique: continue
seen[action[0]] = 1
players.append(action[0])
return players
def firstsBetOrRaiser(self, actions):
"""Returns player name that placed the first bet or raise.
None if there were no bets or raises on that street
"""
for act in actions:
if act[1] in ('bets', 'raises'):
return act[0]
return None
def lastBetOrRaiser(self, street):
"""Returns player name that placed the last bet or raise for that street.
None if there were no bets or raises on that street"""
lastbet = None
for act in self.hand.actions[street]:
if act[1] in ('bets', 'raises'):
lastbet = act[0]
return lastbet
def noBetsBefore(self, street, player):
"""Returns true if there were no bets before the specified players turn, false otherwise"""
betOrRaise = False
@ -345,6 +470,7 @@ class DerivedStats():
break
return betOrRaise
def betStreet(self, street, player):
"""Returns true if player bet/raised the street as their first action"""
betOrRaise = False
@ -355,12 +481,3 @@ class DerivedStats():
break
return betOrRaise
def lastBetOrRaiser(self, street):
"""Returns player name that placed the last bet or raise for that street.
None if there were no bets or raises on that street"""
lastbet = None
for act in self.hand.actions[street]:
if act[1] in ('bets', 'raises'):
lastbet = act[0]
return lastbet

View File

@ -56,7 +56,7 @@ class Filters(threading.Thread):
,'limitstitle':'Limits:', 'seatstitle':'Number of Players:'
,'groupstitle':'Grouping:', 'posnshow':'Show Position Stats:'
,'groupsall':'All Players'
,'limitsFL':'FL', 'limitsNL':'NL', 'ring':'Ring', 'tour':'Tourney'
,'limitsFL':'FL', 'limitsNL':'NL', 'limitsPL':'PL', 'ring':'Ring', 'tour':'Tourney'
}
# For use in date ranges.
@ -107,6 +107,7 @@ class Filters(threading.Thread):
self.cbAllLimits = None
self.cbFL = None
self.cbNL = None
self.cbPL = None
self.rb = {} # radio buttons for ring/tour
self.type = None # ring/tour
self.types = {} # list of all ring/tour values
@ -191,6 +192,9 @@ class Filters(threading.Thread):
def getSites(self):
return self.sites
def getGames(self):
return self.games
def getSiteIds(self):
return self.siteid
@ -303,7 +307,7 @@ class Filters(threading.Thread):
#print w.get_active()
self.limits[limit] = w.get_active()
print "self.limit[%s] set to %s" %(limit, self.limits[limit])
if limit.isdigit() or (len(limit) > 2 and limit[-2:] == 'nl'):
if limit.isdigit() or (len(limit) > 2 and (limit[-2:] == 'nl' or limit[-2:] == 'fl' or limit[-2:] == 'pl')):
if self.limits[limit]:
if self.cbNoLimits is not None:
self.cbNoLimits.set_active(False)
@ -314,9 +318,12 @@ class Filters(threading.Thread):
if limit.isdigit():
if self.cbFL is not None:
self.cbFL.set_active(False)
else:
elif (len(limit) > 2 and (limit[-2:] == 'nl')):
if self.cbNL is not None:
self.cbNL.set_active(False)
else:
if self.cbPL is not None:
self.cbPL.set_active(False)
elif limit == "all":
if self.limits[limit]:
#for cb in self.cbLimits.values():
@ -325,6 +332,8 @@ class Filters(threading.Thread):
self.cbFL.set_active(True)
if self.cbNL is not None:
self.cbNL.set_active(True)
if self.cbPL is not None:
self.cbPL.set_active(True)
elif limit == "none":
if self.limits[limit]:
for cb in self.cbLimits.values():
@ -333,6 +342,8 @@ class Filters(threading.Thread):
self.cbNL.set_active(False)
if self.cbFL is not None:
self.cbFL.set_active(False)
if self.cbPL is not None:
self.cbPL.set_active(False)
elif limit == "fl":
if not self.limits[limit]:
# only toggle all fl limits off if they are all currently on
@ -384,6 +395,30 @@ class Filters(threading.Thread):
self.rb['tour'].set_active(True)
elif self.type == 'tour':
self.rb['ring'].set_active(True)
elif limit == "pl":
if not self.limits[limit]:
# only toggle all nl limits off if they are all currently on
# this stops turning one off from cascading into 'nl' box off
# and then all nl limits being turned off
all_nl_on = True
for cb in self.cbLimits.values():
t = cb.get_children()[0].get_text()
if "pl" in t and len(t) > 2:
if not cb.get_active():
all_nl_on = False
found = {'ring':False, 'tour':False}
for cb in self.cbLimits.values():
t = cb.get_children()[0].get_text()
if "pl" in t and len(t) > 2:
if self.limits[limit] or all_nl_on:
cb.set_active(self.limits[limit])
found[self.types[t]] = True
if self.limits[limit]:
if not found[self.type]:
if self.type == 'ring':
self.rb['tour'].set_active(True)
elif self.type == 'tour':
self.rb['ring'].set_active(True)
elif limit == "ring":
print "set", limit, "to", self.limits[limit]
if self.limits[limit]:
@ -479,7 +514,7 @@ class Filters(threading.Thread):
self.cursor.execute(self.sql.query['getLimits2'])
# selects limitType, bigBlind
result = self.db.cursor.fetchall()
found = {'nl':False, 'fl':False, 'ring':False, 'tour':False}
found = {'nl':False, 'fl':False, 'pl':False, 'ring':False, 'tour':False}
if len(result) >= 1:
hbox = gtk.HBox(True, 0)
@ -497,9 +532,13 @@ class Filters(threading.Thread):
vbox2.pack_start(hbox, False, False, 0)
else:
vbox3.pack_start(hbox, False, False, 0)
if line[0] == 'ring':
if line[1] == 'fl':
name = str(line[2])
found['fl'] = True
elif line[1] == 'pl':
name = str(line[2])+line[1]
found['pl'] = True
else:
name = str(line[2])+line[1]
found['nl'] = True
@ -532,6 +571,9 @@ class Filters(threading.Thread):
hbox = gtk.HBox(False, 0)
vbox3.pack_start(hbox, False, False, 0)
self.cbNL = self.createLimitLine(hbox, 'nl', self.filterText['limitsNL'])
hbox = gtk.HBox(False, 0)
vbox3.pack_start(hbox, False, False, 0)
self.cbPL = self.createLimitLine(hbox, 'pl', self.filterText['limitsPL'])
dest = vbox2 # for ring/tour buttons
else:
print "INFO: No games returned from database"

View File

@ -30,7 +30,6 @@ import gtk
import gobject
# fpdb/FreePokerTools modules
import fpdb_simple
import fpdb_import
import Configuration
import Exceptions

View File

@ -64,7 +64,7 @@ class GuiPlayerStats (threading.Thread):
filters_display = { "Heroes" : True,
"Sites" : True,
"Games" : False,
"Games" : True,
"Limits" : True,
"LimitSep" : True,
"LimitType" : True,
@ -180,6 +180,7 @@ class GuiPlayerStats (threading.Thread):
seats = self.filters.getSeats()
groups = self.filters.getGroups()
dates = self.filters.getDates()
games = self.filters.getGames()
sitenos = []
playerids = []
@ -205,9 +206,9 @@ class GuiPlayerStats (threading.Thread):
print "No limits found"
return
self.createStatsTable(vbox, playerids, sitenos, limits, type, seats, groups, dates)
self.createStatsTable(vbox, playerids, sitenos, limits, type, seats, groups, dates, games)
def createStatsTable(self, vbox, playerids, sitenos, limits, type, seats, groups, dates):
def createStatsTable(self, vbox, playerids, sitenos, limits, type, seats, groups, dates, games):
starttime = time()
# Scrolled window for summary table
@ -223,7 +224,7 @@ class GuiPlayerStats (threading.Thread):
# gridnum - index for grid data structures
flags = [False, self.filters.getNumHands(), 0]
self.addGrid(swin, 'playerDetailedStats', flags, playerids
,sitenos, limits, type, seats, groups, dates)
,sitenos, limits, type, seats, groups, dates, games)
# Separator
vbox2 = gtk.VBox(False, 0)
@ -243,7 +244,7 @@ class GuiPlayerStats (threading.Thread):
flags[0] = True
flags[2] = 1
self.addGrid(swin, 'playerDetailedStats', flags, playerids
,sitenos, limits, type, seats, groups, dates)
,sitenos, limits, type, seats, groups, dates, games)
self.db.rollback()
print "Stats page displayed in %4.2f seconds" % (time() - starttime)
@ -317,7 +318,7 @@ class GuiPlayerStats (threading.Thread):
print "***sortcols error: " + str(sys.exc_info()[1])
print "\n".join( [e[0]+':'+str(e[1])+" "+e[2] for e in err] )
def addGrid(self, vbox, query, flags, playerids, sitenos, limits, type, seats, groups, dates):
def addGrid(self, vbox, query, flags, playerids, sitenos, limits, type, seats, groups, dates, games):
counter = 0
row = 0
sqlrow = 0
@ -325,7 +326,7 @@ class GuiPlayerStats (threading.Thread):
else: holecards,grid = flags[0],flags[2]
tmp = self.sql.query[query]
tmp = self.refineQuery(tmp, flags, playerids, sitenos, limits, type, seats, groups, dates)
tmp = self.refineQuery(tmp, flags, playerids, sitenos, limits, type, seats, groups, dates, games)
self.cursor.execute(tmp)
result = self.cursor.fetchall()
colnames = [desc[0].lower() for desc in self.cursor.description]
@ -428,7 +429,7 @@ class GuiPlayerStats (threading.Thread):
#end def addGrid(self, query, vars, playerids, sitenos, limits, type, seats, groups, dates):
def refineQuery(self, query, flags, playerids, sitenos, limits, type, seats, groups, dates):
def refineQuery(self, query, flags, playerids, sitenos, limits, type, seats, groups, dates, games):
having = ''
if not flags:
holecards = False
@ -466,6 +467,20 @@ class GuiPlayerStats (threading.Thread):
query = query.replace("<playerName>", pname)
query = query.replace("<havingclause>", having)
gametest = ""
q = []
for m in self.filters.display.items():
if m[0] == 'Games' and m[1]:
for n in games:
if games[n]:
q.append(n)
gametest = str(tuple(q))
gametest = gametest.replace("L", "")
gametest = gametest.replace(",)",")")
gametest = gametest.replace("u'","'")
gametest = "and gt.category in %s" % gametest
query = query.replace("<game_test>", gametest)
if seats:
query = query.replace('<seats_test>', 'between ' + str(seats['from']) + ' and ' + str(seats['to']))
if 'show' in seats and seats['show']:
@ -516,8 +531,8 @@ class GuiPlayerStats (threading.Thread):
if holecards: # re-use level variables for hole card query
query = query.replace("<hgameTypeId>", "hp.startcards")
query = query.replace("<orderbyhgameTypeId>"
, ",case when floor(hp.startcards/13) >= mod(hp.startcards,13) then hp.startcards + 0.1 "
+ " else 13*mod(hp.startcards,13) + floor(hp.startcards/13) "
, ",case when floor((hp.startcards-1)/13) >= mod((hp.startcards-1),13) then hp.startcards + 0.1 "
+ " else 13*mod((hp.startcards-1),13) + floor((hp.startcards-1)/13) + 1 "
+ " end desc ")
else:
query = query.replace("<orderbyhgameTypeId>", "")

View File

@ -20,7 +20,6 @@ import pygtk
pygtk.require('2.0')
import gtk
import os
import fpdb_simple
import fpdb_import
import fpdb_db

View File

@ -232,6 +232,9 @@ db: a connected fpdb_db object"""
#Raise Duplicate exception?
pass
def updateHudCache(self, db):
db.storeHudCache(self.dbid_gt, self.dbid_pids, self.starttime, self.stats.getHandsPlayers())
def select(self, handId):
""" Function to create Hand object from database """

View File

@ -65,7 +65,7 @@ follow : whether to tail -f the input"""
log.info("HandHistory init - %s subclass, in_path '%s'; out_path '%s'" % (self.sitename, in_path, out_path) )
self.index = 0
self.index = index
self.starsArchive = starsArchive
self.in_path = in_path

View File

@ -606,6 +606,7 @@ class Hud:
if self.update_table_position() == False: # we got killed by finding our table was gone
return
self.label.modify_fg(gtk.STATE_NORMAL, gtk.gdk.color_parse(self.colors['hudfgcolor']))
for s in self.stat_dict:
try:
statd = self.stat_dict[s]
@ -629,20 +630,16 @@ class Hud:
window = self.stat_windows[statd['seat']]
if this_stat.hudcolor != "":
self.label.modify_fg(gtk.STATE_NORMAL, gtk.gdk.color_parse(self.colors['hudfgcolor']))
window.label[r][c].modify_fg(gtk.STATE_NORMAL, gtk.gdk.color_parse(this_stat.hudcolor))
else:
self.label.modify_fg(gtk.STATE_NORMAL, gtk.gdk.color_parse(self.colors['hudfgcolor']))
window.label[r][c].modify_fg(gtk.STATE_NORMAL, gtk.gdk.color_parse("#FFFFFF"))
window.label[r][c].modify_fg(gtk.STATE_NORMAL, gtk.gdk.color_parse(self.colors['hudfgcolor']))
if this_stat.stat_loth != "":
if number[0] < (float(this_stat.stat_loth)/100):
self.label.modify_fg(gtk.STATE_NORMAL, gtk.gdk.color_parse(self.colors['hudfgcolor']))
window.label[r][c].modify_fg(gtk.STATE_NORMAL, gtk.gdk.color_parse(this_stat.stat_locolor))
if this_stat.stat_hith != "":
if number[0] > (float(this_stat.stat_hith)/100):
self.label.modify_fg(gtk.STATE_NORMAL, gtk.gdk.color_parse(self.colors['hudfgcolor']))
window.label[r][c].modify_fg(gtk.STATE_NORMAL, gtk.gdk.color_parse(this_stat.stat_hicolor))
window.label[r][c].set_text(statstring)

View File

@ -81,6 +81,7 @@ class PokerStars(HandHistoryConverter):
re_Board = re.compile(r"\[(?P<CARDS>.+)\]")
# self.re_setHandInfoRegex('.*#(?P<HID>[0-9]+): Table (?P<TABLE>[ a-zA-Z]+) - \$?(?P<SB>[.0-9]+)/\$?(?P<BB>[.0-9]+) - (?P<GAMETYPE>.*) - (?P<HR>[0-9]+):(?P<MIN>[0-9]+) ET - (?P<YEAR>[0-9]+)/(?P<MON>[0-9]+)/(?P<DAY>[0-9]+)Table (?P<TABLE>[ a-zA-Z]+)\nSeat (?P<BUTTON>[0-9]+)')
re_DateTime = re.compile("""(?P<Y>[0-9]{4})\/(?P<M>[0-9]{2})\/(?P<D>[0-9]{2})[\- ]+(?P<H>[0-9]+):(?P<MIN>[0-9]+):(?P<S>[0-9]+)""", re.MULTILINE)
def compilePlayerRegexs(self, hand):
players = set([player[1] for player in hand.players])
@ -97,7 +98,7 @@ class PokerStars(HandHistoryConverter):
self.re_PostBB = re.compile(r"^%(PLYR)s: posts big blind %(CUR)s(?P<BB>[.0-9]+)" % subst, re.MULTILINE)
self.re_Antes = re.compile(r"^%(PLYR)s: posts the ante %(CUR)s(?P<ANTE>[.0-9]+)" % subst, re.MULTILINE)
self.re_BringIn = re.compile(r"^%(PLYR)s: brings[- ]in( low|) for %(CUR)s(?P<BRINGIN>[.0-9]+)" % subst, re.MULTILINE)
self.re_PostBoth = re.compile(r"^%(PLYR)s: posts small \& big blinds \[%(CUR)s (?P<SBBB>[.0-9]+)" % subst, re.MULTILINE)
self.re_PostBoth = re.compile(r"^%(PLYR)s: posts small \& big blinds %(CUR)s(?P<SBBB>[.0-9]+)" % subst, re.MULTILINE)
self.re_HeroCards = re.compile(r"^Dealt to %(PLYR)s(?: \[(?P<OLDCARDS>.+?)\])?( \[(?P<NEWCARDS>.+?)\])" % subst, re.MULTILINE)
self.re_Action = re.compile(r"""
^%(PLYR)s:(?P<ATYPE>\sbets|\schecks|\sraises|\scalls|\sfolds|\sdiscards|\sstands\spat)
@ -105,7 +106,7 @@ class PokerStars(HandHistoryConverter):
(\scards?(\s\[(?P<DISCARDED>.+?)\])?)?"""
% subst, re.MULTILINE|re.VERBOSE)
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]+): %(PLYR)s (\(button\) |\(small blind\) |\(big blind\) )?(collected|showed \[.*\] and won) \(%(CUR)s(?P<POT>[.\d]+)\)(, mucked| with.*|)" % subst, re.MULTILINE)
self.re_CollectPot = re.compile(r"Seat (?P<SEAT>[0-9]+): %(PLYR)s (\(button\) |\(small blind\) |\(big blind\) |\(button\) \(small blind\) )?(collected|showed \[.*\] and won) \(%(CUR)s(?P<POT>[.\d]+)\)(, mucked| with.*|)" % subst, 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 (\(.*\) )?(?P<SHOWED>showed|mucked) \[(?P<CARDS>.*)\].*" % player_re, re.MULTILINE)
@ -194,12 +195,13 @@ class PokerStars(HandHistoryConverter):
#2008/11/12 10:00:48 CET [2008/11/12 4:00:48 ET]
#2008/08/17 - 01:14:43 (ET)
#2008/09/07 06:23:14 ET
m2 = re.search("(?P<Y>[0-9]{4})\/(?P<M>[0-9]{2})\/(?P<D>[0-9]{2})[\- ]+(?P<H>[0-9]+):(?P<MIN>[0-9]+):(?P<S>[0-9]+)", info[key])
datetimestr = "%s/%s/%s %s:%s:%s" % (m2.group('Y'), m2.group('M'),m2.group('D'),m2.group('H'),m2.group('MIN'),m2.group('S'))
m1 = self.re_DateTime.finditer(info[key])
# m2 = re.search("(?P<Y>[0-9]{4})\/(?P<M>[0-9]{2})\/(?P<D>[0-9]{2})[\- ]+(?P<H>[0-9]+):(?P<MIN>[0-9]+):(?P<S>[0-9]+)", info[key])
for a in m1:
datetimestr = "%s/%s/%s %s:%s:%s" % (a.group('Y'), a.group('M'),a.group('D'),a.group('H'),a.group('MIN'),a.group('S'))
hand.starttime = datetime.datetime.strptime(datetimestr, "%Y/%m/%d %H:%M:%S")
if key == 'HID':
hand.handid = info[key]
if key == 'TOURNO':
hand.tourNo = info[key]
if key == 'BUYIN':

View File

@ -1881,6 +1881,7 @@ class Sql:
inner join Sites s on (s.Id = gt.siteId)
inner join Players p on (p.Id = hp.playerId)
where hp.playerId in <player_test>
<game_test>
/*and hp.tourneysPlayersId IS NULL*/
and h.seats <seats_test>
<flagtest>
@ -1964,6 +1965,7 @@ class Sql:
inner join Sites s on (s.Id = gt.siteId)
inner join Players p on (p.Id = hp.playerId)
where hp.playerId in <player_test>
<game_test>
/*and hp.tourneysPlayersId IS NULL*/
and h.seats <seats_test>
<flagtest>
@ -2047,6 +2049,7 @@ class Sql:
inner join Gametypes gt on (gt.Id = h.gameTypeId)
inner join Sites s on (s.Id = gt.siteId)
where hp.playerId in <player_test>
<game_test>
/*and hp.tourneysPlayersId IS NULL*/
and h.seats <seats_test>
<flagtest>
@ -3088,6 +3091,147 @@ class Sql:
,'d' || substr(strftime('%Y%m%d', h.handStart),3,7)
"""
self.query['insert_hudcache'] = """
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)"""
self.query['update_hudcache'] = """
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"""
self.query['get_hero_hudcache_start'] = """select min(hc.styleKey)
from HudCache hc
where hc.playerId in <playerid_list>

View File

@ -62,9 +62,13 @@ import Database
re_Places = re.compile("_[0-9]$")
re_Percent = re.compile("%$")
# String manipulation
import codecs
encoder = codecs.lookup(Configuration.LOCALE_ENCODING)
def do_tip(widget, tip):
widget.set_tooltip_text(tip)
(_tip, _len) = encoder.encode(tip)
widget.set_tooltip_text(_tip)
def do_stat(stat_dict, player = 24, stat = 'vpip'):
match = re_Places.search(stat)

View File

@ -39,7 +39,6 @@ if os.name == 'nt':
# FreePokerTools modules
import Configuration
from fpdb_simple import LOCALE_ENCODING
# Each TableWindow object must have the following attributes correctly populated:
# tw.name = the table name from the title bar, which must to match the table name
@ -238,7 +237,7 @@ def discover_nt_by_name(c, tablename):
try:
# 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
if not tablename.lower() in titles[hwnd].decode(LOCALE_ENCODING).lower():
if not tablename.lower() in titles[hwnd].decode(Configuration.LOCALE_ENCODING).lower():
continue
except:
continue

View File

@ -38,7 +38,6 @@ except ImportError:
logging.info("Not using numpy to define variance in sqlite.")
use_numpy = False
import fpdb_simple
import FpdbSQLQueries
import Configuration

View File

@ -35,10 +35,8 @@ import gtk
# fpdb/FreePokerTools modules
import fpdb_simple
import fpdb_db
import Database
import fpdb_parse_logic
import Configuration
import Exceptions
@ -409,7 +407,7 @@ class Importer:
conv = None
(stored, duplicates, partial, errors, ttime) = (0, 0, 0, 0, 0)
file = file.decode(fpdb_simple.LOCALE_ENCODING)
file = file.decode(Configuration.LOCALE_ENCODING)
# Load filter, process file, pass returned filename to import_fpdb_file
if self.settings['threads'] > 0 and self.writeq is not None:
@ -429,11 +427,13 @@ class Importer:
mod = __import__(filter)
obj = getattr(mod, filter_name, None)
if callable(obj):
hhc = obj(in_path = file, out_path = out_path, index = 0, starsArchive = self.settings['starsArchive']) # Index into file 0 until changeover
if hhc.getStatus() and self.NEWIMPORT == False:
(stored, duplicates, partial, errors, ttime) = self.import_fpdb_file(db, out_path, site, q)
elif hhc.getStatus() and self.NEWIMPORT == True:
#This code doesn't do anything yet
idx = 0
if file in self.pos_in_file:
idx = self.pos_in_file[file]
else:
self.pos_in_file[file] = 0
hhc = obj(in_path = file, out_path = out_path, index = idx, starsArchive = self.settings['starsArchive'])
if hhc.getStatus() and self.NEWIMPORT == True:
handlist = hhc.getProcessedHands()
self.pos_in_file[file] = hhc.getLastCharacterRead()
to_hud = []
@ -448,6 +448,11 @@ class Importer:
else:
log.error("Hand processed but empty")
self.database.commit()
# Call hudcache update if not in bulk import mode
# FIXME: Need to test for bulk import that isn't rebuilding the cache
if self.callHud:
hand.updateHudCache(self.database)
self.database.commit()
#pipe the Hands.id out to the HUD
for hid in to_hud:
@ -468,162 +473,6 @@ class Importer:
return (stored, duplicates, partial, errors, ttime)
def import_fpdb_file(self, db, file, site, q):
starttime = time()
last_read_hand = 0
loc = 0
(stored, duplicates, partial, errors, ttime) = (0, 0, 0, 0, 0)
# print "file =", file
if file == "stdin":
inputFile = sys.stdin
else:
if os.path.exists(file):
inputFile = open(file, "rU")
else:
self.removeFromFileList[file] = True
return (0, 0, 0, 1, 0)
try:
loc = self.pos_in_file[file]
#size = os.path.getsize(file)
#print "loc =", loc, 'size =', size
except KeyError:
pass
# Read input file into class and close file
inputFile.seek(loc)
#tmplines = inputFile.readlines()
#if tmplines == None or tmplines == []:
# print "tmplines = ", tmplines
#else:
# print "tmplines[0] =", tmplines[0]
self.lines = fpdb_simple.removeTrailingEOL(inputFile.readlines())
self.pos_in_file[file] = inputFile.tell()
inputFile.close()
x = clock()
(stored, duplicates, partial, errors, ttime, handsId) = self.import_fpdb_lines(db, self.lines, starttime, file, site, q)
db.commit()
y = clock()
ttime = y - x
#ttime = time() - starttime
if q is None:
log.info("Total stored: %(stored)d\tduplicates:%(duplicates)d\terrors:%(errors)d\ttime:%(ttime)s" % locals())
if not stored:
if duplicates:
for line_no in xrange(len(self.lines)):
if self.lines[line_no].find("Game #") != -1:
final_game_line = self.lines[line_no]
handsId=fpdb_simple.parseSiteHandNo(final_game_line)
else:
print "failed to read a single hand from file:", inputFile
handsId = 0
#todo: this will cause return of an unstored hand number if the last hand was error
self.handsId = handsId
return (stored, duplicates, partial, errors, ttime)
# end def import_fpdb_file
def import_fpdb_lines(self, db, lines, starttime, file, site, q = None):
"""Import an fpdb hand history held in the list lines, could be one hand or many"""
#db.lock_for_insert() # should be ok when using one thread, but doesn't help??
while gtk.events_pending():
gtk.main_iteration(False)
try: # sometimes we seem to be getting an empty self.lines, in which case, we just want to return.
firstline = lines[0]
except:
# just skip the debug message and return silently:
#print "DEBUG: import_fpdb_file: failed on lines[0]: '%s' '%s' '%s' '%s' " %( file, site, lines, loc)
return (0,0,0,1,0,0)
if "Tournament Summary" in firstline:
print "TODO: implement importing tournament summaries"
#self.faobs = readfile(inputFile)
#self.parseTourneyHistory()
return (0,0,0,1,0,0)
category = fpdb_simple.recogniseCategory(firstline)
startpos = 0
stored = 0 #counter
duplicates = 0 #counter
partial = 0 #counter
errors = 0 #counter
ttime = 0
handsId = 0
for i in xrange(len(lines)):
if len(lines[i]) < 2: #Wierd way to detect for '\r\n' or '\n'
endpos = i
hand = lines[startpos:endpos]
if len(hand[0]) < 2:
hand=hand[1:]
if len(hand) < 3:
pass
#TODO: This is ugly - we didn't actually find the start of the
# hand with the outer loop so we test again...
else:
isTourney = fpdb_simple.isTourney(hand[0])
if not isTourney:
hand = fpdb_simple.filterAnteBlindFold(hand)
self.hand = hand
try:
handsId = fpdb_parse_logic.mainParser( self.settings, self.siteIds[site]
, category, hand, self.config
, db, q )
db.commit()
stored += 1
if self.callHud:
#print "call to HUD here. handsId:",handsId
#pipe the Hands.id out to the HUD
# print "fpdb_import: sending hand to hud", handsId, "pipe =", self.caller.pipe_to_hud
try:
self.caller.pipe_to_hud.stdin.write("%s" % (handsId) + os.linesep)
except IOError: # hud closed
self.callHud = False
pass # continue import without hud
except Exceptions.DuplicateError:
duplicates += 1
db.rollback()
except (ValueError), fe:
errors += 1
self.printEmailErrorMessage(errors, file, hand)
if (self.settings['failOnError']):
db.commit() #dont remove this, in case hand processing was cancelled.
raise
else:
db.rollback()
except (fpdb_simple.FpdbError), fe:
errors += 1
self.printEmailErrorMessage(errors, file, hand)
db.rollback()
if self.settings['failOnError']:
db.commit() #dont remove this, in case hand processing was cancelled.
raise
if self.settings['minPrint']:
if not ((stored+duplicates+errors) % self.settings['minPrint']):
print "stored:", stored, " duplicates:", duplicates, "errors:", errors
if self.settings['handCount']:
if ((stored+duplicates+errors) >= self.settings['handCount']):
if not self.settings['quiet']:
print "quitting due to reaching the amount of hands to be imported"
print "Total stored:", stored, "duplicates:", duplicates, "errors:", errors, " time:", (time() - starttime)
sys.exit(0)
startpos = endpos
return (stored, duplicates, partial, errors, ttime, handsId)
# end def import_fpdb_lines
def printEmailErrorMessage(self, errors, filename, line):
traceback.print_exc(file=sys.stderr)
print "Error No.",errors,", please send the hand causing this to steffen@sycamoretest.info so I can fix it."

View File

@ -1,235 +0,0 @@
#!/usr/bin/python
#Copyright 2008 Steffen Jobbagy-Felso
#This program is free software: you can redistribute it and/or modify
#it under the terms of the GNU Affero General Public License as published by
#the Free Software Foundation, version 3 of the License.
#
#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 Affero General Public License
#along with this program. If not, see <http://www.gnu.org/licenses/>.
#In the "official" distribution you can find the license in
#agpl-3.0.txt in the docs folder of the package.
#parses an in-memory fpdb hand history and calls db routine to store it
import sys
from time import time, strftime
from Exceptions import *
import fpdb_simple
import Database
def mainParser(settings, siteID, category, hand, config, db = None, writeq = None):
""" mainParser for Holdem Hands """
t0 = time()
backend = settings['db-backend']
# Ideally db connection is passed in, if not use sql list if passed in,
# otherwise start from scratch
if db is None:
db = Database.Database(c = config, sql = None)
category = fpdb_simple.recogniseCategory(hand[0])
base = "hold" if (category == "holdem" or category == "omahahi" or
category == "omahahilo") else "stud"
#part 0: create the empty arrays
# lineTypes valid values: header, name, cards, action, win, rake, ignore
# lineStreets valid values: predeal, preflop, flop, turn, river
lineTypes = []
lineStreets = []
cardValues = []
cardSuits = []
boardValues = []
boardSuits = []
antes = []
allIns = []
actionAmounts = []
actionNos = []
actionTypes = []
actionTypeByNo = []
seatLines = []
winnings = []
rakes = []
#part 1: read hand no and check for duplicate
siteHandNo = fpdb_simple.parseSiteHandNo(hand[0])
handStartTime = fpdb_simple.parseHandStartTime(hand[0])
isTourney = fpdb_simple.isTourney(hand[0])
smallBlindLine = None
for i, line in enumerate(hand):
if 'posts small blind' in line or 'posts the small blind' in line:
if line[-2:] == "$0": continue
smallBlindLine = i
break
else:
smallBlindLine = 0
# If we did not find a small blind line, what happens?
# if we leave it at None, it errors two lines down.
gametypeID = fpdb_simple.recogniseGametypeID(backend, db, db.get_cursor(),
hand[0], hand[smallBlindLine],
siteID, category, isTourney)
if isTourney:
siteTourneyNo = fpdb_simple.parseTourneyNo(hand[0])
buyin = fpdb_simple.parseBuyin(hand[0])
fee = fpdb_simple.parseFee(hand[0])
entries = -1 #todo: parse this
prizepool = -1 #todo: parse this
knockout = False
tourneyStartTime= handStartTime #todo: read tourney start time
rebuyOrAddon = fpdb_simple.isRebuyOrAddon(hand[0])
# The tourney site id has to be searched because it may already be in
# db with a TourneyTypeId which is different from the one automatically
# calculated (Summary import first)
tourneyTypeId = fpdb_simple.recogniseTourneyTypeId(db, siteID,
siteTourneyNo,
buyin, fee,
knockout,
rebuyOrAddon)
else:
siteTourneyNo = -1
buyin = -1
fee = -1
entries = -1
prizepool = -1
knockout = 0
tourneyStartTime= None
rebuyOrAddon = -1
tourneyTypeId = 1
fpdb_simple.isAlreadyInDB(db, gametypeID, siteHandNo)
hand = fpdb_simple.filterCrap(hand, isTourney)
#part 2: classify lines by type (e.g. cards, action, win, sectionchange) and street
fpdb_simple.classifyLines(hand, category, lineTypes, lineStreets)
#part 3: read basic player info
#3a read player names, startcashes
for i, line in enumerate(hand):
if lineTypes[i] == "name":
seatLines.append(line)
names = fpdb_simple.parseNames(seatLines)
playerIDs = db.recognisePlayerIDs(names, siteID) # inserts players as needed
tmp = fpdb_simple.parseCashesAndSeatNos(seatLines)
startCashes = tmp['startCashes']
seatNos = tmp['seatNos']
fpdb_simple.createArrays(category, len(names), cardValues, cardSuits, antes,
winnings, rakes, actionTypes, allIns,
actionAmounts, actionNos, actionTypeByNo)
#3b read positions
if base == "hold":
positions = fpdb_simple.parsePositions(hand, names)
#part 4: take appropriate action for each line based on linetype
for i, line in enumerate(hand):
if lineTypes[i] == "cards":
fpdb_simple.parseCardLine(category, lineStreets[i], line, names,
cardValues, cardSuits, boardValues,
boardSuits)
#if category=="studhilo":
# print "hand[i]:", hand[i]
# print "cardValues:", cardValues
# print "cardSuits:", cardSuits
elif lineTypes[i] == "action":
fpdb_simple.parseActionLine(base, isTourney, line, lineStreets[i],
playerIDs, names, actionTypes, allIns,
actionAmounts, actionNos, actionTypeByNo)
elif lineTypes[i] == "win":
fpdb_simple.parseWinLine(line, names, winnings, isTourney)
elif lineTypes[i] == "rake":
totalRake = 0 if isTourney else fpdb_simple.parseRake(line)
fpdb_simple.splitRake(winnings, rakes, totalRake)
elif (lineTypes[i] == "header" or lineTypes[i] == "rake" or
lineTypes[i] == "name" or lineTypes[i] == "ignore"):
pass
elif lineTypes[i] == "ante":
fpdb_simple.parseAnteLine(line, isTourney, names, antes)
elif lineTypes[i] == "table":
tableResult=fpdb_simple.parseTableLine(base, line)
else:
raise FpdbError("unrecognised lineType:" + lineTypes[i])
maxSeats = tableResult['maxSeats']
tableName = tableResult['tableName']
#print "before part5, antes:", antes
#part 5: final preparations, then call Database.* with
# the arrays as they are - that file will fill them.
fpdb_simple.convertCardValues(cardValues)
if base == "hold":
fpdb_simple.convertCardValuesBoard(boardValues)
fpdb_simple.convertBlindBet(actionTypes, actionAmounts)
fpdb_simple.checkPositions(positions)
c = db.get_cursor()
c.execute("SELECT limitType FROM Gametypes WHERE id=%s" % (db.sql.query['placeholder'],), (gametypeID, ))
limit_type = c.fetchone()[0]
fpdb_simple.convert3B4B(category, limit_type, actionTypes, actionAmounts)
totalWinnings = sum(winnings)
# if hold'em, use positions and not antes, if stud do not use positions, use antes
# this is used for handsplayers inserts, so still needed even if hudcache update is being skipped
if base == "hold":
hudImportData = fpdb_simple.generateHudCacheData(playerIDs, base,
category, actionTypes,
allIns, actionTypeByNo,
winnings,
totalWinnings,
positions, actionTypes,
actionAmounts, None)
else:
hudImportData = fpdb_simple.generateHudCacheData(playerIDs, base,
category, actionTypes,
allIns, actionTypeByNo,
winnings,
totalWinnings, None,
actionTypes,
actionAmounts, antes)
try:
db.commit() # need to commit new players as different db connection used
# for other writes. maybe this will change maybe not ...
except: # TODO: this really needs to be narrowed down
print "parse: error during commit: " + str(sys.exc_value)
# HERE's an ugly kludge to keep from failing when positions is undef
# We'll fix this by getting rid of the legacy importer. REB
try:
if positions:
pass
except NameError:
positions = [0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
# save data structures in a HandToWrite instance and then insert into database:
htw = Database.HandToWrite()
htw.set_all( config, settings, base, category, siteTourneyNo, buyin
, fee, knockout, entries, prizepool, tourneyStartTime
, isTourney, tourneyTypeId, siteID, siteHandNo
, gametypeID, handStartTime, names, playerIDs, startCashes
, positions, antes, cardValues, cardSuits, boardValues, boardSuits
, winnings, rakes, actionTypes, allIns, actionAmounts
, actionNos, hudImportData, maxSeats, tableName, seatNos)
# save hand in db via direct call or via q if in a thread
if writeq is None:
result = db.store_the_hand(htw)
else:
writeq.put(htw)
result = -999 # meaning unknown
t9 = time()
#print "parse and save=(%4.3f)" % (t9-t0)
return result
#end def mainParser

File diff suppressed because it is too large Load Diff

View File

@ -89,13 +89,14 @@ def testFlopImport():
print "DEBUG: stored: %s dups: %s partial: %s errs: %s ttime: %s" %(stored, dups, partial, errs, ttime)
importer.clearFileList()
col = { 'sawShowdown': 2
col = { 'sawShowdown': 2, 'street0Aggr':3
}
q = """SELECT
s.name,
p.name,
hp.sawShowdown
hp.sawShowdown,
hp.street0Aggr
FROM
Hands as h,
Sites as s,
@ -119,7 +120,8 @@ and s.id = p.siteid"""
q = """SELECT
s.name,
p.name,
hp.sawShowdown
hp.sawShowdown,
hp.street0Aggr
FROM
Hands as h,
Sites as s,
@ -135,10 +137,10 @@ and s.id = p.siteid"""
c = db.get_cursor()
c.execute(q)
result = c.fetchall()
pstats = { u'Kinewma':0, u'Arbaz':0, u's0rrow':1, u'bys7':0, u'AAALISAAAA':1, u'Bl\xe5veis':0 }
for row, data in enumerate(result):
print "DEBUG: result[%s]: %s" %(row, result[row])
# Assert if any sawShowdown = True
assert result[row][col['sawShowdown']] == 1
print "DEBUG: result[%s]: %s == %s" %(row, result[row], pstats[data[1]])
assert result[row][col['sawShowdown']] == pstats[data[1]]
assert 0 == 1

View File

@ -1,27 +0,0 @@
# -*- coding: utf-8 -*-
import fpdb_simple
import datetime
import py
def checkDateParse(header, site, result):
assert fpdb_simple.parseHandStartTime(header, site) == result
def testPokerStarsHHDate():
tuples = (
("PokerStars Game #21969660557: Hold'em No Limit ($0.50/$1.00) - 2008/11/12 10:00:48 CET [2008/11/12 4:00:48 ET]", "ps",
datetime.datetime(2008,11,12,15,00,48)),
("PokerStars Game #21969660557: Hold'em No Limit ($0.50/$1.00) - 2008/08/17 - 01:14:43 (ET)", "ps",
datetime.datetime(2008,8,17,6,14,43)),
("PokerStars Game #21969660557: Hold'em No Limit ($0.50/$1.00) - 2008/09/07 06:23:14 ET", "ps",
datetime.datetime(2008,9,7,11,23,14))
)
#def testTableDetection():
# result = Tables.clean_title("French (deep)")
# assert result == "French"
# result = Tables.clean_title("French (deep) - $0.25/$0.50 - No Limit Hold'em - Logged In As xxxx")
# assert result == "French"
#
# for (header, site, result) in tuples:
# yield checkDateParse, header, site, result