|
| 1 | +# Release v2.0.0: Async client, TLS enforcement, retries/backoff, and CI upgrades |
| 2 | + |
| 3 | +## Summary |
| 4 | +This major release delivers a production-ready async client with robust TLS handling, resilient request logic (timeouts, retries, rate limits), and a fully wired CI pipeline (lint, type-check, tests, coverage). It replaces the legacy synchronous v1 client and prepares the project for Home Assistant and broader integration. |
| 5 | + |
| 6 | +## Highlights |
| 7 | +- **Async client** |
| 8 | + - New `FmdClient` with an async factory (`await FmdClient.create(...)`) and async context manager (`async with ...`). |
| 9 | + - Clean session lifecycle management and connection pooling controls. |
| 10 | +- **TLS/SSL** |
| 11 | + - HTTPS-only `base_url` enforcement (rejects plain HTTP). |
| 12 | + - Configurable validation: `ssl=False` (dev only) or pass a custom `ssl.SSLContext`. |
| 13 | + - Certificate pinning example included in docs. |
| 14 | +- **Reliability** |
| 15 | + - Timeouts applied across all HTTP requests. |
| 16 | + - Retries with exponential backoff and optional jitter for 5xx and connection errors. |
| 17 | + - 429 rate-limit handling with Retry-After support. |
| 18 | + - Safe behavior for command POSTs (no unsafe retries). |
| 19 | +- **Features** |
| 20 | + - Client-side export to ZIP (locations + pictures). |
| 21 | + - Device helper with convenience actions (e.g., request location, play sound, take picture). |
| 22 | +- **Safety and ergonomics** |
| 23 | + - Sanitized logging (no sensitive payloads); token masking helper. |
| 24 | + - Typed package (`py.typed`) and mypy-clean. |
| 25 | +- **CI/CD** |
| 26 | + - GitHub Actions: lint (flake8), type-check (mypy), unit tests matrix (Ubuntu/Windows; Py 3.8–3.12). |
| 27 | + - Coverage with branch analysis and Codecov upload + badges. |
| 28 | + - Publish workflows for TestPyPI (non-main) and PyPI (main or Release). |
| 29 | + |
| 30 | +## Breaking changes |
| 31 | +- API surface moved to async: |
| 32 | + - Before (v1, sync): `client = FmdApi(...); client.authenticate(...); client.get_all_locations()` |
| 33 | + - Now (v2, async): |
| 34 | + - `client = await FmdClient.create(base_url, fmd_id, password, ...)` |
| 35 | + - `await client.get_locations(...)`, `await client.get_pictures(...)`, `await client.send_command(...)` |
| 36 | + - Prefer: `async with FmdClient.create(...) as client: ...` |
| 37 | +- Transport requirements: |
| 38 | + - `base_url` must be HTTPS; plain HTTP raises `ValueError`. |
| 39 | +- Python versions: |
| 40 | + - Targets Python 3.8+ (3.7 removed from classifiers). |
| 41 | + |
| 42 | +## Migration guide |
| 43 | +- Replace `FmdApi` usage with the async `FmdClient`: |
| 44 | + - Use `await FmdClient.create(...)` and `async with` for safe resource management. |
| 45 | + - Update all calls to await the async methods. |
| 46 | +- TLS and self-signed setups: |
| 47 | + - For dev-only scenarios: pass `ssl=False`. |
| 48 | + - For proper self-signed use: pass a custom `ssl.SSLContext`. |
| 49 | + - For high-security setups: consider the certificate pinning example in README. |
| 50 | +- Connection tuning: |
| 51 | + - Optional: `conn_limit`, `conn_limit_per_host`, `keepalive_timeout` on the TCPConnector via client init. |
| 52 | + |
| 53 | +## Error handling and semantics |
| 54 | +- 401 triggers one automatic re-authenticate then retries the request. |
| 55 | +- 429 honors Retry-After, otherwise uses exponential backoff with jitter. |
| 56 | +- Transient 5xx/connection errors are retried (except unsafe command POST replays). |
| 57 | +- Exceptions are normalized to `FmdApiException` where appropriate; messages mask sensitive data. |
| 58 | + |
| 59 | +## Documentation and examples |
| 60 | +- README: TLS/self-signed guidance, warnings, and certificate pinning example. |
| 61 | +- Debugging: `pin_cert_example.py` demonstrates secure pinning and avoids CLI secrets. |
| 62 | + |
| 63 | +## CI/CD and release automation |
| 64 | +- Tests: unit suite expanded; functional tests run when credentials are available. |
| 65 | +- Coverage: ~83% overall; XML + branch coverage uploaded to Codecov (badges included). |
| 66 | +- Workflows: |
| 67 | + - `test.yml`: runs on push/PR for all branches (lint, mypy, unit tests matrix, coverage, optional functional tests). |
| 68 | + - `publish.yml`: builds on push/releases; publishes to TestPyPI for non-main pushes, PyPI on main or release. |
| 69 | + |
| 70 | +## Checklist |
| 71 | +- [x] All unit tests pass |
| 72 | +- [x] Flake8 clean |
| 73 | +- [x] Mypy clean |
| 74 | +- [x] Coverage collected and uploaded |
| 75 | +- [x] README/docs updated (TLS, pinning, badges) |
| 76 | +- [x] Packaging: sdist and wheel built; publish workflows configured |
| 77 | + |
| 78 | +## Notes |
| 79 | +- Use `ssl=False` sparingly and never in production. |
| 80 | +- Consider adding Dependabot and security scanning in a follow-up. |
| 81 | +- A `CHANGELOG.md` entry for 2.0.0 is recommended if not already included. |
| 82 | + |
| 83 | +> BREAKING CHANGE: v2 switches to an async client, enforces HTTPS, and drops Python 3.7; synchronous v1 usage must be migrated as noted above. |
0 commit comments