Parse PokerNow CSV game logs into structured Python objects.
Project description
pokernow-log-parser
A small, dependency-free Python library that parses PokerNow CSV game logs into clean, structured Python objects.
It focuses on extraction and basic summary statistics — turning the raw text log into hands, actions, boards, shown cards, and per-player net results. It deliberately does not do any plotting or advanced analysis, so you can build whatever analytics you like on top of the structured data.
Features
- Parses the full PokerNow CSV export format (the
entry/at/ordercolumns). - Re-sorts the log into chronological order automatically.
- Extracts, per hand:
- hand number, hand id, game type, dealer / dead button, timestamp
- seats and starting stacks
- blinds, straddles, antes, and missed/missing blinds
- every action (fold / check / call / bet / raise / show) with street and all-in flag
- community cards, including run-it-twice second boards
- shown hole cards and the exporting account's own hand
- pots collected (with showdown hand descriptions)
- reconstructed net chip result for every player (verified zero-sum)
- table position for every player (
BTN,SB,BB,UTG,UTG+1, …)
- Handles mid-hand player ID changes, collapsing them onto one identity.
- Basic session summary: per-player net results, hands played, VPIP, wins, losses, folds by street, biggest win/loss, and more.
- Pure standard library — no third-party runtime dependencies.
Installation
pip install pokernow-log-parser
Install the latest unreleased code straight from GitHub:
pip install "git+https://github.com/horris-umich/pokernow-log-parser.git"
Or, from a checkout of this repository:
pip install .
Quick start
from pokernow_parser import PokerNowParser, summarize
log = PokerNowParser().parse_file("my_game.csv")
print(f"{len(log)} hands, players: {log.players}")
# Inspect a single hand
hand = log.hands[0]
print(hand.number, hand.dealer, hand.board)
print(hand.net_results) # {'Alice @ aaa111': 35.0, 'Bob @ bbb222': -5.0, ...}
print(hand.positions) # {'Alice @ aaa111': 'BTN', 'Bob @ bbb222': 'SB', ...}
print(hand.position_of("Bob @ bbb222")) # 'SB'
# Session summary
summary = summarize(log)
for stats in summary.top_winners():
print(f"{stats.player:>20} net={stats.net_result:+.0f} vpip={stats.vpip:.0%}")
You can also parse directly from a string:
from pokernow_parser import parse_string
log = parse_string(open("my_game.csv").read())
Data model
| Object | Description |
|---|---|
GameLog |
The whole parsed log: .hands, .players, .id_aliases. |
Hand |
One hand: header info, seats, actions, board, pots, net_results, … |
Action |
A single action: player, action (ActionType), street (Street), amount, all_in. |
Seat |
A player's seat number and starting stack. |
Pot |
A pot/portion collected by a player, with optional showdown hand description. |
Card |
A parsed card with rank, suit, and numeric value. |
SessionSummary / PlayerStats |
Aggregated session and per-player statistics. |
How net results are computed
Each player's net for a hand is:
net = chips collected + uncalled chips returned − chips committed
Per-street commitment follows PokerNow's "to-amount" convention: a
call/bet/raise sets the street total (it already includes any blind
posted earlier that street), while dead money (antes, missed/missing blinds) is
additive. Across every sample log this reconstruction is exactly zero-sum per
hand — a useful correctness invariant that the test suite enforces.
Table positions
Positions are labelled clockwise from the button — BTN, SB, BB, UTG,
UTG+1, … — independent of table size. Heads-up is handled (the button is the
small blind), as are "dead small blind" hands (the labels shift up by one when
no small blind is posted). For the rare "dead button" hands the blind labels
remain exact while the button label is a best-effort approximation. Validated
against the sample logs, the small- and big-blind posters are labelled SB and
BB in 100% of standard hands.
Development
pip install -e ".[dev]"
pytest # run the test suite
ruff check src tests # lint
The tests run against a small, fully sanitized sample log
(tests/data/sample_session.csv) containing only fictional names and IDs.
Releasing
Releases are published to PyPI automatically via GitHub Actions using Trusted Publishing (OIDC — no tokens). To cut a release:
- Bump
versioninpyproject.tomland__version__insrc/pokernow_parser/__init__.py, and updateCHANGELOG.md. - Create a GitHub Release with a tag like
v0.2.0. - The
Publish to PyPIworkflow runs the tests, builds, and uploads.
License
MIT — see LICENSE.
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file pokernow_log_parser-0.2.0.tar.gz.
File metadata
- Download URL: pokernow_log_parser-0.2.0.tar.gz
- Upload date:
- Size: 19.3 kB
- Tags: Source
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
d63dde11be766a03420d408d645e3e2a4d32eb364e7feca996bfe5728faed7a3
|
|
| MD5 |
70e5d4cd2f7abe9ae59fd61e1ef950bd
|
|
| BLAKE2b-256 |
c330ca1f840741e9920bb4f9e8faa1442b6576b687e8ac59697aadd42b675246
|
Provenance
The following attestation bundles were made for pokernow_log_parser-0.2.0.tar.gz:
Publisher:
publish.yml on horris-umich/pokernow-log-parser
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
pokernow_log_parser-0.2.0.tar.gz -
Subject digest:
d63dde11be766a03420d408d645e3e2a4d32eb364e7feca996bfe5728faed7a3 - Sigstore transparency entry: 1947126491
- Sigstore integration time:
-
Permalink:
horris-umich/pokernow-log-parser@4b125b69e07cde5741e3b3d3bde63340cae9259f -
Branch / Tag:
- Owner: https://github.com/horris-umich
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish.yml@4b125b69e07cde5741e3b3d3bde63340cae9259f -
Trigger Event:
release
-
Statement type:
File details
Details for the file pokernow_log_parser-0.2.0-py3-none-any.whl.
File metadata
- Download URL: pokernow_log_parser-0.2.0-py3-none-any.whl
- Upload date:
- Size: 18.3 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
91929637fcd76ed80bec0ef10aaa4111ab04441a94b442aca073f18385a214bb
|
|
| MD5 |
69a3996ccb61c1893b86637c03076df5
|
|
| BLAKE2b-256 |
41ef380e9db2af107606398544e519f5d391034c90e5d446728c9eae06f2180c
|
Provenance
The following attestation bundles were made for pokernow_log_parser-0.2.0-py3-none-any.whl:
Publisher:
publish.yml on horris-umich/pokernow-log-parser
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
pokernow_log_parser-0.2.0-py3-none-any.whl -
Subject digest:
91929637fcd76ed80bec0ef10aaa4111ab04441a94b442aca073f18385a214bb - Sigstore transparency entry: 1947126825
- Sigstore integration time:
-
Permalink:
horris-umich/pokernow-log-parser@4b125b69e07cde5741e3b3d3bde63340cae9259f -
Branch / Tag:
- Owner: https://github.com/horris-umich
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish.yml@4b125b69e07cde5741e3b3d3bde63340cae9259f -
Trigger Event:
release
-
Statement type: