Habiticalib 0.1.0a1__py3-none-any.whl → 0.1.0a3__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 +61 -2
- habiticalib/const.py +2 -0
- habiticalib/exceptions.py +24 -1
- habiticalib/helpers.py +28 -5
- habiticalib/lib.py +65 -46
- habiticalib/types.py +89 -67
- habiticalib-0.1.0a3.dist-info/METADATA +97 -0
- habiticalib-0.1.0a3.dist-info/RECORD +11 -0
- {habiticalib-0.1.0a1.dist-info → habiticalib-0.1.0a3.dist-info}/WHEEL +1 -1
- 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.0a3.dist-info}/licenses/LICENSE +0 -0
habiticalib/__init__.py
CHANGED
@@ -1,12 +1,71 @@
|
|
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
|
+
TooManyRequestsError,
|
10
|
+
)
|
4
11
|
from .lib import Habitica
|
12
|
+
from .types import (
|
13
|
+
Attributes,
|
14
|
+
Direction,
|
15
|
+
Frequency,
|
16
|
+
HabiticaClass,
|
17
|
+
HabiticaClassSystemResponse,
|
18
|
+
HabiticaErrorResponse,
|
19
|
+
HabiticaLoginResponse,
|
20
|
+
HabiticaResponse,
|
21
|
+
HabiticaScoreResponse,
|
22
|
+
HabiticaStatsResponse,
|
23
|
+
HabiticaTagResponse,
|
24
|
+
HabiticaTagsResponse,
|
25
|
+
HabiticaTaskOrderResponse,
|
26
|
+
HabiticaTaskResponse,
|
27
|
+
HabiticaTasksResponse,
|
28
|
+
HabiticaUserExport,
|
29
|
+
HabiticaUserResponse,
|
30
|
+
Language,
|
31
|
+
Skill,
|
32
|
+
Task,
|
33
|
+
TaskFilter,
|
34
|
+
TaskType,
|
35
|
+
UserStyles,
|
36
|
+
)
|
5
37
|
|
6
|
-
__version__ = "0.1.0a1"
|
7
38
|
__all__ = [
|
39
|
+
"__version__",
|
40
|
+
"ASSETS_URL",
|
41
|
+
"Attributes",
|
42
|
+
"BadRequestError",
|
43
|
+
"DEFAULT_URL",
|
44
|
+
"Direction",
|
45
|
+
"Frequency",
|
8
46
|
"Habitica",
|
47
|
+
"HabiticaClass",
|
48
|
+
"HabiticaClassSystemResponse",
|
49
|
+
"HabiticaErrorResponse",
|
9
50
|
"HabiticaException",
|
51
|
+
"HabiticaLoginResponse",
|
52
|
+
"HabiticaResponse",
|
53
|
+
"HabiticaScoreResponse",
|
54
|
+
"HabiticaStatsResponse",
|
55
|
+
"HabiticaTagResponse",
|
56
|
+
"HabiticaTagsResponse",
|
57
|
+
"HabiticaTaskOrderResponse",
|
58
|
+
"HabiticaTaskResponse",
|
59
|
+
"HabiticaTasksResponse",
|
60
|
+
"HabiticaUserExport",
|
61
|
+
"HabiticaUserResponse",
|
62
|
+
"Language",
|
10
63
|
"NotAuthorizedError",
|
11
64
|
"NotFoundError",
|
65
|
+
"Skill",
|
66
|
+
"Task",
|
67
|
+
"TaskFilter",
|
68
|
+
"TaskType",
|
69
|
+
"TooManyRequestsError",
|
70
|
+
"UserStyles",
|
12
71
|
]
|
habiticalib/const.py
CHANGED
habiticalib/exceptions.py
CHANGED
@@ -1,16 +1,35 @@
|
|
1
1
|
"""Exceptions for Habiticalib."""
|
2
2
|
|
3
|
+
from datetime import datetime
|
3
4
|
from typing import Self
|
4
5
|
|
6
|
+
from multidict import CIMultiDictProxy
|
7
|
+
|
5
8
|
from habiticalib.types import HabiticaErrorResponse
|
6
9
|
|
7
10
|
|
8
11
|
class HabiticaException(Exception): # noqa: N818
|
9
12
|
"""Base class for Habitica errors."""
|
10
13
|
|
11
|
-
def __init__(
|
14
|
+
def __init__(
|
15
|
+
self: Self,
|
16
|
+
error: HabiticaErrorResponse,
|
17
|
+
headers: CIMultiDictProxy,
|
18
|
+
) -> None:
|
12
19
|
"""Initialize the Exception."""
|
13
20
|
self.error = error
|
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)))
|
14
33
|
|
15
34
|
super().__init__(error.message)
|
16
35
|
|
@@ -25,3 +44,7 @@ class NotFoundError(HabiticaException):
|
|
25
44
|
|
26
45
|
class BadRequestError(HabiticaException):
|
27
46
|
"""BadRequest error."""
|
47
|
+
|
48
|
+
|
49
|
+
class TooManyRequestsError(HabiticaException):
|
50
|
+
"""TooManyRequests error."""
|
habiticalib/helpers.py
CHANGED
@@ -1,13 +1,15 @@
|
|
1
1
|
"""Helper functions for Habiticalib."""
|
2
2
|
|
3
|
-
from dataclasses import asdict
|
4
|
-
from
|
3
|
+
from dataclasses import asdict, is_dataclass
|
4
|
+
from datetime import date, datetime
|
5
|
+
from enum import Enum
|
5
6
|
import platform
|
7
|
+
from typing import Any
|
6
8
|
import uuid
|
7
9
|
|
8
10
|
import aiohttp
|
9
11
|
|
10
|
-
from .const import DEVELOPER_ID
|
12
|
+
from .const import DEVELOPER_ID, __version__
|
11
13
|
from .types import HabiticaUserResponse, UserData, UserStyles
|
12
14
|
|
13
15
|
|
@@ -58,7 +60,7 @@ def get_user_agent() -> str:
|
|
58
60
|
os_info = f"{os_name} {os_release} ({os_version}); {arch}"
|
59
61
|
|
60
62
|
return (
|
61
|
-
f"Habiticalib/{
|
63
|
+
f"Habiticalib/{__version__} ({os_info}) "
|
62
64
|
f"aiohttp/{aiohttp.__version__} Python/{platform.python_version()} "
|
63
65
|
" +https://github.com/tr4nt0r/habiticalib)"
|
64
66
|
)
|
@@ -106,10 +108,31 @@ def get_x_client(x_client: str | None = None) -> str:
|
|
106
108
|
|
107
109
|
return x_client
|
108
110
|
|
109
|
-
return f"{DEVELOPER_ID} - Habiticalib/{
|
111
|
+
return f"{DEVELOPER_ID} - Habiticalib/{__version__}"
|
110
112
|
|
111
113
|
|
112
114
|
def extract_user_styles(user_data: HabiticaUserResponse) -> UserStyles:
|
113
115
|
"""Extract user styles from a user data object."""
|
114
116
|
data: UserData = user_data.data
|
115
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
|
habiticalib/lib.py
CHANGED
@@ -13,12 +13,23 @@ 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
|
17
|
-
|
16
|
+
from .exceptions import (
|
17
|
+
BadRequestError,
|
18
|
+
NotAuthorizedError,
|
19
|
+
NotFoundError,
|
20
|
+
TooManyRequestsError,
|
21
|
+
)
|
22
|
+
from .helpers import (
|
23
|
+
deserialize_task,
|
24
|
+
extract_user_styles,
|
25
|
+
get_user_agent,
|
26
|
+
get_x_client,
|
27
|
+
join_fields,
|
28
|
+
)
|
18
29
|
from .types import (
|
19
30
|
Attributes,
|
20
|
-
Class,
|
21
31
|
Direction,
|
32
|
+
HabiticaClass,
|
22
33
|
HabiticaClassSystemResponse,
|
23
34
|
HabiticaErrorResponse,
|
24
35
|
HabiticaLoginResponse,
|
@@ -87,7 +98,7 @@ class Habitica:
|
|
87
98
|
msg = "Both 'api_user' and 'api_key' must be provided together."
|
88
99
|
raise ValueError(msg)
|
89
100
|
|
90
|
-
self.url = URL(url if url else DEFAULT_URL)
|
101
|
+
self.url = URL(url if url else DEFAULT_URL)
|
91
102
|
|
92
103
|
self._assets_cache: dict[str, IO[bytes]] = {}
|
93
104
|
self._cache_order: list[str] = []
|
@@ -102,15 +113,19 @@ class Habitica:
|
|
102
113
|
) as r:
|
103
114
|
if r.status == HTTPStatus.UNAUTHORIZED:
|
104
115
|
raise NotAuthorizedError(
|
105
|
-
HabiticaErrorResponse.from_json(await r.text()),
|
116
|
+
HabiticaErrorResponse.from_json(await r.text()), r.headers
|
106
117
|
)
|
107
118
|
if r.status == HTTPStatus.NOT_FOUND:
|
108
119
|
raise NotFoundError(
|
109
|
-
HabiticaErrorResponse.from_json(await r.text()),
|
120
|
+
HabiticaErrorResponse.from_json(await r.text()), r.headers
|
110
121
|
)
|
111
122
|
if r.status == HTTPStatus.BAD_REQUEST:
|
112
123
|
raise BadRequestError(
|
113
|
-
HabiticaErrorResponse.from_json(await r.text()),
|
124
|
+
HabiticaErrorResponse.from_json(await r.text()), r.headers
|
125
|
+
)
|
126
|
+
if r.status == HTTPStatus.TOO_MANY_REQUESTS:
|
127
|
+
raise TooManyRequestsError(
|
128
|
+
HabiticaErrorResponse.from_json(await r.text()), r.headers
|
114
129
|
)
|
115
130
|
r.raise_for_status()
|
116
131
|
return await r.text()
|
@@ -169,7 +184,7 @@ class Habitica:
|
|
169
184
|
>>> response.data.apiToken
|
170
185
|
'api-token'
|
171
186
|
"""
|
172
|
-
url = self.url / "v3/user/auth/local/login"
|
187
|
+
url = self.url / "api/v3/user/auth/local/login"
|
173
188
|
data = {
|
174
189
|
"username": username,
|
175
190
|
"password": password,
|
@@ -229,7 +244,7 @@ class Habitica:
|
|
229
244
|
>>> response = await habitica.get_user(user_fields="achievements,items.mounts")
|
230
245
|
>>> response.data # Access the returned data from the response
|
231
246
|
"""
|
232
|
-
url = self.url / "v3/user"
|
247
|
+
url = self.url / "api/v3/user"
|
233
248
|
params = {}
|
234
249
|
|
235
250
|
if user_fields:
|
@@ -290,7 +305,7 @@ class Habitica:
|
|
290
305
|
|
291
306
|
>>> await habitica.get_tasks(TaskType.HABITS, due_date=datetime(2024, 10, 15))
|
292
307
|
"""
|
293
|
-
url = self.url / "v3/tasks/user"
|
308
|
+
url = self.url / "api/v3/tasks/user"
|
294
309
|
params = {}
|
295
310
|
|
296
311
|
if task_type:
|
@@ -334,7 +349,7 @@ class Habitica:
|
|
334
349
|
>>> task_response = await habitica.get_task(task_id)
|
335
350
|
>>> print(task_response.data) # Displays the retrieved task information
|
336
351
|
"""
|
337
|
-
url = self.url / "v3/tasks" / str(task_id)
|
352
|
+
url = self.url / "api/v3/tasks" / str(task_id)
|
338
353
|
|
339
354
|
return HabiticaTaskResponse.from_json(
|
340
355
|
await self._request("get", url=url),
|
@@ -369,14 +384,16 @@ class Habitica:
|
|
369
384
|
|
370
385
|
Examples
|
371
386
|
--------
|
372
|
-
>>> new_task = Task(
|
387
|
+
>>> new_task = Task(text="New Task", type=TaskType.TODO ...)
|
373
388
|
>>> create_response = await habitica.create_task(new_task)
|
374
389
|
>>> print(create_response.data) # Displays the created task information
|
375
390
|
"""
|
376
|
-
url = self.url / "v3/tasks/user"
|
391
|
+
url = self.url / "api/v3/tasks/user"
|
392
|
+
|
393
|
+
json = deserialize_task(task)
|
377
394
|
|
378
395
|
return HabiticaTaskResponse.from_json(
|
379
|
-
await self._request("post", url=url, json=
|
396
|
+
await self._request("post", url=url, json=json),
|
380
397
|
)
|
381
398
|
|
382
399
|
async def update_task(self, task_id: UUID, task: Task) -> HabiticaTaskResponse:
|
@@ -412,14 +429,16 @@ class Habitica:
|
|
412
429
|
Examples
|
413
430
|
--------
|
414
431
|
>>> task_id = UUID("12345678-1234-5678-1234-567812345678")
|
415
|
-
>>> updated_task = Task(
|
432
|
+
>>> updated_task = Task(text="Updated Task", ...)
|
416
433
|
>>> update_response = await habitica.update_task(task_id, updated_task)
|
417
434
|
>>> print(update_response.data) # Displays the updated task information
|
418
435
|
"""
|
419
|
-
url = self.url / "v3/tasks" / str(task_id)
|
436
|
+
url = self.url / "api/v3/tasks" / str(task_id)
|
437
|
+
|
438
|
+
json = deserialize_task(task)
|
420
439
|
|
421
440
|
return HabiticaTaskResponse.from_json(
|
422
|
-
await self._request("put", url=url, json=
|
441
|
+
await self._request("put", url=url, json=json),
|
423
442
|
)
|
424
443
|
|
425
444
|
async def delete_task(self, task_id: UUID) -> HabiticaResponse:
|
@@ -455,7 +474,7 @@ class Habitica:
|
|
455
474
|
>>> delete_response = await habitica.delete_task(task_id)
|
456
475
|
>>> print(delete_response.success) # True if successfully deleted
|
457
476
|
"""
|
458
|
-
url = self.url / "v3/tasks" / str(task_id)
|
477
|
+
url = self.url / "api/v3/tasks" / str(task_id)
|
459
478
|
|
460
479
|
return HabiticaResponse.from_json(
|
461
480
|
await self._request("delete", url=url),
|
@@ -497,7 +516,7 @@ class Habitica:
|
|
497
516
|
>>> reorder_response = await habitica.reorder_task(task_id, 2)
|
498
517
|
>>> print(reorder_response.data) # Displays a list of task IDs in the new order
|
499
518
|
"""
|
500
|
-
url = self.url / "v3/tasks" / str(task_id) / "move/to" / str(to)
|
519
|
+
url = self.url / "api/v3/tasks" / str(task_id) / "move/to" / str(to)
|
501
520
|
|
502
521
|
return HabiticaTaskOrderResponse.from_json(
|
503
522
|
await self._request("post", url=url),
|
@@ -531,7 +550,7 @@ class Habitica:
|
|
531
550
|
TimeoutError
|
532
551
|
If the connection times out.
|
533
552
|
"""
|
534
|
-
url = self.url
|
553
|
+
url = self.url / "export/userdata.json"
|
535
554
|
|
536
555
|
return HabiticaUserExport.from_json(
|
537
556
|
await self._request("get", url=url),
|
@@ -576,7 +595,7 @@ class Habitica:
|
|
576
595
|
TimeoutError
|
577
596
|
If the connection times out.
|
578
597
|
"""
|
579
|
-
url = self.url / "v3/content"
|
598
|
+
url = self.url / "api/v3/content"
|
580
599
|
params = {}
|
581
600
|
|
582
601
|
if language:
|
@@ -612,7 +631,7 @@ class Habitica:
|
|
612
631
|
TimeoutError
|
613
632
|
If the connection times out.
|
614
633
|
"""
|
615
|
-
url = self.url / "v3/cron"
|
634
|
+
url = self.url / "api/v3/cron"
|
616
635
|
return HabiticaResponse.from_json(await self._request("post", url=url))
|
617
636
|
|
618
637
|
async def allocate_single_stat_point(
|
@@ -656,7 +675,7 @@ class Habitica:
|
|
656
675
|
Allocate a single stat point to Strength (default):
|
657
676
|
>>> await habitica.allocate_single_stat_point()
|
658
677
|
"""
|
659
|
-
url = self.url / "v3/user/allocate"
|
678
|
+
url = self.url / "api/v3/user/allocate"
|
660
679
|
params = {"stat": stat}
|
661
680
|
|
662
681
|
return HabiticaStatsResponse.from_json(
|
@@ -690,7 +709,7 @@ class Habitica:
|
|
690
709
|
TimeoutError
|
691
710
|
If the connection times out.
|
692
711
|
"""
|
693
|
-
url = self.url / "v3/user/allocate-now"
|
712
|
+
url = self.url / "api/v3/user/allocate-now"
|
694
713
|
|
695
714
|
return HabiticaStatsResponse.from_json(
|
696
715
|
await self._request("post", url=url),
|
@@ -743,7 +762,7 @@ class Habitica:
|
|
743
762
|
Allocate 2 points to INT and 1 point to STR:
|
744
763
|
>>> await allocate_bulk_stat_points(int_points=2, str_points=1)
|
745
764
|
"""
|
746
|
-
url = self.url / "v3/user/allocate-bulk"
|
765
|
+
url = self.url / "api/v3/user/allocate-bulk"
|
747
766
|
json = {
|
748
767
|
"stats": {
|
749
768
|
"int": int_points,
|
@@ -782,7 +801,7 @@ class Habitica:
|
|
782
801
|
TimeoutError
|
783
802
|
If the connection times out.
|
784
803
|
"""
|
785
|
-
url = self.url / "v3/user/buy-health-potion"
|
804
|
+
url = self.url / "api/v3/user/buy-health-potion"
|
786
805
|
|
787
806
|
return HabiticaStatsResponse.from_json(
|
788
807
|
await self._request("post", url=url),
|
@@ -790,14 +809,14 @@ class Habitica:
|
|
790
809
|
|
791
810
|
async def cast_skill(
|
792
811
|
self,
|
793
|
-
|
812
|
+
skill: Skill,
|
794
813
|
target_id: UUID | None = None,
|
795
814
|
) -> HabiticaUserResponse:
|
796
815
|
"""Cast a skill (spell) in Habitica, optionally targeting a specific user, task or party.
|
797
816
|
|
798
817
|
Parameters
|
799
818
|
----------
|
800
|
-
|
819
|
+
skill : Skill
|
801
820
|
The skill (or spell) to be cast. This should be a valid `Skill` enum value.
|
802
821
|
target_id : UUID, optional
|
803
822
|
The unique identifier of the target for the skill. If the skill does not require a target,
|
@@ -823,7 +842,7 @@ class Habitica:
|
|
823
842
|
TimeoutError
|
824
843
|
If the connection times out.
|
825
844
|
"""
|
826
|
-
url = self.url / "v3/class/cast" /
|
845
|
+
url = self.url / "api/v3/user/class/cast" / skill
|
827
846
|
params = {}
|
828
847
|
|
829
848
|
if target_id:
|
@@ -854,7 +873,7 @@ class Habitica:
|
|
854
873
|
TimeoutError
|
855
874
|
If the connection times out.
|
856
875
|
"""
|
857
|
-
url = self.url / "v3/user/sleep"
|
876
|
+
url = self.url / "api/v3/user/sleep"
|
858
877
|
|
859
878
|
return HabiticaResponse.from_json(await self._request("post", url=url))
|
860
879
|
|
@@ -876,11 +895,11 @@ class Habitica:
|
|
876
895
|
TimeoutError
|
877
896
|
If the connection times out.
|
878
897
|
"""
|
879
|
-
url = self.url / "v3/user/revive"
|
898
|
+
url = self.url / "api/v3/user/revive"
|
880
899
|
|
881
900
|
return HabiticaResponse.from_json(await self._request("post", url=url))
|
882
901
|
|
883
|
-
async def change_class(self, Class:
|
902
|
+
async def change_class(self, Class: HabiticaClass) -> HabiticaClassSystemResponse: # noqa: N803
|
884
903
|
"""Change the user's class in Habitica.
|
885
904
|
|
886
905
|
This method sends a request to the Habitica API to change the user's class
|
@@ -911,11 +930,11 @@ class Habitica:
|
|
911
930
|
|
912
931
|
Examples
|
913
932
|
--------
|
914
|
-
>>> new_class =
|
933
|
+
>>> new_class = HabiticaClass.WARRIOR
|
915
934
|
>>> change_response = await habitica.change_class(new_class)
|
916
935
|
>>> print(change_response.data.stats) # Displays the user's stats after class change
|
917
936
|
"""
|
918
|
-
url = self.url / "v3/user/change-class"
|
937
|
+
url = self.url / "api/v3/user/change-class"
|
919
938
|
params = {"class": Class.value}
|
920
939
|
|
921
940
|
return HabiticaClassSystemResponse.from_json(
|
@@ -948,7 +967,7 @@ class Habitica:
|
|
948
967
|
>>> disable_response = await habitica.disable_classes()
|
949
968
|
>>> print(disable_response.data.stats) # Displays the user's stats after disabling the class system
|
950
969
|
"""
|
951
|
-
url = self.url / "v3/user/disable-classes"
|
970
|
+
url = self.url / "api/v3/user/disable-classes"
|
952
971
|
|
953
972
|
return HabiticaClassSystemResponse.from_json(
|
954
973
|
await self._request("post", url=url)
|
@@ -981,7 +1000,7 @@ class Habitica:
|
|
981
1000
|
>>> delete_response = await habitica.delete_completed_todos()
|
982
1001
|
>>> print(delete_response.success) # True if successfully cleared completed to-dos
|
983
1002
|
"""
|
984
|
-
url = self.url / "v3/tasks/clearCompletedTodos"
|
1003
|
+
url = self.url / "api/v3/tasks/clearCompletedTodos"
|
985
1004
|
|
986
1005
|
return HabiticaClassSystemResponse.from_json(
|
987
1006
|
await self._request("post", url=url)
|
@@ -1023,7 +1042,7 @@ class Habitica:
|
|
1023
1042
|
TimeoutError
|
1024
1043
|
If the connection times out.
|
1025
1044
|
"""
|
1026
|
-
url = self.url / "v3/tasks" / str(task_id) / "score" / direction.value
|
1045
|
+
url = self.url / "api/v3/tasks" / str(task_id) / "score" / direction.value
|
1027
1046
|
|
1028
1047
|
return HabiticaScoreResponse.from_json(
|
1029
1048
|
await self._request("post", url=url),
|
@@ -1056,10 +1075,10 @@ class Habitica:
|
|
1056
1075
|
>>> tags_response = await habitica.get_tags()
|
1057
1076
|
>>> print(tags_response.data)
|
1058
1077
|
"""
|
1059
|
-
url = self.url / "v3/tags"
|
1078
|
+
url = self.url / "api/v3/tags"
|
1060
1079
|
|
1061
1080
|
return HabiticaTagsResponse.from_json(
|
1062
|
-
await self._request("
|
1081
|
+
await self._request("get", url=url),
|
1063
1082
|
)
|
1064
1083
|
|
1065
1084
|
async def get_tag(self, tag_id: UUID) -> HabiticaTagResponse:
|
@@ -1094,10 +1113,10 @@ class Habitica:
|
|
1094
1113
|
>>> tag_response = await habitica.get_tag()
|
1095
1114
|
>>> print(tag_response.data)
|
1096
1115
|
"""
|
1097
|
-
url = self.url / "v3/tags" / str(tag_id)
|
1116
|
+
url = self.url / "api/v3/tags" / str(tag_id)
|
1098
1117
|
|
1099
1118
|
return HabiticaTagResponse.from_json(
|
1100
|
-
await self._request("
|
1119
|
+
await self._request("get", url=url),
|
1101
1120
|
)
|
1102
1121
|
|
1103
1122
|
async def delete_tag(self, tag_id: UUID) -> HabiticaResponse:
|
@@ -1133,7 +1152,7 @@ class Habitica:
|
|
1133
1152
|
>>> delete_response = await habitica.delete_tag(tag_id)
|
1134
1153
|
>>> print(delete_response.success) # True if successfully deleted
|
1135
1154
|
"""
|
1136
|
-
url = self.url / "v3/tags" / str(tag_id)
|
1155
|
+
url = self.url / "api/v3/tags" / str(tag_id)
|
1137
1156
|
|
1138
1157
|
return HabiticaTagResponse.from_json(
|
1139
1158
|
await self._request("delete", url=url),
|
@@ -1172,7 +1191,7 @@ class Habitica:
|
|
1172
1191
|
>>> new_tag_response = await habitica.create_tag("New Tag Name")
|
1173
1192
|
>>> print(new_tag_response.data.id) # Displays the id of the new tag
|
1174
1193
|
"""
|
1175
|
-
url = self.url / "v3/tags"
|
1194
|
+
url = self.url / "api/v3/tags"
|
1176
1195
|
json = {"name": name}
|
1177
1196
|
return HabiticaTagResponse.from_json(
|
1178
1197
|
await self._request("post", url=url, json=json),
|
@@ -1213,7 +1232,7 @@ class Habitica:
|
|
1213
1232
|
>>> update_response = await habitica.update_tag(tag_id, "New Tag Name")
|
1214
1233
|
>>> print(update_response.data) # Displays the updated tag information
|
1215
1234
|
"""
|
1216
|
-
url = self.url / "v3/tags" / str(tag_id)
|
1235
|
+
url = self.url / "api/v3/tags" / str(tag_id)
|
1217
1236
|
json = {"name": name}
|
1218
1237
|
return HabiticaTagResponse.from_json(
|
1219
1238
|
await self._request("put", url=url, json=json),
|
@@ -1254,10 +1273,10 @@ class Habitica:
|
|
1254
1273
|
>>> reorder_response = await habitica.reorder_tag(tag_id, 2)
|
1255
1274
|
>>> print(reorder_response.success) # True if reorder is successful
|
1256
1275
|
"""
|
1257
|
-
url = self.url / "v3/reorder-tags"
|
1276
|
+
url = self.url / "api/v3/reorder-tags"
|
1258
1277
|
json = {"tagId": str(tag_id), "to": to}
|
1259
1278
|
|
1260
|
-
return
|
1279
|
+
return HabiticaResponse.from_json(
|
1261
1280
|
await self._request("post", url=url, json=json),
|
1262
1281
|
)
|
1263
1282
|
|
habiticalib/types.py
CHANGED
@@ -4,26 +4,27 @@
|
|
4
4
|
from __future__ import annotations
|
5
5
|
|
6
6
|
from dataclasses import dataclass, field
|
7
|
+
import datetime as dt
|
7
8
|
from datetime import UTC, datetime
|
8
|
-
from enum import StrEnum
|
9
|
-
from typing import Any
|
9
|
+
from enum import Enum, StrEnum
|
10
|
+
from typing import Any, NotRequired, TypedDict
|
10
11
|
from uuid import UUID # noqa: TCH003
|
11
12
|
|
12
13
|
from mashumaro import field_options
|
13
|
-
from mashumaro.config import BaseConfig
|
14
14
|
from mashumaro.mixins.orjson import DataClassORJSONMixin
|
15
15
|
|
16
16
|
|
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:
|
@@ -60,6 +61,7 @@ class LoginData:
|
|
60
61
|
apiToken: str
|
61
62
|
newUser: bool
|
62
63
|
username: str
|
64
|
+
passwordResetCode: str | None = None
|
63
65
|
|
64
66
|
|
65
67
|
@dataclass(kw_only=True)
|
@@ -73,27 +75,27 @@ class HabiticaLoginResponse(HabiticaResponse):
|
|
73
75
|
class LocalAuth:
|
74
76
|
"""Auth local data."""
|
75
77
|
|
76
|
-
email: str
|
77
|
-
username: str
|
78
|
-
lowerCaseUsername: str
|
79
|
-
has_password: bool
|
78
|
+
email: str | None = None
|
79
|
+
username: str | None = None
|
80
|
+
lowerCaseUsername: str | None = None
|
81
|
+
has_password: bool | None = None
|
80
82
|
|
81
83
|
|
82
84
|
@dataclass(kw_only=True)
|
83
85
|
class LocalTimestamps:
|
84
86
|
"""Timestamps local data."""
|
85
87
|
|
86
|
-
created: datetime
|
87
|
-
loggedin: datetime
|
88
|
-
updated: datetime
|
88
|
+
created: datetime | None = None
|
89
|
+
loggedin: datetime | None = None
|
90
|
+
updated: datetime | None = None
|
89
91
|
|
90
92
|
|
91
93
|
@dataclass(kw_only=True)
|
92
94
|
class AuthUser:
|
93
95
|
"""User auth data."""
|
94
96
|
|
95
|
-
local: LocalAuth
|
96
|
-
timestamps: LocalTimestamps
|
97
|
+
local: LocalAuth = field(default_factory=LocalAuth)
|
98
|
+
timestamps: LocalTimestamps = field(default_factory=LocalTimestamps)
|
97
99
|
facebook: dict | None = None
|
98
100
|
google: dict | None = None
|
99
101
|
apple: dict | None = None
|
@@ -627,6 +629,15 @@ class TrainingStats:
|
|
627
629
|
Int: int | None = field(default=None, metadata=field_options(alias="int"))
|
628
630
|
|
629
631
|
|
632
|
+
class HabiticaClass(StrEnum):
|
633
|
+
"""Habitica's player classes."""
|
634
|
+
|
635
|
+
WARRIOR = "warrior"
|
636
|
+
ROGUE = "rogue"
|
637
|
+
MAGE = "wizard"
|
638
|
+
HEALER = "healer"
|
639
|
+
|
640
|
+
|
630
641
|
@dataclass(kw_only=True)
|
631
642
|
class StatsUser:
|
632
643
|
"""Stats user data."""
|
@@ -638,7 +649,9 @@ class StatsUser:
|
|
638
649
|
exp: int | None = None
|
639
650
|
gp: float | None = None
|
640
651
|
lvl: int | None = None
|
641
|
-
Class:
|
652
|
+
Class: HabiticaClass | None = field(
|
653
|
+
default=None, metadata=field_options(alias="class")
|
654
|
+
)
|
642
655
|
points: int | None = None
|
643
656
|
Str: int | None = field(default=None, metadata=field_options(alias="str"))
|
644
657
|
con: int | None = None
|
@@ -649,6 +662,13 @@ class StatsUser:
|
|
649
662
|
Int: int | None = field(default=None, metadata=field_options(alias="int"))
|
650
663
|
|
651
664
|
|
665
|
+
field(
|
666
|
+
metadata=field_options(
|
667
|
+
deserialize=serialize_datetime,
|
668
|
+
)
|
669
|
+
)
|
670
|
+
|
671
|
+
|
652
672
|
@dataclass(kw_only=True)
|
653
673
|
class TagsUser:
|
654
674
|
"""Tags user data."""
|
@@ -673,10 +693,10 @@ class InboxUser:
|
|
673
693
|
class TasksOrderUser:
|
674
694
|
"""TasksOrder user data."""
|
675
695
|
|
676
|
-
habits: list[
|
677
|
-
dailys: list[
|
678
|
-
todos: list[
|
679
|
-
rewards: list[
|
696
|
+
habits: list[UUID] = field(default_factory=list)
|
697
|
+
dailys: list[UUID] = field(default_factory=list)
|
698
|
+
todos: list[UUID] = field(default_factory=list)
|
699
|
+
rewards: list[UUID] = field(default_factory=list)
|
680
700
|
|
681
701
|
|
682
702
|
@dataclass(kw_only=True)
|
@@ -716,7 +736,7 @@ class UserData:
|
|
716
736
|
|
717
737
|
id: UUID | None = None
|
718
738
|
preferences: PreferencesUser = field(default_factory=PreferencesUser)
|
719
|
-
flags: FlagsUser
|
739
|
+
flags: FlagsUser = field(default_factory=FlagsUser)
|
720
740
|
auth: AuthUser = field(default_factory=AuthUser)
|
721
741
|
achievements: AchievementsUser = field(default_factory=AchievementsUser)
|
722
742
|
backer: BackerUser = field(default_factory=BackerUser)
|
@@ -745,8 +765,8 @@ class UserData:
|
|
745
765
|
balance: float | None = None
|
746
766
|
lastCron: datetime | None = None
|
747
767
|
needsCron: bool | None = None
|
748
|
-
challenges: list[
|
749
|
-
guilds: list[
|
768
|
+
challenges: list[UUID] = field(default_factory=list)
|
769
|
+
guilds: list[UUID] = field(default_factory=list)
|
750
770
|
newMessages: dict[str, bool] = field(default_factory=dict)
|
751
771
|
|
752
772
|
|
@@ -849,38 +869,31 @@ class Frequency(StrEnum):
|
|
849
869
|
YEARLY = "yearly"
|
850
870
|
|
851
871
|
|
852
|
-
|
853
|
-
class Task(DataClassORJSONMixin):
|
872
|
+
class Task(TypedDict("Task", {"type": NotRequired[TaskType]}), total=True):
|
854
873
|
"""Representation of a task."""
|
855
874
|
|
856
|
-
|
857
|
-
|
858
|
-
|
859
|
-
|
860
|
-
|
861
|
-
|
862
|
-
|
863
|
-
|
864
|
-
|
865
|
-
|
866
|
-
|
867
|
-
|
868
|
-
|
869
|
-
|
870
|
-
|
871
|
-
|
872
|
-
|
873
|
-
|
874
|
-
|
875
|
-
|
876
|
-
|
877
|
-
|
878
|
-
everyX: int | None = None
|
879
|
-
repeat: Repeat | None = None
|
880
|
-
daysOfMonth: list[int] | None = None
|
881
|
-
weeksOfMonth: list[int] | None = None
|
882
|
-
completed: bool | None = None
|
883
|
-
streak: int | None = None
|
875
|
+
text: NotRequired[str]
|
876
|
+
attribute: NotRequired[Attributes]
|
877
|
+
alias: NotRequired[str]
|
878
|
+
notes: NotRequired[str]
|
879
|
+
tags: NotRequired[list[UUID]]
|
880
|
+
collapseChecklist: NotRequired[bool]
|
881
|
+
date: NotRequired[datetime | dt.date | None]
|
882
|
+
priority: NotRequired[TaskPriority]
|
883
|
+
reminders: NotRequired[list[Reminders]]
|
884
|
+
checklist: NotRequired[list[str]]
|
885
|
+
up: NotRequired[bool]
|
886
|
+
down: NotRequired[bool]
|
887
|
+
counterUp: NotRequired[int]
|
888
|
+
counterDown: NotRequired[int]
|
889
|
+
startDate: NotRequired[datetime | dt.date]
|
890
|
+
frequency: NotRequired[Frequency]
|
891
|
+
everyX: NotRequired[int]
|
892
|
+
repeat: NotRequired[Repeat]
|
893
|
+
daysOfMonth: NotRequired[list[int]]
|
894
|
+
weeksOfMonth: NotRequired[list[int]]
|
895
|
+
completed: NotRequired[bool]
|
896
|
+
streak: NotRequired[int]
|
884
897
|
|
885
898
|
|
886
899
|
@dataclass(kw_only=True)
|
@@ -894,7 +907,7 @@ class TaskData:
|
|
894
907
|
notes: str | None = None
|
895
908
|
tags: list[UUID] | None = None
|
896
909
|
value: float | None = None
|
897
|
-
priority:
|
910
|
+
priority: TaskPriority | None = None
|
898
911
|
attribute: Attributes | None = None
|
899
912
|
byHabitica: bool | None = None
|
900
913
|
createdAt: datetime | None = None
|
@@ -978,7 +991,7 @@ class StatsUserStyles:
|
|
978
991
|
"""Stats user styles data."""
|
979
992
|
|
980
993
|
buffs: BuffsUserStyles = field(default_factory=BuffsUserStyles)
|
981
|
-
Class:
|
994
|
+
Class: HabiticaClass = field(default=HabiticaClass.WARRIOR)
|
982
995
|
|
983
996
|
|
984
997
|
@dataclass(kw_only=True)
|
@@ -1051,7 +1064,7 @@ class DropTmpScore:
|
|
1051
1064
|
canDrop: bool | None = None
|
1052
1065
|
value: int | None = None
|
1053
1066
|
key: str | None = None
|
1054
|
-
|
1067
|
+
Type: str | None = field(default=None, metadata=field_options(alias="type"))
|
1055
1068
|
dialog: str | None = None
|
1056
1069
|
|
1057
1070
|
|
@@ -1063,12 +1076,21 @@ class TmpScore:
|
|
1063
1076
|
drop: DropTmpScore = field(default_factory=DropTmpScore)
|
1064
1077
|
|
1065
1078
|
|
1079
|
+
@dataclass
|
1080
|
+
class ScoreData(StatsUser):
|
1081
|
+
"""Scora data."""
|
1082
|
+
|
1083
|
+
delta: float | None = None
|
1084
|
+
tmp: TmpScore = field(
|
1085
|
+
default_factory=TmpScore, metadata=field_options(alias="_tmp")
|
1086
|
+
)
|
1087
|
+
|
1088
|
+
|
1066
1089
|
@dataclass(kw_only=True)
|
1067
|
-
class HabiticaScoreResponse(
|
1090
|
+
class HabiticaScoreResponse(HabiticaResponse, DataClassORJSONMixin):
|
1068
1091
|
"""Representation of a score response."""
|
1069
1092
|
|
1070
|
-
|
1071
|
-
_tmp: TmpScore = field(default_factory=TmpScore)
|
1093
|
+
data: ScoreData
|
1072
1094
|
|
1073
1095
|
|
1074
1096
|
@dataclass(kw_only=True)
|
@@ -1106,7 +1128,7 @@ class HabiticaClassSystemResponse(HabiticaResponse, DataClassORJSONMixin):
|
|
1106
1128
|
class HabiticaTaskOrderResponse(HabiticaResponse):
|
1107
1129
|
"""Representation of a reorder task response."""
|
1108
1130
|
|
1109
|
-
data:
|
1131
|
+
data: list[UUID] = field(default_factory=list)
|
1110
1132
|
|
1111
1133
|
|
1112
1134
|
class TaskFilter(StrEnum):
|
@@ -1186,17 +1208,17 @@ class Skill(StrEnum):
|
|
1186
1208
|
PETAL_FREE_POTION = "petalFreePotion"
|
1187
1209
|
|
1188
1210
|
|
1189
|
-
class Class(StrEnum):
|
1190
|
-
"""Habitica's player classes."""
|
1191
|
-
|
1192
|
-
WARRIOR = "warrior"
|
1193
|
-
ROGUE = "rogue"
|
1194
|
-
MAGE = "mage"
|
1195
|
-
HEALER = "healer"
|
1196
|
-
|
1197
|
-
|
1198
1211
|
class Direction(StrEnum):
|
1199
1212
|
"""Direction to score a task."""
|
1200
1213
|
|
1201
1214
|
UP = "up"
|
1202
1215
|
DOWN = "down"
|
1216
|
+
|
1217
|
+
|
1218
|
+
class TaskPriority(Enum):
|
1219
|
+
"""Task difficulties."""
|
1220
|
+
|
1221
|
+
TRIVIAL = 0.1
|
1222
|
+
EASY = 1
|
1223
|
+
MEDIUM = 1.5
|
1224
|
+
HARD = 2
|
@@ -0,0 +1,97 @@
|
|
1
|
+
Metadata-Version: 2.3
|
2
|
+
Name: Habiticalib
|
3
|
+
Version: 0.1.0a3
|
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
|
+
Classifier: License :: OSI Approved :: MIT License
|
10
|
+
Classifier: Operating System :: OS Independent
|
11
|
+
Classifier: Programming Language :: Python :: 3 :: Only
|
12
|
+
Requires-Python: >=3.12
|
13
|
+
Requires-Dist: aiohttp~=3.9
|
14
|
+
Requires-Dist: mashumaro~=3.13
|
15
|
+
Requires-Dist: orjson~=3.10
|
16
|
+
Requires-Dist: pillow~=11.0
|
17
|
+
Description-Content-Type: text/markdown
|
18
|
+
|
19
|
+
# Habiticalib
|
20
|
+
|
21
|
+
<p align="center">
|
22
|
+
<em>Modern asynchronous Python client library for the Habitica API</em>
|
23
|
+
</p>
|
24
|
+
|
25
|
+
[](https://github.com/tr4nt0r/habiticalib/actions)
|
26
|
+
[](https://codecov.io/gh/tr4nt0r/habiticalib)
|
27
|
+
[](https://badge.fury.io/py/habiticalib)
|
28
|
+
|
29
|
+
**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.
|
30
|
+
|
31
|
+
## Key features
|
32
|
+
|
33
|
+
- **Asynchronous**: The library is fully asynchronous, allowing non-blocking API calls.
|
34
|
+
- **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.
|
35
|
+
- **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.
|
36
|
+
**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.
|
37
|
+
- **Task management**: Support for creating, updating, and retrieving Habitica tasks (to-dos, dailies, habits, rewards) is provided.
|
38
|
+
- **Task status updates**: The library allows updates for task statuses, habit scoring, and daily completion.
|
39
|
+
- **Tags**: Habiticalib supports the creation, updating and deletion of tags.
|
40
|
+
- **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)
|
41
|
+
|
42
|
+
## Installation
|
43
|
+
|
44
|
+
```bash
|
45
|
+
pip install habiticalib
|
46
|
+
```
|
47
|
+
|
48
|
+
## Getting started
|
49
|
+
Here’s an example to demonstrate basic usage:
|
50
|
+
|
51
|
+
```python
|
52
|
+
import asyncio
|
53
|
+
|
54
|
+
from aiohttp import ClientSession
|
55
|
+
|
56
|
+
from habiticalib import Habitica, TaskType
|
57
|
+
|
58
|
+
|
59
|
+
async def main():
|
60
|
+
async with ClientSession() as session:
|
61
|
+
habitica = Habitica(session)
|
62
|
+
|
63
|
+
# Login to Habitica
|
64
|
+
habitica.login(username="your_username", password="your_password")
|
65
|
+
|
66
|
+
# Fetch user data
|
67
|
+
user_data = await habitica.user()
|
68
|
+
print(f"Your current health: {user_data.stats.hp}")
|
69
|
+
|
70
|
+
# Fetch all tasks (to-dos, dailies, habits, and rewards)
|
71
|
+
tasks = await habitica.get_tasks()
|
72
|
+
print("All tasks:")
|
73
|
+
for task in tasks:
|
74
|
+
print(f"- {task.text} (type: {task.type})")
|
75
|
+
|
76
|
+
# Fetch only to-dos
|
77
|
+
todos = await habitica.get_tasks(task_type=TaskType.TODO)
|
78
|
+
print("\nTo-Do tasks:")
|
79
|
+
for todo in todos:
|
80
|
+
print(f"- {todo.text} (due: {todo.date})")
|
81
|
+
|
82
|
+
# Fetch only dailies
|
83
|
+
dailies = await habitica.tasks(task_type=TaskType.DAILY)
|
84
|
+
print("\nDailies:")
|
85
|
+
for daily in dailies:
|
86
|
+
print(f"- {daily.text}")
|
87
|
+
|
88
|
+
asyncio.run(main())
|
89
|
+
```
|
90
|
+
|
91
|
+
## Documentation
|
92
|
+
|
93
|
+
For full documentation and detailed usage examples, please visit the [Habiticalib documentation](https://tr4nt0r.github.io/habiticalib/).
|
94
|
+
|
95
|
+
## License
|
96
|
+
|
97
|
+
This project is licensed under the terms of the MIT license.
|
@@ -0,0 +1,11 @@
|
|
1
|
+
habiticalib/__init__.py,sha256=rwRSTk3JFaSnVKRniTC82tA5JKPSuQ-AD_mAok2QU_g,1561
|
2
|
+
habiticalib/const.py,sha256=aeFLubB_xXy_3ChIDmT9Atp_aOe58oOqcAs6vepIsoI,609
|
3
|
+
habiticalib/exceptions.py,sha256=oVFCGbHkVn0UpIKIPZPzXfvzs9US4R05ebdEn6cOpqM,1350
|
4
|
+
habiticalib/helpers.py,sha256=IRZLYWkDVLI0iVBgBMmvZ6L83KCUl-CnzGhUR_tP6Fg,4576
|
5
|
+
habiticalib/lib.py,sha256=MMs3BINdbZUszUy_DCWvFWDZKy2or1UA5R47X3GeUwI,54274
|
6
|
+
habiticalib/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
7
|
+
habiticalib/types.py,sha256=7xpxpvpDQBxsyuD241vQxeXjk6zuEC4yXzw-Of7G7Bw,33187
|
8
|
+
habiticalib-0.1.0a3.dist-info/METADATA,sha256=fmMClL_kOz3sWYotJu9QZT49CfV6sEcq9sq0bfV7YZ8,4156
|
9
|
+
habiticalib-0.1.0a3.dist-info/WHEEL,sha256=C2FUgwZgiLbznR-k0b_5k3Ai_1aASOXDss3lzCUsUug,87
|
10
|
+
habiticalib-0.1.0a3.dist-info/licenses/LICENSE,sha256=oIinIOSJ49l1iVIRI3XGXFWt6SF7a83kEFBAY8ORwNI,1084
|
11
|
+
habiticalib-0.1.0a3.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
|