Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 13 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@

## [Unreleased]

## [1.1.0] - 2026-10-23

### Fixed

- Match pages and `Summary()` load inside Jupyter and other code that already
Expand All @@ -10,8 +12,19 @@

### Added

- `Ground` (city, country, capacity, indoor) from ESPN's venue records, and
`Match.ground` to load a match's ground (#8).
- `Match.get_match_ids(year, match_format)`: every international match id of
one format in a year, from Statsguru, back to 1877. With `Match(match_id)`
this loads every scorecard of a format (#34).
- `Match.get_matches_on(date)`: the matches being played on one day, Tests
included on each of their days (#28).
- `Match(match_id)` works without a series ID: the match page is found from
the match ID and `series_id` is read from it (#50).
- Each `Match.innings` entry has `fours` and `sixes`: ESPN's innings total,
else the sum over batters who batted, else None (#54).
- `Match.over_by_over`: runs and wickets per over for each innings, typed as
`OverEntry` rows; empty where ESPN has no over data (#42).
- `Series.season(key)` finds a season by year or by ESPNcricinfo's two-year
label (`"2024/25"`), and `Season.label` gives that label. Multi-year seasons
live under their own series ID, now reachable as `season.series_id` (#76).
Expand Down
2 changes: 1 addition & 1 deletion CITATION.cff
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ authors:
- family-names: "Sood"
given-names: "Gaurav"
title: "python-espncricinfo: A Python client for ESPNcricinfo match, series and player data"
version: 1.0.1
version: 1.1.0
date-released: 2026-10-23
url: "https://github.com/outside-edge/python-espncricinfo"
repository-code: "https://github.com/outside-edge/python-espncricinfo"
Expand Down
16 changes: 14 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,7 @@ MatchRef(series_id=1523975, match_id=1523981)
>>> series_id, match_id = refs[0] # MatchRefs unpack like tuples
```

`Summary(date=...)` wraps the same call; its result is in `.matches`.
For one day only, `Match.get_matches_on("2026-10-20")` keeps the matches played that day, multi-day matches included on each of their days. `Summary(date=...)` wraps the same call; its result is in `.matches`.

## A single match

Expand All @@ -70,7 +70,19 @@ A match needs only its match ID, the number in a match page URL. Passing the ser
('D Brown', 0)
```

`batting_scorecard` and `bowling_scorecard` hold one list per innings and one dict per player.
To work through every match of a format, list a year's match IDs from Statsguru (1 Test, 2 ODI, 3 T20I, 8/9/10 the women's formats) and load each one. Each load starts a browser, so a year of Tests takes a minute or two:

```python
>>> ids = Match.get_match_ids(2023, 1)
>>> len(ids)
34
>>> Match(ids[0]).description
'New Zealand v Pakistan'
```

`batting_scorecard` and `bowling_scorecard` hold one list per innings and one dict per player. `over_by_over` gives runs and wickets for every over, and each `m.innings` entry has `fours` and `sixes`.

`m.ground` loads the ground record (`Ground` in `espncricinfo.grounds`): name, city, country, capacity.

## Players

Expand Down
7 changes: 7 additions & 0 deletions docs/api/grounds.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
# Grounds

```{eval-rst}
.. autoclass:: espncricinfo.grounds.Ground
:members:
:member-order: bysource
```
2 changes: 2 additions & 0 deletions docs/api/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ types shown here.
series.Series
seasons.Season
teams.Team
grounds.Ground
```

```{toctree}
Expand All @@ -26,5 +27,6 @@ types shown here.
matches
players
series
grounds
exceptions
```
5 changes: 5 additions & 0 deletions docs/api/matches.md
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,11 @@ their keys and value types.
:undoc-members:
:member-order: bysource

.. autoclass:: espncricinfo.match.OverEntry
:members:
:undoc-members:
:member-order: bysource

.. autoclass:: espncricinfo.match.BowlingEntry
:members:
:undoc-members:
Expand Down
4 changes: 4 additions & 0 deletions espncricinfo/exceptions.py
Original file line number Diff line number Diff line change
Expand Up @@ -23,3 +23,7 @@ class NoSeasonError(TypeError):

class NoTeamError(TypeError):
"""Exception raised if a team does not exist in a series."""


class NoGroundError(TypeError):
"""Raised when a ground does not exist."""
53 changes: 53 additions & 0 deletions espncricinfo/grounds.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
"""Grounds (ESPN "venues") from the ESPN core API."""

from typing import Any

from espncricinfo._core import get_json
from espncricinfo.exceptions import NoGroundError

_VENUES = "http://core.espnuk.org/v2/sports/cricket/venues"


class Ground:
"""A cricket ground. Example values are for ``Ground(56293)``."""

#: ESPNcricinfo ground id, as in ``Match.ground_id``.
ground_id: int
#: ``'Adelaide Oval'``.
name: str
#: Short name, often the same as ``name``.
short_name: str | None
#: ``'Adelaide'``, or None.
city: str | None
#: ``'Australia'``, or None.
country: str | None
#: Seating capacity, or None if ESPN has none.
capacity: int | None
#: True for an indoor ground, or None if unknown.
indoor: bool | None
#: The core API venue record.
json: dict[str, Any]

def __init__(self, ground_id: int | str) -> None:
"""Load the ground record.

Args:
ground_id: ESPNcricinfo ground id, e.g. ``Match.ground_id``.
"""
self.ground_id = int(ground_id)
self.json = get_json(f"{_VENUES}/{self.ground_id}", NoGroundError)
address = self.json.get("address") or {}
self.name = self.json["fullName"]
self.short_name = self.json.get("shortName")
self.city = address.get("city") or None
self.country = address.get("country") or None
self.capacity = self.json.get("capacity") or None
self.indoor = self.json.get("indoor")

def __str__(self) -> str:
"""Return the ground's name."""
return self.name

def __repr__(self) -> str:
"""Return ``Ground(ground_id)``."""
return f"Ground({self.ground_id})"
Loading
Loading