Metadata-Version: 2.4
Name: openmatchkit
Version: 0.3.0
Summary: Unofficial open-source football match data toolkit using public sources.
Project-URL: Homepage, https://github.com/patilprashan246/openmatchkit
Project-URL: Repository, https://github.com/patilprashan246/openmatchkit
Project-URL: Issues, https://github.com/patilprashan246/openmatchkit/issues
Author: Prashant Patil
License: MIT License
Keywords: cli,fixtures,football,open-data,prediction,scores,soccer,world-cup
Classifier: Development Status :: 3 - Alpha
Classifier: Intended Audience :: Developers
Classifier: Intended Audience :: Education
Classifier: Intended Audience :: Science/Research
Classifier: License :: OSI Approved :: MIT License
Classifier: Operating System :: OS Independent
Classifier: Programming Language :: Python :: 3
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: Topic :: Software Development :: Libraries :: Python Modules
Requires-Python: >=3.10
Requires-Dist: beautifulsoup4>=4.12
Requires-Dist: httpx>=0.27
Requires-Dist: lxml>=5.0
Requires-Dist: pydantic>=2.7
Requires-Dist: typer>=0.12
Provides-Extra: dev
Requires-Dist: build>=1.2; extra == 'dev'
Requires-Dist: pytest>=8.0; extra == 'dev'
Requires-Dist: ruff>=0.5; extra == 'dev'
Requires-Dist: twine>=5.1; extra == 'dev'
Description-Content-Type: text/markdown

# openmatchkit

