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
50 changes: 0 additions & 50 deletions .github/copilot-instructions.md

This file was deleted.

96 changes: 96 additions & 0 deletions AGENTS.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,96 @@
# Kinexon Handball API - AI Agent Instructions

## Project Overview

Python wrapper for the Kinexon Handball API. Provides a user-friendly abstraction over a raw, auto-generated OpenAPI client.

## Architectural Structure

- **Wrapper Core (`src/kinexon_handball_api/`)**: Hand-written logic, authentication, and high-level helpers. New features go here.
- `api.py`: Two-step authentication and `httpx` client initialization.
- `handball.py`: Main entry point (`HandballAPI`). Convenience methods for common API operations.
- `fetchers.py`: Static data loading (e.g., team IDs from `config/teams.yaml`).
- `statistics_center.py`: Separate wrapper for the Statistics Center REST + WebSocket API. Uses `Games` and `LoginSuccess` from the generated `statistics_center_client`.
- **Generated Clients (`src/_vendor/`)**: Two auto-generated OpenAPI clients via `openapi-python-client`.
- `kinexon_client/` — generated from `openapi/sports_app.json` (main Kinexon Cloud REST API).
- `statistics_center_client/` — generated from `openapi/statistics_center.json` (Statistics Center REST API).
- **CRITICAL: Do NOT edit files in `src/_vendor/` manually.** They are overwritten by `scripts/codegen.sh`.
- If the API spec changes, regenerate using `scripts/codegen.sh` (Linux/Mac) or `scripts/codegen.ps1` (Windows).

See [docs/architecture.md](docs/architecture.md) for the full architectural breakdown.

## Development Workflows

### Adding New API Features

1. Check `src/_vendor/kinexon_client/api/` for an existing generated endpoint. Names are verbose (e.g., `get_public_v_1_events...`).
2. Add a method to `HandballAPI` in `src/kinexon_handball_api/handball.py`.
3. Use the `sync_detailed` method of the generated function to access status codes and parsed data.

```python
from kinexon_client.api.some_module import some_generated_function

def my_wrapper_method(self, param):
resp = some_generated_function.sync_detailed(client=self.client, arg=param)
if resp.status_code != 200:
raise RuntimeError(f"Error: {resp.content}")
return resp.parsed
```

See [docs/api-reference.md](docs/api-reference.md) for all available wrapper methods.

### Updating the Generated Client

If the upstream OpenAPI spec changes:

```bash
./scripts/codegen.sh # Linux/Mac
./scripts/codegen.ps1 # Windows PowerShell
```

This downloads the latest specs to `openapi/sports_app.json` and `openapi/statistics_center.json`, runs `scripts/rename_operation_ids.py` to replace hash-based `operationId`s with readable names, fixes self-referential `allOf` schemas in the Statistics Center spec, then regenerates both `src/_vendor/kinexon_client/` and `src/_vendor/statistics_center_client/`.

See [docs/codegen.md](docs/codegen.md) for details.

### Dependencies

Use `uv` for package management.

```bash
uv pip install -e ".[dev]" # editable install with dev extras
uv run pytest # run tests
uv run ruff check src test # lint
uv run mypy src/kinexon_handball_api # type-check
```

## Conventions & Patterns

- **Authentication**: `KinexonAPI` handles the two-step auth automatically. Do not pass generic auth headers manually; the client injects the `api-key`.
- **Imports**: Import generated classes/functions from `kinexon_client.*` (main REST) or `statistics_center_client.*` (Statistics Center). The build system treats `src/_vendor` as a package source.
- **Type Hints**: Use standard Python typing (`list`, `dict`, `Optional`) and attrs models from `kinexon_client.models` or `statistics_center_client.models`.
- **Config**: Keep configuration (team IDs, seasons) in `config/teams.yaml` via `fetchers.py`. Do not hardcode in logic.
- **Linting**: Ruff (line length 88, target py312). The `src/_vendor/` directory is excluded from all linting.
- **Tests**: `pytest`. Integration tests require a live API and are skipped without credentials (`@pytest.mark.integration`).

## Key Files

| File | Purpose |
|---|---|
| `src/kinexon_handball_api/handball.py` | Main public API class (`HandballAPI`) |
| `src/kinexon_handball_api/api.py` | Auth base class (`KinexonAPI`) |
| `src/kinexon_handball_api/fetchers.py` | Team ID loading from YAML config |
| `src/kinexon_handball_api/statistics_center.py` | Statistics Center API client |
| `src/_vendor/kinexon_client/` | Generated OpenAPI client for main REST API (do not edit) |
| `src/_vendor/statistics_center_client/` | Generated OpenAPI client for Statistics Center (do not edit) |
| `scripts/rename_operation_ids.py` | Pre-processing: replaces hash-based operationIds with readable names |
| `config/teams.yaml` | Team IDs and season configuration |
| `scripts/codegen.sh` | Client regeneration script |
| `pyproject.toml` | Project metadata, dependencies, tool config |

