Habiticalib 0.1.0a0__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 +47 -37
- 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.0a0.dist-info/METADATA +0 -92
- habiticalib-0.1.0a0.dist-info/RECORD +0 -11
- {habiticalib-0.1.0a0.dist-info → habiticalib-0.1.0a2.dist-info}/WHEEL +0 -0
- {habiticalib-0.1.0a0.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.0a0"
|
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,
|
@@ -50,10 +55,7 @@ class Habitica:
|
|
50
55
|
"""Modern asynchronous Python client library for the Habitica API."""
|
51
56
|
|
52
57
|
_close_session: bool = False
|
53
|
-
_headers: dict[str, str]
|
54
|
-
_assets_cache: dict[str, IO[bytes]]
|
55
58
|
_cache_size = 32
|
56
|
-
_cache_order: list[str]
|
57
59
|
|
58
60
|
def __init__(
|
59
61
|
self,
|
@@ -66,7 +68,8 @@ class Habitica:
|
|
66
68
|
"""Initialize the Habitica API client."""
|
67
69
|
client_headers = {"X-CLIENT": get_x_client(x_client)}
|
68
70
|
user_agent = {"User-Agent": get_user_agent()}
|
69
|
-
self._headers = {}
|
71
|
+
self._headers: dict[str, str] = {}
|
72
|
+
|
70
73
|
if session:
|
71
74
|
self._session = session
|
72
75
|
if "User-Agent" not in session.headers:
|
@@ -89,7 +92,10 @@ class Habitica:
|
|
89
92
|
msg = "Both 'api_user' and 'api_key' must be provided together."
|
90
93
|
raise ValueError(msg)
|
91
94
|
|
92
|
-
self.url = URL(url if url else DEFAULT_URL)
|
95
|
+
self.url = URL(url if url else DEFAULT_URL)
|
96
|
+
|
97
|
+
self._assets_cache: dict[str, IO[bytes]] = {}
|
98
|
+
self._cache_order: list[str] = []
|
93
99
|
|
94
100
|
async def _request(self, method: str, url: URL, **kwargs) -> str:
|
95
101
|
"""Handle API request."""
|
@@ -101,15 +107,19 @@ class Habitica:
|
|
101
107
|
) as r:
|
102
108
|
if r.status == HTTPStatus.UNAUTHORIZED:
|
103
109
|
raise NotAuthorizedError(
|
104
|
-
HabiticaErrorResponse.from_json(await r.text()),
|
110
|
+
HabiticaErrorResponse.from_json(await r.text()), r.headers
|
105
111
|
)
|
106
112
|
if r.status == HTTPStatus.NOT_FOUND:
|
107
113
|
raise NotFoundError(
|
108
|
-
HabiticaErrorResponse.from_json(await r.text()),
|
114
|
+
HabiticaErrorResponse.from_json(await r.text()), r.headers
|
109
115
|
)
|
110
116
|
if r.status == HTTPStatus.BAD_REQUEST:
|
111
117
|
raise BadRequestError(
|
112
|
-
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
|
113
123
|
)
|
114
124
|
r.raise_for_status()
|
115
125
|
return await r.text()
|
@@ -168,7 +178,7 @@ class Habitica:
|
|
168
178
|
>>> response.data.apiToken
|
169
179
|
'api-token'
|
170
180
|
"""
|
171
|
-
url = self.url / "v3/user/auth/local/login"
|
181
|
+
url = self.url / "api/v3/user/auth/local/login"
|
172
182
|
data = {
|
173
183
|
"username": username,
|
174
184
|
"password": password,
|
@@ -228,7 +238,7 @@ class Habitica:
|
|
228
238
|
>>> response = await habitica.get_user(user_fields="achievements,items.mounts")
|
229
239
|
>>> response.data # Access the returned data from the response
|
230
240
|
"""
|
231
|
-
url = self.url / "v3/user"
|
241
|
+
url = self.url / "api/v3/user"
|
232
242
|
params = {}
|
233
243
|
|
234
244
|
if user_fields:
|
@@ -289,7 +299,7 @@ class Habitica:
|
|
289
299
|
|
290
300
|
>>> await habitica.get_tasks(TaskType.HABITS, due_date=datetime(2024, 10, 15))
|
291
301
|
"""
|
292
|
-
url = self.url / "v3/tasks/user"
|
302
|
+
url = self.url / "api/v3/tasks/user"
|
293
303
|
params = {}
|
294
304
|
|
295
305
|
if task_type:
|
@@ -333,7 +343,7 @@ class Habitica:
|
|
333
343
|
>>> task_response = await habitica.get_task(task_id)
|
334
344
|
>>> print(task_response.data) # Displays the retrieved task information
|
335
345
|
"""
|
336
|
-
url = self.url / "v3/tasks" / str(task_id)
|
346
|
+
url = self.url / "api/v3/tasks" / str(task_id)
|
337
347
|
|
338
348
|
return HabiticaTaskResponse.from_json(
|
339
349
|
await self._request("get", url=url),
|
@@ -372,7 +382,7 @@ class Habitica:
|
|
372
382
|
>>> create_response = await habitica.create_task(new_task)
|
373
383
|
>>> print(create_response.data) # Displays the created task information
|
374
384
|
"""
|
375
|
-
url = self.url / "v3/tasks/user"
|
385
|
+
url = self.url / "api/v3/tasks/user"
|
376
386
|
|
377
387
|
return HabiticaTaskResponse.from_json(
|
378
388
|
await self._request("post", url=url, json=task.to_dict()),
|
@@ -415,7 +425,7 @@ class Habitica:
|
|
415
425
|
>>> update_response = await habitica.update_task(task_id, updated_task)
|
416
426
|
>>> print(update_response.data) # Displays the updated task information
|
417
427
|
"""
|
418
|
-
url = self.url / "v3/tasks" / str(task_id)
|
428
|
+
url = self.url / "api/v3/tasks" / str(task_id)
|
419
429
|
|
420
430
|
return HabiticaTaskResponse.from_json(
|
421
431
|
await self._request("put", url=url, json=task.to_dict()),
|
@@ -454,7 +464,7 @@ class Habitica:
|
|
454
464
|
>>> delete_response = await habitica.delete_task(task_id)
|
455
465
|
>>> print(delete_response.success) # True if successfully deleted
|
456
466
|
"""
|
457
|
-
url = self.url / "v3/tasks" / str(task_id)
|
467
|
+
url = self.url / "api/v3/tasks" / str(task_id)
|
458
468
|
|
459
469
|
return HabiticaResponse.from_json(
|
460
470
|
await self._request("delete", url=url),
|
@@ -496,7 +506,7 @@ class Habitica:
|
|
496
506
|
>>> reorder_response = await habitica.reorder_task(task_id, 2)
|
497
507
|
>>> print(reorder_response.data) # Displays a list of task IDs in the new order
|
498
508
|
"""
|
499
|
-
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)
|
500
510
|
|
501
511
|
return HabiticaTaskOrderResponse.from_json(
|
502
512
|
await self._request("post", url=url),
|
@@ -530,7 +540,7 @@ class Habitica:
|
|
530
540
|
TimeoutError
|
531
541
|
If the connection times out.
|
532
542
|
"""
|
533
|
-
url = self.url
|
543
|
+
url = self.url / "export/userdata.json"
|
534
544
|
|
535
545
|
return HabiticaUserExport.from_json(
|
536
546
|
await self._request("get", url=url),
|
@@ -575,7 +585,7 @@ class Habitica:
|
|
575
585
|
TimeoutError
|
576
586
|
If the connection times out.
|
577
587
|
"""
|
578
|
-
url = self.url / "v3/content"
|
588
|
+
url = self.url / "api/v3/content"
|
579
589
|
params = {}
|
580
590
|
|
581
591
|
if language:
|
@@ -611,7 +621,7 @@ class Habitica:
|
|
611
621
|
TimeoutError
|
612
622
|
If the connection times out.
|
613
623
|
"""
|
614
|
-
url = self.url / "v3/cron"
|
624
|
+
url = self.url / "api/v3/cron"
|
615
625
|
return HabiticaResponse.from_json(await self._request("post", url=url))
|
616
626
|
|
617
627
|
async def allocate_single_stat_point(
|
@@ -655,7 +665,7 @@ class Habitica:
|
|
655
665
|
Allocate a single stat point to Strength (default):
|
656
666
|
>>> await habitica.allocate_single_stat_point()
|
657
667
|
"""
|
658
|
-
url = self.url / "v3/user/allocate"
|
668
|
+
url = self.url / "api/v3/user/allocate"
|
659
669
|
params = {"stat": stat}
|
660
670
|
|
661
671
|
return HabiticaStatsResponse.from_json(
|
@@ -689,7 +699,7 @@ class Habitica:
|
|
689
699
|
TimeoutError
|
690
700
|
If the connection times out.
|
691
701
|
"""
|
692
|
-
url = self.url / "v3/user/allocate-now"
|
702
|
+
url = self.url / "api/v3/user/allocate-now"
|
693
703
|
|
694
704
|
return HabiticaStatsResponse.from_json(
|
695
705
|
await self._request("post", url=url),
|
@@ -742,7 +752,7 @@ class Habitica:
|
|
742
752
|
Allocate 2 points to INT and 1 point to STR:
|
743
753
|
>>> await allocate_bulk_stat_points(int_points=2, str_points=1)
|
744
754
|
"""
|
745
|
-
url = self.url / "v3/user/allocate-bulk"
|
755
|
+
url = self.url / "api/v3/user/allocate-bulk"
|
746
756
|
json = {
|
747
757
|
"stats": {
|
748
758
|
"int": int_points,
|
@@ -781,7 +791,7 @@ class Habitica:
|
|
781
791
|
TimeoutError
|
782
792
|
If the connection times out.
|
783
793
|
"""
|
784
|
-
url = self.url / "v3/user/buy-health-potion"
|
794
|
+
url = self.url / "api/v3/user/buy-health-potion"
|
785
795
|
|
786
796
|
return HabiticaStatsResponse.from_json(
|
787
797
|
await self._request("post", url=url),
|
@@ -822,7 +832,7 @@ class Habitica:
|
|
822
832
|
TimeoutError
|
823
833
|
If the connection times out.
|
824
834
|
"""
|
825
|
-
url = self.url / "v3/class/cast" / spell
|
835
|
+
url = self.url / "api/v3/class/cast" / spell
|
826
836
|
params = {}
|
827
837
|
|
828
838
|
if target_id:
|
@@ -853,7 +863,7 @@ class Habitica:
|
|
853
863
|
TimeoutError
|
854
864
|
If the connection times out.
|
855
865
|
"""
|
856
|
-
url = self.url / "v3/user/sleep"
|
866
|
+
url = self.url / "api/v3/user/sleep"
|
857
867
|
|
858
868
|
return HabiticaResponse.from_json(await self._request("post", url=url))
|
859
869
|
|
@@ -875,7 +885,7 @@ class Habitica:
|
|
875
885
|
TimeoutError
|
876
886
|
If the connection times out.
|
877
887
|
"""
|
878
|
-
url = self.url / "v3/user/revive"
|
888
|
+
url = self.url / "api/v3/user/revive"
|
879
889
|
|
880
890
|
return HabiticaResponse.from_json(await self._request("post", url=url))
|
881
891
|
|
@@ -914,7 +924,7 @@ class Habitica:
|
|
914
924
|
>>> change_response = await habitica.change_class(new_class)
|
915
925
|
>>> print(change_response.data.stats) # Displays the user's stats after class change
|
916
926
|
"""
|
917
|
-
url = self.url / "v3/user/change-class"
|
927
|
+
url = self.url / "api/v3/user/change-class"
|
918
928
|
params = {"class": Class.value}
|
919
929
|
|
920
930
|
return HabiticaClassSystemResponse.from_json(
|
@@ -947,7 +957,7 @@ class Habitica:
|
|
947
957
|
>>> disable_response = await habitica.disable_classes()
|
948
958
|
>>> print(disable_response.data.stats) # Displays the user's stats after disabling the class system
|
949
959
|
"""
|
950
|
-
url = self.url / "v3/user/disable-classes"
|
960
|
+
url = self.url / "api/v3/user/disable-classes"
|
951
961
|
|
952
962
|
return HabiticaClassSystemResponse.from_json(
|
953
963
|
await self._request("post", url=url)
|
@@ -980,7 +990,7 @@ class Habitica:
|
|
980
990
|
>>> delete_response = await habitica.delete_completed_todos()
|
981
991
|
>>> print(delete_response.success) # True if successfully cleared completed to-dos
|
982
992
|
"""
|
983
|
-
url = self.url / "v3/tasks/clearCompletedTodos"
|
993
|
+
url = self.url / "api/v3/tasks/clearCompletedTodos"
|
984
994
|
|
985
995
|
return HabiticaClassSystemResponse.from_json(
|
986
996
|
await self._request("post", url=url)
|
@@ -1022,7 +1032,7 @@ class Habitica:
|
|
1022
1032
|
TimeoutError
|
1023
1033
|
If the connection times out.
|
1024
1034
|
"""
|
1025
|
-
url = self.url / "v3/tasks" / str(task_id) / "score" / direction.value
|
1035
|
+
url = self.url / "api/v3/tasks" / str(task_id) / "score" / direction.value
|
1026
1036
|
|
1027
1037
|
return HabiticaScoreResponse.from_json(
|
1028
1038
|
await self._request("post", url=url),
|
@@ -1055,7 +1065,7 @@ class Habitica:
|
|
1055
1065
|
>>> tags_response = await habitica.get_tags()
|
1056
1066
|
>>> print(tags_response.data)
|
1057
1067
|
"""
|
1058
|
-
url = self.url / "v3/tags"
|
1068
|
+
url = self.url / "api/v3/tags"
|
1059
1069
|
|
1060
1070
|
return HabiticaTagsResponse.from_json(
|
1061
1071
|
await self._request("post", url=url),
|
@@ -1093,7 +1103,7 @@ class Habitica:
|
|
1093
1103
|
>>> tag_response = await habitica.get_tag()
|
1094
1104
|
>>> print(tag_response.data)
|
1095
1105
|
"""
|
1096
|
-
url = self.url / "v3/tags" / str(tag_id)
|
1106
|
+
url = self.url / "api/v3/tags" / str(tag_id)
|
1097
1107
|
|
1098
1108
|
return HabiticaTagResponse.from_json(
|
1099
1109
|
await self._request("post", url=url),
|
@@ -1132,7 +1142,7 @@ class Habitica:
|
|
1132
1142
|
>>> delete_response = await habitica.delete_tag(tag_id)
|
1133
1143
|
>>> print(delete_response.success) # True if successfully deleted
|
1134
1144
|
"""
|
1135
|
-
url = self.url / "v3/tags" / str(tag_id)
|
1145
|
+
url = self.url / "api/v3/tags" / str(tag_id)
|
1136
1146
|
|
1137
1147
|
return HabiticaTagResponse.from_json(
|
1138
1148
|
await self._request("delete", url=url),
|
@@ -1171,7 +1181,7 @@ class Habitica:
|
|
1171
1181
|
>>> new_tag_response = await habitica.create_tag("New Tag Name")
|
1172
1182
|
>>> print(new_tag_response.data.id) # Displays the id of the new tag
|
1173
1183
|
"""
|
1174
|
-
url = self.url / "v3/tags"
|
1184
|
+
url = self.url / "api/v3/tags"
|
1175
1185
|
json = {"name": name}
|
1176
1186
|
return HabiticaTagResponse.from_json(
|
1177
1187
|
await self._request("post", url=url, json=json),
|
@@ -1212,7 +1222,7 @@ class Habitica:
|
|
1212
1222
|
>>> update_response = await habitica.update_tag(tag_id, "New Tag Name")
|
1213
1223
|
>>> print(update_response.data) # Displays the updated tag information
|
1214
1224
|
"""
|
1215
|
-
url = self.url / "v3/tags" / str(tag_id)
|
1225
|
+
url = self.url / "api/v3/tags" / str(tag_id)
|
1216
1226
|
json = {"name": name}
|
1217
1227
|
return HabiticaTagResponse.from_json(
|
1218
1228
|
await self._request("put", url=url, json=json),
|
@@ -1253,7 +1263,7 @@ class Habitica:
|
|
1253
1263
|
>>> reorder_response = await habitica.reorder_tag(tag_id, 2)
|
1254
1264
|
>>> print(reorder_response.success) # True if reorder is successful
|
1255
1265
|
"""
|
1256
|
-
url = self.url / "v3/reorder-tags"
|
1266
|
+
url = self.url / "api/v3/reorder-tags"
|
1257
1267
|
json = {"tagId": str(tag_id), "to": to}
|
1258
1268
|
|
1259
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.0a0
|
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=veWNJO9Y1tearAF3GXOM3PZgGxqE1Ku3vpMcuFpQWIk,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=FlQUFX1jvbznJLcd1M7xQ7YxAXuU2GAl3R4KMZwefJM,53749
|
6
|
-
habiticalib/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
7
|
-
habiticalib/types.py,sha256=r_5pCRdfZRv7whryAgVOUnqv4qUGfokgq9GqdkdK_y8,32549
|
8
|
-
habiticalib-0.1.0a0.dist-info/METADATA,sha256=7rJ5r71bY1A5mz50twmXizvs9pX5xpCvivJWqaoXIUs,2471
|
9
|
-
habiticalib-0.1.0a0.dist-info/WHEEL,sha256=1yFddiXMmvYK7QYTqtRNtX66WJ0Mz8PYEiEUoOUUxRY,87
|
10
|
-
habiticalib-0.1.0a0.dist-info/licenses/LICENSE,sha256=oIinIOSJ49l1iVIRI3XGXFWt6SF7a83kEFBAY8ORwNI,1084
|
11
|
-
habiticalib-0.1.0a0.dist-info/RECORD,,
|
File without changes
|
File without changes
|