Metadata-Version: 2.4
Name: espn-scores
Version: 1.0.0
Summary: A comprehensive, user-friendly Python wrapper for ESPN's live sports API
Author-email: Drew Hantzmon <drewhantzmon@gmail.com>
License-Expression: MIT
Project-URL: Homepage, https://github.com/drewhantzmon/espn-scores
Project-URL: Repository, https://github.com/drewhantzmon/espn-scores
Project-URL: Issues, https://github.com/drewhantzmon/espn-scores/issues
Keywords: espn,sports,scores,api,nfl,nba,nhl,mlb,wnba,college-football,college-basketball,ncaa,soccer,golf,tennis
Classifier: Development Status :: 5 - Production/Stable
Classifier: Intended Audience :: Developers
Classifier: Topic :: Software Development :: Libraries :: Python Modules
Classifier: Topic :: Internet :: WWW/HTTP
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3.9
Classifier: Programming Language :: Python :: 3.10
Classifier: Programming Language :: Python :: 3.11
Classifier: Programming Language :: Python :: 3.12
Classifier: Programming Language :: Python :: 3.13
Classifier: Typing :: Typed
Requires-Python: >=3.9
Description-Content-Type: text/markdown
License-File: LICENSE
Requires-Dist: requests>=2.31.0
Requires-Dist: python-dateutil>=2.8.2
Provides-Extra: dev
Requires-Dist: pytest>=7.4.0; extra == "dev"
Requires-Dist: pytest-cov>=4.1.0; extra == "dev"
Requires-Dist: black>=23.7.0; extra == "dev"
Requires-Dist: flake8>=6.1.0; extra == "dev"
Requires-Dist: mypy>=1.5.0; extra == "dev"
Requires-Dist: build>=1.0.0; extra == "dev"
Requires-Dist: twine>=5.0.0; extra == "dev"
Dynamic: license-file

# ESPN Scores

