-
Notifications
You must be signed in to change notification settings - Fork 0
Strict typing, more coverage, updated fmd public server #12
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Merged
Merged
Changes from all commits
Commits
Show all changes
3 commits
Select commit
Hold shift + click to select a range
File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
Binary file not shown.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,41 @@ | ||
| # MyPy Strict Typing Errors - Baseline Assessment | ||
|
|
||
| This document captures the initial mypy errors found during Phase 1 of the strict typing enforcement plan. | ||
|
|
||
| Run command: `mypy fmd_api/ --strict --show-error-codes` | ||
|
|
||
| Date: November 18, 2025 | ||
|
|
||
| ## Summary | ||
| - Total errors: 12 | ||
| - Files affected: client.py (9 errors), device.py (3 errors) | ||
| - Checked files: 7 source files | ||
|
|
||
| ## Errors by File | ||
|
|
||
| ### fmd_api/client.py | ||
| 1. Line 99: Function is missing a type annotation for one or more arguments [no-untyped-def] | ||
| 2. Line 103: Function is missing a return type annotation [no-untyped-def] | ||
| 3. Line 202: Returning Any from function declared to return "str" [no-any-return] | ||
| 4. Line 206: Returning Any from function declared to return "str" [no-any-return] | ||
| 5. Line 209: Returning Any from function declared to return "str" [no-any-return] | ||
| 6. Line 372: Function is missing a return type annotation [no-untyped-def] | ||
| 7. Line 821: Returning Any from function declared to return "float" [no-any-return] | ||
|
|
||
| ### fmd_api/device.py | ||
| 1. Line 36: Function is missing a return type annotation [no-untyped-def] | ||
| 2. Line 55: Function is missing a type annotation for one or more arguments [no-untyped-def] | ||
| 3. Line 94: Missing type parameters for generic type "dict" [type-arg] | ||
| 4. Line 124: Missing type parameters for generic type "dict" [type-arg] | ||
| 5. Line 142: Missing type parameters for generic type "dict" [type-arg] | ||
|
|
||
| ## Next Steps | ||
| These errors will be addressed in Phase 2 (Core Module Typing). Priority order: | ||
| 1. Add missing type annotations to functions | ||
| 2. Replace Any returns with proper types | ||
| 3. Add type parameters to generic types | ||
|
|
||
| ## Configuration | ||
| - Python version: 3.9 | ||
| - Strict mode: enabled | ||
| - Tests excluded: yes (ignore_errors = true) |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,120 @@ | ||
| # Release v2.0.4: Password-Free Auth Artifacts, Picture API Cleanup, Stronger Wipe Validation, Higher Coverage | ||
|
|
||
| ## Summary | ||
| v2.0.4 is a hardening + ergonomics release focused on secure password-free resume flows, clarified and modernized picture APIs, safer destructive actions, and significantly expanded test coverage (now ~98%). It remains fully backward compatible for consumers relying on deprecated method names; all new functionality is additive. | ||
|
|
||
| ## Highlights | ||
|
|
||
| ### 1. Authentication Artifacts (Password-Free Resume) | ||
| - New methods: | ||
| - `FmdClient.from_auth_artifacts(artifacts: dict)` – Restore a client without the raw password. | ||
| - `FmdClient.resume(...)` – Lower-level variant accepting explicit fields. | ||
| - `await client.export_auth_artifacts()` – Export `base_url`, `fmd_id`, `access_token`, `private_key` (PEM), optional `password_hash`, `session_duration`, `token_issued_at`. | ||
| - `await client.drop_password()` / `drop_password=True` in `create()` – Immediately discard raw password after onboarding. | ||
| - 401 handling logic hierarchy: | ||
| 1. If raw password present → reauthenticate (existing flow) | ||
| 2. Else if `password_hash` present → hash-based token refresh (`_reauth_with_hash()`) | ||
| 3. Else → raise `FmdApiException` (caller must re-onboard) | ||
| - Private key load now supports both PEM and DER (fallback path tested). | ||
|
|
||
| ### 2. Picture API Renaming & Deprecations | ||
| - New canonical methods on `Device`: | ||
| - `get_picture_blobs()` – fetch encrypted Base64 blobs. | ||
| - `decode_picture()` – decrypt + decode into `PhotoResult`. | ||
| - Deprecated (still functional, emit `DeprecationWarning`): | ||
| - `take_front_photo()`, `take_rear_photo()` → use `take_front_picture()`, `take_rear_picture()` | ||
| - `fetch_pictures()`, `get_pictures()` (Device) → use `get_picture_blobs()` | ||
| - `download_photo()`, `get_picture()` (Device) → use `decode_picture()` | ||
| - `download_photo()` now points directly to `decode_picture()` (avoids chained deprecated call). | ||
|
|
||
| ### 3. Wipe (Factory Reset) Hardening | ||
| - `Device.wipe()` now strictly requires: | ||
| - `confirm=True` | ||
| - `pin` argument present | ||
| - PIN must be alphanumeric ASCII (no spaces). Future enforcement of 16+ length is noted (fmd-android MR 379). | ||
| - Removed redundant space validation branch. | ||
|
|
||
| ### 4. Lock Message Support | ||
| - `Device.lock(message=...)` allows an optional user message; sanitized (quotes / backticks / semicolons removed, whitespace collapsed, 120 char cap). Falls back cleanly if server ignores payload. | ||
|
|
||
| ### 5. Expanded Export Functionality & Robustness | ||
| - `export_data_zip()` improvements: | ||
| - Picture file extension detection: `.png` via magic bytes, default `.jpg` else. | ||
| - Resilient manifest entries capturing per-item decryption errors (non-fatal). | ||
| - Additional validation of location/picture list types with graceful fallbacks. | ||
|
|
||
| ### 6. Coverage & Testing Improvements | ||
| - Overall coverage ~98% (client.py ~98%, device.py mid/high 90s, models 100%). | ||
| - New targeted tests exercise: | ||
| - DER private key resume path | ||
| - Missing artifact field errors | ||
| - 401 reauth when neither password nor hash is available (expected exception) | ||
| - Hash-based 401 reauth success path | ||
| - PNG export branch + unknown image default `.jpg` | ||
| - Deprecated wrapper warning emission | ||
| - Non-dict JSON fallback handling & non-list picture responses | ||
| - Error recording during export (location & picture failures) | ||
| - Retry logic: 429 (Retry-After numeric/date/negative), 500/502 sequences, connection errors, backoff jitter/no-jitter paths | ||
| - Masking helpers and retry-after parsing edge cases | ||
|
|
||
| ### 7. Documentation Updates | ||
| - README: Added password-free artifact usage, wipe PIN notes, lock message mention, community listing. | ||
| - `MIGRATE_FROM_V1.md`: Corrected camera method naming, clarified wipe requirements, updated picture usage. | ||
| - `AUTH_ARTIFACTS_DESIGN.md`: Formal specification of artifact-based resume workflow. | ||
|
|
||
| ### 8. Internal / Quality Enhancements | ||
| - Removed chained deprecation in `Device.download_photo()`. | ||
| - Simplified `wipe()` validation logic (single branch covers spaces & non-alphanumeric). | ||
| - Eliminated redundant PIN space check. | ||
| - Minor consistency and defensive branches now covered or documented. | ||
|
|
||
| ## Deprecations (No Immediate Removal) | ||
| | Deprecated | Replacement | | ||
| |------------|-------------| | ||
| | `Device.take_front_photo()` | `Device.take_front_picture()` | | ||
| | `Device.take_rear_photo()` | `Device.take_rear_picture()` | | ||
| | `Device.fetch_pictures()` | `Device.get_picture_blobs()` | | ||
| | `Device.get_pictures()` (Device wrapper) | `Device.get_picture_blobs()` | | ||
| | `Device.download_photo()` | `Device.decode_picture()` | | ||
| | `Device.get_picture()` | `Device.decode_picture()` | | ||
|
|
||
| Plan: Monitor usage; consider removal or formal EOL notice in a future minor/major once ecosystem migrates. | ||
|
|
||
| ## Security Considerations | ||
| - Encourages immediate password discarding (`drop_password=True`), reducing exposure of raw credentials. | ||
| - `password_hash` still sensitive—store using platform secret storage if possible. | ||
| - Wipe PIN validation prevents accidental destructive actions with weak/empty inputs. | ||
| - Lock message sanitization avoids command injection edge cases in future server parsing contexts. | ||
|
|
||
| ## Migration Notes (2.0.3 → 2.0.4) | ||
| - Existing code continues to function; deprecation warnings guide picture API migration. | ||
| - To adopt password-free resume: | ||
| 1. Onboard normally with `create(..., drop_password=True)`. | ||
| 2. Persist `await client.export_auth_artifacts()` securely. | ||
| 3. Resume with `await FmdClient.from_auth_artifacts(artifacts)`. | ||
|
|
||
| ## Example: Password-Free Cycle | ||
| ```python | ||
| client = await FmdClient.create(url, fmd_id, password, drop_password=True) | ||
| artifacts = await client.export_auth_artifacts() | ||
| # Persist artifacts securely... | ||
| await client.close() | ||
|
|
||
| client2 = await FmdClient.from_auth_artifacts(artifacts) | ||
| locations = await client2.get_locations(1) | ||
| ``` | ||
|
|
||
| ## Potential Follow-Ups (Not Included) | ||
| - Enforce future 16+ PIN length once upstream server mandates it. | ||
| - Add a CHANGELOG.md consolidating releases (this file can seed that entry). | ||
| - Provide optional encrypted artifact export (password-protected ZIP or keyring integration). | ||
| - Add coverage for final remaining defensive lines (currently low-risk). | ||
|
|
||
| ## Version | ||
| `fmd_api.__version__ == "2.0.4"` | ||
|
|
||
| ## Acknowledgements | ||
| Thanks to contributors and early testers providing feedback on artifact-based auth and API naming clarity. | ||
|
|
||
| --- | ||
| Released: 2025-11-09 |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,70 @@ | ||
| # Strict Typing Enforcement Plan for fmd_api | ||
|
|
||
| ## Introduction | ||
| The fmd_api repository currently has warnings related to type checking, likely from mypy or similar tools. This plan outlines a structured approach to enforce strict typing across the codebase, improving code quality, reducing bugs, and enhancing developer experience. | ||
|
|
||
| ## Current State Assessment | ||
| - Run mypy on the codebase to identify current warnings. | ||
| - Categorize issues: missing type annotations, Any types, untyped functions, etc. | ||
| - Baseline coverage: Measure current mypy strictness level. | ||
|
|
||
| ## Goals | ||
| - Achieve 100% mypy strict mode compliance. | ||
| - Ensure all public APIs are fully typed. | ||
| - Integrate type checking into CI pipeline. | ||
| - Provide clear migration path for contributors. | ||
|
|
||
| ## Plan Steps | ||
|
|
||
| ### Phase 1: Assessment and Setup (Week 1) | ||
| - Install and configure mypy with strict settings. | ||
| - Run full mypy check and document all errors. | ||
| - Set up pre-commit hooks for mypy. | ||
| - Update pyproject.toml with mypy configuration. | ||
|
|
||
| ### Phase 2: Core Module Typing (Weeks 2-4) | ||
| - Start with fmd_api/client.py: Add type annotations to all functions, classes, and variables. | ||
| - Move to fmd_api/device.py, models.py, exceptions.py, etc. | ||
| - Replace Any with specific types where possible. | ||
| - Handle complex types like async iterators, optional fields. | ||
|
|
||
| ### Phase 3: Test Suite Typing (Weeks 5-6) | ||
| - Type all test files in tests/unit/ and tests/functional/. | ||
| - Ensure fixtures and mocks are properly typed. | ||
| - Update conftest.py with types. | ||
|
|
||
| ### Phase 4: Utilities and Helpers (Week 7) | ||
| - Type helpers.py, _version.py, and any utility modules. | ||
| - Ensure all imports are typed. | ||
|
|
||
| ### Phase 5: CI Integration and Validation (Week 8) | ||
| - Add mypy to GitHub Actions workflow. | ||
| - Fail CI on mypy errors. | ||
| - Update README with typing requirements. | ||
| - Add typing badges if applicable. | ||
|
|
||
| ### Phase 6: Maintenance and Monitoring (Ongoing) | ||
| - Monitor for new typing issues in PRs. | ||
| - Update types as dependencies change. | ||
| - Consider adding pyright or other type checkers for redundancy. | ||
|
|
||
| ## Tools and Dependencies | ||
| - mypy: Primary type checker. | ||
| - typing_extensions: For backporting newer typing features if needed. | ||
| - Pre-commit: For local checks. | ||
|
|
||
| ## Challenges and Mitigations | ||
| - Complex async code: Use proper typing for coroutines and iterators. | ||
| - Third-party libraries: Ensure stubs are available or add type: ignore comments. | ||
| - Backward compatibility: Maintain Python 3.8+ support. | ||
|
|
||
| ## Timeline | ||
| - Total duration: 8 weeks. | ||
| - Weekly milestones with PRs for each phase. | ||
|
|
||
| ## Resources | ||
| - MyPy documentation: https://mypy.readthedocs.io/ | ||
| - Typing best practices: PEP 484, PEP 526. | ||
|
|
||
| ## Conclusion | ||
| Enforcing strict typing will make the codebase more robust and maintainable. This plan provides a clear path to achieve that goal. |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1 +1 @@ | ||
| __version__ = "2.0.4" | ||
| __version__ = "2.0.5" |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The type annotation
type[BaseException]uses Python 3.10+ syntax. Since this project supports Python 3.8+ (perrequires-python = ">=3.8"in pyproject.toml), this will cause aTypeErrorat import time in Python 3.8 and 3.9.For compatibility, you should use
Optional[Type[BaseException]]and importTypefromtyping: