Habiticalib 0.1.0a1__py3-none-any.whl → 0.1.0a2__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 +59 -2
- habiticalib/const.py +2 -0
- habiticalib/exceptions.py +15 -1
- habiticalib/helpers.py +3 -4
- habiticalib/lib.py +42 -33
- habiticalib/types.py +15 -5
- habiticalib-0.1.0a2.dist-info/METADATA +98 -0
- habiticalib-0.1.0a2.dist-info/RECORD +11 -0
- habiticalib-0.1.0a1.dist-info/METADATA +0 -92
- habiticalib-0.1.0a1.dist-info/RECORD +0 -11
- {habiticalib-0.1.0a1.dist-info → habiticalib-0.1.0a2.dist-info}/WHEEL +0 -0
- {habiticalib-0.1.0a1.dist-info → habiticalib-0.1.0a2.dist-info}/licenses/LICENSE +0 -0
habiticalib/__init__.py
CHANGED
@@ -1,12 +1,69 @@
|
|
1
1
|
"""Modern asynchronous Python client library for the Habitica API."""
|
2
2
|
|
3
|
-
from .
|
3
|
+
from .const import ASSETS_URL, DEFAULT_URL, __version__
|
4
|
+
from .exceptions import (
|
5
|
+
BadRequestError,
|
6
|
+
HabiticaException,
|
7
|
+
NotAuthorizedError,
|
8
|
+
NotFoundError,
|
9
|
+
)
|
4
10
|
from .lib import Habitica
|
11
|
+
from .types import (
|
12
|
+
Attributes,
|
13
|
+
Class,
|
14
|
+
Direction,
|
15
|
+
Frequency,
|
16
|
+
HabiticaClassSystemResponse,
|
17
|
+
HabiticaErrorResponse,
|
18
|
+
HabiticaLoginResponse,
|
19
|
+
HabiticaResponse,
|
20
|
+
HabiticaScoreResponse,
|
21
|
+
HabiticaStatsResponse,
|
22
|
+
HabiticaTagResponse,
|
23
|
+
HabiticaTagsResponse,
|
24
|
+
HabiticaTaskOrderResponse,
|
25
|
+
HabiticaTaskResponse,
|
26
|
+
HabiticaTasksResponse,
|
27
|
+
HabiticaUserExport,
|
28
|
+
HabiticaUserResponse,
|
29
|
+
Language,
|
30
|
+
Skill,
|
31
|
+
Task,
|
32
|
+
TaskFilter,
|
33
|
+
TaskType,
|
34
|
+
UserStyles,
|
35
|
+
)
|
5
36
|
|
6
|
-
__version__ = "0.1.0a1"
|
7
37
|
__all__ = [
|
38
|
+
"__version__",
|
39
|
+
"ASSETS_URL",
|
40
|
+
"Attributes",
|
41
|
+
"BadRequestError",
|
42
|
+
"Class",
|
43
|
+
"DEFAULT_URL",
|
44
|
+
"Direction",
|
45
|
+
"Frequency",
|
8
46
|
"Habitica",
|
47
|
+
"HabiticaClassSystemResponse",
|
48
|
+
"HabiticaErrorResponse",
|
9
49
|
"HabiticaException",
|
50
|
+
"HabiticaLoginResponse",
|
51
|
+
"HabiticaResponse",
|
52
|
+
"HabiticaScoreResponse",
|
53
|
+
"HabiticaStatsResponse",
|
54
|
+
"HabiticaTagResponse",
|
55
|
+
"HabiticaTagsResponse",
|
56
|
+
"HabiticaTaskOrderResponse",
|
57
|
+
"HabiticaTaskResponse",
|
58
|
+
"HabiticaTasksResponse",
|
59
|
+
"HabiticaUserExport",
|
60
|
+
"HabiticaUserResponse",
|
61
|
+
"Language",
|
10
62
|
"NotAuthorizedError",
|
11
63
|
"NotFoundError",
|
64
|
+
"Skill",
|
65
|
+
"Task",
|
66
|
+
"TaskFilter",
|
67
|
+
"TaskType",
|
68
|
+
"UserStyles",
|
12
69
|
]
|
habiticalib/const.py
CHANGED
habiticalib/exceptions.py
CHANGED
@@ -2,15 +2,25 @@
|
|
2
2
|
|
3
3
|
from typing import Self
|
4
4
|
|
5
|
+
from multidict import CIMultiDictProxy
|
6
|
+
|
5
7
|
from habiticalib.types import HabiticaErrorResponse
|
6
8
|
|
7
9
|
|
8
10
|
class HabiticaException(Exception): # noqa: N818
|
9
11
|
"""Base class for Habitica errors."""
|
10
12
|
|
11
|
-
def __init__(
|
13
|
+
def __init__(
|
14
|
+
self: Self,
|
15
|
+
error: HabiticaErrorResponse,
|
16
|
+
headers: CIMultiDictProxy,
|
17
|
+
) -> None:
|
12
18
|
"""Initialize the Exception."""
|
13
19
|
self.error = error
|
20
|
+
self.rate_limit = headers.get("x-ratelimit-limit")
|
21
|
+
self.rate_limit_remaining = headers.get("x-ratelimit-remaining")
|
22
|
+
self.rate_limit_reset = headers.get("x-ratelimit-reset")
|
23
|
+
self.retry_after = headers.get("retry-after")
|
14
24
|
|
15
25
|
super().__init__(error.message)
|
16
26
|
|
@@ -25,3 +35,7 @@ class NotFoundError(HabiticaException):
|
|
25
35
|
|
26
36
|
class BadRequestError(HabiticaException):
|
27
37
|
"""BadRequest error."""
|
38
|
+
|
39
|
+
|
40
|
+
class TooManyRequestsError(HabiticaException):
|
41
|
+
"""TooManyRequests error."""
|
habiticalib/helpers.py
CHANGED
@@ -1,13 +1,12 @@
|
|
1
1
|
"""Helper functions for Habiticalib."""
|
2
2
|
|
3
3
|
from dataclasses import asdict
|
4
|
-
from importlib.metadata import version
|
5
4
|
import platform
|
6
5
|
import uuid
|
7
6
|
|
8
7
|
import aiohttp
|
9
8
|
|
10
|
-
from .const import DEVELOPER_ID
|
9
|
+
from .const import DEVELOPER_ID, __version__
|
11
10
|
from .types import HabiticaUserResponse, UserData, UserStyles
|
12
11
|
|
13
12
|
|
@@ -58,7 +57,7 @@ def get_user_agent() -> str:
|
|
58
57
|
os_info = f"{os_name} {os_release} ({os_version}); {arch}"
|
59
58
|
|
60
59
|
return (
|
61
|
-
f"Habiticalib/{
|
60
|
+
f"Habiticalib/{__version__} ({os_info}) "
|
62
61
|
f"aiohttp/{aiohttp.__version__} Python/{platform.python_version()} "
|
63
62
|
" +https://github.com/tr4nt0r/habiticalib)"
|
64
63
|
)
|
@@ -106,7 +105,7 @@ def get_x_client(x_client: str | None = None) -> str:
|
|
106
105
|
|
107
106
|
return x_client
|
108
107
|
|
109
|
-
return f"{DEVELOPER_ID} - Habiticalib/{
|
108
|
+
return f"{DEVELOPER_ID} - Habiticalib/{__version__}"
|
110
109
|
|
111
110
|
|
112
111
|
def extract_user_styles(user_data: HabiticaUserResponse) -> UserStyles:
|
habiticalib/lib.py
CHANGED
@@ -13,7 +13,12 @@ from PIL import Image
|
|
13
13
|
from yarl import URL
|
14
14
|
|
15
15
|
from .const import ASSETS_URL, BACKER_ONLY_GEAR, DEFAULT_URL
|
16
|
-
from .exceptions import
|
16
|
+
from .exceptions import (
|
17
|
+
BadRequestError,
|
18
|
+
NotAuthorizedError,
|
19
|
+
NotFoundError,
|
20
|
+
TooManyRequestsError,
|
21
|
+
)
|
17
22
|
from .helpers import extract_user_styles, get_user_agent, get_x_client, join_fields
|
18
23
|
from .types import (
|
19
24
|
Attributes,
|
@@ -87,7 +92,7 @@ class Habitica:
|
|
87
92
|
msg = "Both 'api_user' and 'api_key' must be provided together."
|
88
93
|
raise ValueError(msg)
|
89
94
|
|
90
|
-
self.url = URL(url if url else DEFAULT_URL)
|
95
|
+
self.url = URL(url if url else DEFAULT_URL)
|
91
96
|
|
92
97
|
self._assets_cache: dict[str, IO[bytes]] = {}
|
93
98
|
self._cache_order: list[str] = []
|
@@ -102,15 +107,19 @@ class Habitica:
|
|
102
107
|
) as r:
|
103
108
|
if r.status == HTTPStatus.UNAUTHORIZED:
|
104
109
|
raise NotAuthorizedError(
|
105
|
-
HabiticaErrorResponse.from_json(await r.text()),
|
110
|
+
HabiticaErrorResponse.from_json(await r.text()), r.headers
|
106
111
|
)
|
107
112
|
if r.status == HTTPStatus.NOT_FOUND:
|
108
113
|
raise NotFoundError(
|
109
|
-
HabiticaErrorResponse.from_json(await r.text()),
|
114
|
+
HabiticaErrorResponse.from_json(await r.text()), r.headers
|
110
115
|
)
|
111
116
|
if r.status == HTTPStatus.BAD_REQUEST:
|
112
117
|
raise BadRequestError(
|
113
|
-
HabiticaErrorResponse.from_json(await r.text()),
|
118
|
+
HabiticaErrorResponse.from_json(await r.text()), r.headers
|
119
|
+
)
|
120
|
+
if r.status == HTTPStatus.TOO_MANY_REQUESTS:
|
121
|
+
raise TooManyRequestsError(
|
122
|
+
HabiticaErrorResponse.from_json(await r.text()), r.headers
|
114
123
|
)
|
115
124
|
r.raise_for_status()
|
116
125
|
return await r.text()
|
@@ -169,7 +178,7 @@ class Habitica:
|
|
169
178
|
>>> response.data.apiToken
|
170
179
|
'api-token'
|
171
180
|
"""
|
172
|
-
url = self.url / "v3/user/auth/local/login"
|
181
|
+
url = self.url / "api/v3/user/auth/local/login"
|
173
182
|
data = {
|
174
183
|
"username": username,
|
175
184
|
"password": password,
|
@@ -229,7 +238,7 @@ class Habitica:
|
|
229
238
|
>>> response = await habitica.get_user(user_fields="achievements,items.mounts")
|
230
239
|
>>> response.data # Access the returned data from the response
|
231
240
|
"""
|
232
|
-
url = self.url / "v3/user"
|
241
|
+
url = self.url / "api/v3/user"
|
233
242
|
params = {}
|
234
243
|
|
235
244
|
if user_fields:
|
@@ -290,7 +299,7 @@ class Habitica:
|
|
290
299
|
|
291
300
|
>>> await habitica.get_tasks(TaskType.HABITS, due_date=datetime(2024, 10, 15))
|
292
301
|
"""
|
293
|
-
url = self.url / "v3/tasks/user"
|
302
|
+
url = self.url / "api/v3/tasks/user"
|
294
303
|
params = {}
|
295
304
|
|
296
305
|
if task_type:
|
@@ -334,7 +343,7 @@ class Habitica:
|
|
334
343
|
>>> task_response = await habitica.get_task(task_id)
|
335
344
|
>>> print(task_response.data) # Displays the retrieved task information
|
336
345
|
"""
|
337
|
-
url = self.url / "v3/tasks" / str(task_id)
|
346
|
+
url = self.url / "api/v3/tasks" / str(task_id)
|
338
347
|
|
339
348
|
return HabiticaTaskResponse.from_json(
|
340
349
|
await self._request("get", url=url),
|
@@ -373,7 +382,7 @@ class Habitica:
|
|
373
382
|
>>> create_response = await habitica.create_task(new_task)
|
374
383
|
>>> print(create_response.data) # Displays the created task information
|
375
384
|
"""
|
376
|
-
url = self.url / "v3/tasks/user"
|
385
|
+
url = self.url / "api/v3/tasks/user"
|
377
386
|
|
378
387
|
return HabiticaTaskResponse.from_json(
|
379
388
|
await self._request("post", url=url, json=task.to_dict()),
|
@@ -416,7 +425,7 @@ class Habitica:
|
|
416
425
|
>>> update_response = await habitica.update_task(task_id, updated_task)
|
417
426
|
>>> print(update_response.data) # Displays the updated task information
|
418
427
|
"""
|
419
|
-
url = self.url / "v3/tasks" / str(task_id)
|
428
|
+
url = self.url / "api/v3/tasks" / str(task_id)
|
420
429
|
|
421
430
|
return HabiticaTaskResponse.from_json(
|
422
431
|
await self._request("put", url=url, json=task.to_dict()),
|
@@ -455,7 +464,7 @@ class Habitica:
|
|
455
464
|
>>> delete_response = await habitica.delete_task(task_id)
|
456
465
|
>>> print(delete_response.success) # True if successfully deleted
|
457
466
|
"""
|
458
|
-
url = self.url / "v3/tasks" / str(task_id)
|
467
|
+
url = self.url / "api/v3/tasks" / str(task_id)
|
459
468
|
|
460
469
|
return HabiticaResponse.from_json(
|
461
470
|
await self._request("delete", url=url),
|
@@ -497,7 +506,7 @@ class Habitica:
|
|
497
506
|
>>> reorder_response = await habitica.reorder_task(task_id, 2)
|
498
507
|
>>> print(reorder_response.data) # Displays a list of task IDs in the new order
|
499
508
|
"""
|
500
|
-
url = self.url / "v3/tasks" / str(task_id) / "move/to" / str(to)
|
509
|
+
url = self.url / "api/v3/tasks" / str(task_id) / "move/to" / str(to)
|
501
510
|
|
502
511
|
return HabiticaTaskOrderResponse.from_json(
|
503
512
|
await self._request("post", url=url),
|
@@ -531,7 +540,7 @@ class Habitica:
|
|
531
540
|
TimeoutError
|
532
541
|
If the connection times out.
|
533
542
|
"""
|
534
|
-
url = self.url
|
543
|
+
url = self.url / "export/userdata.json"
|
535
544
|
|
536
545
|
return HabiticaUserExport.from_json(
|
537
546
|
await self._request("get", url=url),
|
@@ -576,7 +585,7 @@ class Habitica:
|
|
576
585
|
TimeoutError
|
577
586
|
If the connection times out.
|
578
587
|
"""
|
579
|
-
url = self.url / "v3/content"
|
588
|
+
url = self.url / "api/v3/content"
|
580
589
|
params = {}
|
581
590
|
|
582
591
|
if language:
|
@@ -612,7 +621,7 @@ class Habitica:
|
|
612
621
|
TimeoutError
|
613
622
|
If the connection times out.
|
614
623
|
"""
|
615
|
-
url = self.url / "v3/cron"
|
624
|
+
url = self.url / "api/v3/cron"
|
616
625
|
return HabiticaResponse.from_json(await self._request("post", url=url))
|
617
626
|
|
618
627
|
async def allocate_single_stat_point(
|
@@ -656,7 +665,7 @@ class Habitica:
|
|
656
665
|
Allocate a single stat point to Strength (default):
|
657
666
|
>>> await habitica.allocate_single_stat_point()
|
658
667
|
"""
|
659
|
-
url = self.url / "v3/user/allocate"
|
668
|
+
url = self.url / "api/v3/user/allocate"
|
660
669
|
params = {"stat": stat}
|
661
670
|
|
662
671
|
return HabiticaStatsResponse.from_json(
|
@@ -690,7 +699,7 @@ class Habitica:
|
|
690
699
|
TimeoutError
|
691
700
|
If the connection times out.
|
692
701
|
"""
|
693
|
-
url = self.url / "v3/user/allocate-now"
|
702
|
+
url = self.url / "api/v3/user/allocate-now"
|
694
703
|
|
695
704
|
return HabiticaStatsResponse.from_json(
|
696
705
|
await self._request("post", url=url),
|
@@ -743,7 +752,7 @@ class Habitica:
|
|
743
752
|
Allocate 2 points to INT and 1 point to STR:
|
744
753
|
>>> await allocate_bulk_stat_points(int_points=2, str_points=1)
|
745
754
|
"""
|
746
|
-
url = self.url / "v3/user/allocate-bulk"
|
755
|
+
url = self.url / "api/v3/user/allocate-bulk"
|
747
756
|
json = {
|
748
757
|
"stats": {
|
749
758
|
"int": int_points,
|
@@ -782,7 +791,7 @@ class Habitica:
|
|
782
791
|
TimeoutError
|
783
792
|
If the connection times out.
|
784
793
|
"""
|
785
|
-
url = self.url / "v3/user/buy-health-potion"
|
794
|
+
url = self.url / "api/v3/user/buy-health-potion"
|
786
795
|
|
787
796
|
return HabiticaStatsResponse.from_json(
|
788
797
|
await self._request("post", url=url),
|
@@ -823,7 +832,7 @@ class Habitica:
|
|
823
832
|
TimeoutError
|
824
833
|
If the connection times out.
|
825
834
|
"""
|
826
|
-
url = self.url / "v3/class/cast" / spell
|
835
|
+
url = self.url / "api/v3/class/cast" / spell
|
827
836
|
params = {}
|
828
837
|
|
829
838
|
if target_id:
|
@@ -854,7 +863,7 @@ class Habitica:
|
|
854
863
|
TimeoutError
|
855
864
|
If the connection times out.
|
856
865
|
"""
|
857
|
-
url = self.url / "v3/user/sleep"
|
866
|
+
url = self.url / "api/v3/user/sleep"
|
858
867
|
|
859
868
|
return HabiticaResponse.from_json(await self._request("post", url=url))
|
860
869
|
|
@@ -876,7 +885,7 @@ class Habitica:
|
|
876
885
|
TimeoutError
|
877
886
|
If the connection times out.
|
878
887
|
"""
|
879
|
-
url = self.url / "v3/user/revive"
|
888
|
+
url = self.url / "api/v3/user/revive"
|
880
889
|
|
881
890
|
return HabiticaResponse.from_json(await self._request("post", url=url))
|
882
891
|
|
@@ -915,7 +924,7 @@ class Habitica:
|
|
915
924
|
>>> change_response = await habitica.change_class(new_class)
|
916
925
|
>>> print(change_response.data.stats) # Displays the user's stats after class change
|
917
926
|
"""
|
918
|
-
url = self.url / "v3/user/change-class"
|
927
|
+
url = self.url / "api/v3/user/change-class"
|
919
928
|
params = {"class": Class.value}
|
920
929
|
|
921
930
|
return HabiticaClassSystemResponse.from_json(
|
@@ -948,7 +957,7 @@ class Habitica:
|
|
948
957
|
>>> disable_response = await habitica.disable_classes()
|
949
958
|
>>> print(disable_response.data.stats) # Displays the user's stats after disabling the class system
|
950
959
|
"""
|
951
|
-
url = self.url / "v3/user/disable-classes"
|
960
|
+
url = self.url / "api/v3/user/disable-classes"
|
952
961
|
|
953
962
|
return HabiticaClassSystemResponse.from_json(
|
954
963
|
await self._request("post", url=url)
|
@@ -981,7 +990,7 @@ class Habitica:
|
|
981
990
|
>>> delete_response = await habitica.delete_completed_todos()
|
982
991
|
>>> print(delete_response.success) # True if successfully cleared completed to-dos
|
983
992
|
"""
|
984
|
-
url = self.url / "v3/tasks/clearCompletedTodos"
|
993
|
+
url = self.url / "api/v3/tasks/clearCompletedTodos"
|
985
994
|
|
986
995
|
return HabiticaClassSystemResponse.from_json(
|
987
996
|
await self._request("post", url=url)
|
@@ -1023,7 +1032,7 @@ class Habitica:
|
|
1023
1032
|
TimeoutError
|
1024
1033
|
If the connection times out.
|
1025
1034
|
"""
|
1026
|
-
url = self.url / "v3/tasks" / str(task_id) / "score" / direction.value
|
1035
|
+
url = self.url / "api/v3/tasks" / str(task_id) / "score" / direction.value
|
1027
1036
|
|
1028
1037
|
return HabiticaScoreResponse.from_json(
|
1029
1038
|
await self._request("post", url=url),
|
@@ -1056,7 +1065,7 @@ class Habitica:
|
|
1056
1065
|
>>> tags_response = await habitica.get_tags()
|
1057
1066
|
>>> print(tags_response.data)
|
1058
1067
|
"""
|
1059
|
-
url = self.url / "v3/tags"
|
1068
|
+
url = self.url / "api/v3/tags"
|
1060
1069
|
|
1061
1070
|
return HabiticaTagsResponse.from_json(
|
1062
1071
|
await self._request("post", url=url),
|
@@ -1094,7 +1103,7 @@ class Habitica:
|
|
1094
1103
|
>>> tag_response = await habitica.get_tag()
|
1095
1104
|
>>> print(tag_response.data)
|
1096
1105
|
"""
|
1097
|
-
url = self.url / "v3/tags" / str(tag_id)
|
1106
|
+
url = self.url / "api/v3/tags" / str(tag_id)
|
1098
1107
|
|
1099
1108
|
return HabiticaTagResponse.from_json(
|
1100
1109
|
await self._request("post", url=url),
|
@@ -1133,7 +1142,7 @@ class Habitica:
|
|
1133
1142
|
>>> delete_response = await habitica.delete_tag(tag_id)
|
1134
1143
|
>>> print(delete_response.success) # True if successfully deleted
|
1135
1144
|
"""
|
1136
|
-
url = self.url / "v3/tags" / str(tag_id)
|
1145
|
+
url = self.url / "api/v3/tags" / str(tag_id)
|
1137
1146
|
|
1138
1147
|
return HabiticaTagResponse.from_json(
|
1139
1148
|
await self._request("delete", url=url),
|
@@ -1172,7 +1181,7 @@ class Habitica:
|
|
1172
1181
|
>>> new_tag_response = await habitica.create_tag("New Tag Name")
|
1173
1182
|
>>> print(new_tag_response.data.id) # Displays the id of the new tag
|
1174
1183
|
"""
|
1175
|
-
url = self.url / "v3/tags"
|
1184
|
+
url = self.url / "api/v3/tags"
|
1176
1185
|
json = {"name": name}
|
1177
1186
|
return HabiticaTagResponse.from_json(
|
1178
1187
|
await self._request("post", url=url, json=json),
|
@@ -1213,7 +1222,7 @@ class Habitica:
|
|
1213
1222
|
>>> update_response = await habitica.update_tag(tag_id, "New Tag Name")
|
1214
1223
|
>>> print(update_response.data) # Displays the updated tag information
|
1215
1224
|
"""
|
1216
|
-
url = self.url / "v3/tags" / str(tag_id)
|
1225
|
+
url = self.url / "api/v3/tags" / str(tag_id)
|
1217
1226
|
json = {"name": name}
|
1218
1227
|
return HabiticaTagResponse.from_json(
|
1219
1228
|
await self._request("put", url=url, json=json),
|
@@ -1254,7 +1263,7 @@ class Habitica:
|
|
1254
1263
|
>>> reorder_response = await habitica.reorder_tag(tag_id, 2)
|
1255
1264
|
>>> print(reorder_response.success) # True if reorder is successful
|
1256
1265
|
"""
|
1257
|
-
url = self.url / "v3/reorder-tags"
|
1266
|
+
url = self.url / "api/v3/reorder-tags"
|
1258
1267
|
json = {"tagId": str(tag_id), "to": to}
|
1259
1268
|
|
1260
1269
|
return HabiticaTagResponse.from_json(
|
habiticalib/types.py
CHANGED
@@ -5,7 +5,7 @@ from __future__ import annotations
|
|
5
5
|
|
6
6
|
from dataclasses import dataclass, field
|
7
7
|
from datetime import UTC, datetime
|
8
|
-
from enum import StrEnum
|
8
|
+
from enum import Enum, StrEnum
|
9
9
|
from typing import Any
|
10
10
|
from uuid import UUID # noqa: TCH003
|
11
11
|
|
@@ -17,13 +17,14 @@ from mashumaro.mixins.orjson import DataClassORJSONMixin
|
|
17
17
|
def serialize_datetime(date: str | int | None) -> datetime | None:
|
18
18
|
"""Convert an iso date to a datetime.date object."""
|
19
19
|
if isinstance(date, int):
|
20
|
-
datetime.fromtimestamp(date / 1000, tz=UTC)
|
20
|
+
return datetime.fromtimestamp(date / 1000, tz=UTC)
|
21
21
|
if isinstance(date, str):
|
22
22
|
try:
|
23
23
|
return datetime.fromisoformat(date)
|
24
24
|
except ValueError:
|
25
25
|
# sometimes nextDue dates are JavaScript datetime strings
|
26
26
|
# instead of iso: "Mon May 06 2024 00:00:00 GMT+0200"
|
27
|
+
# This was fixed in Habitica v5.28.9, nextDue dates are now isoformat
|
27
28
|
try:
|
28
29
|
return datetime.strptime(date, "%a %b %d %Y %H:%M:%S %Z%z")
|
29
30
|
except ValueError:
|
@@ -865,10 +866,10 @@ class Task(DataClassORJSONMixin):
|
|
865
866
|
tags: list[UUID] | None = None
|
866
867
|
collapseChecklist: bool | None = None
|
867
868
|
date: datetime | None = None
|
868
|
-
priority:
|
869
|
+
priority: TaskPriority | None = None
|
869
870
|
reminders: list[Reminders] | None = None
|
870
871
|
checklist: list[str] | None = None
|
871
|
-
|
872
|
+
Type: TaskType | None = field(default=None, metadata=field_options(alias="type"))
|
872
873
|
up: bool | None = None
|
873
874
|
down: bool | None = None
|
874
875
|
counterUp: int | None = None
|
@@ -894,7 +895,7 @@ class TaskData:
|
|
894
895
|
notes: str | None = None
|
895
896
|
tags: list[UUID] | None = None
|
896
897
|
value: float | None = None
|
897
|
-
priority:
|
898
|
+
priority: TaskPriority | None = None
|
898
899
|
attribute: Attributes | None = None
|
899
900
|
byHabitica: bool | None = None
|
900
901
|
createdAt: datetime | None = None
|
@@ -1200,3 +1201,12 @@ class Direction(StrEnum):
|
|
1200
1201
|
|
1201
1202
|
UP = "up"
|
1202
1203
|
DOWN = "down"
|
1204
|
+
|
1205
|
+
|
1206
|
+
class TaskPriority(Enum):
|
1207
|
+
"""Task difficulties."""
|
1208
|
+
|
1209
|
+
TRIVIAL = 0.1
|
1210
|
+
EASY = 1
|
1211
|
+
MEDIUM = 1.5
|
1212
|
+
HARD = 2
|
@@ -0,0 +1,98 @@
|
|
1
|
+
Metadata-Version: 2.3
|
2
|
+
Name: Habiticalib
|
3
|
+
Version: 0.1.0a2
|
4
|
+
Summary: Asynchronous Python client library for the Habitica API
|
5
|
+
Project-URL: Documentation, https://tr4nt0r.github.io/habiticalib/
|
6
|
+
Project-URL: Source, https://github.com/tr4nt0r/habiticalib
|
7
|
+
Author-email: Manfred Dennerlein Rodelo <manfred@dennerlein.name>
|
8
|
+
License: MIT License
|
9
|
+
License-File: LICENSE
|
10
|
+
Classifier: License :: OSI Approved :: MIT License
|
11
|
+
Classifier: Operating System :: OS Independent
|
12
|
+
Classifier: Programming Language :: Python :: 3 :: Only
|
13
|
+
Requires-Python: >=3.12
|
14
|
+
Requires-Dist: aiohttp~=3.9
|
15
|
+
Requires-Dist: mashumaro~=3.13
|
16
|
+
Requires-Dist: orjson~=3.10
|
17
|
+
Requires-Dist: pillow~=10.4
|
18
|
+
Description-Content-Type: text/markdown
|
19
|
+
|
20
|
+
# Habiticalib
|
21
|
+
|
22
|
+
<p align="center">
|
23
|
+
<em>Modern asynchronous Python client library for the Habitica API</em>
|
24
|
+
</p>
|
25
|
+
|
26
|
+
[](https://github.com/tr4nt0r/habiticalib/actions)
|
27
|
+
[](https://codecov.io/gh/tr4nt0r/habiticalib)
|
28
|
+
[](https://badge.fury.io/py/habiticalib)
|
29
|
+
|
30
|
+
**Habiticalib** is a Python library for interacting with the [Habitica API](https://habitica.com). It provides an organized, typed interface to work with Habitica’s features, including tasks, user data, and avatars. The goal of this library is to simplify integration with Habitica.
|
31
|
+
|
32
|
+
## Key features
|
33
|
+
|
34
|
+
- **Asynchronous**: The library is fully asynchronous, allowing non-blocking API calls.
|
35
|
+
- **Fully typed with Dataclasses**: The library is fully typed using Python `dataclasses`. It handles serialization with `mashumaro` and `orjson` for efficient conversion between Habitica API JSON data and Python objects.
|
36
|
+
- **Dynamic avatar image generation**: Habiticalib can fetch all necessary assets (like equipped items, pets, and mounts) and combine them into a single avatar image. This image can be saved to disk or returned as a byte buffer for further processing.
|
37
|
+
**Fetch user data**: Retrieve and manage user data such as stats, preferences, and items. User data is structured with dataclasses to make it easy to work with.
|
38
|
+
- **Task management**: Support for creating, updating, and retrieving Habitica tasks (to-dos, dailies, habits, rewards) is provided.
|
39
|
+
- **Task status updates**: The library allows updates for task statuses, habit scoring, and daily completion.
|
40
|
+
- **Tags**: Habiticalib supports the creation, updating and deletion of tags.
|
41
|
+
- **Stat allocation, class cystem and sleep**: The library offers methods for stat point allocation and switching between Habitica classes. It also provides the ability to disable the class system and pausing damage(resting in the inn)
|
42
|
+
|
43
|
+
## Installation
|
44
|
+
|
45
|
+
```bash
|
46
|
+
pip install habiticalib
|
47
|
+
```
|
48
|
+
|
49
|
+
## Getting started
|
50
|
+
Here’s an example to demonstrate basic usage:
|
51
|
+
|
52
|
+
```python
|
53
|
+
import asyncio
|
54
|
+
|
55
|
+
from aiohttp import ClientSession
|
56
|
+
|
57
|
+
from habiticalib import Habitica, TaskType
|
58
|
+
|
59
|
+
|
60
|
+
async def main():
|
61
|
+
async with ClientSession() as session:
|
62
|
+
habitica = Habitica(session)
|
63
|
+
|
64
|
+
# Login to Habitica
|
65
|
+
habitica.login(username="your_username", password="your_password")
|
66
|
+
|
67
|
+
# Fetch user data
|
68
|
+
user_data = await habitica.user()
|
69
|
+
print(f"Your current health: {user_data.stats.hp}")
|
70
|
+
|
71
|
+
# Fetch all tasks (to-dos, dailies, habits, and rewards)
|
72
|
+
tasks = await habitica.get_tasks()
|
73
|
+
print("All tasks:")
|
74
|
+
for task in tasks:
|
75
|
+
print(f"- {task.text} (type: {task.type})")
|
76
|
+
|
77
|
+
# Fetch only to-dos
|
78
|
+
todos = await habitica.get_tasks(task_type=TaskType.TODO)
|
79
|
+
print("\nTo-Do tasks:")
|
80
|
+
for todo in todos:
|
81
|
+
print(f"- {todo.text} (due: {todo.date})")
|
82
|
+
|
83
|
+
# Fetch only dailies
|
84
|
+
dailies = await habitica.tasks(task_type=TaskType.DAILY)
|
85
|
+
print("\nDailies:")
|
86
|
+
for daily in dailies:
|
87
|
+
print(f"- {daily.text}")
|
88
|
+
|
89
|
+
asyncio.run(main())
|
90
|
+
```
|
91
|
+
|
92
|
+
## Documentation
|
93
|
+
|
94
|
+
For full documentation and detailed usage examples, please visit the [Habiticalib documentation](https://tr4nt0r.github.io/habiticalib/).
|
95
|
+
|
96
|
+
## License
|
97
|
+
|
98
|
+
This project is licensed under the terms of the MIT license.
|
@@ -0,0 +1,11 @@
|
|
1
|
+
habiticalib/__init__.py,sha256=_RUFLOZSqQWr_j3TnhHhtD5szaf59HR-sS7aOpE4NTg,1491
|
2
|
+
habiticalib/const.py,sha256=NsbZeJ3Z_OuZcGzFZESInj9vpyYzjjCpJnVhGmu30vw,609
|
3
|
+
habiticalib/exceptions.py,sha256=Db7lDDdT97FsK4S9N45gcusiMMWiqeIcab0H8i7xTtE,1032
|
4
|
+
habiticalib/helpers.py,sha256=Y7lAlufK2isnNp7ybcqcWLG9xkWltouCiXaBeLOkobg,3479
|
5
|
+
habiticalib/lib.py,sha256=F_tqIULUC8mhYXLak2RYGA_AeaFuAQY6Ie8NImslv_g,54130
|
6
|
+
habiticalib/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
7
|
+
habiticalib/types.py,sha256=zF9HzSXkuUYwuUv9F8fXfg6sxWy0nlfUo9hFqQG8eGA,32825
|
8
|
+
habiticalib-0.1.0a2.dist-info/METADATA,sha256=3hI8OP0ECfHdmYPaZ9zGyX0Nx04kRly2635ll4yfrYY,4178
|
9
|
+
habiticalib-0.1.0a2.dist-info/WHEEL,sha256=1yFddiXMmvYK7QYTqtRNtX66WJ0Mz8PYEiEUoOUUxRY,87
|
10
|
+
habiticalib-0.1.0a2.dist-info/licenses/LICENSE,sha256=oIinIOSJ49l1iVIRI3XGXFWt6SF7a83kEFBAY8ORwNI,1084
|
11
|
+
habiticalib-0.1.0a2.dist-info/RECORD,,
|
@@ -1,92 +0,0 @@
|
|
1
|
-
Metadata-Version: 2.3
|
2
|
-
Name: Habiticalib
|
3
|
-
Version: 0.1.0a1
|
4
|
-
Summary: Asynchronous Python client library for the Habitica API
|
5
|
-
Project-URL: Documentation, https://tr4nt0r.github.io/habiticalib/
|
6
|
-
Project-URL: Source, https://github.com/tr4nt0r/habiticalib
|
7
|
-
Author-email: Manfred Dennerlein Rodelo <manfred@dennerlein.name>
|
8
|
-
License: MIT License
|
9
|
-
License-File: LICENSE
|
10
|
-
Classifier: License :: OSI Approved :: MIT License
|
11
|
-
Classifier: Operating System :: OS Independent
|
12
|
-
Classifier: Programming Language :: Python :: 3 :: Only
|
13
|
-
Requires-Python: >=3.12
|
14
|
-
Requires-Dist: aiohttp~=3.9
|
15
|
-
Requires-Dist: mashumaro~=3.13
|
16
|
-
Requires-Dist: orjson~=3.10
|
17
|
-
Requires-Dist: pillow~=10.4
|
18
|
-
Description-Content-Type: text/markdown
|
19
|
-
|
20
|
-
# Habiticalib
|
21
|
-
|
22
|
-
<p align="center">
|
23
|
-
<em>Modern asynchronous Python client library for the Habitica API</em>
|
24
|
-
</p>
|
25
|
-
|
26
|
-
[](https://github.com/tr4nt0r/habiticalib/actions)
|
27
|
-
[](https://codecov.io/gh/tr4nt0r/habiticalib)
|
28
|
-
[](https://badge.fury.io/py/habiticalib)
|
29
|
-
|
30
|
-
---
|
31
|
-
|
32
|
-
**Documentation**: <a href="https://tr4nt0r.github.io/habiticalib/" target="_blank">https://tr4nt0r.github.io/habiticalib/</a>
|
33
|
-
|
34
|
-
**Source Code**: <a href="https://github.com/tr4nt0r/habiticalib" target="_blank">https://github.com/tr4nt0r/habiticalib</a>
|
35
|
-
|
36
|
-
---
|
37
|
-
|
38
|
-
## Development
|
39
|
-
|
40
|
-
### Setup environment
|
41
|
-
|
42
|
-
We use [Hatch](https://hatch.pypa.io/latest/install/) to manage the development environment and production build. Ensure it's installed on your system.
|
43
|
-
|
44
|
-
### Run unit tests
|
45
|
-
|
46
|
-
You can run all the tests with:
|
47
|
-
|
48
|
-
```bash
|
49
|
-
hatch run test
|
50
|
-
```
|
51
|
-
|
52
|
-
### Format the code
|
53
|
-
|
54
|
-
Execute the following command to apply linting and check typing:
|
55
|
-
|
56
|
-
```bash
|
57
|
-
hatch run lint
|
58
|
-
```
|
59
|
-
|
60
|
-
### Publish a new version
|
61
|
-
|
62
|
-
You can bump the version, create a commit and associated tag with one command:
|
63
|
-
|
64
|
-
```bash
|
65
|
-
hatch version patch
|
66
|
-
```
|
67
|
-
|
68
|
-
```bash
|
69
|
-
hatch version minor
|
70
|
-
```
|
71
|
-
|
72
|
-
```bash
|
73
|
-
hatch version major
|
74
|
-
```
|
75
|
-
|
76
|
-
Your default Git text editor will open so you can add information about the release.
|
77
|
-
|
78
|
-
When you push the tag on GitHub, the workflow will automatically publish it on PyPi and a GitHub release will be created as draft.
|
79
|
-
|
80
|
-
## Serve the documentation
|
81
|
-
|
82
|
-
You can serve the Mkdocs documentation with:
|
83
|
-
|
84
|
-
```bash
|
85
|
-
hatch run docs-serve
|
86
|
-
```
|
87
|
-
|
88
|
-
It'll automatically watch for changes in your code.
|
89
|
-
|
90
|
-
## License
|
91
|
-
|
92
|
-
This project is licensed under the terms of the MIT license.
|
@@ -1,11 +0,0 @@
|
|
1
|
-
habiticalib/__init__.py,sha256=k4L3Ik4KZ7U_mtIseyqGHG0TdBE7iwxgQfazr2zli5U,301
|
2
|
-
habiticalib/const.py,sha256=HeIl1dPAeAxt1V-9PkPCt60ThAJJWkUKpCzMEEAR-ik,584
|
3
|
-
habiticalib/exceptions.py,sha256=V7QAPQM4HbGxq7-BYDSdG9Zi2u9F2w3tX8XwualJbWM,601
|
4
|
-
habiticalib/helpers.py,sha256=1PEq8tjOgotMnGRUcRcFcLCEa7jFWUORD9ZPHEVH2sU,3527
|
5
|
-
habiticalib/lib.py,sha256=S0wLsSCSSoEtq-nlx9Wy7TsqI20iLBYUZhrDOkq6Z3o,53766
|
6
|
-
habiticalib/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
7
|
-
habiticalib/types.py,sha256=r_5pCRdfZRv7whryAgVOUnqv4qUGfokgq9GqdkdK_y8,32549
|
8
|
-
habiticalib-0.1.0a1.dist-info/METADATA,sha256=t7hoV7_9JMYFVUqZgjLN9qh3RFuz7CFaPPL24zB0TlY,2471
|
9
|
-
habiticalib-0.1.0a1.dist-info/WHEEL,sha256=1yFddiXMmvYK7QYTqtRNtX66WJ0Mz8PYEiEUoOUUxRY,87
|
10
|
-
habiticalib-0.1.0a1.dist-info/licenses/LICENSE,sha256=oIinIOSJ49l1iVIRI3XGXFWt6SF7a83kEFBAY8ORwNI,1084
|
11
|
-
habiticalib-0.1.0a1.dist-info/RECORD,,
|
File without changes
|
File without changes
|