Coverage for icloudpy/exceptions.py: 96%
25 statements
« prev ^ index » next coverage.py v7.16.2, created at 2026-10-15 15:10 +0000
« prev ^ index » next coverage.py v7.16.2, created at 2026-10-15 15:10 +0000
1"""Library exceptions."""
4class ICloudPyException(Exception):
5 """Generic iCloud exception."""
8# API
9class ICloudPyAPIResponseException(ICloudPyException):
10 """iCloud response exception."""
12 def __init__(self, reason, code=None, retry=False):
13 self.reason = reason
14 self.code = code
15 message = reason or ""
16 if code:
17 message += f" ({code})"
18 if retry:
19 message += ". Retrying ..."
21 super().__init__(message)
24class ICloudPyServiceNotActivatedException(ICloudPyAPIResponseException):
25 """iCloud service not activated exception."""
28class ICloudPyLibraryUnavailableException(ICloudPyAPIResponseException):
29 """A single iCloud Photos library (CloudKit zone) is unusable.
31 Raised when Apple definitively rejects a zone-scoped query -- e.g.
32 ``400 Index has invalid data`` or ``ZONE_NOT_FOUND`` -- while the account
33 and the other libraries are fine. Subclassing ``ICloudPyAPIResponseException``
34 keeps existing handlers working; callers that want to skip one library and
35 carry on with the rest can catch this type on its own.
36 """
38 def __init__(self, reason, code=None, zone_name=None):
39 self.zone_name = zone_name
40 if zone_name:
41 reason = f"{reason} [{zone_name}]"
42 super().__init__(reason, code)
45# Login
46class ICloudPyFailedLoginException(ICloudPyException):
47 """iCloud failed login exception."""
50class ICloudPy2SARequiredException(ICloudPyException):
51 """iCloud 2SA required exception."""
53 def __init__(self, apple_id):
54 message = f"Two-step authentication required for account:{apple_id}"
55 super().__init__(message)
58class ICloudPyNoStoredPasswordAvailableException(ICloudPyException):
59 """iCloud no stored password exception."""
62# Webservice specific
63class ICloudPyNoDevicesException(ICloudPyException):
64 """iCloud no device exception."""