[![CI](https://github.com/patilprashan246/openmatchkit/actions/workflows/ci.yml/badge.svg)](https://github.com/patilprashan246/openmatchkit/actions/workflows/ci.yml)
[![PyPI](https://img.shields.io/pypi/v/openmatchkit)](https://pypi.org/project/openmatchkit/)
[![Release](https://img.shields.io/github/v/release/patilprashan246/openmatchkit)](https://github.com/patilprashan246/openmatchkit/releases)
[![Python](https://img.shields.io/badge/python-3.10%2B-blue)](pyproject.toml)
[![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](LICENSE)

Unofficial open-source football match data toolkit for fixtures, results, best-effort live score adapters, standings, exports, and simple prediction models.

> This project is unofficial and not affiliated with FIFA, any league, club, broadcaster, federation, or data provider. It does not provide official FIFA data.

## Why openmatchkit?

openmatchkit gives Python developers a clean, source-attributed way to work with public football match facts without paid API keys. It starts with open/public datasets, keeps scraping optional and conservative, and returns structured JSON-ready models.

## Install

```bash
pip install openmatchkit
```

From GitHub:

```bash
pip install git+https://github.com/patilprashan246/openmatchkit.git@v0.3.0
```

For local development:

```bash
python -m venv .venv
.venv\Scripts\activate
python -m pip install --upgrade pip
python -m pip install -e ".[dev]"
pytest
```

## Quick Start

```python
from openmatchkit import MatchClient

client = MatchClient()
next_match = client.next_match(competition="worldcup", season="2026")

print(next_match.model_dump(mode="json"))
```

```bash
openmatch next-match --competition worldcup --season 2026
```

## Python API

```python
from openmatchkit import MatchClient

client = MatchClient()

fixtures = client.fixtures(competition="worldcup", season="2026")
results = client.results(competition="worldcup", season="2026")
live = client.live_scores()
next_match = client.next_match(competition="worldcup", season="2026")
prediction = client.predict(home="Mexico", away="South Africa", history=results)

client.export_json(fixtures, "fixtures.json")
client.export_csv(fixtures, "fixtures.csv")
```

League datasets from OpenFootball can be fetched with codes such as:

```python
matches = client.fixtures(competition="en.1", season="2015-16")
```

## Functionality Reference

All public models are Pydantic models. Use `.model_dump(mode="json")` when you want JSON-ready dictionaries, or use the CLI commands when you want JSON printed directly.

### Source Metadata

```python
client.source_capabilities()
client.source_health()
```

Returns source capability and local health metadata:

```json
[
  {
    "source": "openfootball",
    "fixtures": true,
    "results": true,
    "live_scores": false,
    "scoreboards": true,
    "player_history": false,
    "standings": true,
    "prediction_history": true,
    "notes": [
      "OpenFootball provides fixtures/results; detailed player data is unavailable."
    ]
  }
]
```

### Fixtures, Results, Search, Upcoming, Recent

```python
fixtures = client.fixtures("worldcup", "2026")
results = client.results("worldcup", "2026")
matches = client.search_matches("worldcup", "2026", team="Canada", status="scheduled")
upcoming = client.upcoming_matches("worldcup", "2026", team="Canada", limit=3)
recent = client.recent_results("worldcup", "2026", limit=5)
next_match = client.next_match("worldcup", "2026")
match = client.match_by_id(match_id="...", competition="worldcup", season="2026")
```

Each item is a `Match`:

```json
{
  "match_id": "ded80f9a2a529045",
  "competition": "World Cup 2026",
  "season": "2026",
  "round": "Matchday 2",
  "group": "Group B",
  "kickoff": "2026-06-12T15:00:00-04:00",
  "home": {"name": "Canada", "code": null, "country": null},
  "away": {"name": "Bosnia & Herzegovina", "code": null, "country": null},
  "score": {"home": null, "away": null},
  "status": "scheduled",
  "venue": "Toronto",
  "source": "openfootball",
  "source_url": "https://raw.githubusercontent.com/openfootball/worldcup.json/master/2026/worldcup.json",
  "fetched_at": "2026-06-12T10:46:21.427460Z"
}
```

### Scoreboards and Match Summaries

```python
summary = client.match_summary(match_id="detail-1", competition="Demo Cup", season="2026")
scoreboard = client.scoreboard(match_id="detail-1")
scoreboards = client.scoreboards(competition="Demo Cup", season="2026")
live_boards = client.live_scoreboards()
```

`Scoreboard` can include match clock, lineups, events, team stats, and player stats when the configured source provides them:

```json
{
  "match": {
    "match_id": "detail-1",
    "competition": "Demo Cup",
    "home": {"name": "Team A"},
    "away": {"name": "Team B"},
    "score": {"home": 1, "away": 0},
    "status": "live"
  },
  "clock": {"minute": 45, "added_time": 2, "period": "first_half", "display": "45+2"},
  "events": [
    {
      "event_type": "goal",
      "team": "Team A",
      "player": "Alex Demo",
      "assist": "Sam Creator",
      "minute": 34,
      "home_score": 1,
      "away_score": 0
    }
  ],
  "team_stats": [
    {"team": "Team A", "possession": 58.4, "shots": 7, "shots_on_target": 3}
  ],
  "player_stats": [
    {"player": {"name": "Alex Demo", "team": "Team A"}, "goals": 1, "minutes_played": 45}
  ],
  "source_notes": ["Demo fixture representing an authorized detailed public JSON feed."]
}
```

### Teams, Standings, Form, Head-to-Head

```python
teams = client.teams("worldcup", "2026")
table = client.standings("worldcup", "2026", group="Group A")
form = client.team_form("Mexico", "worldcup", "2026", last=5)
h2h = client.head_to_head("Mexico", "South Africa", "worldcup", "2026")
```

`TeamForm` returns recent results from the team perspective:

```json
{
  "team": "Mexico",
  "competition": "worldcup",
  "season": "2026",
  "requested_last": 5,
  "played": 1,
  "wins": 1,
  "draws": 0,
  "losses": 0,
  "goals_for": 2,
  "goals_against": 0,
  "goal_difference": 2,
  "points": 3,
  "form": ["W"],
  "matches": [
    {
      "opponent": "South Africa",
      "home_away": "home",
      "team_score": 2,
      "opponent_score": 0,
      "result": "W"
    }
  ]
}
```

`HeadToHeadSummary` returns aggregate history plus latest matches:

```json
{
  "team_a": "Mexico",
  "team_b": "South Africa",
  "matches": 1,
  "team_a_wins": 1,
  "draws": 0,
  "team_b_wins": 0,
  "team_a_goals": 2,
  "team_b_goals": 0,
  "latest_matches": []
}
```

### Player History

Player history depends on a source that legally provides player-level public match facts. The default OpenFootball adapter does not include player stats, but `JsonFileSource` supports detailed authorized feeds:

```python
from openmatchkit import MatchClient
from openmatchkit.sources.json_file import JsonFileSource

client = MatchClient(sources=[JsonFileSource("tests/fixtures/sample_detailed_source.json")])
history = client.player_history("Alex Demo")
print(history.model_dump(mode="json"))
```

```json
{
  "player": {"name": "Alex Demo", "team": "Team A", "position": "FW", "shirt_number": 9},
  "totals": {
    "appearances": 1,
    "starts": 1,
    "minutes_played": 45,
    "goals": 1,
    "assists": 0,
    "yellow_cards": 1,
    "red_cards": 0
  },
  "appearances": [
    {
      "match_id": "detail-1",
      "team": "Team A",
      "opponent": "Team B",
      "home_away": "home",
      "goals": 1,
      "source": "demo_public_feed"
    }
  ]
}
```

### Prediction

```python
history = client.results("worldcup", "2026")
prediction = client.predict(home="Mexico", away="South Africa", history=history)
```

Returns an educational baseline only:

```json
{
  "home": "Mexico",
  "away": "South Africa",
  "home_win_probability": 0.45,
  "draw_probability": 0.27,
  "away_win_probability": 0.28,
  "expected_home_goals": 1.2,
  "expected_away_goals": 0.9,
  "model": "simple_poisson",
  "training_matches": 2,
  "note": "Educational baseline only. Not betting, financial, or professional advice."
}
```

### Export

```python
client.export_json(fixtures, "fixtures.json")
client.export_csv(fixtures, "fixtures.csv")
```

JSON export keeps full nested model data. CSV export flattens match-level fields for spreadsheet tools.

## CLI

```bash
openmatch sources
openmatch health
openmatch fixtures --competition worldcup --season 2026
openmatch search --competition worldcup --season 2026 --team Canada --status scheduled
openmatch results --competition en.1 --season 2015-16 --format csv --output results.csv
openmatch upcoming --competition worldcup --season 2026 --team Canada --limit 3
openmatch recent --competition worldcup --season 2026 --limit 5
openmatch next-match --competition worldcup --season 2026
openmatch match-summary --match-id detail-1 --data-file tests/fixtures/sample_detailed_source.json
openmatch standings --competition worldcup --season 2026
openmatch team-form --team Mexico --competition worldcup --season 2026
openmatch head-to-head --team-a Mexico --team-b "South Africa" --competition worldcup --season 2026
openmatch predict --home Mexico --away "South Africa" --competition worldcup --season 2026
```

Detailed JSON feeds can expose richer scoreboards and player history:

```bash
openmatch scoreboards --data-file tests/fixtures/sample_detailed_source.json
openmatch scoreboard --match-id detail-1 --data-file tests/fixtures/sample_detailed_source.json
openmatch live-scoreboards --data-file tests/fixtures/sample_detailed_source.json
openmatch player-history --player "Alex Demo" --data-file tests/fixtures/sample_detailed_source.json
```

```python
from openmatchkit import MatchClient
from openmatchkit.sources.json_file import JsonFileSource

client = MatchClient(sources=[JsonFileSource("tests/fixtures/sample_detailed_source.json")])
scoreboard = client.scoreboard(match_id="detail-1")
history = client.player_history("Alex Demo")
print(scoreboard.model_dump(mode="json"))
print(history.model_dump(mode="json"))
```

## Example Output

```json
{
  "competition": "World Cup 2026",
  "home": {"name": "Canada"},
  "away": {"name": "Bosnia & Herzegovina"},
  "status": "scheduled",
  "source": "openfootball"
}
```

## Features

- Unified match, scoreboard, player history, standings, and prediction models
- OpenFootball JSON adapter
- Football-Data.co.uk CSV adapter
- Local detailed JSON adapter for authorized/public detailed feeds
- Generic optional public HTML adapter
- Safe HTTP client with robots.txt checks, caching, user agent, and per-origin delay
- Fixtures, results, search, upcoming/recent matches, next match, live score adapter interface
- Source capabilities and health metadata
- Team info, grouped standings, team form, and head-to-head summaries
- Detailed scoreboards: clock, events, lineups, team stats, and player match stats when provided
- Player histories aggregated from player-level source data
- Simple Poisson prediction baseline and small Elo rating helper
- JSON and CSV export helpers
- Offline tests using local fixtures

## Current Status

- Stable enough for demos, research, education, and early open-source feedback
- Not official live FIFA data
- True live/player-level data requires a lawful source adapter that provides those facts
- Public roadmap: [ROADMAP.md](ROADMAP.md)
- Release notes: [CHANGELOG.md](CHANGELOG.md)

## Source and legal policy

The package code is MIT licensed. Third-party data sources have their own licenses and terms. Optional scraping adapters must respect Terms of Service, robots.txt, caching, and rate limits. Player-level data should only come from public or authorized sources and should contain public sporting facts, not private or sensitive information.

See [DATA_SOURCES.md](DATA_SOURCES.md), [PRIVACY.md](PRIVACY.md), and [CONTRIBUTING.md](CONTRIBUTING.md).

## Development

```bash
python -m pip install -e ".[dev]"
ruff check .
ruff format .
pytest
python -m build
```

The prediction output is an educational baseline only. It is not betting, financial, or professional advice.
