Merge branch 'master' of git://git.assembla.com/fpdboz
Conflicts: pyfpdb/Configuration.py pyfpdb/Database.py
This commit is contained in:
commit
358de81f3b
116
pyfpdb/AlchemyFacilities.py
Normal file
116
pyfpdb/AlchemyFacilities.py
Normal 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
464
pyfpdb/AlchemyMappings.py
Normal 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
438
pyfpdb/AlchemyTables.py
Normal 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
|
||||
|
|
@ -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()
|
|
@ -31,6 +31,7 @@ import inspect
|
|||
import string
|
||||
import traceback
|
||||
import shutil
|
||||
import locale
|
||||
import xml.dom.minidom
|
||||
from xml.dom.minidom import Node
|
||||
|
||||
|
@ -142,7 +143,8 @@ log.info("DIR SELF = %s" % DIR_SELF)
|
|||
log.info("DIR CONFIG = %s" % DIR_CONFIG)
|
||||
log.info("DIR DATABASE = %s" % DIR_DATABASE)
|
||||
log.info("DIR LOG = %s" % DIR_LOG)
|
||||
NEWIMPORT = False
|
||||
NEWIMPORT = True
|
||||
LOCALE_ENCODING = locale.getdefaultlocale()[1]
|
||||
|
||||
########################################################################
|
||||
def string_to_bool(string, default=True):
|
||||
|
|
1186
pyfpdb/Database.py
1186
pyfpdb/Database.py
File diff suppressed because it is too large
Load Diff
|
@ -216,6 +216,7 @@ class DerivedStats():
|
|||
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):
|
||||
|
@ -349,8 +350,9 @@ class DerivedStats():
|
|||
|
||||
CG: CheckCall would be a much better name for this.
|
||||
"""
|
||||
for i, street in enumerate(hand.actionStreets[2:], start=1):
|
||||
actions = hand.actions[hand.actionStreets[i]]
|
||||
#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:
|
||||
|
@ -360,8 +362,8 @@ class DerivedStats():
|
|||
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] = True
|
||||
self.handsplayers[pname]['street%dCheckCallRaiseDone' % i] = act!='folds'
|
||||
self.handsplayers[pname]['street%dCheckCallRaiseChance' % (i+1)] = True
|
||||
self.handsplayers[pname]['street%dCheckCallRaiseDone' % (i+1)] = act!='folds'
|
||||
|
||||
def seen(self, hand, i):
|
||||
pas = set()
|
||||
|
@ -468,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
|
||||
|
|
|
@ -30,7 +30,6 @@ import gtk
|
|||
import gobject
|
||||
|
||||
# fpdb/FreePokerTools modules
|
||||
import fpdb_simple
|
||||
import fpdb_import
|
||||
import Configuration
|
||||
import Exceptions
|
||||
|
|
|
@ -20,7 +20,6 @@ import pygtk
|
|||
pygtk.require('2.0')
|
||||
import gtk
|
||||
import os
|
||||
import fpdb_simple
|
||||
|
||||
import fpdb_import
|
||||
import fpdb_db
|
||||
|
|
|
@ -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 """
|
||||
|
||||
|
@ -393,7 +396,7 @@ Add a raise on [street] by [player] to [amountTo]
|
|||
Bc = reduce(operator.add, self.bets[street][player], 0)
|
||||
Rt = Decimal(amountTo)
|
||||
C = Bp - Bc
|
||||
Rb = Rt - C
|
||||
Rb = Rt - C - Bc
|
||||
self._addRaise(street, player, C, Rb, Rt)
|
||||
|
||||
def _addRaise(self, street, player, C, Rb, Rt):
|
||||
|
|
|
@ -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
|
||||
|
|
141
pyfpdb/SQL.py
141
pyfpdb/SQL.py
|
@ -3088,6 +3088,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>
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
|
@ -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."
|
||||
|
|
|
@ -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
|
@ -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
|
||||
|
||||
|
|
|
@ -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
|
||||
|
Loading…
Reference in New Issue
Block a user