Cricket NRR, DLS par scores, and tournament standings — done correctly
Project description
cricket-nrr
A robust, production-ready Python package for cricket analytics. It calculates exact cricket over arithmetic, ICC-compliant Net Run Rates (NRR), Duckworth-Lewis-Stern (DLS) par scores/revised targets, and tournament standings with what-if predictors and qualification margin solvers.
Designed for developers, analysts, and sports enthusiasts, cricket-nrr has zero external dependencies (pure Python standard library), though it integrates seamlessly with pandas if available.
Key Features
-
Exact Cricket Over Arithmetic (
cricket_nrr.overs)- Native Python floats break under cricket base-6 decimal notation (e.g.
14.3 + 0.4is not14.7but15.1). - Automatically validates over notation (rejecting inputs like
19.6or19.7). - Uses
fractions.Fractioninternally for exact fraction math (e.g.19.3overs is represented as exactly117/6overs). - Full operator overloading for intuitive arithmetic:
Over("19.3") + Over("0.4") == Over("20.1").
- Native Python floats break under cricket base-6 decimal notation (e.g.
-
ICC-Compliant NRR Calculator (
cricket_nrr.nrr)- The All-Out Rule: If a team is bowled out, their full over quota (e.g.
20or50overs) is automatically used as the denominator instead of the actual overs faced. - DLS Match Rule: In rain-curtailed matches, the team batting second has their target and overs quota adjusted to the revised target and overs allotment, and the team batting first has their score adjusted to the DLS par score for those revised overs.
- Super-Over Exclusion: Super-overs are strictly excluded from NRR calculations.
- No-Result Exclusion: Abandoned/no-result matches are excluded.
- Cumulative NRR Aggregation: Automatically aggregates runs and overs across matches first, and then divides, instead of averaging per-match NRR values.
- The All-Out Rule: If a team is bowled out, their full over quota (e.g.
-
DLS Standard Edition Engine (
cricket_nrr.dls)- Implements the complete 51×10 Duckworth-Lewis-Stern (DLS) Standard Edition resource table (covering 0 to 50 overs left, and 0 to 9 wickets lost).
- Supports 2-dimensional interpolation for fractional overs.
- Calculates revised targets and par scores for both between-innings and mid-innings interruptions (using standard ICC $G_{50}$ constants).
- Zero-dependency logic with optional vectorised pandas integrations for high-performance match simulation.
-
Standings Tables & Qualification Predictors (
cricket_nrr.standings)- Renders formatted tournament standings tables sorted by points, NRR, and wins.
- What-If Predictor: Solves equations to answer queries like:
- "If we score 195 batting first, what is the maximum we can concede to hit an NRR of +0.000?"
- "If the opponent scores 170, what is the minimum runs we must score to exceed +0.300 NRR?"
- Qualification Margin Solver: Checks if a final group match qualifies a team ahead of their closest rival, detailing the points margin, NRR margin, or the NRR gap shortfall.
-
Universal Data Loaders (
cricket_nrr.loaders)- Out-of-the-box support for:
- IPL 2026/matches.csv schema
- Cricsheet ball-by-ball CSV data
- Cricsheet JSON data structures
- Standard Python dict list representations
- Out-of-the-box support for:
Installation
# Pure python installation (Zero dependencies)
pip install cricket-nrr
# Optional: Install with pandas support
pip install "cricket-nrr[pandas]"
Quick Start
1. Cricket Over Arithmetic
from cricket_nrr import Over, InvalidOverError
# Parse overs from strings, floats, ints, or balls
o1 = Over("19.3")
o2 = Over(0.4)
print(o1 + o2) # Output: Over("20.1") (20 overs and 1 ball)
print((o1 + o2).balls) # Output: 121
# Subtracting and comparing overs
diff = Over("50.0") - Over("48.2")
print(diff) # Output: Over("1.4")
assert Over("20.0") > Over("19.5")
# Invalid overs raise custom error
try:
Over("19.6")
except InvalidOverError as e:
print(e) # Output: Invalid over notation: '19.6' (extra balls must be between 0 and 5)
2. Match & Cumulative Tournament NRR
from cricket_nrr import Tournament
from cricket_nrr.loaders import from_dict
# Load matches from dict representation
matches = from_dict([
{
"match_id": "1", "team1": "RCB", "team2": "CSK",
"innings1": {"runs": 218, "overs": "20.0", "wickets": 5, "all_out": False},
"innings2": {"runs": 191, "overs": "20.0", "wickets": 7, "all_out": False},
"result": "team1", "max_overs": 20,
},
{
"match_id": "2", "team1": "RCB", "team2": "MI",
"innings1": {"runs": 140, "overs": "15.2", "wickets": 10, "all_out": True}, # Bowled out!
"innings2": {"runs": 143, "overs": "14.1", "wickets": 3, "all_out": False},
"result": "team2", "max_overs": 20,
}
])
# NRR respects the 'All Out' rule: RCB's batting overs for match 2 count as full 20.0.
t = Tournament(matches)
table = t.standings()
for row in table:
print(f"{row.team:<5} | Pts: {row.points} | NRR: {row.nrr_str()}")
# Output:
# CSK | Pts: 0 | NRR: -1.350
# RCB | Pts: 2 | NRR: +0.243
# MI | Pts: 2 | NRR: +2.188
3. DLS Target and Par Scores
from cricket_nrr import DLSEngine, Over
# Match interrupted in 1st Innings:
# Match starts as a 50-over match.
# In the 1st innings, after 35 overs (score 180/3), play is stopped by rain and overs reduced to 42 overs per side.
engine = DLSEngine(g50=244)
par, revised_target = engine.calculate_target_mid_innings(
team1_score_before=180,
overs_played_before=Over("35.0"),
wickets_lost_before=3,
overs_curtailed_to=Over("42.0"),
max_overs_initial=Over("50.0")
)
print(f"Revised Target for Team 2: {revised_target} runs in 42.0 overs")
# Output: Revised Target for Team 2: 219 runs in 42.0 overs
4. Standings What-If Predictor
# Check how a team can qualify or achieve a certain NRR in their final match
# Let's say RCB wants to know the conceding threshold to keep their NRR above +0.500:
result = t.whatif_nrr(
team="RCB",
batting_first=True,
runs_scored=185,
overs_batted=Over("20.0"),
all_out=False,
max_overs=Over("20.0"),
target_nrr=0.500,
)
print(result.scenario)
# Output: "RCB scored 185 in 20.0 overs (not all out). To achieve NRR +0.500, they must concede AT MOST 141 runs in 20.0 overs."
print(f"Is achievable? {result.achievable}") # Output: True
Integration with pandas
If pandas is installed, you can effortlessly export standings tables to dataframes:
import pandas as pd
from cricket_nrr import Tournament
# Build tournament
t = Tournament(matches)
# Export standings to DataFrame
df = t.to_dataframe()
print(df[["Team", "Played", "Won", "Points", "NRR"]])
Directory Structure
cricket-nrr/
├── cricket_nrr/ # Main package source
│ ├── loaders/ # CSV, Cricsheet, JSON data loaders
│ ├── dls.py # Duckworth-Lewis-Stern Engine
│ ├── formatters.py # Helper functions to print scores & NRR
│ ├── models.py # Match and Innings data structures
│ ├── nrr.py # ICC Net Run Rate calculator
│ ├── overs.py # Cricket Over representation and arithmetic
│ ├── standings.py # Tournament standings and predictors
│ └── validators.py # Input boundaries validation
├── examples/ # Example usage scripts
├── tests/ # Complete test suite (pytest)
├── pyproject.toml # Package installation & metadata
└── README.md # User manual
Testing
The package has 100% test coverage for math, validation, and ICC regulations. To run tests:
# Install development dependencies
pip install "cricket-nrr[dev]"
# Run tests
python -m pytest
License
This project is licensed under the MIT License - see the LICENSE file for details.
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 cricket_nrr-0.1.0.tar.gz.
File metadata
- Download URL: cricket_nrr-0.1.0.tar.gz
- Upload date:
- Size: 41.7 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.11.9
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
90ff4e7f6477fdc5b99bf43bd479da83a925f08053bac28b4524c8a0c633e1c3
|
|
| MD5 |
754dbb26f2a8e3ab7afc2fae675532cb
|
|
| BLAKE2b-256 |
879c2ee50f31602846de18ca8053e149d58437056619c460cd2db23e07cfece5
|
File details
Details for the file cricket_nrr-0.1.0-py3-none-any.whl.
File metadata
- Download URL: cricket_nrr-0.1.0-py3-none-any.whl
- Upload date:
- Size: 37.3 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.11.9
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
115dd238f458a259a171e46174433a8015e8ba3154e8ba44377312a9f6feccf3
|
|
| MD5 |
f3a6cd50eea2f88161c5d40ab53d2928
|
|
| BLAKE2b-256 |
88bde07a7cc3109b9527e4dc0561b30bfdffb1f312520a08eed22190794bafb8
|