[![Tests](https://github.com/drewhantzmon/espn-scores/actions/workflows/tests.yml/badge.svg)](https://github.com/drewhantzmon/espn-scores/actions/workflows/tests.yml)
[![PyPI version](https://img.shields.io/pypi/v/espn-scores.svg)](https://pypi.org/project/espn-scores/)
[![Python versions](https://img.shields.io/pypi/pyversions/espn-scores.svg)](https://pypi.org/project/espn-scores/)
[![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](LICENSE)

A Python package for fetching live sports data from ESPN's API, with a clean, minimal, dictionary-based interface. Supports **NFL, NBA, NHL, MLB, WNBA, College Football (CFB), College Basketball (CBB), Soccer** (top leagues + any ESPN-supported competition), **Golf** (PGA/LPGA), and **Tennis** (ATP/WTA).

## Features

- NFL support (weeks, preseason, playoffs)
- NBA, NHL, MLB, WNBA support (date-based queries)
- CFB support (weeks, postseason, conference filtering)
- CBB support (date-based queries, conference filtering)
- Soccer support: named top-league instances (EPL, La Liga, Bundesliga, Serie A, Ligue 1, MLS, Champions League) plus a generic function for any other ESPN-supported competition
- Golf (PGA/LPGA) and Tennis (ATP/WTA) support, with their own leaderboard/match-based response shapes
- Simple dictionary-based responses
- Real-time data from ESPN
- Filter by game status (final, live, upcoming)
- Opt-in "rich data" functions for teams, standings, box scores, news, and rankings - kept separate from the default minimal scoreboard response

## Installation

```bash
pip install espn-scores
```

## Quick Start

### NFL (Week-based)
```python
from espn_scores import nfl

# Get current week's scores
scores = nfl.current_week()

# Get only final games
final_games = nfl.final_games()

# Get a specific week
week_10 = nfl.week(10)

# Get preseason/playoff games
preseason = nfl.preseason(3)
playoffs = nfl.playoffs(1)  # Wild Card
```

### NBA / NHL / MLB / WNBA (Date-based)

These four leagues share an identical date-based interface:

```python
from espn_scores import nba, nhl, mlb, wnba

# Get today's games
games = nba.today()

# Get games from a specific date
yesterday = nba.date("20251117")  # or "2025-11-17"

# Get only final games from today
finals = nba.final_games()

# Same interface for nhl, mlb, and wnba
mlb.today()
wnba.date("20260801", status='final')
```

### CFB (Week-based)
```python
from espn_scores import cfb

# Get current week's scores
scores = cfb.current_week()

# Get only final games
final_games = cfb.final_games()

# Get a specific week
week_1 = cfb.week(1)

# Get postseason games (bowl games + playoffs)
bowls = cfb.postseason()

# Filter by conference using string names (case-insensitive)
sec_games = cfb.current_week(groups='SEC')
acc_games = cfb.current_week(groups='acc')
big_ten = cfb.week(5, groups='Big Ten')
```

### CBB (Date-based)
```python
from espn_scores import cbb

# Get today's games
games = cbb.today()

# Get games from a specific date
yesterday = cbb.date("20251117")

# Get only final games from today
finals = cbb.final_games()

# Filter by conference using string names (case-insensitive)
acc_games = cbb.today(groups='ACC')
big_ten = cbb.date("20251117", groups='Big Ten')
sec_finals = cbb.final_games(groups='SEC')
```

### Soccer

Named instances for the most popular club competitions, plus a generic `soccer.league(slug)` for anything else ESPN covers. All soccer leagues use the same date-based interface as NBA/NHL/MLB/WNBA (today/date/final_games/live_games/upcoming_games).

```python
from espn_scores import soccer

# Named top-league instances
epl_games = soccer.epl.today()
la_liga_games = soccer.la_liga.today()
bundesliga_games = soccer.bundesliga.today()
serie_a_games = soccer.serie_a.today()
ligue_1_games = soccer.ligue_1.today()
mls_games = soccer.mls.today()
ucl_games = soccer.champions_league.today()

mls_finals = soccer.mls.final_games()

# Any other ESPN-supported competition, by slug
liga_portugal = soccer.league("por.1").today()
europa_league = soccer.league("uefa.europa", display_name="Europa League").today()
```

### Golf

⚠️ **Golf has a different response shape from every other sport** - it's a many-player leaderboard, not a head-to-head matchup, so there's no `sport`/`games` key.

```python
from espn_scores import golf

pga_leaderboard = golf.pga.today()
lpga_leaderboard = golf.lpga.today()

# Or for a specific date
masters = golf.pga.date("20260410")
```

Response format:
```python
{
    "tournament": "The Open Championship",
    "status": "in_progress",  # "scheduled" | "in_progress" | "final"
    "leaderboard": [
        {"rank": 1, "player": "Rory McIlroy", "score_to_par": -12, "thru": "F", "rounds": [-5, -4, -3]},
        {"rank": 2, "player": "Scottie Scheffler", "score_to_par": -11, "thru": "F", "rounds": [-4, -4, -3]},
        ...
    ]
}
```

### Tennis

⚠️ **Tennis also has a different response shape** - matches are grouped by tournament "draw" (e.g. Men's Singles), not simple head-to-head events.

```python
from espn_scores import tennis

atp_matches = tennis.atp.today()
wta_matches = tennis.wta.today()

# Filter to a specific draw
mens_singles = tennis.atp.today(draw="singles")

# Or for a specific date
matches = tennis.atp.date("20260701")
```

Response format:
```python
{
    "tournament": "Wimbledon",
    "matches": [
        {
            "draw": "Men's Singles",
            "status": "final",  # "scheduled" | "in_progress" | "final"
            "players": [
                {"name": "Novak Djokovic", "winner": True, "sets": [6, 6, 4]},
                {"name": "Carlos Alcaraz", "winner": False, "sets": [4, 3, 6]},
            ]
        },
        ...
    ]
}
```

## Response Format

Every team-sport method (NFL/NBA/NHL/MLB/WNBA/CFB/CBB/soccer) returns a dictionary with minimal game data:

```python
{
  "sport": "NFL",
  "league": "NFL",   # alias for "sport"
  "week": 11,
  "season": 2025,
  "games": [
    {
      "id": "401772945",
      "status": "final",  # or "in_progress" or "scheduled"
      "away_team": {"name": "Jets", "abbreviation": "NYJ", "score": 14},
      "home_team": {"name": "Patriots", "abbreviation": "NE", "score": 27}
    }
  ]
}
```

Live games include `game_time` with quarter/period and clock. Scheduled games include `start_time`.

Date-based leagues (NBA/NHL/MLB/WNBA/CBB/soccer) return a `"date"` key instead of `"week"`.

Golf and tennis use their own response shapes entirely - see the sections above.

## Opt-in Rich Data

The default scoreboard methods above stay intentionally minimal. Every team-sport league instance (`nfl`, `nba`, `nhl`, `mlb`, `wnba`, `cfb`, `cbb`, and every `soccer.*` league) also exposes these opt-in methods for richer ESPN data:

| Method | Description |
|--------|-------------|
| `.teams()` | List all teams in the league |
| `.team(id_or_abbreviation)` | Detail for a single team: record, next scheduled game |
| `.roster(id_or_abbreviation)` | A team's current roster (name, position, jersey, age, height/weight, status) |
| `.schedule(id_or_abbreviation, season=None)` | A team's full season schedule (past + upcoming), in the same game shape as a scoreboard result |
| `.standings(season=None)` | Standings, grouped by conference/division where applicable |
| `.box_score(event_id, raw=False)` | Curated box score digest for a game (final score, stat leaders, injuries, odds). Pass `raw=True` for ESPN's full unfiltered payload. |
| `.play_by_play(event_id, limit=None)` | Play-by-play for a game. `limit`, if given, returns only the most recent N plays. |
| `.win_probability(event_id)` | The win-probability curve for a game |
| `.athlete(athlete_id)` | A player's profile: position, jersey, team, bio, status |
| `.gamelog(athlete_id, season=None)` | A player's per-game stat lines for a season |
| `.news(limit=10)` | Recent headlines |
| `.rankings(poll=None)` | Poll-based rankings (e.g. AP Top 25). **CFB and CBB only** - raises `UnsupportedOperationException` elsewhere, since pro leagues don't have a meaningful equivalent. |

```python
from espn_scores import nfl, mlb, cfb

teams = nfl.teams()
bills = nfl.team("BUF")             # by abbreviation
bills = nfl.team("2")               # or by ESPN team ID
roster = nfl.roster("BUF")
season_schedule = nfl.schedule("BUF")
standings = nfl.standings()
box_score = nfl.box_score("401772945")
headlines = nfl.news(limit=5)

top_25 = cfb.rankings(poll="AP")

# Player-level data
player_id = mlb.roster("CIN")["roster"][0]["id"]
profile = mlb.athlete(player_id)
game_log = mlb.gamelog(player_id)

# In-game detail for a specific matchup
plays = mlb.play_by_play("401901849", limit=10)  # 10 most recent plays
win_prob = mlb.win_probability("401901849")
```

`event_id` for `box_score()`/`play_by_play()`/`win_probability()` is the `"id"` field from a game in a scoreboard result. `athlete_id` for `athlete()`/`gamelog()` is the `"id"` field from a player in a `roster()` result. Both `athlete()` and `team()` raise `AthleteNotFoundException`/`TeamNotFoundException` respectively for an unresolvable id.

## API Reference

### NFL

| Method | Description |
|--------|-------------|
| `nfl.current_week(status=None, season_type=2)` | Get current week games |
| `nfl.week(week_number, status=None, season_type=2)` | Get specific week (1-18 regular, 1-4 preseason, 1-5 playoffs) |
| `nfl.preseason(week_number=None, status=None)` | Get preseason games (weeks 1-4) |
| `nfl.playoffs(round_number=None, status=None)` | Get playoff games (rounds 1-5) |
| `nfl.final_games()` | Current week completed games |
| `nfl.live_games()` | Current week in-progress games |
| `nfl.upcoming_games()` | Current week scheduled games |

**Season Types:** `1` = Preseason, `2` = Regular Season, `3` = Postseason

### NBA / NHL / MLB / WNBA

Identical interface across all four:

| Method | Description |
|--------|-------------|
| `.today(status=None)` | Get today's games |
| `.date(date_str, status=None)` | Get games by date (YYYYMMDD or YYYY-MM-DD) |
| `.final_games()` | Today's completed games |
| `.live_games()` | Today's in-progress games |
| `.upcoming_games()` | Today's scheduled games |

### CFB

| Method | Description |
|--------|-------------|
| `cfb.current_week(status=None, season_type=2, groups=None)` | Get current week games |
| `cfb.week(week_number, status=None, season_type=2, groups=None)` | Get specific week (1-15 regular season) |
| `cfb.postseason(week_number=None, status=None, groups=None)` | Get postseason games (bowl games + playoffs) |
| `cfb.final_games()` | Current week completed games |
| `cfb.live_games()` | Current week in-progress games |
| `cfb.upcoming_games()` | Current week scheduled games |
| `cfb.rankings(poll=None)` | AP Top 25 / Coaches Poll rankings |

**Season Types:** `2` = Regular Season, `3` = Postseason

**Conference Groups:** Use `groups` parameter to filter games involving teams from a conference (string or int).
- String names (case-insensitive): `'SEC'`, `'ACC'`, `'Big Ten'`, `'Big 12'`, `'American'`, `'Sun Belt'`, etc.
- Or numeric IDs: `1`=ACC, `4`=Big 12, `5`=Big Ten, `8`=SEC
- Or constants: `Conferences.SEC`, `Conferences.BIG_TEN`, etc.
- Note: Returns ALL games involving teams from that conference (including non-conference games)

### CBB

| Method | Description |
|--------|-------------|
| `cbb.today(status=None, groups=None)` | Get today's games |
| `cbb.date(date_str, status=None, groups=None)` | Get games by date (YYYYMMDD or YYYY-MM-DD) |
| `cbb.final_games(groups=None)` | Today's completed games |
| `cbb.live_games(groups=None)` | Today's in-progress games |
| `cbb.upcoming_games(groups=None)` | Today's scheduled games |
| `cbb.rankings(poll=None)` | AP Top 25 / Coaches Poll rankings |

**Conference Groups:** Use `groups` parameter to filter games involving teams from a conference (string or int).
- String names (case-insensitive): `'ACC'`, `'Big Ten'`, `'Big 12'`, `'SEC'`, `'Big East'`, `'American'`, `'A-10'`, `'WCC'`, etc.
- Or numeric IDs: `2`=ACC, `4`=Big East, `7`=Big Ten, `8`=Big 12, `23`=SEC
- Or constants: `CBBConferences.ACC`, `CBBConferences.BIG_TEN`, etc.
- Note: Returns ALL games involving teams from that conference (including non-conference games)

### Soccer

| Method | Description |
|--------|-------------|
| `soccer.epl` / `.la_liga` / `.bundesliga` / `.serie_a` / `.ligue_1` / `.mls` / `.champions_league` | Named league instances, same date-based interface as NBA/NHL |
| `soccer.league(slug, display_name=None)` | Any other ESPN-supported competition, by slug (e.g. `"por.1"`) |

### Golf

| Method | Description |
|--------|-------------|
| `golf.pga.today()` / `golf.lpga.today()` | Current/most recent tournament leaderboard |
| `golf.pga.date(date_str)` / `golf.lpga.date(date_str)` | Leaderboard for the tournament active on a given date |

### Tennis

| Method | Description |
|--------|-------------|
| `tennis.atp.today(draw=None)` / `tennis.wta.today(draw=None)` | Current tournament's matches, optionally filtered by draw name |
| `tennis.atp.date(date_str, draw=None)` / `tennis.wta.date(date_str, draw=None)` | Matches for the tournament active on a given date |

**Status Filters:** `'final'`, `'in_progress'`, `'scheduled'`

## Examples

```python
from espn_scores import nfl, nba, nhl, mlb, wnba, cfb, cbb, soccer, golf, tennis

# NFL - Current week
games = nfl.current_week()
finals = nfl.final_games()

# NFL - Specific week and playoffs
week_10 = nfl.week(10, status='final')
playoffs = nfl.playoffs(1)  # Wild Card

# NBA / NHL / MLB / WNBA - Today's games
games = nba.today()
finals = mlb.final_games()

# NBA - Specific date
yesterday = nba.date("20251117")
finals = nba.date("2025-11-17", status='final')

# CFB - Current week
games = cfb.current_week()
finals = cfb.final_games()

# CFB - Specific week and postseason
week_1 = cfb.week(1, status='final')
bowls = cfb.postseason()  # Bowl games + playoffs

# CFB - Conference filtering (strings or IDs)
sec_games = cfb.current_week(groups='SEC')      # String name
acc_games = cfb.current_week(groups='acc')      # Case-insensitive
big_ten_w5 = cfb.week(5, groups='Big Ten')      # String name

# CBB - Today's games
games = cbb.today()
finals = cbb.final_games()

# CBB - Conference filtering (strings or IDs)
acc_games = cbb.today(groups='ACC')             # String name
big_ten = cbb.date("20251117", groups='Big Ten') # Case-insensitive
sec_finals = cbb.final_games(groups='SEC')      # String name

# Soccer - named leagues + generic fallback
epl_games = soccer.epl.today()
mls_finals = soccer.mls.final_games()
liga_portugal = soccer.league('por.1').today()

# Golf / Tennis - different response shape (see sections above)
pga_leaderboard = golf.pga.today()
atp_matches = tennis.atp.today()

# Opt-in rich data
standings = nfl.standings()
bills = nfl.team('BUF')
top_25 = cfb.rankings(poll='AP')
```

## Requirements

- Python 3.9+
- requests
- python-dateutil

## License

MIT License

## Disclaimer

This package is not affiliated with ESPN. It uses ESPN's publicly available API.
