From 239bc012fbf692a1449683d7812d024c165d58f7 Mon Sep 17 00:00:00 2001 From: "Mike A." Date: Tue, 3 Sep 2024 17:40:05 +0200 Subject: [PATCH 1/4] ci: Update pre-commit tool revisions --- .pre-commit-config.yaml | 4 ++-- pyproject.toml | 5 +++-- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 482936a..41eeaa0 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -1,11 +1,11 @@ repos: - repo: https://github.com/astral-sh/ruff-pre-commit - rev: v0.1.9 + rev: v0.6.3 hooks: - id: ruff args: ["--fix"] - id: ruff-format - repo: https://github.com/RobertCraigie/pyright-python - rev: v1.1.350 + rev: v1.1.378 hooks: - id: pyright diff --git a/pyproject.toml b/pyproject.toml index 4e08a78..fa56134 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -41,11 +41,14 @@ typeCheckingMode = "standard" reportImplicitOverride = true [tool.ruff] +line-length = 100 + exclude = [ "docs/", "tests/" ] +[tool.ruff.lint] select = [ "ALL", ] @@ -65,8 +68,6 @@ ignore = [ "FBT", # boolean "traps" ] -line-length = 100 - [tool.ruff.lint.per-file-ignores] "examples/*" = [ "T201", # use of "print" From 1c185195b01ba2d08a61e6eae359e20ed78d683c Mon Sep 17 00:00:00 2001 From: "Mike A." Date: Tue, 3 Sep 2024 17:46:12 +0200 Subject: [PATCH 2/4] chore: Reformat files --- examples/_login.py | 2 ++ examples/real_airtag.py | 1 + findmy/__init__.py | 1 + findmy/accessory.py | 9 +++---- findmy/keys.py | 7 +++-- findmy/reports/__init__.py | 1 + findmy/reports/account.py | 54 +++++++++++++------------------------ findmy/reports/anisette.py | 1 + findmy/reports/reports.py | 9 +++---- findmy/reports/state.py | 1 + findmy/reports/twofactor.py | 1 + findmy/scanner/__init__.py | 1 + findmy/scanner/scanner.py | 2 +- findmy/util/__init__.py | 1 + findmy/util/closable.py | 1 + findmy/util/http.py | 1 + findmy/util/parsers.py | 1 + 17 files changed, 42 insertions(+), 52 deletions(-) diff --git a/examples/_login.py b/examples/_login.py index eb821e0..5412ac1 100644 --- a/examples/_login.py +++ b/examples/_login.py @@ -1,3 +1,5 @@ +# ruff: noqa: ASYNC230 + import json from pathlib import Path diff --git a/examples/real_airtag.py b/examples/real_airtag.py index 5661e9b..5eeb858 100644 --- a/examples/real_airtag.py +++ b/examples/real_airtag.py @@ -1,6 +1,7 @@ """ Example showing how to fetch locations of an AirTag, or any other FindMy accessory. """ + from __future__ import annotations import logging diff --git a/findmy/__init__.py b/findmy/__init__.py index f0fc461..7431bad 100644 --- a/findmy/__init__.py +++ b/findmy/__init__.py @@ -1,4 +1,5 @@ """A package providing everything you need to work with Apple's FindMy network.""" + from . import errors, keys, reports, scanner from .accessory import FindMyAccessory from .keys import KeyPair diff --git a/findmy/accessory.py b/findmy/accessory.py index d21d4e1..230239a 100644 --- a/findmy/accessory.py +++ b/findmy/accessory.py @@ -3,6 +3,7 @@ Accessories could be anything ranging from AirTags to iPhones. """ + from __future__ import annotations import logging @@ -64,7 +65,7 @@ def keys_between(self, start: int | datetime, end: int | datetime) -> set[KeyPai class FindMyAccessory(RollingKeyPairSource): """A findable Find My-accessory using official key rollover.""" - def __init__( # noqa: PLR0913 + def __init__( self, master_key: bytes, skn: bytes, @@ -235,12 +236,10 @@ def __next__(self) -> KeyPair: return self._get_keypair(self._iter_ind) @overload - def __getitem__(self, val: int) -> KeyPair: - ... + def __getitem__(self, val: int) -> KeyPair: ... @overload - def __getitem__(self, val: slice) -> Generator[KeyPair, None, None]: - ... + def __getitem__(self, val: slice) -> Generator[KeyPair, None, None]: ... @override def __getitem__(self, val: int | slice) -> KeyPair | Generator[KeyPair, None, None]: diff --git a/findmy/keys.py b/findmy/keys.py index 97a1fda..a5c8932 100644 --- a/findmy/keys.py +++ b/findmy/keys.py @@ -1,4 +1,5 @@ """Module to work with private and public keys as used in FindMy accessories.""" + from __future__ import annotations import base64 @@ -156,13 +157,11 @@ def __next__(self) -> K: @overload @abstractmethod - def __getitem__(self, val: int) -> K: - ... + def __getitem__(self, val: int) -> K: ... @overload @abstractmethod - def __getitem__(self, val: slice) -> Generator[K, None, None]: - ... + def __getitem__(self, val: slice) -> Generator[K, None, None]: ... @abstractmethod def __getitem__(self, val: int | slice) -> K | Generator[K, None, None]: diff --git a/findmy/reports/__init__.py b/findmy/reports/__init__.py index a5c3851..dfba250 100644 --- a/findmy/reports/__init__.py +++ b/findmy/reports/__init__.py @@ -1,4 +1,5 @@ """Code related to fetching location reports.""" + from .account import AppleAccount, AsyncAppleAccount from .anisette import BaseAnisetteProvider, RemoteAnisetteProvider from .state import LoginState diff --git a/findmy/reports/account.py b/findmy/reports/account.py index 5cc5374..59dbe3d 100644 --- a/findmy/reports/account.py +++ b/findmy/reports/account.py @@ -228,8 +228,7 @@ def fetch_reports( keys: HasHashedPublicKey, date_from: datetime, date_to: datetime | None, - ) -> MaybeCoro[list[LocationReport]]: - ... + ) -> MaybeCoro[list[LocationReport]]: ... @overload @abstractmethod @@ -238,8 +237,7 @@ def fetch_reports( keys: Sequence[HasHashedPublicKey], date_from: datetime, date_to: datetime | None, - ) -> MaybeCoro[dict[HasHashedPublicKey, list[LocationReport]]]: - ... + ) -> MaybeCoro[dict[HasHashedPublicKey, list[LocationReport]]]: ... @overload @abstractmethod @@ -248,8 +246,7 @@ def fetch_reports( keys: RollingKeyPairSource, date_from: datetime, date_to: datetime | None, - ) -> MaybeCoro[list[LocationReport]]: - ... + ) -> MaybeCoro[list[LocationReport]]: ... @abstractmethod def fetch_reports( @@ -271,8 +268,7 @@ def fetch_last_reports( self, keys: HasHashedPublicKey, hours: int = 7 * 24, - ) -> MaybeCoro[list[LocationReport]]: - ... + ) -> MaybeCoro[list[LocationReport]]: ... @overload @abstractmethod @@ -280,8 +276,7 @@ def fetch_last_reports( self, keys: Sequence[HasHashedPublicKey], hours: int = 7 * 24, - ) -> MaybeCoro[dict[HasHashedPublicKey, list[LocationReport]]]: - ... + ) -> MaybeCoro[dict[HasHashedPublicKey, list[LocationReport]]]: ... @overload @abstractmethod @@ -289,8 +284,7 @@ def fetch_last_reports( self, keys: RollingKeyPairSource, hours: int = 7 * 24, - ) -> MaybeCoro[list[LocationReport]]: - ... + ) -> MaybeCoro[list[LocationReport]]: ... @abstractmethod def fetch_last_reports( @@ -629,8 +623,7 @@ async def fetch_reports( keys: HasHashedPublicKey, date_from: datetime, date_to: datetime | None, - ) -> list[LocationReport]: - ... + ) -> list[LocationReport]: ... @overload async def fetch_reports( @@ -638,8 +631,7 @@ async def fetch_reports( keys: Sequence[HasHashedPublicKey], date_from: datetime, date_to: datetime | None, - ) -> dict[HasHashedPublicKey, list[LocationReport]]: - ... + ) -> dict[HasHashedPublicKey, list[LocationReport]]: ... @overload async def fetch_reports( @@ -647,8 +639,7 @@ async def fetch_reports( keys: RollingKeyPairSource, date_from: datetime, date_to: datetime | None, - ) -> list[LocationReport]: - ... + ) -> list[LocationReport]: ... @require_login_state(LoginState.LOGGED_IN) @override @@ -672,24 +663,21 @@ async def fetch_last_reports( self, keys: HasHashedPublicKey, hours: int = 7 * 24, - ) -> list[LocationReport]: - ... + ) -> list[LocationReport]: ... @overload async def fetch_last_reports( self, keys: Sequence[HasHashedPublicKey], hours: int = 7 * 24, - ) -> dict[HasHashedPublicKey, list[LocationReport]]: - ... + ) -> dict[HasHashedPublicKey, list[LocationReport]]: ... @overload async def fetch_last_reports( self, keys: RollingKeyPairSource, hours: int = 7 * 24, - ) -> list[LocationReport]: - ... + ) -> list[LocationReport]: ... @require_login_state(LoginState.LOGGED_IN) @override @@ -1035,8 +1023,7 @@ def fetch_reports( keys: HasHashedPublicKey, date_from: datetime, date_to: datetime | None, - ) -> list[LocationReport]: - ... + ) -> list[LocationReport]: ... @overload def fetch_reports( @@ -1044,8 +1031,7 @@ def fetch_reports( keys: Sequence[HasHashedPublicKey], date_from: datetime, date_to: datetime | None, - ) -> dict[HasHashedPublicKey, list[LocationReport]]: - ... + ) -> dict[HasHashedPublicKey, list[LocationReport]]: ... @overload def fetch_reports( @@ -1053,8 +1039,7 @@ def fetch_reports( keys: RollingKeyPairSource, date_from: datetime, date_to: datetime | None, - ) -> list[LocationReport]: - ... + ) -> list[LocationReport]: ... @override def fetch_reports( @@ -1072,24 +1057,21 @@ def fetch_last_reports( self, keys: HasHashedPublicKey, hours: int = 7 * 24, - ) -> list[LocationReport]: - ... + ) -> list[LocationReport]: ... @overload def fetch_last_reports( self, keys: Sequence[HasHashedPublicKey], hours: int = 7 * 24, - ) -> dict[HasHashedPublicKey, list[LocationReport]]: - ... + ) -> dict[HasHashedPublicKey, list[LocationReport]]: ... @overload def fetch_last_reports( self, keys: RollingKeyPairSource, hours: int = 7 * 24, - ) -> list[LocationReport]: - ... + ) -> list[LocationReport]: ... @override def fetch_last_reports( diff --git a/findmy/reports/anisette.py b/findmy/reports/anisette.py index 7c17722..bcf2bf1 100644 --- a/findmy/reports/anisette.py +++ b/findmy/reports/anisette.py @@ -1,4 +1,5 @@ """Module for Anisette header providers.""" + from __future__ import annotations import base64 diff --git a/findmy/reports/reports.py b/findmy/reports/reports.py index 73defec..3f17be3 100644 --- a/findmy/reports/reports.py +++ b/findmy/reports/reports.py @@ -232,8 +232,7 @@ async def fetch_reports( date_from: datetime, date_to: datetime, device: HasHashedPublicKey, - ) -> list[LocationReport]: - ... + ) -> list[LocationReport]: ... @overload async def fetch_reports( @@ -241,8 +240,7 @@ async def fetch_reports( date_from: datetime, date_to: datetime, device: Sequence[HasHashedPublicKey], - ) -> dict[HasHashedPublicKey, list[LocationReport]]: - ... + ) -> dict[HasHashedPublicKey, list[LocationReport]]: ... @overload async def fetch_reports( @@ -250,8 +248,7 @@ async def fetch_reports( date_from: datetime, date_to: datetime, device: RollingKeyPairSource, - ) -> list[LocationReport]: - ... + ) -> list[LocationReport]: ... async def fetch_reports( self, diff --git a/findmy/reports/state.py b/findmy/reports/state.py index c818a8d..165f5ae 100644 --- a/findmy/reports/state.py +++ b/findmy/reports/state.py @@ -1,4 +1,5 @@ """Account login state.""" + from enum import Enum from typing_extensions import override diff --git a/findmy/reports/twofactor.py b/findmy/reports/twofactor.py index 307a3be..6a51e5b 100644 --- a/findmy/reports/twofactor.py +++ b/findmy/reports/twofactor.py @@ -1,4 +1,5 @@ """Public classes related to handling two-factor authentication.""" + from abc import ABC, abstractmethod from typing import TYPE_CHECKING, Generic, TypeVar diff --git a/findmy/scanner/__init__.py b/findmy/scanner/__init__.py index 944547f..b2c0954 100644 --- a/findmy/scanner/__init__.py +++ b/findmy/scanner/__init__.py @@ -1,4 +1,5 @@ """Utilities related to physically discoverable FindMy-devices.""" + from .scanner import ( NearbyOfflineFindingDevice, OfflineFindingScanner, diff --git a/findmy/scanner/scanner.py b/findmy/scanner/scanner.py index a9ea170..810abbf 100644 --- a/findmy/scanner/scanner.py +++ b/findmy/scanner/scanner.py @@ -139,7 +139,7 @@ def payload_len(cls) -> int: """Length of OfflineFinding data payload in bytes.""" return 0x02 # 2 - def __init__( # noqa: PLR0913 + def __init__( self, mac_bytes: bytes, status_byte: int, diff --git a/findmy/util/__init__.py b/findmy/util/__init__.py index 6ed65f1..3f4b47c 100644 --- a/findmy/util/__init__.py +++ b/findmy/util/__init__.py @@ -1,4 +1,5 @@ """Utility functions and classes. Intended for internal use.""" + from .http import HttpResponse, HttpSession from .parsers import decode_plist diff --git a/findmy/util/closable.py b/findmy/util/closable.py index fbac882..d210bdc 100644 --- a/findmy/util/closable.py +++ b/findmy/util/closable.py @@ -1,4 +1,5 @@ """ABC for async classes that need to be cleaned up before exiting.""" + from __future__ import annotations import asyncio diff --git a/findmy/util/http.py b/findmy/util/http.py index 0c941e7..c68ee7f 100644 --- a/findmy/util/http.py +++ b/findmy/util/http.py @@ -1,4 +1,5 @@ """Module to simplify asynchronous HTTP calls.""" + from __future__ import annotations import json diff --git a/findmy/util/parsers.py b/findmy/util/parsers.py index 74b5dae..2f06769 100644 --- a/findmy/util/parsers.py +++ b/findmy/util/parsers.py @@ -1,4 +1,5 @@ """Parsers for various forms of data formats.""" + import plistlib from typing import Any From 470fb667bdf203a7704866e2d3458d010091b335 Mon Sep 17 00:00:00 2001 From: "Mike A." Date: Tue, 3 Sep 2024 18:19:02 +0200 Subject: [PATCH 3/4] fix: Pass pre-commit checks --- findmy/util/http.py | 19 +++++++++++++++---- pyproject.toml | 5 +++++ 2 files changed, 20 insertions(+), 4 deletions(-) diff --git a/findmy/util/http.py b/findmy/util/http.py index c68ee7f..027694f 100644 --- a/findmy/util/http.py +++ b/findmy/util/http.py @@ -4,7 +4,7 @@ import json import logging -from typing import Any, TypedDict +from typing import Any, TypedDict, cast from aiohttp import BasicAuth, ClientSession, ClientTimeout from typing_extensions import Unpack, override @@ -15,13 +15,20 @@ logging.getLogger(__name__) -class _HttpRequestOptions(TypedDict, total=False): +class _RequestOptions(TypedDict, total=False): json: dict[str, Any] | None headers: dict[str, str] - auth: tuple[str, str] | BasicAuth data: bytes +class _AiohttpRequestOptions(_RequestOptions): + auth: BasicAuth + + +class _HttpRequestOptions(_RequestOptions, total=False): + auth: BasicAuth | tuple[str, str] + + class HttpResponse: """Response of a request made by `HttpSession`.""" @@ -95,15 +102,19 @@ async def request( """ session = await self._get_session() + # cast from http options to library supported options auth = kwargs.get("auth") if isinstance(auth, tuple): kwargs["auth"] = BasicAuth(auth[0], auth[1]) + else: + kwargs.pop("auth") + options = cast(_AiohttpRequestOptions, kwargs) async with await session.request( method, url, ssl=False, - **kwargs, + **options, ) as r: return HttpResponse(r.status, await r.content.read()) diff --git a/pyproject.toml b/pyproject.toml index fa56134..87edb04 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -40,6 +40,11 @@ venv = ".venv" typeCheckingMode = "standard" reportImplicitOverride = true +# examples should be run from their own directory +executionEnvironments = [ + { root = "examples/" } +] + [tool.ruff] line-length = 100 From 180d703dccb25de22ae5a62c5f8c6639189b96fb Mon Sep 17 00:00:00 2001 From: "Mike A." Date: Tue, 3 Sep 2024 18:26:47 +0200 Subject: [PATCH 4/4] ci: Install test deps in pre-commit workflow --- .github/workflows/pre-commit.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/pre-commit.yml b/.github/workflows/pre-commit.yml index fe0267f..72eadf7 100644 --- a/.github/workflows/pre-commit.yml +++ b/.github/workflows/pre-commit.yml @@ -20,7 +20,7 @@ jobs: run: | python -m pip install poetry poetry config virtualenvs.in-project true - poetry install --with dev + poetry install --with dev,test - uses: pre-commit/action@v3.0.1