openmatchkit 0.2.1__tar.gz → 0.3.0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {openmatchkit-0.2.1 → openmatchkit-0.3.0}/CHANGELOG.md +16 -0
- openmatchkit-0.3.0/PKG-INFO +435 -0
- openmatchkit-0.3.0/README.md +400 -0
- {openmatchkit-0.2.1 → openmatchkit-0.3.0}/pyproject.toml +1 -1
- {openmatchkit-0.2.1 → openmatchkit-0.3.0}/src/openmatchkit/__init__.py +12 -0
- {openmatchkit-0.2.1 → openmatchkit-0.3.0}/src/openmatchkit/cli.py +140 -0
- {openmatchkit-0.2.1 → openmatchkit-0.3.0}/src/openmatchkit/client.py +405 -1
- {openmatchkit-0.2.1 → openmatchkit-0.3.0}/src/openmatchkit/http.py +1 -1
- {openmatchkit-0.2.1 → openmatchkit-0.3.0}/src/openmatchkit/models.py +74 -1
- {openmatchkit-0.2.1 → openmatchkit-0.3.0}/tests/test_client.py +63 -0
- openmatchkit-0.2.1/PKG-INFO +0 -192
- openmatchkit-0.2.1/README.md +0 -157
- {openmatchkit-0.2.1 → openmatchkit-0.3.0}/.github/ISSUE_TEMPLATE/bug_report.md +0 -0
- {openmatchkit-0.2.1 → openmatchkit-0.3.0}/.github/ISSUE_TEMPLATE/config.yml +0 -0
- {openmatchkit-0.2.1 → openmatchkit-0.3.0}/.github/ISSUE_TEMPLATE/feature_request.md +0 -0
- {openmatchkit-0.2.1 → openmatchkit-0.3.0}/.github/ISSUE_TEMPLATE/source_adapter.md +0 -0
- {openmatchkit-0.2.1 → openmatchkit-0.3.0}/.github/pull_request_template.md +0 -0
- {openmatchkit-0.2.1 → openmatchkit-0.3.0}/.github/workflows/ci.yml +0 -0
- {openmatchkit-0.2.1 → openmatchkit-0.3.0}/.github/workflows/publish.yml +0 -0
- {openmatchkit-0.2.1 → openmatchkit-0.3.0}/.gitignore +0 -0
- {openmatchkit-0.2.1 → openmatchkit-0.3.0}/CODE_OF_CONDUCT.md +0 -0
- {openmatchkit-0.2.1 → openmatchkit-0.3.0}/CONTRIBUTING.md +0 -0
- {openmatchkit-0.2.1 → openmatchkit-0.3.0}/DATA_SOURCES.md +0 -0
- {openmatchkit-0.2.1 → openmatchkit-0.3.0}/LICENSE +0 -0
- {openmatchkit-0.2.1 → openmatchkit-0.3.0}/PRIVACY.md +0 -0
- {openmatchkit-0.2.1 → openmatchkit-0.3.0}/ROADMAP.md +0 -0
- {openmatchkit-0.2.1 → openmatchkit-0.3.0}/SECURITY.md +0 -0
- {openmatchkit-0.2.1 → openmatchkit-0.3.0}/docs/detailed-data.md +0 -0
- {openmatchkit-0.2.1 → openmatchkit-0.3.0}/docs/index.md +0 -0
- {openmatchkit-0.2.1 → openmatchkit-0.3.0}/docs/prediction.md +0 -0
- {openmatchkit-0.2.1 → openmatchkit-0.3.0}/docs/sources.md +0 -0
- {openmatchkit-0.2.1 → openmatchkit-0.3.0}/examples/fixtures_demo.py +0 -0
- {openmatchkit-0.2.1 → openmatchkit-0.3.0}/examples/live_demo.py +0 -0
- {openmatchkit-0.2.1 → openmatchkit-0.3.0}/examples/prediction_demo.py +0 -0
- {openmatchkit-0.2.1 → openmatchkit-0.3.0}/src/openmatchkit/exceptions.py +0 -0
- {openmatchkit-0.2.1 → openmatchkit-0.3.0}/src/openmatchkit/export.py +0 -0
- {openmatchkit-0.2.1 → openmatchkit-0.3.0}/src/openmatchkit/prediction/__init__.py +0 -0
- {openmatchkit-0.2.1 → openmatchkit-0.3.0}/src/openmatchkit/prediction/elo.py +0 -0
- {openmatchkit-0.2.1 → openmatchkit-0.3.0}/src/openmatchkit/prediction/poisson.py +0 -0
- {openmatchkit-0.2.1 → openmatchkit-0.3.0}/src/openmatchkit/sources/__init__.py +0 -0
- {openmatchkit-0.2.1 → openmatchkit-0.3.0}/src/openmatchkit/sources/base.py +0 -0
- {openmatchkit-0.2.1 → openmatchkit-0.3.0}/src/openmatchkit/sources/football_data_uk.py +0 -0
- {openmatchkit-0.2.1 → openmatchkit-0.3.0}/src/openmatchkit/sources/json_file.py +0 -0
- {openmatchkit-0.2.1 → openmatchkit-0.3.0}/src/openmatchkit/sources/openfootball.py +0 -0
- {openmatchkit-0.2.1 → openmatchkit-0.3.0}/src/openmatchkit/sources/public_html.py +0 -0
- {openmatchkit-0.2.1 → openmatchkit-0.3.0}/tests/fixtures/sample_detailed_source.json +0 -0
- {openmatchkit-0.2.1 → openmatchkit-0.3.0}/tests/fixtures/sample_football_data.csv +0 -0
- {openmatchkit-0.2.1 → openmatchkit-0.3.0}/tests/fixtures/sample_openfootball.json +0 -0
- {openmatchkit-0.2.1 → openmatchkit-0.3.0}/tests/test_detailed_data.py +0 -0
- {openmatchkit-0.2.1 → openmatchkit-0.3.0}/tests/test_export.py +0 -0
- {openmatchkit-0.2.1 → openmatchkit-0.3.0}/tests/test_football_data_uk.py +0 -0
- {openmatchkit-0.2.1 → openmatchkit-0.3.0}/tests/test_http.py +0 -0
- {openmatchkit-0.2.1 → openmatchkit-0.3.0}/tests/test_models.py +0 -0
- {openmatchkit-0.2.1 → openmatchkit-0.3.0}/tests/test_openfootball.py +0 -0
- {openmatchkit-0.2.1 → openmatchkit-0.3.0}/tests/test_prediction.py +0 -0
|
@@ -1,5 +1,21 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## v0.3.0 - 2026-06-12
|
|
4
|
+
|
|
5
|
+
- Added source capability and source health models.
|
|
6
|
+
- Added match search/filter helpers.
|
|
7
|
+
- Added upcoming and recent result helpers.
|
|
8
|
+
- Added match lookup and match summary helpers.
|
|
9
|
+
- Added team form and head-to-head summaries.
|
|
10
|
+
- Added CLI commands for new features.
|
|
11
|
+
- Expanded README with detailed function-by-function JSON examples.
|
|
12
|
+
- Increased tests from 16 to 19.
|
|
13
|
+
|
|
14
|
+
## v0.2.2 - 2026-06-12
|
|
15
|
+
|
|
16
|
+
- Updated README and PyPI project description to use `pip install openmatchkit`.
|
|
17
|
+
- Added PyPI version badge.
|
|
18
|
+
|
|
3
19
|
## v0.2.1 - 2026-06-12
|
|
4
20
|
|
|
5
21
|
- Added GitHub Actions trusted publishing workflow for PyPI.
|
|
@@ -0,0 +1,435 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: openmatchkit
|
|
3
|
+
Version: 0.3.0
|
|
4
|
+
Summary: Unofficial open-source football match data toolkit using public sources.
|
|
5
|
+
Project-URL: Homepage, https://github.com/patilprashan246/openmatchkit
|
|
6
|
+
Project-URL: Repository, https://github.com/patilprashan246/openmatchkit
|
|
7
|
+
Project-URL: Issues, https://github.com/patilprashan246/openmatchkit/issues
|
|
8
|
+
Author: Prashant Patil
|
|
9
|
+
License: MIT License
|
|
10
|
+
Keywords: cli,fixtures,football,open-data,prediction,scores,soccer,world-cup
|
|
11
|
+
Classifier: Development Status :: 3 - Alpha
|
|
12
|
+
Classifier: Intended Audience :: Developers
|
|
13
|
+
Classifier: Intended Audience :: Education
|
|
14
|
+
Classifier: Intended Audience :: Science/Research
|
|
15
|
+
Classifier: License :: OSI Approved :: MIT License
|
|
16
|
+
Classifier: Operating System :: OS Independent
|
|
17
|
+
Classifier: Programming Language :: Python :: 3
|
|
18
|
+
Classifier: Programming Language :: Python :: 3.10
|
|
19
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
20
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
21
|
+
Classifier: Programming Language :: Python :: 3.13
|
|
22
|
+
Classifier: Topic :: Software Development :: Libraries :: Python Modules
|
|
23
|
+
Requires-Python: >=3.10
|
|
24
|
+
Requires-Dist: beautifulsoup4>=4.12
|
|
25
|
+
Requires-Dist: httpx>=0.27
|
|
26
|
+
Requires-Dist: lxml>=5.0
|
|
27
|
+
Requires-Dist: pydantic>=2.7
|
|
28
|
+
Requires-Dist: typer>=0.12
|
|
29
|
+
Provides-Extra: dev
|
|
30
|
+
Requires-Dist: build>=1.2; extra == 'dev'
|
|
31
|
+
Requires-Dist: pytest>=8.0; extra == 'dev'
|
|
32
|
+
Requires-Dist: ruff>=0.5; extra == 'dev'
|
|
33
|
+
Requires-Dist: twine>=5.1; extra == 'dev'
|
|
34
|
+
Description-Content-Type: text/markdown
|
|
35
|
+
|
|
36
|
+
# openmatchkit
|
|
37
|
+
|
|
38
|
+
[](https://github.com/patilprashan246/openmatchkit/actions/workflows/ci.yml)
|
|
39
|
+
[](https://pypi.org/project/openmatchkit/)
|
|
40
|
+
[](https://github.com/patilprashan246/openmatchkit/releases)
|
|
41
|
+
[](pyproject.toml)
|
|
42
|
+
[](LICENSE)
|
|
43
|
+
|
|
44
|
+
Unofficial open-source football match data toolkit for fixtures, results, best-effort live score adapters, standings, exports, and simple prediction models.
|
|
45
|
+
|
|
46
|
+
> This project is unofficial and not affiliated with FIFA, any league, club, broadcaster, federation, or data provider. It does not provide official FIFA data.
|
|
47
|
+
|
|
48
|
+
## Why openmatchkit?
|
|
49
|
+
|
|
50
|
+
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.
|
|
51
|
+
|
|
52
|
+
## Install
|
|
53
|
+
|
|
54
|
+
```bash
|
|
55
|
+
pip install openmatchkit
|
|
56
|
+
```
|
|
57
|
+
|
|
58
|
+
From GitHub:
|
|
59
|
+
|
|
60
|
+
```bash
|
|
61
|
+
pip install git+https://github.com/patilprashan246/openmatchkit.git@v0.3.0
|
|
62
|
+
```
|
|
63
|
+
|
|
64
|
+
For local development:
|
|
65
|
+
|
|
66
|
+
```bash
|
|
67
|
+
python -m venv .venv
|
|
68
|
+
.venv\Scripts\activate
|
|
69
|
+
python -m pip install --upgrade pip
|
|
70
|
+
python -m pip install -e ".[dev]"
|
|
71
|
+
pytest
|
|
72
|
+
```
|
|
73
|
+
|
|
74
|
+
## Quick Start
|
|
75
|
+
|
|
76
|
+
```python
|
|
77
|
+
from openmatchkit import MatchClient
|
|
78
|
+
|
|
79
|
+
client = MatchClient()
|
|
80
|
+
next_match = client.next_match(competition="worldcup", season="2026")
|
|
81
|
+
|
|
82
|
+
print(next_match.model_dump(mode="json"))
|
|
83
|
+
```
|
|
84
|
+
|
|
85
|
+
```bash
|
|
86
|
+
openmatch next-match --competition worldcup --season 2026
|
|
87
|
+
```
|
|
88
|
+
|
|
89
|
+
## Python API
|
|
90
|
+
|
|
91
|
+
```python
|
|
92
|
+
from openmatchkit import MatchClient
|
|
93
|
+
|
|
94
|
+
client = MatchClient()
|
|
95
|
+
|
|
96
|
+
fixtures = client.fixtures(competition="worldcup", season="2026")
|
|
97
|
+
results = client.results(competition="worldcup", season="2026")
|
|
98
|
+
live = client.live_scores()
|
|
99
|
+
next_match = client.next_match(competition="worldcup", season="2026")
|
|
100
|
+
prediction = client.predict(home="Mexico", away="South Africa", history=results)
|
|
101
|
+
|
|
102
|
+
client.export_json(fixtures, "fixtures.json")
|
|
103
|
+
client.export_csv(fixtures, "fixtures.csv")
|
|
104
|
+
```
|
|
105
|
+
|
|
106
|
+
League datasets from OpenFootball can be fetched with codes such as:
|
|
107
|
+
|
|
108
|
+
```python
|
|
109
|
+
matches = client.fixtures(competition="en.1", season="2015-16")
|
|
110
|
+
```
|
|
111
|
+
|
|
112
|
+
## Functionality Reference
|
|
113
|
+
|
|
114
|
+
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.
|
|
115
|
+
|
|
116
|
+
### Source Metadata
|
|
117
|
+
|
|
118
|
+
```python
|
|
119
|
+
client.source_capabilities()
|
|
120
|
+
client.source_health()
|
|
121
|
+
```
|
|
122
|
+
|
|
123
|
+
Returns source capability and local health metadata:
|
|
124
|
+
|
|
125
|
+
```json
|
|
126
|
+
[
|
|
127
|
+
{
|
|
128
|
+
"source": "openfootball",
|
|
129
|
+
"fixtures": true,
|
|
130
|
+
"results": true,
|
|
131
|
+
"live_scores": false,
|
|
132
|
+
"scoreboards": true,
|
|
133
|
+
"player_history": false,
|
|
134
|
+
"standings": true,
|
|
135
|
+
"prediction_history": true,
|
|
136
|
+
"notes": [
|
|
137
|
+
"OpenFootball provides fixtures/results; detailed player data is unavailable."
|
|
138
|
+
]
|
|
139
|
+
}
|
|
140
|
+
]
|
|
141
|
+
```
|
|
142
|
+
|
|
143
|
+
### Fixtures, Results, Search, Upcoming, Recent
|
|
144
|
+
|
|
145
|
+
```python
|
|
146
|
+
fixtures = client.fixtures("worldcup", "2026")
|
|
147
|
+
results = client.results("worldcup", "2026")
|
|
148
|
+
matches = client.search_matches("worldcup", "2026", team="Canada", status="scheduled")
|
|
149
|
+
upcoming = client.upcoming_matches("worldcup", "2026", team="Canada", limit=3)
|
|
150
|
+
recent = client.recent_results("worldcup", "2026", limit=5)
|
|
151
|
+
next_match = client.next_match("worldcup", "2026")
|
|
152
|
+
match = client.match_by_id(match_id="...", competition="worldcup", season="2026")
|
|
153
|
+
```
|
|
154
|
+
|
|
155
|
+
Each item is a `Match`:
|
|
156
|
+
|
|
157
|
+
```json
|
|
158
|
+
{
|
|
159
|
+
"match_id": "ded80f9a2a529045",
|
|
160
|
+
"competition": "World Cup 2026",
|
|
161
|
+
"season": "2026",
|
|
162
|
+
"round": "Matchday 2",
|
|
163
|
+
"group": "Group B",
|
|
164
|
+
"kickoff": "2026-06-12T15:00:00-04:00",
|
|
165
|
+
"home": {"name": "Canada", "code": null, "country": null},
|
|
166
|
+
"away": {"name": "Bosnia & Herzegovina", "code": null, "country": null},
|
|
167
|
+
"score": {"home": null, "away": null},
|
|
168
|
+
"status": "scheduled",
|
|
169
|
+
"venue": "Toronto",
|
|
170
|
+
"source": "openfootball",
|
|
171
|
+
"source_url": "https://raw.githubusercontent.com/openfootball/worldcup.json/master/2026/worldcup.json",
|
|
172
|
+
"fetched_at": "2026-06-12T10:46:21.427460Z"
|
|
173
|
+
}
|
|
174
|
+
```
|
|
175
|
+
|
|
176
|
+
### Scoreboards and Match Summaries
|
|
177
|
+
|
|
178
|
+
```python
|
|
179
|
+
summary = client.match_summary(match_id="detail-1", competition="Demo Cup", season="2026")
|
|
180
|
+
scoreboard = client.scoreboard(match_id="detail-1")
|
|
181
|
+
scoreboards = client.scoreboards(competition="Demo Cup", season="2026")
|
|
182
|
+
live_boards = client.live_scoreboards()
|
|
183
|
+
```
|
|
184
|
+
|
|
185
|
+
`Scoreboard` can include match clock, lineups, events, team stats, and player stats when the configured source provides them:
|
|
186
|
+
|
|
187
|
+
```json
|
|
188
|
+
{
|
|
189
|
+
"match": {
|
|
190
|
+
"match_id": "detail-1",
|
|
191
|
+
"competition": "Demo Cup",
|
|
192
|
+
"home": {"name": "Team A"},
|
|
193
|
+
"away": {"name": "Team B"},
|
|
194
|
+
"score": {"home": 1, "away": 0},
|
|
195
|
+
"status": "live"
|
|
196
|
+
},
|
|
197
|
+
"clock": {"minute": 45, "added_time": 2, "period": "first_half", "display": "45+2"},
|
|
198
|
+
"events": [
|
|
199
|
+
{
|
|
200
|
+
"event_type": "goal",
|
|
201
|
+
"team": "Team A",
|
|
202
|
+
"player": "Alex Demo",
|
|
203
|
+
"assist": "Sam Creator",
|
|
204
|
+
"minute": 34,
|
|
205
|
+
"home_score": 1,
|
|
206
|
+
"away_score": 0
|
|
207
|
+
}
|
|
208
|
+
],
|
|
209
|
+
"team_stats": [
|
|
210
|
+
{"team": "Team A", "possession": 58.4, "shots": 7, "shots_on_target": 3}
|
|
211
|
+
],
|
|
212
|
+
"player_stats": [
|
|
213
|
+
{"player": {"name": "Alex Demo", "team": "Team A"}, "goals": 1, "minutes_played": 45}
|
|
214
|
+
],
|
|
215
|
+
"source_notes": ["Demo fixture representing an authorized detailed public JSON feed."]
|
|
216
|
+
}
|
|
217
|
+
```
|
|
218
|
+
|
|
219
|
+
### Teams, Standings, Form, Head-to-Head
|
|
220
|
+
|
|
221
|
+
```python
|
|
222
|
+
teams = client.teams("worldcup", "2026")
|
|
223
|
+
table = client.standings("worldcup", "2026", group="Group A")
|
|
224
|
+
form = client.team_form("Mexico", "worldcup", "2026", last=5)
|
|
225
|
+
h2h = client.head_to_head("Mexico", "South Africa", "worldcup", "2026")
|
|
226
|
+
```
|
|
227
|
+
|
|
228
|
+
`TeamForm` returns recent results from the team perspective:
|
|
229
|
+
|
|
230
|
+
```json
|
|
231
|
+
{
|
|
232
|
+
"team": "Mexico",
|
|
233
|
+
"competition": "worldcup",
|
|
234
|
+
"season": "2026",
|
|
235
|
+
"requested_last": 5,
|
|
236
|
+
"played": 1,
|
|
237
|
+
"wins": 1,
|
|
238
|
+
"draws": 0,
|
|
239
|
+
"losses": 0,
|
|
240
|
+
"goals_for": 2,
|
|
241
|
+
"goals_against": 0,
|
|
242
|
+
"goal_difference": 2,
|
|
243
|
+
"points": 3,
|
|
244
|
+
"form": ["W"],
|
|
245
|
+
"matches": [
|
|
246
|
+
{
|
|
247
|
+
"opponent": "South Africa",
|
|
248
|
+
"home_away": "home",
|
|
249
|
+
"team_score": 2,
|
|
250
|
+
"opponent_score": 0,
|
|
251
|
+
"result": "W"
|
|
252
|
+
}
|
|
253
|
+
]
|
|
254
|
+
}
|
|
255
|
+
```
|
|
256
|
+
|
|
257
|
+
`HeadToHeadSummary` returns aggregate history plus latest matches:
|
|
258
|
+
|
|
259
|
+
```json
|
|
260
|
+
{
|
|
261
|
+
"team_a": "Mexico",
|
|
262
|
+
"team_b": "South Africa",
|
|
263
|
+
"matches": 1,
|
|
264
|
+
"team_a_wins": 1,
|
|
265
|
+
"draws": 0,
|
|
266
|
+
"team_b_wins": 0,
|
|
267
|
+
"team_a_goals": 2,
|
|
268
|
+
"team_b_goals": 0,
|
|
269
|
+
"latest_matches": []
|
|
270
|
+
}
|
|
271
|
+
```
|
|
272
|
+
|
|
273
|
+
### Player History
|
|
274
|
+
|
|
275
|
+
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:
|
|
276
|
+
|
|
277
|
+
```python
|
|
278
|
+
from openmatchkit import MatchClient
|
|
279
|
+
from openmatchkit.sources.json_file import JsonFileSource
|
|
280
|
+
|
|
281
|
+
client = MatchClient(sources=[JsonFileSource("tests/fixtures/sample_detailed_source.json")])
|
|
282
|
+
history = client.player_history("Alex Demo")
|
|
283
|
+
print(history.model_dump(mode="json"))
|
|
284
|
+
```
|
|
285
|
+
|
|
286
|
+
```json
|
|
287
|
+
{
|
|
288
|
+
"player": {"name": "Alex Demo", "team": "Team A", "position": "FW", "shirt_number": 9},
|
|
289
|
+
"totals": {
|
|
290
|
+
"appearances": 1,
|
|
291
|
+
"starts": 1,
|
|
292
|
+
"minutes_played": 45,
|
|
293
|
+
"goals": 1,
|
|
294
|
+
"assists": 0,
|
|
295
|
+
"yellow_cards": 1,
|
|
296
|
+
"red_cards": 0
|
|
297
|
+
},
|
|
298
|
+
"appearances": [
|
|
299
|
+
{
|
|
300
|
+
"match_id": "detail-1",
|
|
301
|
+
"team": "Team A",
|
|
302
|
+
"opponent": "Team B",
|
|
303
|
+
"home_away": "home",
|
|
304
|
+
"goals": 1,
|
|
305
|
+
"source": "demo_public_feed"
|
|
306
|
+
}
|
|
307
|
+
]
|
|
308
|
+
}
|
|
309
|
+
```
|
|
310
|
+
|
|
311
|
+
### Prediction
|
|
312
|
+
|
|
313
|
+
```python
|
|
314
|
+
history = client.results("worldcup", "2026")
|
|
315
|
+
prediction = client.predict(home="Mexico", away="South Africa", history=history)
|
|
316
|
+
```
|
|
317
|
+
|
|
318
|
+
Returns an educational baseline only:
|
|
319
|
+
|
|
320
|
+
```json
|
|
321
|
+
{
|
|
322
|
+
"home": "Mexico",
|
|
323
|
+
"away": "South Africa",
|
|
324
|
+
"home_win_probability": 0.45,
|
|
325
|
+
"draw_probability": 0.27,
|
|
326
|
+
"away_win_probability": 0.28,
|
|
327
|
+
"expected_home_goals": 1.2,
|
|
328
|
+
"expected_away_goals": 0.9,
|
|
329
|
+
"model": "simple_poisson",
|
|
330
|
+
"training_matches": 2,
|
|
331
|
+
"note": "Educational baseline only. Not betting, financial, or professional advice."
|
|
332
|
+
}
|
|
333
|
+
```
|
|
334
|
+
|
|
335
|
+
### Export
|
|
336
|
+
|
|
337
|
+
```python
|
|
338
|
+
client.export_json(fixtures, "fixtures.json")
|
|
339
|
+
client.export_csv(fixtures, "fixtures.csv")
|
|
340
|
+
```
|
|
341
|
+
|
|
342
|
+
JSON export keeps full nested model data. CSV export flattens match-level fields for spreadsheet tools.
|
|
343
|
+
|
|
344
|
+
## CLI
|
|
345
|
+
|
|
346
|
+
```bash
|
|
347
|
+
openmatch sources
|
|
348
|
+
openmatch health
|
|
349
|
+
openmatch fixtures --competition worldcup --season 2026
|
|
350
|
+
openmatch search --competition worldcup --season 2026 --team Canada --status scheduled
|
|
351
|
+
openmatch results --competition en.1 --season 2015-16 --format csv --output results.csv
|
|
352
|
+
openmatch upcoming --competition worldcup --season 2026 --team Canada --limit 3
|
|
353
|
+
openmatch recent --competition worldcup --season 2026 --limit 5
|
|
354
|
+
openmatch next-match --competition worldcup --season 2026
|
|
355
|
+
openmatch match-summary --match-id detail-1 --data-file tests/fixtures/sample_detailed_source.json
|
|
356
|
+
openmatch standings --competition worldcup --season 2026
|
|
357
|
+
openmatch team-form --team Mexico --competition worldcup --season 2026
|
|
358
|
+
openmatch head-to-head --team-a Mexico --team-b "South Africa" --competition worldcup --season 2026
|
|
359
|
+
openmatch predict --home Mexico --away "South Africa" --competition worldcup --season 2026
|
|
360
|
+
```
|
|
361
|
+
|
|
362
|
+
Detailed JSON feeds can expose richer scoreboards and player history:
|
|
363
|
+
|
|
364
|
+
```bash
|
|
365
|
+
openmatch scoreboards --data-file tests/fixtures/sample_detailed_source.json
|
|
366
|
+
openmatch scoreboard --match-id detail-1 --data-file tests/fixtures/sample_detailed_source.json
|
|
367
|
+
openmatch live-scoreboards --data-file tests/fixtures/sample_detailed_source.json
|
|
368
|
+
openmatch player-history --player "Alex Demo" --data-file tests/fixtures/sample_detailed_source.json
|
|
369
|
+
```
|
|
370
|
+
|
|
371
|
+
```python
|
|
372
|
+
from openmatchkit import MatchClient
|
|
373
|
+
from openmatchkit.sources.json_file import JsonFileSource
|
|
374
|
+
|
|
375
|
+
client = MatchClient(sources=[JsonFileSource("tests/fixtures/sample_detailed_source.json")])
|
|
376
|
+
scoreboard = client.scoreboard(match_id="detail-1")
|
|
377
|
+
history = client.player_history("Alex Demo")
|
|
378
|
+
print(scoreboard.model_dump(mode="json"))
|
|
379
|
+
print(history.model_dump(mode="json"))
|
|
380
|
+
```
|
|
381
|
+
|
|
382
|
+
## Example Output
|
|
383
|
+
|
|
384
|
+
```json
|
|
385
|
+
{
|
|
386
|
+
"competition": "World Cup 2026",
|
|
387
|
+
"home": {"name": "Canada"},
|
|
388
|
+
"away": {"name": "Bosnia & Herzegovina"},
|
|
389
|
+
"status": "scheduled",
|
|
390
|
+
"source": "openfootball"
|
|
391
|
+
}
|
|
392
|
+
```
|
|
393
|
+
|
|
394
|
+
## Features
|
|
395
|
+
|
|
396
|
+
- Unified match, scoreboard, player history, standings, and prediction models
|
|
397
|
+
- OpenFootball JSON adapter
|
|
398
|
+
- Football-Data.co.uk CSV adapter
|
|
399
|
+
- Local detailed JSON adapter for authorized/public detailed feeds
|
|
400
|
+
- Generic optional public HTML adapter
|
|
401
|
+
- Safe HTTP client with robots.txt checks, caching, user agent, and per-origin delay
|
|
402
|
+
- Fixtures, results, search, upcoming/recent matches, next match, live score adapter interface
|
|
403
|
+
- Source capabilities and health metadata
|
|
404
|
+
- Team info, grouped standings, team form, and head-to-head summaries
|
|
405
|
+
- Detailed scoreboards: clock, events, lineups, team stats, and player match stats when provided
|
|
406
|
+
- Player histories aggregated from player-level source data
|
|
407
|
+
- Simple Poisson prediction baseline and small Elo rating helper
|
|
408
|
+
- JSON and CSV export helpers
|
|
409
|
+
- Offline tests using local fixtures
|
|
410
|
+
|
|
411
|
+
## Current Status
|
|
412
|
+
|
|
413
|
+
- Stable enough for demos, research, education, and early open-source feedback
|
|
414
|
+
- Not official live FIFA data
|
|
415
|
+
- True live/player-level data requires a lawful source adapter that provides those facts
|
|
416
|
+
- Public roadmap: [ROADMAP.md](ROADMAP.md)
|
|
417
|
+
- Release notes: [CHANGELOG.md](CHANGELOG.md)
|
|
418
|
+
|
|
419
|
+
## Source and legal policy
|
|
420
|
+
|
|
421
|
+
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.
|
|
422
|
+
|
|
423
|
+
See [DATA_SOURCES.md](DATA_SOURCES.md), [PRIVACY.md](PRIVACY.md), and [CONTRIBUTING.md](CONTRIBUTING.md).
|
|
424
|
+
|
|
425
|
+
## Development
|
|
426
|
+
|
|
427
|
+
```bash
|
|
428
|
+
python -m pip install -e ".[dev]"
|
|
429
|
+
ruff check .
|
|
430
|
+
ruff format .
|
|
431
|
+
pytest
|
|
432
|
+
python -m build
|
|
433
|
+
```
|
|
434
|
+
|
|
435
|
+
The prediction output is an educational baseline only. It is not betting, financial, or professional advice.
|