Habiticalib 0.2.0a2__tar.gz → 0.3.0__tar.gz
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-0.2.0a2 → habiticalib-0.3.0}/.github/release-drafter.yml +5 -0
- {habiticalib-0.2.0a2 → habiticalib-0.3.0}/PKG-INFO +2 -1
- {habiticalib-0.2.0a2 → habiticalib-0.3.0}/pyproject.toml +13 -12
- {habiticalib-0.2.0a2 → habiticalib-0.3.0}/src/habiticalib/__init__.py +28 -2
- {habiticalib-0.2.0a2 → habiticalib-0.3.0}/src/habiticalib/const.py +1 -1
- {habiticalib-0.2.0a2 → habiticalib-0.3.0}/src/habiticalib/lib.py +77 -12
- {habiticalib-0.2.0a2 → habiticalib-0.3.0}/src/habiticalib/types.py +16 -1
- {habiticalib-0.2.0a2 → habiticalib-0.3.0}/.cruft.json +0 -0
- {habiticalib-0.2.0a2 → habiticalib-0.3.0}/.editorconfig +0 -0
- {habiticalib-0.2.0a2 → habiticalib-0.3.0}/.github/FUNDING.yml +0 -0
- {habiticalib-0.2.0a2 → habiticalib-0.3.0}/.github/dependabot.yml +0 -0
- {habiticalib-0.2.0a2 → habiticalib-0.3.0}/.github/labels.yml +0 -0
- {habiticalib-0.2.0a2 → habiticalib-0.3.0}/.github/workflows/build.yml +0 -0
- {habiticalib-0.2.0a2 → habiticalib-0.3.0}/.github/workflows/documentation.yml +0 -0
- {habiticalib-0.2.0a2 → habiticalib-0.3.0}/.github/workflows/draft.yml +0 -0
- {habiticalib-0.2.0a2 → habiticalib-0.3.0}/.github/workflows/labeler.yml +0 -0
- {habiticalib-0.2.0a2 → habiticalib-0.3.0}/.gitignore +0 -0
- {habiticalib-0.2.0a2 → habiticalib-0.3.0}/.pre-commit-config.yaml +0 -0
- {habiticalib-0.2.0a2 → habiticalib-0.3.0}/.vscode/settings.json +0 -0
- {habiticalib-0.2.0a2 → habiticalib-0.3.0}/LICENSE +0 -0
- {habiticalib-0.2.0a2 → habiticalib-0.3.0}/README.md +0 -0
- {habiticalib-0.2.0a2 → habiticalib-0.3.0}/docs/index.md +0 -0
- {habiticalib-0.2.0a2 → habiticalib-0.3.0}/docs/reference/habiticalib.md +0 -0
- {habiticalib-0.2.0a2 → habiticalib-0.3.0}/mkdocs.yml +0 -0
- {habiticalib-0.2.0a2 → habiticalib-0.3.0}/src/habiticalib/exceptions.py +0 -0
- {habiticalib-0.2.0a2 → habiticalib-0.3.0}/src/habiticalib/helpers.py +0 -0
- {habiticalib-0.2.0a2 → habiticalib-0.3.0}/src/habiticalib/py.typed +0 -0
- {habiticalib-0.2.0a2 → habiticalib-0.3.0}/tests/__init__.py +0 -0
- {habiticalib-0.2.0a2 → habiticalib-0.3.0}/tests/__snapshots__/test_avatar.ambr +0 -0
- {habiticalib-0.2.0a2 → habiticalib-0.3.0}/tests/__snapshots__/test_lib.ambr +0 -0
- {habiticalib-0.2.0a2 → habiticalib-0.3.0}/tests/conftest.py +0 -0
- {habiticalib-0.2.0a2 → habiticalib-0.3.0}/tests/fixtures/login.json +0 -0
- {habiticalib-0.2.0a2 → habiticalib-0.3.0}/tests/fixtures/user.json +0 -0
- {habiticalib-0.2.0a2 → habiticalib-0.3.0}/tests/fixtures/user_styles.json +0 -0
- {habiticalib-0.2.0a2 → habiticalib-0.3.0}/tests/fixtures/user_styles_kickstarter.json +0 -0
- {habiticalib-0.2.0a2 → habiticalib-0.3.0}/tests/fixtures/user_styles_seafoam.json +0 -0
- {habiticalib-0.2.0a2 → habiticalib-0.3.0}/tests/fixtures/user_styles_shinySeed.json +0 -0
- {habiticalib-0.2.0a2 → habiticalib-0.3.0}/tests/fixtures/user_styles_sleeping.json +0 -0
- {habiticalib-0.2.0a2 → habiticalib-0.3.0}/tests/fixtures/user_styles_snowball.json +0 -0
- {habiticalib-0.2.0a2 → habiticalib-0.3.0}/tests/fixtures/user_styles_spookySparkles.json +0 -0
- {habiticalib-0.2.0a2 → habiticalib-0.3.0}/tests/fixtures/user_styles_with_chair.json +0 -0
- {habiticalib-0.2.0a2 → habiticalib-0.3.0}/tests/test_avatar.py +0 -0
- {habiticalib-0.2.0a2 → habiticalib-0.3.0}/tests/test_init.py +0 -0
- {habiticalib-0.2.0a2 → habiticalib-0.3.0}/tests/test_lib.py +0 -0
@@ -39,6 +39,7 @@ autolabeler:
|
|
39
39
|
- label: 'feature'
|
40
40
|
title:
|
41
41
|
- '/adds/i'
|
42
|
+
- '/add method/i'
|
42
43
|
- label: 'bug'
|
43
44
|
title:
|
44
45
|
- '/fix/i'
|
@@ -48,6 +49,7 @@ autolabeler:
|
|
48
49
|
- label: 'testing'
|
49
50
|
title:
|
50
51
|
- '/test:/i'
|
52
|
+
- '/add test/i'
|
51
53
|
files:
|
52
54
|
- 'test_*'
|
53
55
|
- 'conftest.py'
|
@@ -78,12 +80,15 @@ version-resolver:
|
|
78
80
|
major:
|
79
81
|
labels:
|
80
82
|
- 'major'
|
83
|
+
- 'breaking'
|
81
84
|
minor:
|
82
85
|
labels:
|
83
86
|
- 'minor'
|
87
|
+
- 'feature'
|
84
88
|
patch:
|
85
89
|
labels:
|
86
90
|
- 'patch'
|
91
|
+
- 'bug'
|
87
92
|
default: patch
|
88
93
|
|
89
94
|
template: |
|
@@ -1,6 +1,6 @@
|
|
1
1
|
Metadata-Version: 2.3
|
2
2
|
Name: Habiticalib
|
3
|
-
Version: 0.
|
3
|
+
Version: 0.3.0
|
4
4
|
Summary: Asynchronous Python client library for the Habitica API
|
5
5
|
Project-URL: Documentation, https://tr4nt0r.github.io/habiticalib/
|
6
6
|
Project-URL: Source, https://github.com/tr4nt0r/habiticalib
|
@@ -11,6 +11,7 @@ Classifier: Operating System :: OS Independent
|
|
11
11
|
Classifier: Programming Language :: Python :: 3 :: Only
|
12
12
|
Requires-Python: >=3.12
|
13
13
|
Requires-Dist: aiohttp~=3.9
|
14
|
+
Requires-Dist: habitipy~=0.3.3
|
14
15
|
Requires-Dist: mashumaro~=3.13
|
15
16
|
Requires-Dist: orjson~=3.10
|
16
17
|
Requires-Dist: pillow~=11.0
|
@@ -24,7 +24,7 @@ indent-style = "space"
|
|
24
24
|
max-complexity = 25
|
25
25
|
|
26
26
|
[tool.ruff.lint.per-file-ignores]
|
27
|
-
"types.py" = ["N815"]
|
27
|
+
"types.py" = ["N815", "TCH003"]
|
28
28
|
"tests/*" = ["SLF001", "S101", "ARG001"]
|
29
29
|
|
30
30
|
[tool.pytest.ini_options]
|
@@ -66,20 +66,20 @@ path = "src/habiticalib/const.py"
|
|
66
66
|
[tool.hatch.envs.default]
|
67
67
|
python = "3.12"
|
68
68
|
dependencies = [
|
69
|
-
"aiohttp==3.
|
70
|
-
"mashumaro==3.
|
71
|
-
"orjson==3.10.
|
69
|
+
"aiohttp==3.11.7",
|
70
|
+
"mashumaro==3.15",
|
71
|
+
"orjson==3.10.12",
|
72
72
|
"Pillow==11.0.0",
|
73
|
-
"mypy==1.
|
74
|
-
"ruff==0.
|
73
|
+
"mypy==1.13.0",
|
74
|
+
"ruff==0.8.0",
|
75
75
|
"pytest==8.3.3",
|
76
|
-
"pytest-cov==
|
77
|
-
"mkdocs-material==9.5.
|
78
|
-
"mkdocstrings[python]==0.
|
76
|
+
"pytest-cov==6.0.0",
|
77
|
+
"mkdocs-material==9.5.45",
|
78
|
+
"mkdocstrings[python]==0.27.0",
|
79
79
|
"pytest-asyncio==0.24.0",
|
80
|
-
"aioresponses==0.7.
|
80
|
+
"aioresponses==0.7.7",
|
81
81
|
"pre-commit==4.0.1",
|
82
|
-
"syrupy==4.
|
82
|
+
"syrupy==4.8.0"
|
83
83
|
]
|
84
84
|
installer = "uv"
|
85
85
|
|
@@ -125,7 +125,8 @@ dependencies = [
|
|
125
125
|
"aiohttp~=3.9",
|
126
126
|
"mashumaro~=3.13",
|
127
127
|
"orjson~=3.10",
|
128
|
-
"Pillow~=11.0"
|
128
|
+
"Pillow~=11.0",
|
129
|
+
"habitipy~=0.3.3"
|
129
130
|
]
|
130
131
|
|
131
132
|
[project.urls]
|
@@ -8,9 +8,12 @@ from .exceptions import (
|
|
8
8
|
NotFoundError,
|
9
9
|
TooManyRequestsError,
|
10
10
|
)
|
11
|
+
from .helpers import deserialize_task
|
11
12
|
from .lib import Habitica
|
12
13
|
from .types import (
|
13
14
|
Attributes,
|
15
|
+
ChangeClassData,
|
16
|
+
ContentData,
|
14
17
|
Direction,
|
15
18
|
Frequency,
|
16
19
|
HabiticaClass,
|
@@ -29,22 +32,33 @@ from .types import (
|
|
29
32
|
HabiticaTaskOrderResponse,
|
30
33
|
HabiticaTaskResponse,
|
31
34
|
HabiticaTasksResponse,
|
35
|
+
HabiticaUserAnonymized,
|
32
36
|
HabiticaUserExport,
|
33
37
|
HabiticaUserResponse,
|
34
38
|
Language,
|
39
|
+
LoginData,
|
40
|
+
QuestData,
|
41
|
+
ScoreData,
|
35
42
|
Skill,
|
43
|
+
StatsUser,
|
44
|
+
TagsUser,
|
36
45
|
Task,
|
46
|
+
TaskData,
|
37
47
|
TaskFilter,
|
48
|
+
TaskPriority,
|
38
49
|
TaskType,
|
50
|
+
UserAnonymizedData,
|
51
|
+
UserData,
|
39
52
|
UserStyles,
|
40
53
|
)
|
41
54
|
|
42
55
|
__all__ = [
|
43
|
-
"__version__",
|
44
56
|
"ASSETS_URL",
|
57
|
+
"DEFAULT_URL",
|
45
58
|
"Attributes",
|
46
59
|
"BadRequestError",
|
47
|
-
"
|
60
|
+
"ChangeClassData",
|
61
|
+
"ContentData",
|
48
62
|
"Direction",
|
49
63
|
"Frequency",
|
50
64
|
"Habitica",
|
@@ -65,15 +79,27 @@ __all__ = [
|
|
65
79
|
"HabiticaTaskOrderResponse",
|
66
80
|
"HabiticaTaskResponse",
|
67
81
|
"HabiticaTasksResponse",
|
82
|
+
"HabiticaUserAnonymized",
|
68
83
|
"HabiticaUserExport",
|
69
84
|
"HabiticaUserResponse",
|
70
85
|
"Language",
|
86
|
+
"LoginData",
|
71
87
|
"NotAuthorizedError",
|
72
88
|
"NotFoundError",
|
89
|
+
"QuestData",
|
90
|
+
"ScoreData",
|
73
91
|
"Skill",
|
92
|
+
"StatsUser",
|
93
|
+
"TagsUser",
|
74
94
|
"Task",
|
95
|
+
"TaskData",
|
75
96
|
"TaskFilter",
|
97
|
+
"TaskPriority",
|
76
98
|
"TaskType",
|
77
99
|
"TooManyRequestsError",
|
100
|
+
"UserAnonymizedData",
|
101
|
+
"UserData",
|
78
102
|
"UserStyles",
|
103
|
+
"__version__",
|
104
|
+
"deserialize_task",
|
79
105
|
]
|
@@ -6,9 +6,10 @@ import asyncio
|
|
6
6
|
from http import HTTPStatus
|
7
7
|
from io import BytesIO
|
8
8
|
import logging
|
9
|
-
from typing import IO, TYPE_CHECKING, Self
|
9
|
+
from typing import IO, TYPE_CHECKING, Any, Self
|
10
10
|
|
11
11
|
from aiohttp import ClientError, ClientResponseError, ClientSession
|
12
|
+
from habitipy.aio import HabitipyAsync # type: ignore[import-untyped]
|
12
13
|
from PIL import Image
|
13
14
|
from yarl import URL
|
14
15
|
|
@@ -45,6 +46,7 @@ from .types import (
|
|
45
46
|
HabiticaTaskOrderResponse,
|
46
47
|
HabiticaTaskResponse,
|
47
48
|
HabiticaTasksResponse,
|
49
|
+
HabiticaUserAnonymized,
|
48
50
|
HabiticaUserExport,
|
49
51
|
HabiticaUserResponse,
|
50
52
|
Language,
|
@@ -206,10 +208,7 @@ class Habitica:
|
|
206
208
|
return response
|
207
209
|
|
208
210
|
async def get_user(
|
209
|
-
self,
|
210
|
-
user_fields: str | list[str] | None = None,
|
211
|
-
*,
|
212
|
-
anonymized: bool = False,
|
211
|
+
self, user_fields: str | list[str] | None = None
|
213
212
|
) -> HabiticaUserResponse:
|
214
213
|
"""Get the authenticated user's profile.
|
215
214
|
|
@@ -219,11 +218,6 @@ class Habitica:
|
|
219
218
|
A string or a list of fields to include in the response.
|
220
219
|
If provided as a list, the fields will be joined with commas.
|
221
220
|
If None, the full user profile document is returned. Default is None.
|
222
|
-
anonymized : bool
|
223
|
-
When True, returns the user's data without: Authentication information,
|
224
|
-
New Messages/Invitations/Inbox, Profile, Purchased information,
|
225
|
-
Contributor information, Special items, Webhooks, Notifications.
|
226
|
-
(default is False)
|
227
221
|
|
228
222
|
Returns
|
229
223
|
-------
|
@@ -253,13 +247,54 @@ class Habitica:
|
|
253
247
|
|
254
248
|
if user_fields:
|
255
249
|
params = {"userFields": join_fields(user_fields)}
|
256
|
-
if anonymized:
|
257
|
-
url = url / "anonymized"
|
258
250
|
|
259
251
|
return HabiticaUserResponse.from_json(
|
260
252
|
await self._request("get", url=url, params=params),
|
261
253
|
)
|
262
254
|
|
255
|
+
async def get_user_anonymized(
|
256
|
+
self,
|
257
|
+
) -> HabiticaUserAnonymized:
|
258
|
+
"""Get the authenticated user's anonymized profile.
|
259
|
+
|
260
|
+
This method retrieves the user's profile data while excluding sensitive
|
261
|
+
and personally identifiable information such as authentication details,
|
262
|
+
profile data, purchased items, contributor information, special items,
|
263
|
+
webhooks, and notifications.
|
264
|
+
|
265
|
+
Returns
|
266
|
+
-------
|
267
|
+
HabiticaUserAnonymized
|
268
|
+
A response object containing the anonymized user profile data.
|
269
|
+
|
270
|
+
|
271
|
+
Raises
|
272
|
+
------
|
273
|
+
NotAuthorizedError
|
274
|
+
If the API request is unauthorized (HTTP 401).
|
275
|
+
aiohttp.ClientResponseError
|
276
|
+
For other HTTP-related errors raised by aiohttp, such as HTTP 400 or 500.
|
277
|
+
aiohttp.ClientConnectionError
|
278
|
+
If the connection to the API fails.
|
279
|
+
aiohttp.ClientError
|
280
|
+
For any other exceptions raised by aiohttp during the request.
|
281
|
+
TimeoutError
|
282
|
+
If the connection times out.
|
283
|
+
|
284
|
+
Examples
|
285
|
+
--------
|
286
|
+
>>> response = await habitica.get_user_anonymized()
|
287
|
+
>>> response.data.user # Access the anonymized user data
|
288
|
+
>>> response.data.tasks # Access the user's anonymized tasks
|
289
|
+
"""
|
290
|
+
url = self.url / "api/v3/user"
|
291
|
+
|
292
|
+
url = url / "anonymized"
|
293
|
+
|
294
|
+
return HabiticaUserAnonymized.from_json(
|
295
|
+
await self._request("get", url=url),
|
296
|
+
)
|
297
|
+
|
263
298
|
async def get_tasks(
|
264
299
|
self,
|
265
300
|
task_type: TaskFilter | None = None,
|
@@ -1998,3 +2033,33 @@ class Habitica:
|
|
1998
2033
|
image.save(fp, fmt)
|
1999
2034
|
|
2000
2035
|
return user_styles
|
2036
|
+
|
2037
|
+
async def habitipy(self) -> HabitipyAsync:
|
2038
|
+
"""Create a Habitipy instance."""
|
2039
|
+
|
2040
|
+
_session = self._session
|
2041
|
+
_headers = self._headers
|
2042
|
+
loop = asyncio.get_running_loop()
|
2043
|
+
|
2044
|
+
class HAHabitipyAsync(HabitipyAsync):
|
2045
|
+
"""Closure API class to hold session."""
|
2046
|
+
|
2047
|
+
def __call__(self, **kwargs) -> Any:
|
2048
|
+
"""Pass session to habitipy."""
|
2049
|
+
return super().__call__(_session, **kwargs)
|
2050
|
+
|
2051
|
+
def _make_headers(self) -> dict[str, str]:
|
2052
|
+
"""Inject headers."""
|
2053
|
+
headers = super()._make_headers()
|
2054
|
+
headers.update(_headers)
|
2055
|
+
return headers
|
2056
|
+
|
2057
|
+
return await loop.run_in_executor(
|
2058
|
+
None,
|
2059
|
+
HAHabitipyAsync,
|
2060
|
+
{
|
2061
|
+
"url": str(self.url),
|
2062
|
+
"login": self._headers.get("X-API-USER"),
|
2063
|
+
"password": self._headers.get("X-API-KEY"),
|
2064
|
+
}, # type: ignore[var-annotated]
|
2065
|
+
)
|
@@ -8,7 +8,7 @@ import datetime as dt
|
|
8
8
|
from datetime import UTC, datetime
|
9
9
|
from enum import Enum, StrEnum
|
10
10
|
from typing import Any, NotRequired, TypedDict
|
11
|
-
from uuid import UUID
|
11
|
+
from uuid import UUID
|
12
12
|
|
13
13
|
from mashumaro import field_options
|
14
14
|
from mashumaro.mixins.orjson import DataClassORJSONMixin
|
@@ -1041,6 +1041,21 @@ class HabiticaUserExport(UserData, DataClassORJSONMixin):
|
|
1041
1041
|
tasks: TasksUserExport = field(default_factory=TasksUserExport)
|
1042
1042
|
|
1043
1043
|
|
1044
|
+
@dataclass
|
1045
|
+
class UserAnonymizedData:
|
1046
|
+
"""Anonymized user data."""
|
1047
|
+
|
1048
|
+
user: UserData = field(default_factory=UserData)
|
1049
|
+
tasks: list[TaskData] = field(default_factory=list)
|
1050
|
+
|
1051
|
+
|
1052
|
+
@dataclass(kw_only=True)
|
1053
|
+
class HabiticaUserAnonymized(DataClassORJSONMixin):
|
1054
|
+
"""Representation of a anonymized user data export."""
|
1055
|
+
|
1056
|
+
data: UserAnonymizedData
|
1057
|
+
|
1058
|
+
|
1044
1059
|
@dataclass(kw_only=True)
|
1045
1060
|
class HabiticaStatsResponse(HabiticaResponse):
|
1046
1061
|
"""Representation of a response containing stats data."""
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|