docs: somewhat fix references in source code

This commit is contained in:
Mike A.
2025-08-04 16:16:30 +02:00
parent ea880d5d49
commit def535f819
12 changed files with 113 additions and 109 deletions

View File

@@ -41,7 +41,7 @@ class FindMyAccessoryMapping(TypedDict):
class RollingKeyPairSource(ABC):
"""A class that generates rolling `KeyPair`s."""
"""A class that generates rolling :meth:`KeyPair`s."""
@property
@abstractmethod

View File

@@ -21,5 +21,5 @@ class InvalidStateError(RuntimeError):
"""
Raised when a method is used that is in conflict with the internal account state.
For example: calling `BaseAppleAccount.login` while already logged in.
For example: calling :meth:`BaseAppleAccount.login` while already logged in.
"""

View File

@@ -91,7 +91,7 @@ class HasPublicKey(HasHashedPublicKey, ABC):
@property
@override
def hashed_adv_key_bytes(self) -> bytes:
"""See `HasHashedPublicKey.hashed_adv_key_bytes`."""
"""See :meth:`HasHashedPublicKey.hashed_adv_key_bytes`."""
return hashlib.sha256(self.adv_key_bytes).digest()
@property
@@ -136,7 +136,7 @@ class KeyPair(HasPublicKey, Serializable[KeyPairMapping]):
key_type: KeyType = KeyType.UNKNOWN,
name: str | None = None,
) -> None:
"""Initialize the `KeyPair` with the private key bytes."""
"""Initialize the :meth:`KeyPair` with the private key bytes."""
priv_int = crypto.bytes_to_int(private_key)
self._priv_key = ec.derive_private_key(
priv_int,
@@ -162,15 +162,15 @@ class KeyPair(HasPublicKey, Serializable[KeyPairMapping]):
@classmethod
def new(cls) -> KeyPair:
"""Generate a new random `KeyPair`."""
"""Generate a new random :meth:`KeyPair`."""
return cls(secrets.token_bytes(28))
@classmethod
def from_b64(cls, key_b64: str) -> KeyPair:
"""
Import an existing `KeyPair` from its base64-encoded representation.
Import an existing :meth:`KeyPair` from its base64-encoded representation.
Same format as returned by `KeyPair.private_key_b64`.
Same format as returned by :meth:`KeyPair.private_key_b64`.
"""
return cls(base64.b64decode(key_b64))
@@ -185,7 +185,7 @@ class KeyPair(HasPublicKey, Serializable[KeyPairMapping]):
"""
Return the private key as a base64-encoded string.
Can be re-imported using `KeyPair.from_b64`.
Can be re-imported using :meth:`KeyPair.from_b64`.
"""
return base64.b64encode(self.private_key_bytes).decode("ascii")

View File

@@ -31,7 +31,7 @@ def get_key() -> bytes:
def decrypt_plist(encrypted: str | Path | bytes | IO[bytes], key: bytes) -> dict:
"""
Decrypts the encrypted plist file at `encrypted` using the provided `key`.
Decrypts the encrypted plist file at :meth:`encrypted` using the provided :meth:`key`.
:param encrypted: If bytes or IO, the encrypted plist data.
If str or Path, the path to the encrypted plist file, which is

View File

@@ -200,7 +200,7 @@ class BaseAppleAccount(Closable, Serializable[AccountStateMapping], ABC):
"""
Request a 2FA code to be sent to a specific phone number ID.
Consider using `BaseSecondFactorMethod.request` instead.
Consider using :meth:`BaseSecondFactorMethod.request` instead.
"""
raise NotImplementedError
@@ -209,7 +209,7 @@ class BaseAppleAccount(Closable, Serializable[AccountStateMapping], ABC):
"""
Submit a 2FA code that was sent to a specific phone number ID.
Consider using `BaseSecondFactorMethod.submit` instead.
Consider using :meth:`BaseSecondFactorMethod.submit` instead.
"""
raise NotImplementedError
@@ -218,7 +218,7 @@ class BaseAppleAccount(Closable, Serializable[AccountStateMapping], ABC):
"""
Request a 2FA code to be sent to a trusted device.
Consider using `BaseSecondFactorMethod.request` instead.
Consider using :meth:`BaseSecondFactorMethod.request` instead.
"""
raise NotImplementedError
@@ -227,7 +227,7 @@ class BaseAppleAccount(Closable, Serializable[AccountStateMapping], ABC):
"""
Submit a 2FA code that was sent to a trusted device.
Consider using `BaseSecondFactorMethod.submit` instead.
Consider using :meth:`BaseSecondFactorMethod.submit` instead.
"""
raise NotImplementedError
@@ -270,9 +270,9 @@ class BaseAppleAccount(Closable, Serializable[AccountStateMapping], ABC):
list[LocationReport] | dict[HasHashedPublicKey | RollingKeyPairSource, list[LocationReport]]
]:
"""
Fetch location reports for `HasHashedPublicKey`s between `date_from` and `date_end`.
Fetch location reports for :class:`HasHashedPublicKey`s between `date_from` and `date_end`.
Returns a dictionary mapping `HasHashedPublicKey`s to a list of their location reports.
Returns a dictionary mapping :class:`HasHashedPublicKey`s to their location reports.
"""
raise NotImplementedError
@@ -311,9 +311,9 @@ class BaseAppleAccount(Closable, Serializable[AccountStateMapping], ABC):
list[LocationReport] | dict[HasHashedPublicKey | RollingKeyPairSource, list[LocationReport]]
]:
"""
Fetch location reports for a sequence of `HasHashedPublicKey`s for the last `hours` hours.
Fetch location reports for :class:`HasHashedPublicKey`s for the last `hours` hours.
Utility method as an alternative to using `BaseAppleAccount.fetch_reports` directly.
Utility method as an alternative to using :meth:`BaseAppleAccount.fetch_reports` directly.
"""
raise NotImplementedError
@@ -326,13 +326,13 @@ class BaseAppleAccount(Closable, Serializable[AccountStateMapping], ABC):
"""
Retrieve a complete dictionary of Anisette headers.
Utility method for `AnisetteProvider.get_headers` using this account's user and device ID.
Utility method for :meth:`AnisetteProvider.get_headers` using this account's user/device ID.
"""
raise NotImplementedError
class AsyncAppleAccount(BaseAppleAccount):
"""An async implementation of `BaseAppleAccount`."""
"""An async implementation of :meth:`BaseAppleAccount`."""
# auth endpoints
_ENDPOINT_GSA = "https://gsa.apple.com/grandslam/GsService2"
@@ -357,7 +357,7 @@ class AsyncAppleAccount(BaseAppleAccount):
"""
Initialize the apple account.
:param anisette: An instance of `AsyncAnisetteProvider`.
:param anisette: An instance of :meth:`AsyncAnisetteProvider`.
"""
super().__init__()
@@ -401,7 +401,7 @@ class AsyncAppleAccount(BaseAppleAccount):
@property
@override
def login_state(self) -> LoginState:
"""See `BaseAppleAccount.login_state`."""
"""See :meth:`BaseAppleAccount.login_state`."""
return self._login_state
@property
@@ -412,7 +412,7 @@ class AsyncAppleAccount(BaseAppleAccount):
)
@override
def account_name(self) -> str | None:
"""See `BaseAppleAccount.account_name`."""
"""See :meth:`BaseAppleAccount.account_name`."""
return self._account_info["account_name"] if self._account_info else None
@property
@@ -423,7 +423,7 @@ class AsyncAppleAccount(BaseAppleAccount):
)
@override
def first_name(self) -> str | None:
"""See `BaseAppleAccount.first_name`."""
"""See :meth:`BaseAppleAccount.first_name`."""
return self._account_info["first_name"] if self._account_info else None
@property
@@ -434,7 +434,7 @@ class AsyncAppleAccount(BaseAppleAccount):
)
@override
def last_name(self) -> str | None:
"""See `BaseAppleAccount.last_name`."""
"""See :meth:`BaseAppleAccount.last_name`."""
return self._account_info["last_name"] if self._account_info else None
@override
@@ -501,7 +501,7 @@ class AsyncAppleAccount(BaseAppleAccount):
@require_login_state(LoginState.LOGGED_OUT)
@override
async def login(self, username: str, password: str) -> LoginState:
"""See `BaseAppleAccount.login`."""
"""See :meth:`BaseAppleAccount.login`."""
# LOGGED_OUT -> (REQUIRE_2FA or AUTHENTICATED)
new_state = await self._gsa_authenticate(username, password)
if new_state == LoginState.REQUIRE_2FA: # pass control back to handle 2FA
@@ -513,7 +513,7 @@ class AsyncAppleAccount(BaseAppleAccount):
@require_login_state(LoginState.REQUIRE_2FA)
@override
async def get_2fa_methods(self) -> Sequence[AsyncSecondFactorMethod]:
"""See `BaseAppleAccount.get_2fa_methods`."""
"""See :meth:`BaseAppleAccount.get_2fa_methods`."""
methods: list[AsyncSecondFactorMethod] = []
if self._account_info is None:
@@ -542,7 +542,7 @@ class AsyncAppleAccount(BaseAppleAccount):
@require_login_state(LoginState.REQUIRE_2FA)
@override
async def sms_2fa_request(self, phone_number_id: int) -> None:
"""See `BaseAppleAccount.sms_2fa_request`."""
"""See :meth:`BaseAppleAccount.sms_2fa_request`."""
data = {"phoneNumber": {"id": phone_number_id}, "mode": "sms"}
await self._sms_2fa_request(
@@ -554,7 +554,7 @@ class AsyncAppleAccount(BaseAppleAccount):
@require_login_state(LoginState.REQUIRE_2FA)
@override
async def sms_2fa_submit(self, phone_number_id: int, code: str) -> LoginState:
"""See `BaseAppleAccount.sms_2fa_submit`."""
"""See :meth:`BaseAppleAccount.sms_2fa_submit`."""
data = {
"phoneNumber": {"id": phone_number_id},
"securityCode": {"code": str(code)},
@@ -579,7 +579,7 @@ class AsyncAppleAccount(BaseAppleAccount):
@require_login_state(LoginState.REQUIRE_2FA)
@override
async def td_2fa_request(self) -> None:
"""See `BaseAppleAccount.td_2fa_request`."""
"""See :meth:`BaseAppleAccount.td_2fa_request`."""
headers = {
"Content-Type": "text/x-xml-plist",
"Accept": "text/x-xml-plist",
@@ -593,7 +593,7 @@ class AsyncAppleAccount(BaseAppleAccount):
@require_login_state(LoginState.REQUIRE_2FA)
@override
async def td_2fa_submit(self, code: str) -> LoginState:
"""See `BaseAppleAccount.td_2fa_submit`."""
"""See :meth:`BaseAppleAccount.td_2fa_submit`."""
headers = {
"security-code": code,
"Content-Type": "text/x-xml-plist",
@@ -717,7 +717,7 @@ class AsyncAppleAccount(BaseAppleAccount):
) -> (
list[LocationReport] | dict[HasHashedPublicKey | RollingKeyPairSource, list[LocationReport]]
):
"""See `BaseAppleAccount.fetch_reports`."""
"""See :meth:`BaseAppleAccount.fetch_reports`."""
date_to = date_to or datetime.now().astimezone()
return await self._reports.fetch_reports(
@@ -758,7 +758,7 @@ class AsyncAppleAccount(BaseAppleAccount):
) -> (
list[LocationReport] | dict[HasHashedPublicKey | RollingKeyPairSource, list[LocationReport]]
):
"""See `BaseAppleAccount.fetch_last_reports`."""
"""See :meth:`BaseAppleAccount.fetch_last_reports`."""
end = datetime.now(tz=timezone.utc)
start = end - timedelta(hours=hours)
@@ -971,15 +971,15 @@ class AsyncAppleAccount(BaseAppleAccount):
with_client_info: bool = False,
serial: str = "0",
) -> dict[str, str]:
"""See `BaseAppleAccount.get_anisette_headers`."""
"""See :meth:`BaseAppleAccount.get_anisette_headers`."""
return await self._anisette.get_headers(self._uid, self._devid, serial, with_client_info)
class AppleAccount(BaseAppleAccount):
"""
A sync implementation of `BaseappleAccount`.
A sync implementation of :meth:`BaseappleAccount`.
Uses `AsyncappleAccount` internally.
Uses :meth:`AsyncappleAccount` internally.
"""
def __init__(
@@ -988,7 +988,7 @@ class AppleAccount(BaseAppleAccount):
*,
state_info: AccountStateMapping | None = None,
) -> None:
"""See `AsyncAppleAccount.__init__`."""
"""See :meth:`AsyncAppleAccount.__init__`."""
self._asyncacc = AsyncAppleAccount(anisette=anisette, state_info=state_info)
try:
@@ -1001,31 +1001,31 @@ class AppleAccount(BaseAppleAccount):
@override
async def close(self) -> None:
"""See `AsyncAppleAccount.close`."""
"""See :meth:`AsyncAppleAccount.close`."""
await self._asyncacc.close()
@property
@override
def login_state(self) -> LoginState:
"""See `AsyncAppleAccount.login_state`."""
"""See :meth:`AsyncAppleAccount.login_state`."""
return self._asyncacc.login_state
@property
@override
def account_name(self) -> str | None:
"""See `AsyncAppleAccount.login_state`."""
"""See :meth:`AsyncAppleAccount.login_state`."""
return self._asyncacc.account_name
@property
@override
def first_name(self) -> str | None:
"""See `AsyncAppleAccount.first_name`."""
"""See :meth:`AsyncAppleAccount.first_name`."""
return self._asyncacc.first_name
@property
@override
def last_name(self) -> str | None:
"""See `AsyncAppleAccount.last_name`."""
"""See :meth:`AsyncAppleAccount.last_name`."""
return self._asyncacc.last_name
@override
@@ -1051,13 +1051,13 @@ class AppleAccount(BaseAppleAccount):
@override
def login(self, username: str, password: str) -> LoginState:
"""See `AsyncAppleAccount.login`."""
"""See :meth:`AsyncAppleAccount.login`."""
coro = self._asyncacc.login(username, password)
return self._evt_loop.run_until_complete(coro)
@override
def get_2fa_methods(self) -> Sequence[SyncSecondFactorMethod]:
"""See `AsyncAppleAccount.get_2fa_methods`."""
"""See :meth:`AsyncAppleAccount.get_2fa_methods`."""
coro = self._asyncacc.get_2fa_methods()
methods = self._evt_loop.run_until_complete(coro)
@@ -1078,25 +1078,25 @@ class AppleAccount(BaseAppleAccount):
@override
def sms_2fa_request(self, phone_number_id: int) -> None:
"""See `AsyncAppleAccount.sms_2fa_request`."""
"""See :meth:`AsyncAppleAccount.sms_2fa_request`."""
coro = self._asyncacc.sms_2fa_request(phone_number_id)
return self._evt_loop.run_until_complete(coro)
@override
def sms_2fa_submit(self, phone_number_id: int, code: str) -> LoginState:
"""See `AsyncAppleAccount.sms_2fa_submit`."""
"""See :meth:`AsyncAppleAccount.sms_2fa_submit`."""
coro = self._asyncacc.sms_2fa_submit(phone_number_id, code)
return self._evt_loop.run_until_complete(coro)
@override
def td_2fa_request(self) -> None:
"""See `AsyncAppleAccount.td_2fa_request`."""
"""See :meth:`AsyncAppleAccount.td_2fa_request`."""
coro = self._asyncacc.td_2fa_request()
return self._evt_loop.run_until_complete(coro)
@override
def td_2fa_submit(self, code: str) -> LoginState:
"""See `AsyncAppleAccount.td_2fa_submit`."""
"""See :meth:`AsyncAppleAccount.td_2fa_submit`."""
coro = self._asyncacc.td_2fa_submit(code)
return self._evt_loop.run_until_complete(coro)
@@ -1135,7 +1135,7 @@ class AppleAccount(BaseAppleAccount):
) -> (
list[LocationReport] | dict[HasHashedPublicKey | RollingKeyPairSource, list[LocationReport]]
):
"""See `AsyncAppleAccount.fetch_reports`."""
"""See :meth:`AsyncAppleAccount.fetch_reports`."""
coro = self._asyncacc.fetch_reports(keys, date_from, date_to)
return self._evt_loop.run_until_complete(coro)
@@ -1170,7 +1170,7 @@ class AppleAccount(BaseAppleAccount):
) -> (
list[LocationReport] | dict[HasHashedPublicKey | RollingKeyPairSource, list[LocationReport]]
):
"""See `AsyncAppleAccount.fetch_last_reports`."""
"""See :meth:`AsyncAppleAccount.fetch_last_reports`."""
coro = self._asyncacc.fetch_last_reports(keys, hours)
return self._evt_loop.run_until_complete(coro)
@@ -1180,6 +1180,6 @@ class AppleAccount(BaseAppleAccount):
with_client_info: bool = False,
serial: str = "0",
) -> dict[str, str]:
"""See `AsyncAppleAccount.get_anisette_headers`."""
"""See :meth:`AsyncAppleAccount.get_anisette_headers`."""
coro = self._asyncacc.get_anisette_headers(with_client_info, serial)
return self._evt_loop.run_until_complete(coro)

View File

@@ -135,7 +135,7 @@ class BaseAnisetteProvider(Closable, Serializable, ABC):
"""
Generate a complete dictionary of Anisette headers.
Consider using `BaseAppleAccount.get_anisette_headers` instead.
Consider using :meth:`BaseAppleAccount.get_anisette_headers` instead.
"""
headers = {
# Current Time
@@ -207,7 +207,7 @@ class RemoteAnisetteProvider(BaseAnisetteProvider, Serializable[RemoteAnisetteMa
@override
def to_json(self, dst: str | Path | None = None, /) -> RemoteAnisetteMapping:
"""See `BaseAnisetteProvider.serialize`."""
"""See :meth:`BaseAnisetteProvider.serialize`."""
return save_and_return_json(
{
"type": "aniRemote",
@@ -219,7 +219,7 @@ class RemoteAnisetteProvider(BaseAnisetteProvider, Serializable[RemoteAnisetteMa
@classmethod
@override
def from_json(cls, val: str | Path | RemoteAnisetteMapping) -> RemoteAnisetteProvider:
"""See `BaseAnisetteProvider.deserialize`."""
"""See :meth:`BaseAnisetteProvider.deserialize`."""
val = read_data_json(val)
assert val["type"] == "aniRemote"
@@ -231,7 +231,7 @@ class RemoteAnisetteProvider(BaseAnisetteProvider, Serializable[RemoteAnisetteMa
@property
@override
def otp(self) -> str:
"""See `BaseAnisetteProvider.otp`_."""
"""See :meth:`BaseAnisetteProvider.otp`."""
otp = (self._anisette_data or {}).get("X-Apple-I-MD")
if otp is None:
logger.warning("X-Apple-I-MD header not found! Returning fallback...")
@@ -240,7 +240,7 @@ class RemoteAnisetteProvider(BaseAnisetteProvider, Serializable[RemoteAnisetteMa
@property
@override
def machine(self) -> str:
"""See `BaseAnisetteProvider.machine`_."""
"""See :meth:`BaseAnisetteProvider.machine`."""
machine = (self._anisette_data or {}).get("X-Apple-I-MD-M")
if machine is None:
logger.warning("X-Apple-I-MD-M header not found! Returning fallback...")
@@ -254,7 +254,7 @@ class RemoteAnisetteProvider(BaseAnisetteProvider, Serializable[RemoteAnisetteMa
serial: str = "0",
with_client_info: bool = False,
) -> dict[str, str]:
"""See `BaseAnisetteProvider.get_headers`_."""
"""See :meth::meth:`BaseAnisetteProvider.get_headers`."""
if self._closed:
msg = "RemoteAnisetteProvider has been closed and cannot be used"
raise RuntimeError(msg)
@@ -270,7 +270,7 @@ class RemoteAnisetteProvider(BaseAnisetteProvider, Serializable[RemoteAnisetteMa
@override
async def close(self) -> None:
"""See `AnisetteProvider.close`."""
"""See :meth:`AnisetteProvider.close`."""
if self._closed:
return # Already closed, make it idempotent
@@ -283,7 +283,7 @@ class RemoteAnisetteProvider(BaseAnisetteProvider, Serializable[RemoteAnisetteMa
class LocalAnisetteProvider(BaseAnisetteProvider, Serializable[LocalAnisetteMapping]):
"""Anisette provider. Generates headers without a remote server using the `anisette` library."""
"""Local anisette provider using the `anisette` library."""
def __init__(
self,
@@ -328,7 +328,7 @@ class LocalAnisetteProvider(BaseAnisetteProvider, Serializable[LocalAnisetteMapp
@override
def to_json(self, dst: str | Path | None = None, /) -> LocalAnisetteMapping:
"""See `BaseAnisetteProvider.serialize`."""
"""See :meth:`BaseAnisetteProvider.serialize`."""
with BytesIO() as buf:
self._ani.save_provisioning(buf)
prov_data = base64.b64encode(buf.getvalue()).decode("utf-8")
@@ -349,7 +349,7 @@ class LocalAnisetteProvider(BaseAnisetteProvider, Serializable[LocalAnisetteMapp
*,
libs_path: str | Path | None = None,
) -> LocalAnisetteProvider:
"""See `BaseAnisetteProvider.deserialize`."""
"""See :meth:`BaseAnisetteProvider.deserialize`."""
val = read_data_json(val)
assert val["type"] == "aniLocal"
@@ -366,7 +366,7 @@ class LocalAnisetteProvider(BaseAnisetteProvider, Serializable[LocalAnisetteMapp
serial: str = "0",
with_client_info: bool = False,
) -> dict[str, str]:
"""See `BaseAnisetteProvider.get_headers`_."""
"""See :meth:`BaseAnisetteProvider.get_headers`."""
self._ani_data = self._ani.get_data()
return await super().get_headers(user_id, device_id, serial, with_client_info)
@@ -374,7 +374,7 @@ class LocalAnisetteProvider(BaseAnisetteProvider, Serializable[LocalAnisetteMapp
@property
@override
def otp(self) -> str:
"""See `BaseAnisetteProvider.otp`_."""
"""See :meth:`BaseAnisetteProvider.otp`."""
machine = (self._ani_data or {}).get("X-Apple-I-MD")
if machine is None:
logger.warning("X-Apple-I-MD header not found! Returning fallback...")
@@ -383,7 +383,7 @@ class LocalAnisetteProvider(BaseAnisetteProvider, Serializable[LocalAnisetteMapp
@property
@override
def machine(self) -> str:
"""See `BaseAnisetteProvider.machine`_."""
"""See :meth:`BaseAnisetteProvider.machine`."""
machine = (self._ani_data or {}).get("X-Apple-I-MD-M")
if machine is None:
logger.warning("X-Apple-I-MD-M header not found! Returning fallback...")
@@ -391,4 +391,4 @@ class LocalAnisetteProvider(BaseAnisetteProvider, Serializable[LocalAnisetteMapp
@override
async def close(self) -> None:
"""See `BaseAnisetteProvider.close`_."""
"""See :meth:`BaseAnisetteProvider.close`."""

View File

@@ -52,14 +52,18 @@ LocationReportMapping = Union[LocationReportEncryptedMapping, LocationReportDecr
class LocationReport(HasHashedPublicKey, Serializable[LocationReportMapping]):
"""Location report corresponding to a certain `HasHashedPublicKey`."""
"""Location report corresponding to a certain :meth:`HasHashedPublicKey`."""
def __init__(
self,
payload: bytes,
hashed_adv_key: bytes,
) -> None:
"""Initialize a `KeyReport`. You should probably use `KeyReport.from_payload` instead."""
"""
Initialize a :class:`LocationReport`.
You should probably use :meth:`LocationReport.from_payload` instead.
"""
self._payload: bytes = payload
self._hashed_adv_key: bytes = hashed_adv_key
@@ -68,7 +72,7 @@ class LocationReport(HasHashedPublicKey, Serializable[LocationReportMapping]):
@property
@override
def hashed_adv_key_bytes(self) -> bytes:
"""See `HasHashedPublicKey.hashed_adv_key_bytes`."""
"""See :meth:`HasHashedPublicKey.hashed_adv_key_bytes`."""
return self._hashed_adv_key
@property
@@ -96,7 +100,7 @@ class LocationReport(HasHashedPublicKey, Serializable[LocationReportMapping]):
return key.hashed_adv_key_bytes == self._hashed_adv_key
def decrypt(self, key: KeyPair) -> None:
"""Decrypt the report using its corresponding `KeyPair`."""
"""Decrypt the report using its corresponding :meth:`KeyPair`."""
if not self.can_decrypt(key):
msg = "Cannot decrypt with this key!"
raise ValueError(msg)
@@ -136,7 +140,7 @@ class LocationReport(HasHashedPublicKey, Serializable[LocationReportMapping]):
@property
def timestamp(self) -> datetime:
"""The `datetime` when this report was recorded by a device."""
"""The :meth:`datetime` when this report was recorded by a device."""
timestamp_int = int.from_bytes(self._payload[0:4], "big") + (60 * 60 * 24 * 11323)
return datetime.fromtimestamp(timestamp_int, tz=timezone.utc).astimezone()
@@ -302,9 +306,9 @@ class LocationReport(HasHashedPublicKey, Serializable[LocationReportMapping]):
def __lt__(self, other: LocationReport) -> bool:
"""
Compare against another `KeyReport`.
Compare against another :meth:`KeyReport`.
A `KeyReport` is said to be "less than" another `KeyReport` iff its recorded
A :meth:`KeyReport` is said to be "less than" another :meth:`KeyReport` iff its recorded
timestamp is strictly less than the other report.
"""
if isinstance(other, LocationReport):
@@ -369,12 +373,12 @@ class LocationReportsFetcher:
"""
Fetch location reports for a certain device.
When ``device`` is a single :class:`.HasHashedPublicKey`, this method will return
When `device` is a single :class:`HasHashedPublicKey`, this method will return
a list of location reports corresponding to that key.
When ``device`` is a :class:`.RollingKeyPairSource`, it will return a list of
When `device` is a :class:`RollingKeyPairSource`, it will return a list of
location reports corresponding to that source.
When ``device`` is a sequence of :class:`.HasHashedPublicKey`s or RollingKeyPairSource's,
it will return a dictionary with the :class:`.HasHashedPublicKey` or `.RollingKeyPairSource`
When `device` is a sequence of :class:`HasHashedPublicKey`s or RollingKeyPairSource's,
it will return a dictionary with the provided object
as key, and a list of location reports as value.
"""
key_devs: dict[HasHashedPublicKey, HasHashedPublicKey | RollingKeyPairSource] = {}

View File

@@ -6,7 +6,7 @@ from typing_extensions import override
class LoginState(Enum):
"""Enum of possible login states. Used for `AppleAccount`'s internal state machine."""
"""Enum of possible login states. Used for :meth:`AppleAccount`'s internal state machine."""
LOGGED_OUT = 0
REQUIRE_2FA = 1
@@ -15,9 +15,9 @@ class LoginState(Enum):
def __lt__(self, other: "LoginState") -> bool:
"""
Compare against another `LoginState`.
Compare against another :meth:`LoginState`.
A `LoginState` is said to be "less than" another `LoginState` iff it is in
A :meth:`LoginState` is said to be "less than" another :meth:`LoginState` iff it is in
an "earlier" stage of the login process, going from LOGGED_OUT to LOGGED_IN.
"""
if isinstance(other, LoginState):

View File

@@ -63,13 +63,13 @@ class AsyncSecondFactorMethod(BaseSecondFactorMethod, ABC):
@override
@abstractmethod
async def request(self) -> None:
"""See `BaseSecondFactorMethod.request`."""
"""See :meth:`BaseSecondFactorMethod.request`."""
raise NotImplementedError
@override
@abstractmethod
async def submit(self, code: str) -> LoginState:
"""See `BaseSecondFactorMethod.submit`."""
"""See :meth:`BaseSecondFactorMethod.submit`."""
raise NotImplementedError
@@ -93,13 +93,13 @@ class SyncSecondFactorMethod(BaseSecondFactorMethod, ABC):
@override
@abstractmethod
def request(self) -> None:
"""See `BaseSecondFactorMethod.request`."""
"""See :meth:`BaseSecondFactorMethod.request`."""
raise NotImplementedError
@override
@abstractmethod
def submit(self, code: str) -> LoginState:
"""See `BaseSecondFactorMethod.submit`."""
"""See :meth:`BaseSecondFactorMethod.submit`."""
raise NotImplementedError
@@ -128,7 +128,7 @@ class TrustedDeviceSecondFactorMethod(BaseSecondFactorMethod, ABC):
class AsyncSmsSecondFactor(AsyncSecondFactorMethod, SmsSecondFactorMethod):
"""An async implementation of `SmsSecondFactorMethod`."""
"""An async implementation of :meth:`SmsSecondFactorMethod`."""
def __init__(
self,
@@ -139,7 +139,7 @@ class AsyncSmsSecondFactor(AsyncSecondFactorMethod, SmsSecondFactorMethod):
"""
Initialize the second factor method.
Should not be done manually; use `AsyncAppleAccount.get_2fa_methods` instead.
Should not be done manually; use :meth:`AsyncAppleAccount.get_2fa_methods` instead.
"""
super().__init__(account)
@@ -174,7 +174,7 @@ class AsyncSmsSecondFactor(AsyncSecondFactorMethod, SmsSecondFactorMethod):
class SyncSmsSecondFactor(SyncSecondFactorMethod, SmsSecondFactorMethod):
"""A sync implementation of `SmsSecondFactorMethod`."""
"""A sync implementation of :meth:`SmsSecondFactorMethod`."""
def __init__(
self,
@@ -182,7 +182,7 @@ class SyncSmsSecondFactor(SyncSecondFactorMethod, SmsSecondFactorMethod):
number_id: int,
phone_number: str,
) -> None:
"""See `AsyncSmsSecondFactor.__init__`."""
"""See :meth:`AsyncSmsSecondFactor.__init__`."""
super().__init__(account)
self._phone_number_id: int = number_id
@@ -191,28 +191,28 @@ class SyncSmsSecondFactor(SyncSecondFactorMethod, SmsSecondFactorMethod):
@property
@override
def phone_number_id(self) -> int:
"""See `AsyncSmsSecondFactor.phone_number_id`."""
"""See :meth:`AsyncSmsSecondFactor.phone_number_id`."""
return self._phone_number_id
@property
@override
def phone_number(self) -> str:
"""See `AsyncSmsSecondFactor.phone_number`."""
"""See :meth:`AsyncSmsSecondFactor.phone_number`."""
return self._phone_number
@override
def request(self) -> None:
"""See `AsyncSmsSecondFactor.request`."""
"""See :meth:`AsyncSmsSecondFactor.request`."""
return self.account.sms_2fa_request(self._phone_number_id)
@override
def submit(self, code: str) -> LoginState:
"""See `AsyncSmsSecondFactor.submit`."""
"""See :meth:`AsyncSmsSecondFactor.submit`."""
return self.account.sms_2fa_submit(self._phone_number_id, code)
class AsyncTrustedDeviceSecondFactor(AsyncSecondFactorMethod, TrustedDeviceSecondFactorMethod):
"""An async implementation of `TrustedDeviceSecondFactorMethod`."""
"""An async implementation of :meth:`TrustedDeviceSecondFactorMethod`."""
@override
async def request(self) -> None:
@@ -224,14 +224,14 @@ class AsyncTrustedDeviceSecondFactor(AsyncSecondFactorMethod, TrustedDeviceSecon
class SyncTrustedDeviceSecondFactor(SyncSecondFactorMethod, TrustedDeviceSecondFactorMethod):
"""A sync implementation of `TrustedDeviceSecondFactorMethod`."""
"""A sync implementation of :meth:`TrustedDeviceSecondFactorMethod`."""
@override
def request(self) -> None:
"""See `AsyncTrustedDeviceSecondFactor.request`."""
"""See :meth:`AsyncTrustedDeviceSecondFactor.request`."""
return self.account.td_2fa_request()
@override
def submit(self, code: str) -> LoginState:
"""See `AsyncTrustedDeviceSecondFactor.submit`."""
"""See :meth:`AsyncTrustedDeviceSecondFactor.submit`."""
return self.account.td_2fa_submit(code)

View File

@@ -211,7 +211,7 @@ class SeparatedOfflineFindingDevice(OfflineFindingDevice, HasPublicKey):
detected_at: datetime,
additional_data: dict[Any, Any] | None = None,
) -> None:
"""Initialize a `SeparatedOfflineFindingDevice`."""
"""Initialize a :meth:`SeparatedOfflineFindingDevice`."""
super().__init__(mac_bytes, status, detected_at, additional_data)
self._public_key: bytes = public_key
@@ -225,7 +225,7 @@ class SeparatedOfflineFindingDevice(OfflineFindingDevice, HasPublicKey):
@property
@override
def adv_key_bytes(self) -> bytes:
"""See `HasPublicKey.adv_key_bytes`."""
"""See :meth:`HasPublicKey.adv_key_bytes`."""
return self._public_key
@override
@@ -300,7 +300,7 @@ _DEVICE_TYPES = {
class OfflineFindingScanner:
"""BLE scanner that searches for `OfflineFindingDevice`s."""
"""BLE scanner that searches for :meth:`OfflineFindingDevice`s."""
_scan_ctrl_lock = asyncio.Lock()
@@ -311,7 +311,7 @@ class OfflineFindingScanner:
Initialize an instance of the Scanner using an event loop.
You most likely do not want to use this yourself;
check out `OfflineFindingScanner.create` instead.
check out :meth:`OfflineFindingScanner.create` instead.
"""
self._scanner: BleakScanner = BleakScanner(self._scan_callback, cb={"use_bdaddr": True})
@@ -377,10 +377,10 @@ class OfflineFindingScanner:
extend_timeout: bool = False,
) -> AsyncGenerator[OfflineFindingDevice, None]:
"""
Scan for `OfflineFindingDevice`s for up to `timeout` seconds.
Scan for :meth:`OfflineFindingDevice`s for up to :meth:`timeout` seconds.
If `extend_timeout` is set, the timer will be extended
by `timeout` seconds every time a new device is discovered.
If :meth:`extend_timeout` is set, the timer will be extended
by :meth:`timeout` seconds every time a new device is discovered.
"""
await self._start_scan()

View File

@@ -19,9 +19,9 @@ class Closable(ABC):
def __init__(self, loop: asyncio.AbstractEventLoop | None = None) -> None:
"""
Initialize the ``Closable``.
Initialize the :class:`Closable`.
If an event loop is given, the ``Closable`` will attempt to close itself
If an event loop is given, the :class:`Closable` will attempt to close itself
using the loop when it is garbage collected.
"""
self._loop: asyncio.AbstractEventLoop | None = loop
@@ -57,7 +57,7 @@ class Serializable(Generic[_T], ABC):
If an argument is provided, the output will also be written to that file.
The output of this method is guaranteed to be JSON-serializable, and passing
the return value of this function as an argument to `Serializable.from_json`
the return value of this function as an argument to :meth:`Serializable.from_json`
will always result in an exact copy of the internal state as it was when exported.
You are encouraged to save and load object states to and from disk whenever possible,
@@ -69,11 +69,11 @@ class Serializable(Generic[_T], ABC):
@abstractmethod
def from_json(cls, val: str | Path | _T, /) -> Self:
"""
Restore state from a previous `Closable.to_json` export.
Restore state from a previous :meth:`Closable.to_json` export.
If given a str or Path, it must point to a json file from `Serializable.to_json`.
If given a str or Path, it must point to a json file from :meth:`Serializable.to_json`.
Otherwise, it should be the Mapping itself.
See `Serializable.to_json` for more information.
See :meth:`Serializable.to_json` for more information.
"""
raise NotImplementedError

View File

@@ -33,7 +33,7 @@ class _HttpRequestOptions(_RequestOptions, total=False):
class HttpResponse:
"""Response of a request made by `HttpSession`."""
"""Response of a request made by :meth:`HttpSession`."""
def __init__(self, status_code: int, content: bytes) -> None:
"""Initialize the response."""
@@ -115,7 +115,7 @@ class HttpSession(Closable):
"""
Make an HTTP request.
Keyword arguments will directly be passed to `aiohttp.ClientSession.request`.
Keyword arguments will directly be passed to :meth:`aiohttp.ClientSession.request`.
"""
session = await self._get_session()