Poker package documentation¶
A Python framework for poker related operations.
It contains classes for parsing card Suits, Cards, Hand combinations (called Combos), construct hand Ranges and check for syntax, parse Hand histories.
It can get information from poker related websites like Pocketfives, TwoplusTwo Forum, or PokerStars website by scraping them. In the long term, it will have a fast hand evaluator and an equity calculator.
It uses the MIT license, so its code can be used in any product without legal consequences.
It aims for quality, fully tested code and easy usability with nice APIs, suitable for beginners to play with.
Contents¶
Installation¶
Simple from PYPI:
$ pip install poker
Advanced, directly from package in development mode:
$ git clone git@github.com:pokerregion/poker.git
$ cd poker
$ pip install -e .
Basic operations¶
Card suits¶
Enumeration of suits:
>>> from poker import Suit
>>> list(Suit)
[Suit('♣'), Suit('♦'), Suit('♥'), Suit('♠')]
Suits are comparable:
>>> Suit.CLUBS < Suit.DIAMONDS
True
Card ranks¶
Enumeration of ranks:
>>> from poker import Rank
>>> list(Rank)
[Rank('2'), Rank('3'), Rank('4'), Rank('5'), Rank('6'), Rank('7'), Rank('8'), Rank('9'), Rank('T'), Rank('J'), Rank('Q'), Rank('K'), Rank('A')]
Ranks are comparable:
>>> Rank('2') < Rank('A')
True
Making a random Rank:
>> Rank.make_random()
Rank('2')
Cards¶
Making a random Card:
>>> Card.make_random()
Card('As')
Comparing Cards:
>>> Card('As') > Card('Ks')
True
>>> Card('Tc') < Card('Td')
True
Implementing a deck¶
A deck is just a list of poker.card.Card
s.
Making a new deck and simulating shuffling is easy:
import random
from poker import Card
deck = list(Card)
random.shuffle(deck)
flop = [deck.pop() for __ in range(3)]
turn = deck.pop()
river = deck.pop()
Operations with Hands and Combos¶
>>> from poker.hand import Hand, Combo
List of all hands:
>>> list(Hand)
[Hand('32o'), Hand('32s'), Hand('42o'), Hand('42s'), Hand('43o'), Hand('43s'), Hand('52o'),
..., Hand('JJ'), Hand('QQ'), Hand('KK'), Hand('AA')]
Comparing:
>>> Hand('AAd') > Hand('KK')
True
>>> Combo('7s6s') > Combo('6d5d')
True
Sorting:
>>> sorted([Hand('22'), Hand('66'), Hand('76o')])
[Hand('76o'), Hand('22'), Hand('66')]
Making a random hand:
>>> Hand.make_random()
Hand('AJs')
Range parsing¶
The poker.hand.Range
class parses human readable (text) ranges like "22+ 54s 76s 98s AQo+"
to a set of Hands and
hand Combos.
"22+ AQo+ 33 AKo"
–> "22+ AQo+"
Defining ranges¶
Atomic signs
X means “any card” A K Q J T 9 8 7 6 5 4 3 2 Ace, King, Queen, Jack, Ten, 9, …, deuce “s” or “o” after hands like AKo or 76s suited and offsuit. Pairs have no suit ( ''
)- hands worse, down to deuces + hands better, up to pairs
Available formats for defining ranges:
Format Parsed range 22 one pair 44+ all pairs better than 33 66- all pairs worse than 77 55-33 55, 44, 33
None of these below select pairs (for unambiguity):
AKo, J9o offsuit hands AKs, 72s suited hands AJo+ Q8o+ offsuit hands above this: AJo, AQo, AKo Q8o, Q9o, QTo, QJo AJs+ same as offsuit 76s+ this is valid, although “+” is not neccessary, because there are no suited cards above 76s A5o- offsuit hands; A5o-A2o A5s- suited hands; A5s-A2s K7 suited and offsuited version of hand; K7o, K7s J8o-J4o J8o, J7o, J6o, J5o, J4o 76s-74s 76s, 75s, 74s J8-J4 both ranges in suited an offsuited form; J8o, J7o, J6o, J5o, J4o, J8s, J7s, J6s, J5s, J4s A5+ either suited or offsuited hands that contains an Ace and the other is bigger than 5. Same as “A5o+ A5s+”. A5- downward, same as above XX every hand (100% range) In this special case, pairs are also included (but only this) AX Any hand that contains an ace either suited or offsuit (no pairs) AXo Any offsuit hand that contains an Ace (equivalent to A2o+) AXs Any suited hand that contains an Ace (equivalent to A2s+) QX+ Any hand that contains a card bigger than a Jack; Q2+, K2+, A2+ 5X- any hand that contains a card lower than 6 KXs+ Any suited hand that contains a card bigger than a Queen KXo+ same as above with offsuit hands 7Xs- same as above 8Xo- same as above 2s2h, AsKc exact hand Combos Note
“Q+” and “Q-” are invalid ranges, because in Hold’em, there are two hands to start with not one.
Ranges are case insensitive, so "AKs"
and "aks"
and "aKS"
means the same.
Also the order of the cards doesn’t matter. "AK"
is the same as "KA"
.
Hands can be separated by space (even multiple), comma, colon or semicolon, and Combo of them (multiple spaces, etc.).
Normalization¶
Ranges should be rearranged and parsed according to these rules:
- hands separated with one space only in repr, with “, ” in str representation
- in any given hand the first card is bigger than second (except pairs of course)
- pairs first, if hyphened, bigger first
- suited hands after pairs, descending by rank
- offsuited hands at the end
Printing the range as an HTML table¶
Range has a method to_html()
. When you print the result of that, you get a simple HTML table representation of it.
Range('XX').to_html()
looks like this:
AA | AKs | AQs | AJs | ATs | A9s | A8s | A7s | A6s | A5s | A4s | A3s | A2s |
AKo | KK | KQs | KJs | KTs | K9s | K8s | K7s | K6s | K5s | K4s | K3s | K2s |
AQo | KQo | QJs | QTs | Q9s | Q8s | Q7s | Q6s | Q5s | Q4s | Q3s | Q2s | |
AJo | KJo | QJo | JJ | JTs | J9s | J8s | J7s | J6s | J5s | J4s | J3s | J2s |
ATo | KTo | QTo | JTo | TT | T9s | T8s | T7s | T6s | T5s | T4s | T3s | T2s |
A9o | K9o | Q9o | J9o | T9o | 99 | 98s | 97s | 96s | 95s | 94s | 93s | 92s |
A8o | K8o | Q8o | J8o | T8o | 98o | 88 | 87s | 86s | 85s | 84s | 83s | 82s |
A7o | K7o | Q7o | J7o | T7o | 97o | 87o | 77 | 76s | 75s | 74s | 73s | 72s |
A6o | K6o | Q6o | J6o | T6o | 96o | 86o | 76o | 66 | 65s | 64s | 63s | 62s |
A5o | K5o | Q5o | J5o | T5o | 95o | 85o | 75o | 65o | 55 | 54s | 53s | 52s |
A4o | K4o | Q4o | J4o | T4o | 94o | 84o | 74o | 64o | 54o | 44 | 43s | 42s |
A3o | K3o | Q3o | J3o | T3o | 93o | 83o | 73o | 63o | 53o | 43o | 33 | 32s |
A2o | K2o | Q2o | J2o | T2o | 92o | 82o | 72o | 62o | 52o | 42o | 32o | 22 |
You can format it with CSS, you only need to define td.pair
, td.offsuit
and td.suited
selectors.
It’s easy to recreate PokerStove style colors:
<style>
td {
/* Make cells same width and height and centered */
width: 30px;
height: 30px;
text-align: center;
vertical-align: middle;
}
td.pair {
background: #aaff9f;
}
td.offsuit {
background: #bbced3;
}
td.suited {
background: #e37f7d;
}
</style>
AA | AKs | AQs | AJs | ATs | A9s | A8s | A7s | A6s | A5s | A4s | A3s | A2s |
AKo | KK | KQs | KJs | KTs | K9s | K8s | K7s | K6s | K5s | K4s | K3s | K2s |
AQo | KQo | QJs | QTs | Q9s | Q8s | Q7s | Q6s | Q5s | Q4s | Q3s | Q2s | |
AJo | KJo | QJo | JJ | JTs | J9s | J8s | J7s | J6s | J5s | J4s | J3s | J2s |
ATo | KTo | QTo | JTo | TT | T9s | T8s | T7s | T6s | T5s | T4s | T3s | T2s |
A9o | K9o | Q9o | J9o | T9o | 99 | 98s | 97s | 96s | 95s | 94s | 93s | 92s |
A8o | K8o | Q8o | J8o | T8o | 98o | 88 | 87s | 86s | 85s | 84s | 83s | 82s |
A7o | K7o | Q7o | J7o | T7o | 97o | 87o | 77 | 76s | 75s | 74s | 73s | 72s |
A6o | K6o | Q6o | J6o | T6o | 96o | 86o | 76o | 66 | 65s | 64s | 63s | 62s |
A5o | K5o | Q5o | J5o | T5o | 95o | 85o | 75o | 65o | 55 | 54s | 53s | 52s |
A4o | K4o | Q4o | J4o | T4o | 94o | 84o | 74o | 64o | 54o | 44 | 43s | 42s |
A3o | K3o | Q3o | J3o | T3o | 93o | 83o | 73o | 63o | 53o | 43o | 33 | 32s |
A2o | K2o | Q2o | J2o | T2o | 92o | 82o | 72o | 62o | 52o | 42o | 32o | 22 |
Printing the range as an ASCII table¶
to_ascii()
can print a nicely formatted ASCII table to the
terminal:
>>> print(Range('22+ A2+ KT+ QJ+ 32 42 52 62 72').to_ascii())
AA AKs AQs AJs ATs A9s A8s A7s A6s A5s A4s A3s A2s
AKo KK KQs KJs KTs
AQo KQo QQ QJs
AJo KJo QJo JJ
ATo KTo TT
A9o 99
A8o 88
A7o 77 72s
A6o 66 62s
A5o 55 52s
A4o 44 42s
A3o 33 32s
A2o 72o 62o 52o 42o 32o 22
Hand history parsing¶
The classes in poker.room
can parse hand histories
for different poker rooms. Right now for PokerStars, Full Tilt Poker and PKR,
very efficiently with a simple API.
Parsing from hand history text¶
In one step:
from poker.room.pokerstars import PokerStarsHandHistory
# First step, only raw hand history is saved, no parsing will happen yet
hh = PokerStarsHandHistory(hand_text)
# You need to explicitly parse. This will parse the whole hh at once.
hh.parse()
Or in two steps:
from poker.room.pokerstars import PokerStarsHandHistory
hh = PokerStarsHandHistory(hand_text)
# parse the basic information only (really fast)
hh.parse_header()
# And later parse the body part. This might happen e.g. in a background task
>>> hh.parse()
I decided to implement this way, and not parse right away at object instantiation, because probably the most common operation will be looking into the hand history as fast as possible for basic information like hand id, or deferring the parsing e.g. to a message queue. This way, you basically just save the raw hand history in the instance, pass it to the queue and it will take care of parsing by the parse() call.
And also because “Explicit is better than implicit.”
Parsing from file¶
>>> hh = PokerStarsHandHistory.from_file(filename)
>>> hh.parse()
Example¶
>>> from poker.room.pokerstars import PokerStarsHandHistory
>>> hh = PokerStarsHandHistory(hand_text)
>>> hh.parse()
>>> hh.players
[_Player(name='flettl2', stack=1500, seat=1, combo=None),
_Player(name='santy312', stack=3000, seat=2, combo=None),
_Player(name='flavio766', stack=3000, seat=3, combo=None),
_Player(name='strongi82', stack=3000, seat=4, combo=None),
_Player(name='W2lkm2n', stack=3000, seat=5, combo=Combo('A♣J♥')),
_Player(name='MISTRPerfect', stack=3000, seat=6, combo=None),
_Player(name='blak_douglas', stack=3000, seat=7, combo=None),
_Player(name='sinus91', stack=1500, seat=8, combo=None),
_Player(name='STBIJUJA', stack=1500, seat=9, combo=None)]
>>> hh.date
datetime.datetime(2013, 10, 4, 19, 18, 18, tzinfo=<DstTzInfo 'US/Eastern' EDT-1 day, 20:00:00 DST>)
>>> hh.hero
_Player(name='W2lkm2n', stack=3000, seat=5, combo=Combo('A♣J♥')),
>>> hh.limit, hh.game
('NL', 'HOLDEM')
>>> hh.board
(Card('2♠'), Card('6♦'), Card('6♥'))
>>> hh.flop.is_rainbow
True
>>> hh.flop.has_pair
True
>>> hh.flop.actions
(('W2lkm2n', <Action.BET: ('bet', 'bets')>, Decimal('80')),
('MISTRPerfect', <Action.FOLD: ('fold', 'folded', 'folds')>),
('W2lkm2n', <Action.RETURN: ('return', 'returned', 'uncalled')>, Decimal('80')),
('W2lkm2n', <Action.WIN: ('win', 'won', 'collected')>, Decimal('150')),
('W2lkm2n', <Action.MUCK: ("don't show", "didn't show", 'did not show', 'mucks')>))
API¶
See all the room specific classes in them Hand history parsing API documentation.
About hand history changes¶
Poker rooms sometimes change the hand history format significally. My goal is to cover all hand histories after 2014.01.01., because it is the best compromise between fast development and good coverage. This way we don’t have to deal with ancient hand history files and overcomplicate the code and we can concentrate on the future instead of the past. Also, hopefully hand history formats are stable enough nowadays to follow this plan, less and less new game types coming up.
One of the “recent” changes made by Full Tilt is from 2013.05.10.:
“In the software update from Wednesday, changed the format of the . This means that Hold’em Manager does no longer import these hands, and the HUD is not working. … B.t.w. They just renamed “No Limit Hold’em” to “NL Hold’em”, and swapped position with the blinds, inside the handhistory files.”
Details: http://www.bankrollmob.com/forum.asp?mode=thread&id=307215
Room specific operations¶
Manipulating PokerStars player notes¶
poker.room.pokerstars.Notes
class is capable of handling PokerStars Players notes.
You can add and delete labels, and notes, save the modifications to a new file or just print the object instance and get the full XML.
>>> from poker.room.pokerstars import Notes
>>> notes = Notes.from_file('notes.W2lkm2n.xml')
>>> notes.players
('regplayer', 'sharkplayer', 'fishplayer', '"htmlchar"', '$dollarsign', 'nonoteforplayer',
'-=strangename=-', '//ÄMGS', '0bullmarket0', 'CarlGardner', 'µ (x+t)', 'Walkman')
>>> notes.labels
(_Label(id='0', color='30DBFF', name='FISH'),
_Label(id='1', color='30FF97', name='SHARK'),
_Label(id='2', color='E1FF80', name='REG'),
_Label(id='3', color='E1FF80', name='GENERAL'))
>>> notes.add_label('NIT', 'FF0000')
>>> notes.labels
(_Label(id='0', color='30DBFF', name='FISH'),
_Label(id='1', color='30FF97', name='SHARK'),
_Label(id='2', color='E1FF80', name='REG'),
_Label(id='3', color='E1FF80', name='GENERAL'))
_Label(id='4', color='FF0000', name='NIT'))
For the full API, see the Room specific classes API.
Development¶
Git repository¶
You find the repository on github: https://github.com/pokerregion/poker
In the dend/
branches, there are ideas which doesn’t work or has been abandoned for some reason.
They are there for reference as “this has been tried”.
I develop in a very simple Workflow. (Before 662f5d73be1efbf6eaf173da448e0410da431b2c you can see bigger merge bubbles, because I handled hand history parser code and the rest as two separate projects, but made a subtree merge and handle them in this package.) Feature branches with rebases on top of master. Only merge stable code into master.
The repository tags will match PyPi release numbers.
Versioning¶
I use Semantic Versioning, except for major versions like 1.0, 2.0, because I think 1.0.0 looks stupid :)
Coding style¶
PEP8 except for line length, which is 99 max (hard limit). If your code exceeds 99 characters, you do something wrong anyway, you need to refactor it (e.g. to deeply nested, harder to understand)
Dates and times¶
Every datetime throughout the library is in UTC with tzinfo set to pytz.UTC
.
If you found a case where it’s not, it’s a bug, please report it on GitHub!
The right way for setting a date correctly e.g. from PokerStars ET time is:
>>> import pytz
>>> ET = pytz.timezone('US/Eastern')
>>> ET.localize(some_datetime).astimezone(pytz.UTC)
This will consider DST settings and ambiguous times. For more information, see pytz documentation!
Unicode vs Bytes¶
The library uses the strategy from Python 3: internally, everything is using unicode, and things are converted only the I/O boundaries (e.g. opening/writing files). This is implemented by the future mechanism:
from __future__ import unicode_literals
this way, all newly defined text will be unicode by default. I only check for unicode everywhere in the code, not str, please watch this! It might feel strange the first time, but when the time comes to convert the library to Python3, it will be much easier!
New hand history parser¶
Note
Hand history parsing API will change for sure until 1.0 is done.
If you want to support a new poker room you have to subclass the appropriate class from
poker.handhistory
like poker.handhistory._SplittableHandHistory
depending on the
type of hand history file, like XML, or similar to pokerstars and FTP,
define a couple of methods and done.
class NewPokerRoomHandHistory(HandHistory):
"""Implement PokerRoom specific parsing."""
def parse_header(self):
# Parse header only! Usually just the first line. The whole purpose is to do it fast!
# No need to call super()
def _parse_table(self):
# parses table name
def _parse_players(self):
# parses players, player positions, stacks, etc
# set self.players attribute
def _parse_button(self):
def _parse_hero(self):
def _parse_preflop(self):
def _parse_street(self):
def _parse_showdown(self):
def _parse_pot(self):
def _parse_board(self):
def _parse_winners(self):
def _parse_extra(self):
You have to provide all common attributes, and may provide PokerRoom specific extra
attributes described in the base poker.handhistory.HandHistory
class API documentation.
Testing¶
The framework contains a lot of tests (over 400). The basic elements like Card, Hand, Range, etc. are fully tested.
All the unit tests are written in pytest. I choose it because it offers very nice functionality,
and no-boilerplate code for tests. No need to subclass anything, just prefix classes with Test
and methods with test_
.
All assertion use the default python assert
keyword.
You need to install the poker
package in development mode:
# from directory where setup.py file is
$ pip install -e .
and install pytest and run it directly:
$ pip install pytest
$ py.test
from the poker module directory and pytest will automatically pick up all unit tests.
About the state of Python3¶
Originally I started the library in Python3.4 only, and though everything worked well for a while and library support seemed fine, the tooling around Python3 is not there at all yet. PyPy, PyInstaller Kivy, etc, etc. doesn’t support Python3.4 at all, but even if they do, there are bugs/problems which are hard to solve, because nobody experienced it before. A nice example is that I found a bug in the 3.4 standard library enum module.
As a consequence of this, at v0.22.0 I converted the whole repository to Python2 only. The long-term strategy is to use Python2 for everything until the tooling for Python3.4 catch up, and at that point, convert it to Python3.4 and continue from there. I don’t want to develop a 2 and 3 compatible library for such a niche market, because it’s very time consuming, please don’t even ask me! (E.g. it took straight 10 hours to convert the whole library to Python2, with no new code at all…)
Glossary¶
- Suit
One of ‘c’, ‘d’, ‘h’, or ‘s’. Alternatively ‘♣’, ‘♦’, ‘♥’, ‘♠’. According to Wikipedia, suits are ranked as:
spades > hearts > diamonds > clubs
- Shape
A hand can have three “Shapes” according to Wikipedia.
‘o’ for offsuit, ‘s’ for suited hands ‘’ for pairs.
- Rank
- One card without suit. One of ‘2’, ‘3’, ‘4’, ‘5’, ‘6’, ‘7’, ‘8’, ‘9’, ‘T’, ‘J’, ‘Q’, ‘K’, ‘A’.
- Card
- One exact card with a suit. e.g. ‘As’, ‘2s’. It has a Rank and a Suit.
- Hand
- Consists two Ranks without precise suits like “AKo”, “22”.
- Hand comparisons
Comparisons in this library has nothing to do with equities or if a hand beats another. They are only defined so that a consistent ordering can be ensured when representing objects. If you want to compare hands by equity, use pypoker-eval instead.
- Comparison rules:
- pairs are ‘better’ than none-pairs
- non-pairs are better if at least one of the cards are bigger
- suited better than offsuit
- Combo
- Exact two cards with suits specified like “2s2c”, “7s6c”. There are total of 1326 Combos.
- Range
- A range of hands with either in Hand form or Combo. e.g. “55+ AJo+ 7c6h 8s6s”, “66-33 76o-73o AsJc 2s2h” or with other speical notation. (See above.)
- Range percent
- Compared to the total of 1326 hand Combos, how many are in the range?
- Range length
- Range size
- How many concrete hand Combos are in the range?
- Range is “bigger” than another
- If there are more hand Combos in it. (Equity vs each other doesn’t matter here.)
- Token
- Denote one part of a range. In a “66-33 76o-73o AsJc 2s2h” range, there are 4 tokens: - “66-33” meaning 33, 44, 55, 66 - “AsJc” specific Combo - “2s2h” a specific pair of deuces - “76o-73o” several offsuit Hands
- Broadway card
- T, J, Q, K, A
- Face card
Only: J, Q, K.
Warning
Ace is not a face card!
License¶
The MIT License (MIT)
Copyright (c) 2013-2014 Kiss György
Permission is hereby granted, free of charge, to any person obtaining a copy of
this software and associated documentation files (the "Software"), to deal in
the Software without restriction, including without limitation the rights to
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
the Software, and to permit persons to whom the Software is furnished to do so,
subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
API¶
Card API¶
The poker.card
module has three basic classes for dealing with card suits, card ranks
and cards. It also has a DECK, which is just a tuple of Cards.
Hand API¶
Shape¶
Warning
This might be removed in future version for simplify API.
Hand¶
-
class
poker.hand.
Hand
(hand)[source]¶ General hand without a precise suit. Only knows about two ranks and shape.
Parameters: hand (str) – e.g. ‘AKo’, ‘22’
Variables: -
rank_difference
¶ The difference between the first and second rank of the Hand.
Type: int
-
first
¶ Type: poker.card.Rank
-
second
¶ Type: poker.card.Rank
-
is_broadway
¶
-
is_connector
¶
-
is_offsuit
¶
-
is_one_gapper
¶
-
is_pair
¶
-
is_suited
¶
-
is_suited_connector
¶
-
is_two_gapper
¶
-
-
poker.hand.
PAIR_HANDS
= (Hand('22'), Hand('33'), Hand('44'), Hand('55'), Hand('66'), Hand('77'), Hand('88'), Hand('99'), Hand('TT'), Hand('JJ'), Hand('QQ'), Hand('KK'), Hand('AA'))¶ Tuple of all pair hands in ascending order.
-
poker.hand.
OFFSUIT_HANDS
= (Hand('32o'), Hand('42o'), Hand('43o'), Hand('52o'), Hand('53o'), Hand('54o'), Hand('62o'), Hand('63o'), Hand('64o'), Hand('65o'), Hand('72o'), Hand('73o'), Hand('74o'), Hand('75o'), Hand('76o'), Hand('82o'), Hand('83o'), Hand('84o'), Hand('85o'), Hand('86o'), Hand('87o'), Hand('92o'), Hand('93o'), Hand('94o'), Hand('95o'), Hand('96o'), Hand('97o'), Hand('98o'), Hand('T2o'), Hand('T3o'), Hand('T4o'), Hand('T5o'), Hand('T6o'), Hand('T7o'), Hand('T8o'), Hand('T9o'), Hand('J2o'), Hand('J3o'), Hand('J4o'), Hand('J5o'), Hand('J6o'), Hand('J7o'), Hand('J8o'), Hand('J9o'), Hand('JTo'), Hand('Q2o'), Hand('Q3o'), Hand('Q4o'), Hand('Q5o'), Hand('Q6o'), Hand('Q7o'), Hand('Q8o'), Hand('Q9o'), Hand('QTo'), Hand('QJo'), Hand('K2o'), Hand('K3o'), Hand('K4o'), Hand('K5o'), Hand('K6o'), Hand('K7o'), Hand('K8o'), Hand('K9o'), Hand('KTo'), Hand('KJo'), Hand('KQo'), Hand('A2o'), Hand('A3o'), Hand('A4o'), Hand('A5o'), Hand('A6o'), Hand('A7o'), Hand('A8o'), Hand('A9o'), Hand('ATo'), Hand('AJo'), Hand('AQo'), Hand('AKo'))¶ Tuple of offsuit hands in ascending order.
-
poker.hand.
SUITED_HANDS
= (Hand('32s'), Hand('42s'), Hand('43s'), Hand('52s'), Hand('53s'), Hand('54s'), Hand('62s'), Hand('63s'), Hand('64s'), Hand('65s'), Hand('72s'), Hand('73s'), Hand('74s'), Hand('75s'), Hand('76s'), Hand('82s'), Hand('83s'), Hand('84s'), Hand('85s'), Hand('86s'), Hand('87s'), Hand('92s'), Hand('93s'), Hand('94s'), Hand('95s'), Hand('96s'), Hand('97s'), Hand('98s'), Hand('T2s'), Hand('T3s'), Hand('T4s'), Hand('T5s'), Hand('T6s'), Hand('T7s'), Hand('T8s'), Hand('T9s'), Hand('J2s'), Hand('J3s'), Hand('J4s'), Hand('J5s'), Hand('J6s'), Hand('J7s'), Hand('J8s'), Hand('J9s'), Hand('JTs'), Hand('Q2s'), Hand('Q3s'), Hand('Q4s'), Hand('Q5s'), Hand('Q6s'), Hand('Q7s'), Hand('Q8s'), Hand('Q9s'), Hand('QTs'), Hand('QJs'), Hand('K2s'), Hand('K3s'), Hand('K4s'), Hand('K5s'), Hand('K6s'), Hand('K7s'), Hand('K8s'), Hand('K9s'), Hand('KTs'), Hand('KJs'), Hand('KQs'), Hand('A2s'), Hand('A3s'), Hand('A4s'), Hand('A5s'), Hand('A6s'), Hand('A7s'), Hand('A8s'), Hand('A9s'), Hand('ATs'), Hand('AJs'), Hand('AQs'), Hand('AKs'))¶ Tuple of suited hands in ascending order.
Combo¶
-
class
poker.hand.
Combo
[source]¶ Hand combination.
See Combo
-
first
¶ Type: poker.card.Card
-
second
¶ Type: poker.card.Card
-
is_broadway
¶
-
is_connector
¶
-
is_offsuit
¶
-
is_one_gapper
¶
-
is_pair
¶
-
is_suited
¶
-
is_suited_connector
¶
-
is_two_gapper
¶
-
rank_difference
¶ The difference between the first and second rank of the Combo.
-
Range¶
-
class
poker.hand.
Range
(range=u'')[source]¶ Parses a str range into tuple of Combos (or Hands).
Parameters: range (str) – Readable range in unicode Note
All of the properties below are cached_property, so make sure you invalidate the cache if you manipulate them!
-
hands
¶ Tuple of hands contained in this range. If only one combo of the same hand is present, it will be shown here. e.g.
Range('2s2c').hands == (Hand('22'),)
Type: tuple of poker.hand.Hand
s
-
combos
¶ Type: tuple of poker.hand.Combo
s
-
percent
¶ What percent of combos does this range have compared to all the possible combos.
There are 1326 total combos in Hold’em: 52 * 51 / 2 (because order doesn’t matter) Precision: 2 decimal point
Type: float (1-100)
-
rep_pieces
¶ List of str pieces how the Range is represented.
Type: list of str
-
to_html
()[source]¶ Returns a 13x13 HTML table representing the range.
The table’s CSS class is
range
, pair cells (td element) arepair
, offsuit hands areoffsuit
and suited hand cells hassuited
css class. The HTML contains no extra whitespace at all. Calculating it should not take more than 30ms (which takes calculating a 100% range).Return type: str
-
to_ascii
(border=False)[source]¶ Returns a nicely formatted ASCII table with optional borders.
Return type: str
-
classmethod
from_file
(filename)[source]¶ Creates an instance from a given file, containing a range. It can handle the PokerCruncher (.rng extension) format.
-
classmethod
from_objects
(iterable)[source]¶ Make an instance from an iterable of Combos, Hands or both.
-
slots
= (u'_hands', u'_combos')¶
-
Hand history parsing API¶
Note
Hand history parsing API will change for sure until 1.0 is done.
Constant values¶
These enumerations are used to identify common values like limit types, game, etc.
By unifying these into groups of enumeration classes, it’s possible to have common values
accross the whole framework, even when parsing totally different kind of hand histories, which
uses different values. (Data normalization)
It’s recommended to use keys (name property) to save in database, and print them to the user.
(E.g. in a web application template, {{ PokerRoom.STARS }}
will be converted to 'PokerStars'
.)
-
class
poker.constants.
Action
[source]¶ -
BET
= (u'bet', u'bets')¶
-
CALL
= (u'call', u'calls')¶
-
CHECK
= (u'check', u'checks')¶
-
FOLD
= (u'fold', u'folded', u'folds')¶
-
MUCK
= (u"don't show", u"didn't show", u'did not show', u'mucks')¶
-
RAISE
= (u'raise', u'raises')¶
-
RETURN
= (u'return', u'returned', u'uncalled')¶
-
SHOW
= (u'show',)¶
-
THINK
= (u'seconds left to act',)¶
-
WIN
= (u'win', u'won', u'collected')¶
-
-
class
poker.constants.
Currency
[source]¶ -
EUR
= (u'EUR', u'\u20ac')¶
-
GBP
= (u'GBP', u'\xa3')¶
-
STARS_COIN
= (u'SC', u'StarsCoin')¶
-
USD
= (u'USD', u'$')¶
-
-
class
poker.constants.
Game
[source]¶ -
HOLDEM
= (u"Hold'em", u'HOLDEM')¶
-
OHILO
= (u'Omaha Hi/Lo',)¶
-
OMAHA
= (u'Omaha',)¶
-
RAZZ
= (u'Razz',)¶
-
STUD
= (u'Stud',)¶
-
-
class
poker.constants.
GameType
[source]¶ -
CASH
= (u'Cash game', u'CASH', u'RING')¶
-
SNG
= (u'Sit & Go', u'SNG', u'SIT AND GO', u'Sit&go')¶
-
TOUR
= (u'Tournament', u'TOUR')¶
-
-
class
poker.constants.
Limit
[source]¶ -
FL
= (u'FL', u'Fixed limit', u'Limit')¶
-
NL
= (u'NL', u'No limit')¶
-
PL
= (u'PL', u'Pot limit')¶
-
-
class
poker.constants.
PokerRoom
[source]¶ -
EIGHT
= (u'888', u'888poker')¶
-
FTP
= (u'Full Tilt Poker', u'FTP', u'FULL TILT')¶
-
PKR
= (u'PKR', u'PKR POKER')¶
-
STARS
= (u'PokerStars', u'STARS', u'PS')¶
-
-
class
poker.constants.
Position
[source]¶ -
BB
= (u'BB', u'big blind')¶
-
BTN
= (u'BTN', u'bu', u'button')¶
-
CO
= (u'CO', u'cutoff', u'cut off')¶
-
HJ
= (u'HJ', u'hijack', u'utg+5', u'utg + 5')¶
-
SB
= (u'SB', u'small blind')¶
-
UTG
= (u'UTG', u'under the gun')¶
-
UTG1
= (u'UTG1', u'utg+1', u'utg + 1')¶
-
UTG2
= (u'UTG2', u'utg+2', u'utg + 2')¶
-
UTG3
= (u'UTG3', u'utg+3', u'utg + 3')¶
-
UTG4
= (u'UTG4', u'utg+4', u'utg + 4')¶
-
Base classes¶
-
class
poker.handhistory.
_BaseHandHistory
(hand_text)[source]¶ Abstract base class for all kinds of parser.
Parameters: hand_text (str) – poker hand text The attributes can be iterated.The class can read like a dictionary.Every attribute default value isNone
.Variables: - date_format (str) – default date format for the given poker room
- ident (str) – hand id
- game_type (poker.constants.GameType) –
"TOUR"
for tournaments or"SNG"
for Sit&Go-s - tournament_ident (str) – tournament id
- tournament_level (str) – level of tournament blinds
- currency (poker.constants.Currency) – 3 letter iso code
"USD"
,"HUF"
,"EUR"
, etc. - buyin (decimal.Decimal) – buyin without rake
- rake (decimal.Decimal) – if game_type is
"TOUR"
it’s buyin rake, if"CASH"
it’s rake from pot - game (poker.constants.Game) –
"HOLDEM"
,"OMAHA"
,"STUD"
,"RAZZ"
, etc. - limit (poker.constants.Limit) –
"NL"
,"PL"
or"FL"
- sb (decimal.Decimal) – amount of small blind
- bb (decimal.Decimal) – amount of big blind
- date (datetime) – hand date in UTC
- table_name (str) – name of the table. it’s
"tournament_number table_number"
- max_players (int) – maximum players can sit on the table, 2, 4, 6, 7, 8, 9
- button (poker.handhistory._Player) – player on the button
- hero (poker.handhistory._Player) – hero player
- players (list) – list of
poker.handhistory._Player
. the sequence is the seating order at the table at the start of the hand - flop (_Flop) – room specific Flop object
- turn (poker.card.Card) – turn card, e.g.
Card('Ah')
- river (poker.card.Card) – river card, e.g.
Card('2d')
- board (tuple) – board cards, e.g.
(Card('4s'), Card('4d'), Card('4c'), Card('5h'))
- preflop_actions (tuple) – action lines in str
- turn_actions (tuple) – turn action lines
- turn_pot (decimal.Decimal) – pot size before turn
- turn_num_players (int) – number of players seen the turn
- river_actions (tuple) – river action lines
- river_pot (decimal.Decimal) – pot size before river
- river_num_players (int) – number of players seen the river
- tournament_name (str) – e.g.
"$750 Guarantee"
,"$5 Sit & Go (Super Turbo)"
- total_pot (decimal.Decimal) – total pot after end of actions (rake included)
- show_down (bool) – There was show_down or wasn’t
- winners (tuple) – winner names, tuple if even when there is only one winner. e.g.
('W2lkm2n',)
- extra (dict) – Contains information which are specific to a concrete hand history and not common accross all. When iterating through the instance, this extra attribute will not be included. default value is None
-
class
poker.handhistory.
_Player
(name, stack, seat, combo)[source]¶ Player participating in the hand history.
Variables:
Every hand history has an attribute flop
which is an instance of the room specific _Flop
object which has the following attributes:
-
class
_Flop
¶ Variables: - cards (tuple) – tuple of
poker.card.Card
s - pot (decimal.Decimal) – pot size after actions
- players (tuple) – tuple of player names
- actions (tuple) – tuple of
poker.constants.Action
in the order of happening.Form:(Player name, Action, Amount) or(Player name, Action) if no amount needed (e.g. in case of Check)
It also has properties about flop texture like:
Variables: - cards (tuple) – tuple of
PokerStars¶
Full Tilt Poker¶
-
class
poker.room.fulltiltpoker.
FullTiltPokerHandHistory
(hand_text)[source]¶ Parses Full Tilt Poker hands the same way as PokerStarsHandHistory class.
PokerStars and Full Tilt hand histories are very similar, so parsing them is almost identical. There are small differences though.
Class specific
Variables: - tournament_level –
None
- buyin –
None
: it’s not in the hand history, but the filename - rake –
None
: also - currency –
None
- table_name (str) – just a number, but str type
Extra
Variables: - tournament_level –
Room specific classes API¶
Pokerstars player notes¶
-
class
poker.room.pokerstars.
Notes
(notes)[source]¶ Class for parsing pokerstars XML notes.
-
get_note
(player)[source]¶ Return
_Note
tuple for the player.Raises: poker.room.pokerstars.NoteNotFoundError –
-
add_note
(player, text, label=None, update=None)[source]¶ Add a note to the xml. If update param is None, it will be the current time.
Raises: poker.room.pokerstars.LabelNotFoundError – if there is no such label name
-
del_note
(player)[source]¶ Delete a note by player name.
Raises: poker.room.pokerstars.NoteNotFoundError –
-
label_names
¶ Tuple of label names.
-
labels
¶ Tuple of labels.
-
notes
¶ Tuple of notes..
-
players
¶ Tuple of player names.
-
Website API¶
This package contains mostly scraping tools for well known websites like Two Plus Two forum, Pocketsfives, etc…
Two Plus Two Forum API¶
-
poker.website.twoplustwo.
FORUM_URL
¶
-
poker.website.twoplustwo.
FORUM_MEMBER_URL
¶
-
class
poker.website.twoplustwo.
ForumMember
(username)[source]¶ Download and store a member data from the Two Plus Two forum.
Parameters: Forum id (last part of members URL, e.g. in case ofthe id is 407153)Variables: - id (str) – Forum id
- username (str) – Forum username
- rank (str) – Forum rank like
'enthusiast'
- profile_picture (str,None) – URL of profile if set.
- location (str) – Location (country)
- total_posts (int) – Total posts
- posts_per_day (float) – Posts per day on account page
- last_activity (datetime) – Last activity with the website timezone
- join_date (date) – Join date on account page
- public_usergroups (tuple) – Public usergroup permission as in the box on the top right
- donwload_date (datetime) – When were the data downloaded from TwoplusTwo
Pocketfives API¶
-
class
poker.website.pocketfives.
_Player
(name, country, triple_crowns, monthly_win, biggest_cash, plb_score, biggest_score, average_score, previous_rank)[source]¶ Pocketfives player data.
Variables: - name (str) – Player name
- country (str) – Country name
- triple_crowns (int) – Number of triple crowns won
- monthly_win (int) –
- biggest_cash (str) –
- plb_score (float) –
- biggest_score (float) – Biggest Pocketfives score
- average_score (float) – Average pocketfives score
- previous_rank (str) – Previous pocketfives rank
PokerStars website API¶
-
poker.website.pokerstars.
WEBSITE_URL
¶
-
poker.website.pokerstars.
TOURNAMENTS_XML_URL
¶ http://www.pokerstars.eu/datafeed_global/tournaments/all.xml
-
poker.website.pokerstars.
STATUS_URL
¶
-
poker.website.pokerstars.
get_current_tournaments
()[source]¶ Get the next 200 tournaments from pokerstars.
Returns: generator of _Tournament
Note
Downloading this list is an extremly slow operation!
-
poker.website.pokerstars.
get_status
()[source]¶ Get pokerstars status: players online, number of tables, etc.
Returns: _Status
-
class
poker.website.pokerstars.
_Tournament
(start_date, name, game, buyin, players)[source]¶ Upcoming pokerstars tournament.
Variables:
-
class
poker.website.pokerstars.
_Status
(updated, tables, next_update, players, clubs, active_tournaments, total_tournaments, sites, club_members)[source]¶ PokerStars status.
Variables: - updated (datetime) – Status last updated
- tables (int) – Number of tournament tables
- players (int) – Number of players logged in to PokerStars
- clubs (int) – Total number of Home Game clubs created
- club_members (int) – Total number of Home Game club members
- active_tournaments (int) –
- total_tournaments (int) –
- sites (tuple) – Tuple of
_SiteStatus