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 .github/dependabot.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
version: 2
updates:
- package-ecosystem: "pip"
directory: "/"
schedule:
interval: "weekly"
open-pull-requests-limit: 5

- package-ecosystem: "github-actions"
directory: "/"
schedule:
interval: "weekly"
open-pull-requests-limit: 5
50 changes: 50 additions & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
name: CI

on:
push:
branches: [main]
pull_request:
branches: [main]

jobs:
lint-and-test:
runs-on: ubuntu-latest
strategy:
fail-fast: false
matrix:
python-version: ["3.12", "3.13"]

container: astral/uv:python${{ matrix.python-version }}-bookworm-slim

steps:
- uses: actions/checkout@v6

# If you have uv.lock → prefer: uv sync --locked
- name: Install deps
run: uv pip install --system -e ".[dev]"

- name: Ruff
run: uv run ruff check src test

- name: Mypy
run: uv run mypy src/kinexon_handball_api

- name: Pytest
run: uv run pytest

build:
runs-on: ubuntu-latest
needs: lint-and-test
container: astral/uv:python3.13-bookworm-slim

steps:
- uses: actions/checkout@v6

- name: Build package
run: uv build

- name: Upload dist artifacts
uses: actions/upload-artifact@v7
with:
name: kinexon-dist
path: dist/
32 changes: 32 additions & 0 deletions .github/workflows/codeql.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
name: CodeQL

on:
push:
branches: [main]
pull_request:
branches: [main]
paths-ignore:
- "src/_vendor/**"
schedule:
- cron: "23 3 * * 1"
workflow_dispatch:

jobs:
analyze:
name: Analyze
runs-on: ubuntu-latest
permissions:
actions: read
contents: read
security-events: write

steps:
- uses: actions/checkout@v6

- name: Initialize CodeQL
uses: github/codeql-action/init@v3
with:
languages: python

- name: Perform CodeQL analysis
uses: github/codeql-action/analyze@v3
85 changes: 85 additions & 0 deletions .github/workflows/release.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,85 @@
name: Release

on:
push:
tags:
- "v*.*.*"

jobs:
publish-release:
runs-on: ubuntu-latest
permissions:
contents: write
id-token: write
attestations: write

steps:
- uses: actions/checkout@v6

- uses: actions/setup-python@v6
with:
python-version: "3.13"

- uses: astral-sh/setup-uv@v5

- name: Verify tag matches version
run: |
python - <<'PY'
import os
import sys
import tomllib

tag = os.environ.get("GITHUB_REF_NAME", "")
with open("pyproject.toml", "rb") as handle:
version = tomllib.load(handle)["project"]["version"]
expected = f"v{version}"
if tag != expected:
print(f"Tag {tag} does not match version {version}")
sys.exit(1)
PY

- name: Install deps
run: uv pip install --system -e ".[dev]"

- name: Ruff
run: uv run ruff check src test

- name: Mypy
run: uv run mypy src/sportradar_datacore_api

- name: Pytest
run: uv run pytest

- name: Build artifacts
run: |
uv build

- name: Generate SBOM
uses: anchore/sbom-action@v0
with:
path: dist
artifact-name: sportradar-sbom

