Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
15 commits
Select commit Hold shift + click to select a range
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
23 changes: 22 additions & 1 deletion .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -69,7 +69,7 @@ jobs:
strategy:
fail-fast: false
matrix:
python-version: ["3.10", "3.11", "3.12", "3.13"]
python-version: ["3.10", "3.11", "3.12", "3.13", "3.14"]
steps:
- uses: actions/checkout@v4

Expand Down Expand Up @@ -99,6 +99,27 @@ jobs:
name: coverage-report
path: coverage.xml

# ── Docs build ────────────────────────────────────────────────────────
docs:
name: Docs
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4

- name: Install uv
uses: astral-sh/setup-uv@v7

- name: Set up Python
uses: actions/setup-python@v6
with:
python-version: "3.12"

- name: Install dependencies
run: uv pip install --system -e "." mkdocs-material "mkdocstrings[python]>=0.28.0"

- name: Build docs
run: mkdocs build --strict

# ── Build verification ─────────────────────────────────────────────────
build:
name: Build
Expand Down
26 changes: 26 additions & 0 deletions .github/workflows/commit-lint.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
name: Commit Lint

on:
pull_request:
types: [opened, synchronize, reopened, edited]

permissions:
contents: read

jobs:
commitlint:
runs-on: ubuntu-latest

steps:
- name: Checkout
uses: actions/checkout@v4
with:
fetch-depth: 0

- name: Lint commits
uses: wagoid/commitlint-github-action@v6
with:
configFile: commitlint.config.cjs
firstParent: true
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
63 changes: 63 additions & 0 deletions .github/workflows/integration.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
name: Integration Tests

on:
pull_request:
branches: [main, 2.0-development]
push:
branches: [main]
workflow_dispatch:

permissions:
contents: read

concurrency:
group: integration-${{ github.ref }}
cancel-in-progress: true

jobs:
integration:
name: Integration Tests
runs-on: ubuntu-latest
services:
comlink:
image: ghcr.io/swgoh-utils/swgoh-comlink:latest
ports:
- 3000:3000
comlink-hmac:
image: ghcr.io/swgoh-utils/swgoh-comlink:latest
env:
ACCESS_KEY: test_public_key
SECRET_KEY: test_secret_key
ports:
- 3001:3000
steps:
- uses: actions/checkout@v4

- name: Install uv
uses: astral-sh/setup-uv@v7

- name: Set up Python
uses: actions/setup-python@v6
with:
python-version: "3.12"

- name: Install dependencies
run: uv pip install --system -e "." pytest pytest-asyncio

- name: Wait for Comlink services
run: |
for i in $(seq 1 30); do
curl -sf http://localhost:3000/metadata && break
echo "Waiting for Comlink... ($i/30)"
sleep 2
done
for i in $(seq 1 30); do
curl -sf http://localhost:3001/metadata && break
echo "Waiting for Comlink HMAC... ($i/30)"
sleep 2
done

- name: Run integration tests
env:
RUN_INTEGRATION_TESTS: "1"
run: python -m pytest tests/integration/ -v
35 changes: 35 additions & 0 deletions .github/workflows/test.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
name: Test

on:
pull_request:
push:
branches:
- main

permissions:
contents: read

jobs:
test:
runs-on: ubuntu-latest

steps:
- name: Checkout
uses: actions/checkout@v4

- name: Setup Python
uses: actions/setup-python@v5
with:
python-version: "3.12"

- name: Setup uv
uses: astral-sh/setup-uv@v3

- name: Sync dependencies
run: uv sync --group dev --group docs

- name: Run unit tests
run: uv run pytest -q

- name: Build docs
run: uv run mkdocs build --strict
3 changes: 3 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,9 @@ coverage.xml
*.py,cover
.hypothesis/
.pytest_cache/
.ruff_cache/
.parity-cache/
parity/.cache-gameData.json
cover/


Expand Down
136 changes: 136 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,142 @@

<!-- insertion marker -->

## [v2.0.0 Pending Release] - feature/async

### Breaking Changes

- remove `OPTIONAL` and `NotSet` sentinel exports from `swgoh_comlink.helpers`.
Replace any usage with plain `None` defaults or `int` defaults as appropriate.
- remove external `sentinels` library dependency. The package now uses an inline
`Sentinel` class. Code importing sentinels from `swgoh_comlink.helpers` should
remove references to `OPTIONAL` and `NotSet`.
- change `get_gac_brackets()` and `async_get_gac_brackets()` `limit` parameter
from sentinel-based default to `int` with default `0` (meaning no limit).

### Bug Fixes

