Habiticalib 0.1.0a2__py3-none-any.whl → 0.2.0__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- habiticalib/__init__.py +34 -2
- habiticalib/const.py +3 -1
- habiticalib/exceptions.py +13 -4
- habiticalib/helpers.py +25 -1
- habiticalib/lib.py +508 -25
- habiticalib/types.py +488 -66
- {habiticalib-0.1.0a2.dist-info → habiticalib-0.2.0.dist-info}/METADATA +3 -3
- habiticalib-0.2.0.dist-info/RECORD +11 -0
- {habiticalib-0.1.0a2.dist-info → habiticalib-0.2.0.dist-info}/WHEEL +1 -1
- habiticalib-0.1.0a2.dist-info/RECORD +0 -11
- {habiticalib-0.1.0a2.dist-info → habiticalib-0.2.0.dist-info}/licenses/LICENSE +0 -0
habiticalib/__init__.py
CHANGED
@@ -6,18 +6,26 @@ from .exceptions import (
|
|
6
6
|
HabiticaException,
|
7
7
|
NotAuthorizedError,
|
8
8
|
NotFoundError,
|
9
|
+
TooManyRequestsError,
|
9
10
|
)
|
11
|
+
from .helpers import deserialize_task
|
10
12
|
from .lib import Habitica
|
11
13
|
from .types import (
|
12
14
|
Attributes,
|
13
|
-
|
15
|
+
ChangeClassData,
|
16
|
+
ContentData,
|
14
17
|
Direction,
|
15
18
|
Frequency,
|
19
|
+
HabiticaClass,
|
16
20
|
HabiticaClassSystemResponse,
|
21
|
+
HabiticaContentResponse,
|
17
22
|
HabiticaErrorResponse,
|
23
|
+
HabiticaGroupMembersResponse,
|
18
24
|
HabiticaLoginResponse,
|
25
|
+
HabiticaQuestResponse,
|
19
26
|
HabiticaResponse,
|
20
27
|
HabiticaScoreResponse,
|
28
|
+
HabiticaSleepResponse,
|
21
29
|
HabiticaStatsResponse,
|
22
30
|
HabiticaTagResponse,
|
23
31
|
HabiticaTagsResponse,
|
@@ -27,10 +35,18 @@ from .types import (
|
|
27
35
|
HabiticaUserExport,
|
28
36
|
HabiticaUserResponse,
|
29
37
|
Language,
|
38
|
+
LoginData,
|
39
|
+
QuestData,
|
40
|
+
ScoreData,
|
30
41
|
Skill,
|
42
|
+
StatsUser,
|
43
|
+
TagsUser,
|
31
44
|
Task,
|
45
|
+
TaskData,
|
32
46
|
TaskFilter,
|
47
|
+
TaskPriority,
|
33
48
|
TaskType,
|
49
|
+
UserData,
|
34
50
|
UserStyles,
|
35
51
|
)
|
36
52
|
|
@@ -39,17 +55,24 @@ __all__ = [
|
|
39
55
|
"ASSETS_URL",
|
40
56
|
"Attributes",
|
41
57
|
"BadRequestError",
|
42
|
-
"
|
58
|
+
"ChangeClassData",
|
59
|
+
"ContentData",
|
43
60
|
"DEFAULT_URL",
|
61
|
+
"deserialize_task",
|
44
62
|
"Direction",
|
45
63
|
"Frequency",
|
46
64
|
"Habitica",
|
65
|
+
"HabiticaClass",
|
47
66
|
"HabiticaClassSystemResponse",
|
67
|
+
"HabiticaContentResponse",
|
48
68
|
"HabiticaErrorResponse",
|
49
69
|
"HabiticaException",
|
70
|
+
"HabiticaGroupMembersResponse",
|
50
71
|
"HabiticaLoginResponse",
|
72
|
+
"HabiticaQuestResponse",
|
51
73
|
"HabiticaResponse",
|
52
74
|
"HabiticaScoreResponse",
|
75
|
+
"HabiticaSleepResponse",
|
53
76
|
"HabiticaStatsResponse",
|
54
77
|
"HabiticaTagResponse",
|
55
78
|
"HabiticaTagsResponse",
|
@@ -59,11 +82,20 @@ __all__ = [
|
|
59
82
|
"HabiticaUserExport",
|
60
83
|
"HabiticaUserResponse",
|
61
84
|
"Language",
|
85
|
+
"LoginData",
|
62
86
|
"NotAuthorizedError",
|
63
87
|
"NotFoundError",
|
88
|
+
"QuestData",
|
89
|
+
"ScoreData",
|
64
90
|
"Skill",
|
91
|
+
"StatsUser",
|
92
|
+
"TagsUser",
|
65
93
|
"Task",
|
94
|
+
"TaskData",
|
66
95
|
"TaskFilter",
|
96
|
+
"TaskPriority",
|
67
97
|
"TaskType",
|
98
|
+
"TooManyRequestsError",
|
99
|
+
"UserData",
|
68
100
|
"UserStyles",
|
69
101
|
]
|
habiticalib/const.py
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
"""Constants for Habiticalib."""
|
2
2
|
|
3
|
-
__version__ = "0.
|
3
|
+
__version__ = "0.2.0"
|
4
4
|
|
5
5
|
DEFAULT_URL = "https://habitica.com/"
|
6
6
|
ASSETS_URL = "https://habitica-assets.s3.amazonaws.com/mobileApp/images/"
|
@@ -14,3 +14,5 @@ BACKER_ONLY_GEAR = {
|
|
14
14
|
"shield_special_ks2019": "BackerOnly-Equip-MythicGryphonShield.gif",
|
15
15
|
"weapon_special_ks2019": "BackerOnly-Equip-MythicGryphonGlaive.gif",
|
16
16
|
}
|
17
|
+
|
18
|
+
PAGE_LIMIT = 60
|
habiticalib/exceptions.py
CHANGED
@@ -1,5 +1,6 @@
|
|
1
1
|
"""Exceptions for Habiticalib."""
|
2
2
|
|
3
|
+
from datetime import datetime
|
3
4
|
from typing import Self
|
4
5
|
|
5
6
|
from multidict import CIMultiDictProxy
|
@@ -17,10 +18,18 @@ class HabiticaException(Exception): # noqa: N818
|
|
17
18
|
) -> None:
|
18
19
|
"""Initialize the Exception."""
|
19
20
|
self.error = error
|
20
|
-
self.rate_limit =
|
21
|
-
|
22
|
-
|
23
|
-
self.
|
21
|
+
self.rate_limit: int | None = (
|
22
|
+
int(r) if (r := headers.get("x-ratelimit-limit")) else None
|
23
|
+
)
|
24
|
+
self.rate_limit_remaining: int | None = (
|
25
|
+
int(r) if (r := headers.get("x-ratelimit-remaining")) else None
|
26
|
+
)
|
27
|
+
self.rate_limit_reset: datetime | None = (
|
28
|
+
datetime.strptime(r[:33], "%a %b %d %Y %H:%M:%S %Z%z")
|
29
|
+
if (r := headers.get("x-ratelimit-reset"))
|
30
|
+
else None
|
31
|
+
)
|
32
|
+
self.retry_after: int = round(float(headers.get("retry-after", 0)))
|
24
33
|
|
25
34
|
super().__init__(error.message)
|
26
35
|
|
habiticalib/helpers.py
CHANGED
@@ -1,7 +1,10 @@
|
|
1
1
|
"""Helper functions for Habiticalib."""
|
2
2
|
|
3
|
-
from dataclasses import asdict
|
3
|
+
from dataclasses import asdict, is_dataclass
|
4
|
+
from datetime import date, datetime
|
5
|
+
from enum import Enum
|
4
6
|
import platform
|
7
|
+
from typing import Any
|
5
8
|
import uuid
|
6
9
|
|
7
10
|
import aiohttp
|
@@ -112,3 +115,24 @@ def extract_user_styles(user_data: HabiticaUserResponse) -> UserStyles:
|
|
112
115
|
"""Extract user styles from a user data object."""
|
113
116
|
data: UserData = user_data.data
|
114
117
|
return UserStyles.from_dict(asdict(data))
|
118
|
+
|
119
|
+
|
120
|
+
def deserialize_task(value: Any) -> Any: # noqa: PLR0911
|
121
|
+
"""Recursively convert Enums to values, dates to ISO strings, UUIDs to strings."""
|
122
|
+
|
123
|
+
if is_dataclass(value) and not isinstance(value, type):
|
124
|
+
# Convert dataclass to dict and recursively deserialize
|
125
|
+
return deserialize_task(asdict(value))
|
126
|
+
if isinstance(value, Enum):
|
127
|
+
return value.value # Convert Enum to its value
|
128
|
+
if isinstance(value, uuid.UUID):
|
129
|
+
return str(value) # Convert UUID to string
|
130
|
+
if isinstance(value, datetime | date):
|
131
|
+
return value.isoformat() # Convert datetime/date to ISO string
|
132
|
+
if isinstance(value, list):
|
133
|
+
# Recursively apply deserialization to each item in the list
|
134
|
+
return [deserialize_task(item) for item in value]
|
135
|
+
if isinstance(value, dict):
|
136
|
+
# Recursively apply deserialization to each key-value pair in the dictionary
|
137
|
+
return {k: deserialize_task(v) for k, v in value.items()}
|
138
|
+
return value # Return other types unchanged
|