- name: Upload release artifacts
uses: actions/upload-artifact@v7
with:
name: sportradar-dist
path: dist/*

- name: Attest build provenance
uses: actions/attest-build-provenance@v2
with:
subject-path: dist/*

- name: Create GitHub Release
uses: softprops/action-gh-release@v2
with:
generate_release_notes: true
files: dist/*
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}

- name: Publish to PyPI
uses: pypa/gh-action-pypi-publish@release/v1
with:
packages-dir: dist
49 changes: 29 additions & 20 deletions .pre-commit-config.yaml
Original file line number Diff line number Diff line change
@@ -1,37 +1,46 @@
repos:
# Generic hygiene
- repo: https://github.com/pre-commit/pre-commit-hooks
rev: v4.5.0
rev: v5.0.0
hooks:
- id: trailing-whitespace
- id: end-of-file-fixer
exclude: ^log/
- id: check-yaml
- id: check-merge-conflict
- id: debug-statements

- repo: https://github.com/psf/black
rev: 25.9.0
# Ruff: lint + format + import sort
- repo: https://github.com/astral-sh/ruff-pre-commit
rev: v0.5.7
hooks:
- id: black
language_version: python3
exclude: ^src/_vendor/kinexon_client/
- id: ruff
args: ["--fix"]
exclude: ^src/_vendor/
- id: ruff-format
exclude: ^src/_vendor/

- repo: https://github.com/pycqa/isort
rev: 5.13.2
# mypy: static typing
- repo: https://github.com/pre-commit/mirrors-mypy
rev: v1.10.0
hooks:
- id: isort
name: isort (python)
args: ["--profile", "black", "--line-length", "88"]
exclude: ^src/_vendor/kinexon_client/

- repo: https://github.com/pycqa/flake8
rev: 7.0.0
hooks:
- id: flake8
args: ["--max-line-length=88", "--extend-ignore=E203,W503,D200,D103,E501"]
exclude: ^src/_vendor/kinexon_client/
- id: mypy
exclude: ^src/_vendor/
additional_dependencies:
- pydantic>=2.6
- types-PyYAML>=6.0.12.20250915

# Strip notebook outputs
- repo: https://github.com/kynan/nbstripout
rev: 0.7.1
hooks:
- id: nbstripout
name: Strip output from Jupyter notebooks

# Tests (via uv-managed env)
- repo: local
hooks:
- id: pytest
name: pytest
entry: uv run pytest test
language: system
pass_filenames: false
60 changes: 37 additions & 23 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,8 @@

[![Python](https://img.shields.io/badge/python-3.13+-blue.svg)](https://www.python.org/downloads/)
[![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)
[![Code Style: Black](https://img.shields.io/badge/code%20style-black-000000.svg)](https://github.com/psf/black)
[![Code style: ruff](https://img.shields.io/endpoint?url=https://raw.githubusercontent.com/astral-sh/ruff/main/assets/badge/v2.json)](https://github.com/astral-sh/ruff)


A Python wrapper for the Kinexon Handball API.

Expand All @@ -22,22 +23,19 @@ This library simplifies interaction with the Kinexon API by handling complex two

This project requires **Python 3.13+**.

### Standard Installation
Clone the repository and install using pip:
### Using uv (Recommended)
If you use [uv](https://github.com/astral-sh/uv) for fast package management:

```bash
git clone https://github.com/mad4ms/KinexonHandballAPI.git
cd KinexonHandballAPI
pip install .
uv sync
```

### Using uv (Recommended)
If you use [uv](https://github.com/astral-sh/uv) for fast package management:
If you prefer an editable install instead of syncing a lockfile:

```bash
git clone https://github.com/mad4ms/KinexonHandballAPI.git
cd KinexonHandballAPI
uv pip install .
uv pip install -e "."
```

## Configuration
Expand All @@ -60,11 +58,11 @@ USERNAME_KINEXON_MAIN=your_main_username
PASSWORD_KINEXON_MAIN=your_main_password
ENDPOINT_KINEXON_MAIN=https://hbl-cloud.kinexon.com/checklogin

# API Base Configuration
ENDPOINT_KINEXON_API=https://hbl-cloud.kinexon.com/public/v1/
# API Base Configuration (no trailing /public/v1)
ENDPOINT_KINEXON_API=https://hbl-cloud.kinexon.com
```

yeah i know it's confusing, but the two-step authentication requires separate credentials for each step. Don't shoot the messenger!
Note: The two-step authentication requires separate credentials for each step.

## Usage

Expand All @@ -83,12 +81,14 @@ load_dotenv()

# 2. Initialize the API
api = HandballAPI(
base_url=os.getenv("ENDPOINT_KINEXON_API"),
api_key=os.getenv("API_KEY_KINEXON"),
username_basic=os.getenv("USERNAME_KINEXON_SESSION"),
password_basic=os.getenv("PASSWORD_KINEXON_SESSION"),
username_main=os.getenv("USERNAME_KINEXON_MAIN"),
password_main=os.getenv("PASSWORD_KINEXON_MAIN"),
base_url=os.getenv("ENDPOINT_KINEXON_API", ""),
api_key=os.getenv("API_KEY_KINEXON", ""),
username_basic=os.getenv("USERNAME_KINEXON_SESSION", ""),
password_basic=os.getenv("PASSWORD_KINEXON_SESSION", ""),
username_main=os.getenv("USERNAME_KINEXON_MAIN", ""),
password_main=os.getenv("PASSWORD_KINEXON_MAIN", ""),
endpoint_session=os.getenv("ENDPOINT_KINEXON_SESSION", ""),
endpoint_main=os.getenv("ENDPOINT_KINEXON_MAIN", ""),
)

# 3. Use high-level helpers
Expand All @@ -109,11 +109,11 @@ if teams:
For endpoints not covered by high-level helpers, accessing the generated client directly is supported and encouraged. The generated client resides in `kinexon_client`.

```python
from kinexon_client.api.players import get_team_players
from kinexon_client.api.players import get_public_v1_teams_by_team_id_players
from kinexon_client.models import PlayerModel

# You can access the authenticated low-level client via `api.client`
response = get_team_players.sync_detailed(
response = get_public_v1_teams_by_team_id_players.sync_detailed(
client=api.client,
team_id=12345
)
Expand All @@ -125,7 +125,7 @@ if response.status_code == 200:
```

### Advanced: Adding new teams
You can add new teams by modifying the `config/teams.json`. Somehow there is no API endpoint to fetch all teams, so this is a manual step for now.
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.

## Architecture

Expand All @@ -136,6 +136,18 @@ This project uses a **Wrapper Pattern** around a generated OpenAPI client.
- *Note*: This directory allows us to ship the generated code without external dependencies or 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.
- **`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`.

## Development

### Setup
Expand All @@ -148,8 +160,10 @@ uv pip install -e ".[dev]"
### Running Tests

```bash
# Run unit tests
uv run pytest -m "not integration"
pytest

Note: The integration tests use live API calls and will be skipped if required
environment variables are not set.
```

### Code Generation
Expand Down
Loading
Loading