- fix HMAC empty payload serialization to use empty string (`""`) instead of
empty object (`{}`) for compatibility with comlink v4 (#51).

### Features

- add `SwgohComlinkAsync` async client with full API parity to `SwgohComlink`.
Both clients inherit from a shared `SwgohComlinkBase` class.
- add `StatCalcAsync` async stat calculator with `create()` factory method for
non-blocking game data initialization. Inherits all calculation methods from
`StatCalc`.
- add `GameDataBuilder` / `GameDataBuilderAsync` to build StatCalc game data
dynamically from a running Comlink service instead of fetching a static file
from GitHub.
- replace `requests` library with `httpx` for both sync and async HTTP support.
- add connection pooling via persistent `httpx.Client` / `httpx.AsyncClient` instances.
- add context manager support (`with SwgohComlink()` and `async with SwgohComlinkAsync()`).
- add async helper variants: `async_get_current_gac_event()`, `async_get_gac_brackets()`,
and `async_get_guild_members()` for use with `SwgohComlinkAsync`.
- add exponential probing with binary search for GAC bracket boundary discovery,
reducing HTTP requests from O(n) to O(log n).
- add parallel batch fetching via `asyncio.gather` in `async_get_gac_brackets()`
for significantly faster bracket collection.
- add comprehensive Helpers API reference and Exceptions documentation pages.

### Code Refactoring

- replace external `sentinels` library with inline `Sentinel` class; remove
unused sentinels (`OPTIONAL`, `NotSet`, `EMPTY`, `NotGiven`, `SET`,
`MutualRequiredNotSet`).
- extract shared logic (HMAC auth, payload builders, URL sanitization, param_alias decorator)
into `_base.py` base class.
- unify all HTTP communication through a single `_request()` gateway method
in both sync and async clients.
- refactor monolithic `helpers.py` (1,970 lines) into a focused `helpers/` subpackage
with domain-specific modules (`_arena.py`, `_gac.py`, `_game_data.py`, `_guild.py`,
`_omicron.py`, `_utils.py`, `_decorators.py`, `_sentinels.py`, `_data_items.py`,
`_stat_data.py`, `_constants.py`). All existing import paths are preserved via
backward-compatible re-export shim in `helpers/__init__.py`.
- consolidate 4 duplicate copies of stat data (Constants.STAT_ENUMS,
Constants.UNIT_STAT_ENUMS_MAP, Constants.STATS, StatCalc.STATS_NAME_MAP) into a
single canonical `STATS` dict in `helpers/_stat_data.py` with derived views.
- replace 489-line inline `STATS_NAME_MAP` dict in `StatCalc/calculator.py` with
import from `helpers/_stat_data`.

### Dependencies

- replace `requests>=2.32.4` with `httpx>=0.28`.
- add `pytest-httpx>=0.35` and `pytest-asyncio>=0.24` to dev dependencies.

### Logging

- refactor logging to follow Python library best practice: attach only `NullHandler`
to the package root logger; remove forced `StreamHandler` and level configuration.
- remove unused logger instances from `_base.py`, `swgoh_comlink.py`, and
`swgoh_comlink_async.py`.
- switch `exceptions.py` and `helpers.py` to use `logging.getLogger(__name__)` directly.
- keep `LoggingFormatter` as an opt-in convenience in `globals.py`.
- rewrite `docs/logging.md` for the new approach.

### Tools

- add `swgoh-migrate` CLI tool (`python -m swgoh_comlink.migrate`) for scanning
user codebases and identifying deprecated import patterns, API changes, and
migration steps needed when upgrading from v1.x. Supports `--severity`,
`--no-color`, and `--exclude` options.

### Documentation

- add migration guide (`docs/migration.md`) covering dependency changes, exception
handling, logging configuration, and client lifecycle.
- add migration summary section to README with link to the full guide.

### Testing

- rewrite unit tests to use `pytest-httpx` mocking instead of `monkeypatch`.
- add comprehensive async client test suite mirroring sync coverage.
- add `test_base.py` with tests for base class utilities, HMAC, payload builders,
and validation logic.
- increase test coverage from 38% to 48% (100% on core modules `_base.py`,
`swgoh_comlink.py`, and `swgoh_comlink_async.py`).

---

## [v1.18.0rc1](https://github.com/swgoh-utils/comlink-python/releases/tag/v1.18.0rc1) - 2026-03-03

<small>[Compare with v1.17.0](https://github.com/swgoh-utils/comlink-python/compare/v1.17.0...v1.18.0rc1)</small>

### Features

- add StatCalc module for local stat and GP calculation without an external
swgoh-stats service ([a880097](https://github.com/swgoh-utils/comlink-python/commit/a880097889b30e345c80ec99ff207d4e50daa431) by
MarTrepodi).

### Bug Fixes

- remove duplicate `_rename_stats` call in `calc_char_stats` that caused
`AttributeError` on second pass ([a880097](https://github.com/swgoh-utils/comlink-python/commit/a880097889b30e345c80ec99ff207d4e50daa431) by
MarTrepodi).
- fix `calc_player_stats` type annotations, `isinstance` syntax, and list
mutation bug ([a880097](https://github.com/swgoh-utils/comlink-python/commit/a880097889b30e345c80ec99ff207d4e50daa431) by
MarTrepodi).
- remove stray `print()` statements and unnecessary `deepcopy` in
`_rename_stats` ([a880097](https://github.com/swgoh-utils/comlink-python/commit/a880097889b30e345c80ec99ff207d4e50daa431) by
MarTrepodi).

### Documentation

- expand StatCalc usage guide in README and mkdocs API
reference ([a880097](https://github.com/swgoh-utils/comlink-python/commit/a880097889b30e345c80ec99ff207d4e50daa431) by
MarTrepodi).
- add missing `get_name_spaces` and `get_segmented_content` methods to README
table ([a880097](https://github.com/swgoh-utils/comlink-python/commit/a880097889b30e345c80ec99ff207d4e50daa431) by
MarTrepodi).
- update CONTRIBUTING.md project structure and key modules for StatCalc and
test subdirectories ([a880097](https://github.com/swgoh-utils/comlink-python/commit/a880097889b30e345c80ec99ff207d4e50daa431) by
MarTrepodi).

### Chores

- remove unused `scripts/verify-upstream.sh` ([a880097](https://github.com/swgoh-utils/comlink-python/commit/a880097889b30e345c80ec99ff207d4e50daa431) by
MarTrepodi).

## [v1.17.0](https://github.com/swgoh-utils/comlink-python/releases/tag/v1.17.0) - 2025-11-18

<small>[Compare with v1.16.0](https://github.com/swgoh-utils/comlink-python/compare/v1.16.0...v1.17.0)</small>
Expand Down
20 changes: 16 additions & 4 deletions CONTRIBUTING.md
Original file line number Diff line number Diff line change
Expand Up @@ -119,19 +119,30 @@ comlink-python/
│ ├── labeler.yml # Label-to-path configuration
│ └── pull_request_template.md # PR checklist template
├── docs/
│ └── logging.md # Logging configuration guide
│ ├── api/
│ │ ├── comlink.md # SwgohComlink API reference
│ │ └── statcalc.md # StatCalc API reference
│ ├── index.md # Documentation home
│ └── logging.md # Logging configuration guide
├── examples/ # Usage examples for each endpoint
├── scripts/
│ └── verify-upstream.sh # Pre-release upstream verification
├── src/
│ └── swgoh_comlink/
│ ├── StatCalc/
│ │ ├── __init__.py # StatCalc package exports
│ │ └── calculator.py # Local stat/GP calculator
│ ├── __init__.py # Package entry point, public exports
│ ├── exceptions.py # Custom exception classes
│ ├── globals.py # Logging configuration
│ ├── helpers.py # Constants, enums, and utility functions
│ ├── swgoh_comlink.py # Main SwgohComlink client class
│ └── version.py # Package version (managed by hatch)
├── tests/ # Test suite
├── tests/
│ ├── resources/ # Test fixture data (example-player.json, etc.)
│ ├── statcalc/ # StatCalc-specific tests (import, parity, offline)
│ ├── unit/ # Mocked unit tests for SwgohComlink client
│ ├── conftest.py # Shared pytest fixtures and markers
│ ├── integration_support.py # Helper for integration test setup
│ └── test_*.py # Integration tests (require running comlink)
├── .commitlintrc.json # Commit message lint config (local + CI)
├── pyproject.toml # Project metadata, build config, tool settings
├── uv.lock # Locked dependency versions
Expand All @@ -146,6 +157,7 @@ comlink-python/
| Module | Purpose |
|--------|---------|
| `swgoh_comlink.py` | The `SwgohComlink` class — HTTP client, HMAC signing, all endpoint methods |
| `StatCalc/calculator.py` | The `StatCalc` class — local stat and GP calculation for game units |
| `helpers.py` | `DataItems` IntFlag enum, `Constants` class, 25+ utility functions for game data processing |
| `exceptions.py` | `SwgohComlinkException` and `SwgohComlinkValueError` |
| `globals.py` | Shared logging setup (`get_logger()`) |
Expand Down
Loading
Loading