## Further Reading

- [docs/architecture.md](docs/architecture.md) - Full architectural overview and design decisions
- [docs/authentication.md](docs/authentication.md) - Two-step authentication deep dive
- [docs/api-reference.md](docs/api-reference.md) - All wrapper methods and usage examples
- [docs/codegen.md](docs/codegen.md) - How to regenerate the OpenAPI client
- [docs/contributing.md](docs/contributing.md) - Development setup and contribution guidelines
67 changes: 60 additions & 7 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -127,26 +127,79 @@ if response.status_code == 200:
### Advanced: Adding new teams
You can add new teams by modifying `config/teams.yaml`. Somehow there is no API endpoint to fetch all teams, so this is a manual step for now.

### Statistics Center (REST + Websocket)

The package also provides a dedicated wrapper for the Statistics Center API. REST responses use typed models from the generated `statistics_center_client`:

```python
from kinexon_handball_api import StatisticsCenterAPI
from statistics_center_client.models import Games

sc = StatisticsCenterAPI(
username="<USERNAME>",
password="<PASSWORD>",
interfaces_api_url="https://hbl.kinexon.com/statistics-center/interfaces-api",
outputs_push_url="https://hbl.kinexon.com/statistics-center/outputs-push",
)

# JWT login
jwt = sc.login()

# Typed REST responses
games: list[Games] = sc.get_games(season="2025_2026")
stats = sc.get_stats("<MATCH_ID>") # list[dict]
events = sc.get_events("<MATCH_ID>") # list[dict]

# Push endpoints
all_endpoints = sc.list_endpoints()

# WebSocket
def on_message(data):
print("message", data)

def on_error(error):
print("error", error)

socket_client = sc.connect_websocket(
on_message=on_message,
on_error=on_error,
)

sc.subscribe(socket_client, subscription_type="matches", identifier="2019_2020")
sc.subscribe(socket_client, subscription_type="stats", identifier="<MATCH_ID>")
sc.subscribe(
socket_client,
subscription_type="events",
identifier="<MATCH_ID>",
filter={"event": "shot"},
)
sc.subscribe(socket_client, subscription_type="live_events", identifier="<MATCH_ID>")
```

Supported websocket subscription types are `matches`, `stats`, `events`, and `live_events`.

## Architecture

This project uses a **Wrapper Pattern** around a generated OpenAPI client.

- **`src/kinexon_handball_api/`**: The public-facing code. Contains the `HandballAPI` class, authentication logic, and user-friendly helpers.
- **`src/_vendor/kinexon_client/`**: The low-level client code generated from the Kinexon OpenAPI specification.
- *Note*: This directory allows us to ship the generated code without external dependencies or versioning conflicts.
- **`src/kinexon_handball_api/`**: The public-facing code. Contains the `HandballAPI` and `StatisticsCenterAPI` classes, authentication logic, and user-friendly helpers.
- **`src/_vendor/kinexon_client/`**: Generated client for the main Kinexon Cloud REST API (from `openapi/sports_app.json`).
- **`src/_vendor/statistics_center_client/`**: Generated client for the Statistics Center API (from `openapi/statistics_center.json`). Provides typed models (`Games`, `LoginSuccess`) used by `StatisticsCenterAPI`.
- *Note*: Vendoring the generated clients avoids external dependencies and versioning conflicts.
- **Do not edit files in `_vendor` manually.** They are overwritten during code generation.

## Repository Layout

- **`src/kinexon_handball_api/`**: Hand-written wrapper and helper APIs.
- **`src/_vendor/kinexon_client/`**: Generated OpenAPI client (do not edit by hand).
- **`scripts/`**: Code generation helpers for the OpenAPI client.
- **`src/_vendor/kinexon_client/`**: Generated OpenAPI client for main REST API (do not edit).
- **`src/_vendor/statistics_center_client/`**: Generated OpenAPI client for Statistics Center (do not edit).
- **`openapi/`**: OpenAPI specs (`sports_app.json`, `statistics_center.json`) and generator configs.
- **`scripts/`**: Code generation helpers (`codegen.sh`, `rename_operation_ids.py`).
- **`test/`**: Test suite executed with `pytest`.

## AI Assistance

If you are using GitHub Copilot in this repo, see the project-specific guidance in
`.github/copilot-instructions.md`.
If you are using an AI coding agent (Claude Code, GitHub Copilot, Cursor, etc.) in this repo, see the project-specific guidance in [AGENTS.md](AGENTS.md).

## Development

Expand Down
Loading