Habiticalib 0.1.0a3__py3-none-any.whl → 0.2.0__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- habiticalib/__init__.py +30 -0
- habiticalib/const.py +3 -1
- habiticalib/lib.py +484 -11
- habiticalib/types.py +419 -9
- {habiticalib-0.1.0a3.dist-info → habiticalib-0.2.0.dist-info}/METADATA +2 -1
- habiticalib-0.2.0.dist-info/RECORD +11 -0
- habiticalib-0.1.0a3.dist-info/RECORD +0 -11
- {habiticalib-0.1.0a3.dist-info → habiticalib-0.2.0.dist-info}/WHEEL +0 -0
- {habiticalib-0.1.0a3.dist-info → habiticalib-0.2.0.dist-info}/licenses/LICENSE +0 -0
habiticalib/__init__.py
CHANGED
@@ -8,17 +8,24 @@ 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,
|
17
20
|
HabiticaClassSystemResponse,
|
21
|
+
HabiticaContentResponse,
|
18
22
|
HabiticaErrorResponse,
|
23
|
+
HabiticaGroupMembersResponse,
|
19
24
|
HabiticaLoginResponse,
|
25
|
+
HabiticaQuestResponse,
|
20
26
|
HabiticaResponse,
|
21
27
|
HabiticaScoreResponse,
|
28
|
+
HabiticaSleepResponse,
|
22
29
|
HabiticaStatsResponse,
|
23
30
|
HabiticaTagResponse,
|
24
31
|
HabiticaTagsResponse,
|
@@ -28,10 +35,18 @@ from .types import (
|
|
28
35
|
HabiticaUserExport,
|
29
36
|
HabiticaUserResponse,
|
30
37
|
Language,
|
38
|
+
LoginData,
|
39
|
+
QuestData,
|
40
|
+
ScoreData,
|
31
41
|
Skill,
|
42
|
+
StatsUser,
|
43
|
+
TagsUser,
|
32
44
|
Task,
|
45
|
+
TaskData,
|
33
46
|
TaskFilter,
|
47
|
+
TaskPriority,
|
34
48
|
TaskType,
|
49
|
+
UserData,
|
35
50
|
UserStyles,
|
36
51
|
)
|
37
52
|
|
@@ -40,17 +55,24 @@ __all__ = [
|
|
40
55
|
"ASSETS_URL",
|
41
56
|
"Attributes",
|
42
57
|
"BadRequestError",
|
58
|
+
"ChangeClassData",
|
59
|
+
"ContentData",
|
43
60
|
"DEFAULT_URL",
|
61
|
+
"deserialize_task",
|
44
62
|
"Direction",
|
45
63
|
"Frequency",
|
46
64
|
"Habitica",
|
47
65
|
"HabiticaClass",
|
48
66
|
"HabiticaClassSystemResponse",
|
67
|
+
"HabiticaContentResponse",
|
49
68
|
"HabiticaErrorResponse",
|
50
69
|
"HabiticaException",
|
70
|
+
"HabiticaGroupMembersResponse",
|
51
71
|
"HabiticaLoginResponse",
|
72
|
+
"HabiticaQuestResponse",
|
52
73
|
"HabiticaResponse",
|
53
74
|
"HabiticaScoreResponse",
|
75
|
+
"HabiticaSleepResponse",
|
54
76
|
"HabiticaStatsResponse",
|
55
77
|
"HabiticaTagResponse",
|
56
78
|
"HabiticaTagsResponse",
|
@@ -60,12 +82,20 @@ __all__ = [
|
|
60
82
|
"HabiticaUserExport",
|
61
83
|
"HabiticaUserResponse",
|
62
84
|
"Language",
|
85
|
+
"LoginData",
|
63
86
|
"NotAuthorizedError",
|
64
87
|
"NotFoundError",
|
88
|
+
"QuestData",
|
89
|
+
"ScoreData",
|
65
90
|
"Skill",
|
91
|
+
"StatsUser",
|
92
|
+
"TagsUser",
|
66
93
|
"Task",
|
94
|
+
"TaskData",
|
67
95
|
"TaskFilter",
|
96
|
+
"TaskPriority",
|
68
97
|
"TaskType",
|
69
98
|
"TooManyRequestsError",
|
99
|
+
"UserData",
|
70
100
|
"UserStyles",
|
71
101
|
]
|
habiticalib/const.py
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
"""Constants for Habiticalib."""
|
2
2
|
|
3
|
-
__version__ = "0.
|
3
|
+
__version__ = "0.2.0"
|
4
4
|
|
5
5
|
DEFAULT_URL = "https://habitica.com/"
|
6
6
|
ASSETS_URL = "https://habitica-assets.s3.amazonaws.com/mobileApp/images/"
|
@@ -14,3 +14,5 @@ BACKER_ONLY_GEAR = {
|
|
14
14
|
"shield_special_ks2019": "BackerOnly-Equip-MythicGryphonShield.gif",
|
15
15
|
"weapon_special_ks2019": "BackerOnly-Equip-MythicGryphonGlaive.gif",
|
16
16
|
}
|
17
|
+
|
18
|
+
PAGE_LIMIT = 60
|
habiticalib/lib.py
CHANGED
@@ -6,13 +6,14 @@ 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
|
|
15
|
-
from .const import ASSETS_URL, BACKER_ONLY_GEAR, DEFAULT_URL
|
16
|
+
from .const import ASSETS_URL, BACKER_ONLY_GEAR, DEFAULT_URL, PAGE_LIMIT
|
16
17
|
from .exceptions import (
|
17
18
|
BadRequestError,
|
18
19
|
NotAuthorizedError,
|
@@ -31,10 +32,14 @@ from .types import (
|
|
31
32
|
Direction,
|
32
33
|
HabiticaClass,
|
33
34
|
HabiticaClassSystemResponse,
|
35
|
+
HabiticaContentResponse,
|
34
36
|
HabiticaErrorResponse,
|
37
|
+
HabiticaGroupMembersResponse,
|
35
38
|
HabiticaLoginResponse,
|
39
|
+
HabiticaQuestResponse,
|
36
40
|
HabiticaResponse,
|
37
41
|
HabiticaScoreResponse,
|
42
|
+
HabiticaSleepResponse,
|
38
43
|
HabiticaStatsResponse,
|
39
44
|
HabiticaTagResponse,
|
40
45
|
HabiticaTagsResponse,
|
@@ -260,14 +265,15 @@ class Habitica:
|
|
260
265
|
self,
|
261
266
|
task_type: TaskFilter | None = None,
|
262
267
|
due_date: datetime | None = None,
|
263
|
-
) ->
|
268
|
+
) -> HabiticaTasksResponse:
|
264
269
|
"""Get the authenticated user's tasks.
|
265
270
|
|
266
271
|
Parameters
|
267
272
|
----------
|
268
273
|
task_type : TaskFilter | None
|
269
274
|
The type of task to retrieve, defined in TaskFilter enum.
|
270
|
-
If `None`, all task types will be retrieved
|
275
|
+
If `None`, all task types will be retrieved except completed to-dos
|
276
|
+
(default is None).
|
271
277
|
|
272
278
|
due_date : datetime | None
|
273
279
|
Optional date to use for computing the nextDue field for each returned task.
|
@@ -455,7 +461,7 @@ class Habitica:
|
|
455
461
|
Returns
|
456
462
|
-------
|
457
463
|
HabiticaTaskResponse
|
458
|
-
A response
|
464
|
+
A response containing an empty data object.
|
459
465
|
|
460
466
|
Raises
|
461
467
|
------
|
@@ -559,7 +565,7 @@ class Habitica:
|
|
559
565
|
async def get_content(
|
560
566
|
self,
|
561
567
|
language: Language | None = None,
|
562
|
-
) ->
|
568
|
+
) -> HabiticaContentResponse:
|
563
569
|
"""
|
564
570
|
Fetch game content from the Habitica API.
|
565
571
|
|
@@ -601,7 +607,7 @@ class Habitica:
|
|
601
607
|
if language:
|
602
608
|
params.update({"language": language.value})
|
603
609
|
|
604
|
-
return
|
610
|
+
return HabiticaContentResponse.from_json(
|
605
611
|
await self._request("get", url=url, params=params),
|
606
612
|
)
|
607
613
|
|
@@ -848,17 +854,17 @@ class Habitica:
|
|
848
854
|
if target_id:
|
849
855
|
params.update({"targetId": str(target_id)})
|
850
856
|
return HabiticaUserResponse.from_json(
|
851
|
-
await self._request("post", url=url,
|
857
|
+
await self._request("post", url=url, params=params),
|
852
858
|
)
|
853
859
|
|
854
860
|
async def toggle_sleep(
|
855
861
|
self,
|
856
|
-
) ->
|
862
|
+
) -> HabiticaSleepResponse:
|
857
863
|
"""Toggles the user's sleep mode in Habitica.
|
858
864
|
|
859
865
|
Returns
|
860
866
|
-------
|
861
|
-
|
867
|
+
HabiticaSleepResponse
|
862
868
|
A response object containing the result of the sleep mode toggle,
|
863
869
|
and the new sleep state (True if sleeping, False if not).
|
864
870
|
|
@@ -875,7 +881,7 @@ class Habitica:
|
|
875
881
|
"""
|
876
882
|
url = self.url / "api/v3/user/sleep"
|
877
883
|
|
878
|
-
return
|
884
|
+
return HabiticaSleepResponse.from_json(await self._request("post", url=url))
|
879
885
|
|
880
886
|
async def revive(
|
881
887
|
self,
|
@@ -1280,6 +1286,443 @@ class Habitica:
|
|
1280
1286
|
await self._request("post", url=url, json=json),
|
1281
1287
|
)
|
1282
1288
|
|
1289
|
+
async def get_group_members(
|
1290
|
+
self,
|
1291
|
+
group_id: UUID | None = None,
|
1292
|
+
*,
|
1293
|
+
limit: int | None = None,
|
1294
|
+
tasks: bool = False,
|
1295
|
+
public_fields: bool = False,
|
1296
|
+
last_id: UUID | None = None,
|
1297
|
+
) -> HabiticaGroupMembersResponse:
|
1298
|
+
"""Get members of the party or a specific group.
|
1299
|
+
|
1300
|
+
This method retrieves a list of members for a party or a specified group
|
1301
|
+
from the Habitica API. Additional options allow including tasks or public
|
1302
|
+
through results if necessary to collect all members. If the API rate limit is
|
1303
|
+
exceeded, the method will pause for the duration specified in the `retry-after`
|
1304
|
+
header and retry the request.
|
1305
|
+
|
1306
|
+
|
1307
|
+
Parameters
|
1308
|
+
----------
|
1309
|
+
group_id : UUID, optional
|
1310
|
+
The UUID of the group. Defaults to the user's party if not specified.
|
1311
|
+
limit : int, optional
|
1312
|
+
Maximum number of members per request (default: 30, max: 60).
|
1313
|
+
tasks : bool, optional
|
1314
|
+
Whether to include tasks associated with the group.
|
1315
|
+
public_fields : bool, optional
|
1316
|
+
Whether to include all public fields for group members.
|
1317
|
+
last_id : UUID, optional
|
1318
|
+
For paginated requests, the UUID of the last member retrieved.
|
1319
|
+
|
1320
|
+
Returns
|
1321
|
+
-------
|
1322
|
+
HabiticaGroupMembersResponse
|
1323
|
+
A response object containing the group member data.
|
1324
|
+
|
1325
|
+
Raises
|
1326
|
+
------
|
1327
|
+
aiohttp.ClientResponseError
|
1328
|
+
For HTTP-related errors, such as HTTP 400 or 500 response status.
|
1329
|
+
aiohttp.ClientConnectionError
|
1330
|
+
If the connection to the API fails.
|
1331
|
+
aiohttp.ClientError
|
1332
|
+
For any other exceptions raised by aiohttp during the request.
|
1333
|
+
TimeoutError
|
1334
|
+
If the connection times out.
|
1335
|
+
|
1336
|
+
Examples
|
1337
|
+
--------
|
1338
|
+
>>> members_response = await habitica.get_group_members()
|
1339
|
+
>>> for member in members_response.data:
|
1340
|
+
... print(member.profile.name)
|
1341
|
+
"""
|
1342
|
+
|
1343
|
+
if limit is not None and (limit < 1 or limit > PAGE_LIMIT):
|
1344
|
+
msg = f"The 'limit' parameter must be between 1 and {PAGE_LIMIT}."
|
1345
|
+
raise ValueError(msg)
|
1346
|
+
|
1347
|
+
group = "party" if not group_id else str(group_id)
|
1348
|
+
url = self.url / "api/v3/groups" / group / "members"
|
1349
|
+
|
1350
|
+
params: dict[str, str | int] = {}
|
1351
|
+
|
1352
|
+
if tasks:
|
1353
|
+
params["includeTasks"] = "true"
|
1354
|
+
if public_fields:
|
1355
|
+
params["includeAllPublicFields"] = "true"
|
1356
|
+
if last_id:
|
1357
|
+
params["lastId"] = str(last_id)
|
1358
|
+
if limit:
|
1359
|
+
params["limit"] = limit
|
1360
|
+
|
1361
|
+
while True:
|
1362
|
+
try:
|
1363
|
+
response = HabiticaGroupMembersResponse.from_json(
|
1364
|
+
await self._request("get", url=url, params=params),
|
1365
|
+
)
|
1366
|
+
break
|
1367
|
+
except TooManyRequestsError as e:
|
1368
|
+
await asyncio.sleep(e.retry_after)
|
1369
|
+
|
1370
|
+
if len(response.data) == limit:
|
1371
|
+
next_page = await self.get_group_members(
|
1372
|
+
group_id=group_id,
|
1373
|
+
limit=limit,
|
1374
|
+
tasks=tasks,
|
1375
|
+
public_fields=public_fields,
|
1376
|
+
last_id=response.data[-1].id,
|
1377
|
+
)
|
1378
|
+
response.data.extend(next_page.data)
|
1379
|
+
|
1380
|
+
return response
|
1381
|
+
|
1382
|
+
async def abort_quest(self, group_id: UUID | None = None) -> HabiticaQuestResponse:
|
1383
|
+
"""Abort an active quest for the party or a specific group.
|
1384
|
+
|
1385
|
+
Prematurely terminates an ongoing quest, causing all progress to be lost.
|
1386
|
+
The quest scroll will be returned to the owner's inventory.
|
1387
|
+
Only the quest leader or group leader is allowed to perform this action.
|
1388
|
+
|
1389
|
+
Parameters
|
1390
|
+
----------
|
1391
|
+
group_id : UUID, optional
|
1392
|
+
The UUID of the specific group whose quest should be aborted.
|
1393
|
+
Defaults to the user's party if not specified.
|
1394
|
+
|
1395
|
+
Returns
|
1396
|
+
-------
|
1397
|
+
HabiticaQuestResponse
|
1398
|
+
A response object containing updated quest data of the group or party.
|
1399
|
+
|
1400
|
+
Raises
|
1401
|
+
------
|
1402
|
+
NotFoundError
|
1403
|
+
If the specified group or quest could not be found.
|
1404
|
+
NotAuthorizedError
|
1405
|
+
If the user does not have permission to abort the quest.
|
1406
|
+
aiohttp.ClientResponseError
|
1407
|
+
For HTTP-related errors, such as HTTP 400 or 500 response status.
|
1408
|
+
aiohttp.ClientConnectionError
|
1409
|
+
If the connection to the API fails.
|
1410
|
+
aiohttp.ClientError
|
1411
|
+
For any other exceptions raised by aiohttp during the request.
|
1412
|
+
TimeoutError
|
1413
|
+
If the connection times out.
|
1414
|
+
|
1415
|
+
Examples
|
1416
|
+
--------
|
1417
|
+
Abort the party's current quest:
|
1418
|
+
>>> response = await habitica.abort_quest()
|
1419
|
+
>>> print(response.success) # True if the quest was successfully aborted.
|
1420
|
+
|
1421
|
+
Abort a quest for a specific group:
|
1422
|
+
>>> group_id = UUID("12345678-1234-5678-1234-567812345678")
|
1423
|
+
>>> response = await habitica.abort_quest(group_id)
|
1424
|
+
>>> print(response.success) # True if the quest was successfully aborted.
|
1425
|
+
"""
|
1426
|
+
group = "party" if not group_id else str(group_id)
|
1427
|
+
url = self.url / "api/v3/groups" / group / "quests/abort"
|
1428
|
+
|
1429
|
+
return HabiticaQuestResponse.from_json(
|
1430
|
+
await self._request("post", url=url),
|
1431
|
+
)
|
1432
|
+
|
1433
|
+
async def accept_quest(self, group_id: UUID | None = None) -> HabiticaQuestResponse:
|
1434
|
+
"""Accept a pending invitation to a quest from the party or a specific group.
|
1435
|
+
|
1436
|
+
Allows a user to accept an invitation to participate in a quest within a
|
1437
|
+
specified group.
|
1438
|
+
|
1439
|
+
Parameters
|
1440
|
+
----------
|
1441
|
+
group_id : UUID, optional
|
1442
|
+
The UUID of the group for which the quest invitation is being accepted.
|
1443
|
+
Defaults to the user's party if not specified.
|
1444
|
+
|
1445
|
+
|
1446
|
+
Returns
|
1447
|
+
-------
|
1448
|
+
HabiticaQuestResponse
|
1449
|
+
A response object containing updated quest data of the group or party.
|
1450
|
+
|
1451
|
+
Raises
|
1452
|
+
------
|
1453
|
+
NotFoundError
|
1454
|
+
If the specified group or quest could not be found.
|
1455
|
+
aiohttp.ClientResponseError
|
1456
|
+
Raised for HTTP-related errors, such as HTTP 400 or 500 response status.
|
1457
|
+
aiohttp.ClientConnectionError
|
1458
|
+
If the connection to the API fails.
|
1459
|
+
aiohttp.ClientError
|
1460
|
+
Raised for any other exceptions encountered by `aiohttp` during the request.
|
1461
|
+
TimeoutError
|
1462
|
+
If the connection to the API times out.
|
1463
|
+
|
1464
|
+
Examples
|
1465
|
+
--------
|
1466
|
+
Accept a pending quest invitation from the party:
|
1467
|
+
>>> response = await habitica.accept_quest()
|
1468
|
+
>>> print(response.success) # True if the quest invitation was successfully accepted.
|
1469
|
+
"""
|
1470
|
+
group = "party" if not group_id else str(group_id)
|
1471
|
+
url = self.url / "api/v3/groups" / group / "quests/accept"
|
1472
|
+
|
1473
|
+
return HabiticaQuestResponse.from_json(
|
1474
|
+
await self._request("post", url=url),
|
1475
|
+
)
|
1476
|
+
|
1477
|
+
async def reject_quest(self, group_id: UUID | None = None) -> HabiticaQuestResponse:
|
1478
|
+
"""Reject a pending quest invitation from the party or a specific group.
|
1479
|
+
|
1480
|
+
Allows a user to reject an invitation to participate in a quest within a
|
1481
|
+
specified group. The user will not join the quest and will be excluded from
|
1482
|
+
its progress and rewards.
|
1483
|
+
|
1484
|
+
Parameters
|
1485
|
+
----------
|
1486
|
+
group_id : UUID, optional
|
1487
|
+
The UUID of the group for which the quest invitation is being rejected.
|
1488
|
+
Defaults to the user's party if not specified.
|
1489
|
+
|
1490
|
+
|
1491
|
+
Returns
|
1492
|
+
-------
|
1493
|
+
HabiticaQuestResponse
|
1494
|
+
A response object containing updated quest data of the group or party.
|
1495
|
+
|
1496
|
+
Raises
|
1497
|
+
------
|
1498
|
+
NotFoundError
|
1499
|
+
If the specified group or quest could not be found.
|
1500
|
+
aiohttp.ClientResponseError
|
1501
|
+
Raised for HTTP-related errors, such as HTTP 400 or 500 response status.
|
1502
|
+
aiohttp.ClientConnectionError
|
1503
|
+
If the connection to the API fails.
|
1504
|
+
aiohttp.ClientError
|
1505
|
+
Raised for any other exceptions encountered by `aiohttp` during the request.
|
1506
|
+
TimeoutError
|
1507
|
+
If the connection to the API times out.
|
1508
|
+
|
1509
|
+
Examples
|
1510
|
+
--------
|
1511
|
+
Reject a pending quest invitation from the party:
|
1512
|
+
>>> response = await habitica.reject_quest()
|
1513
|
+
>>> print(response.success) # True if the quest invitation was successfully rejected.
|
1514
|
+
|
1515
|
+
Reject a pending quest invitation from a specific group:
|
1516
|
+
>>> group_id = UUID("12345678-1234-5678-1234-567812345678")
|
1517
|
+
>>> response = await habitica.reject_quest(group_id)
|
1518
|
+
>>> print(response.success) # True if the quest invitation was successfully rejected.
|
1519
|
+
"""
|
1520
|
+
group = "party" if not group_id else str(group_id)
|
1521
|
+
url = self.url / "api/v3/groups" / group / "quests/reject"
|
1522
|
+
|
1523
|
+
return HabiticaQuestResponse.from_json(
|
1524
|
+
await self._request("post", url=url),
|
1525
|
+
)
|
1526
|
+
|
1527
|
+
async def cancel_quest(self, group_id: UUID | None = None) -> HabiticaQuestResponse:
|
1528
|
+
"""Cancel a pending quest for the party or a specific group.
|
1529
|
+
|
1530
|
+
Cancel a quest that has not yet startet. All accepted and pending invitations
|
1531
|
+
will be canceled and the quest roll returned to the owner's inventory.
|
1532
|
+
Only quest leader or group leader can perform this action.
|
1533
|
+
|
1534
|
+
Parameters
|
1535
|
+
----------
|
1536
|
+
group_id : UUID, optional
|
1537
|
+
The UUID of the group for which the quest is being canceled.
|
1538
|
+
Defaults to the user's party if not specified.
|
1539
|
+
|
1540
|
+
Returns
|
1541
|
+
-------
|
1542
|
+
HabiticaQuestResponse
|
1543
|
+
A response object containing details about the canceled quest.
|
1544
|
+
|
1545
|
+
Raises
|
1546
|
+
------
|
1547
|
+
NotFoundError
|
1548
|
+
If the specified group or quest could not be found.
|
1549
|
+
NotAuthorizedError
|
1550
|
+
If the user does not have permission to cancel the quest.
|
1551
|
+
aiohttp.ClientResponseError
|
1552
|
+
Raised for HTTP-related errors, such as HTTP 400 or 500 response status.
|
1553
|
+
aiohttp.ClientConnectionError
|
1554
|
+
If the connection to the API fails.
|
1555
|
+
aiohttp.ClientError
|
1556
|
+
Raised for any other exceptions encountered by `aiohttp` during the request.
|
1557
|
+
TimeoutError
|
1558
|
+
If the connection to the API times out.
|
1559
|
+
|
1560
|
+
Examples
|
1561
|
+
--------
|
1562
|
+
Cancel a pending quest for the party:
|
1563
|
+
>>> response = await habitica.cancel_quest()
|
1564
|
+
>>> print(response.success) # True if the quest was successfully canceled.
|
1565
|
+
"""
|
1566
|
+
group = "party" if not group_id else str(group_id)
|
1567
|
+
url = self.url / "api/v3/groups" / group / "quests/cancel"
|
1568
|
+
|
1569
|
+
return HabiticaQuestResponse.from_json(
|
1570
|
+
await self._request("post", url=url),
|
1571
|
+
)
|
1572
|
+
|
1573
|
+
async def start_quest(self, group_id: UUID | None = None) -> HabiticaQuestResponse:
|
1574
|
+
"""Force-start a quest for the party or a specific group.
|
1575
|
+
|
1576
|
+
Begins a quest immediately, bypassing any pending invitations that haven't been
|
1577
|
+
accepted or rejected.
|
1578
|
+
Only quest leader or group leader can perform this action.
|
1579
|
+
|
1580
|
+
Parameters
|
1581
|
+
----------
|
1582
|
+
group_id : UUID, optional
|
1583
|
+
The UUID of the group for which the quest should be started.
|
1584
|
+
Defaults to the user's party if not specified.
|
1585
|
+
|
1586
|
+
|
1587
|
+
Returns
|
1588
|
+
-------
|
1589
|
+
HabiticaQuestResponse
|
1590
|
+
A response object containing updated quest data of the group or party.
|
1591
|
+
|
1592
|
+
Raises
|
1593
|
+
------
|
1594
|
+
NotFoundError
|
1595
|
+
If the specified group or quest could not be found.
|
1596
|
+
NotAuthorizedError
|
1597
|
+
If the user does not have permission to start the quest.
|
1598
|
+
aiohttp.ClientResponseError
|
1599
|
+
Raised for HTTP-related errors, such as HTTP 400 or 500 response status.
|
1600
|
+
aiohttp.ClientConnectionError
|
1601
|
+
If the connection to the API fails.
|
1602
|
+
aiohttp.ClientError
|
1603
|
+
Raised for any other exceptions encountered by `aiohttp` during the request.
|
1604
|
+
TimeoutError
|
1605
|
+
If the connection to the API times out.
|
1606
|
+
|
1607
|
+
Examples
|
1608
|
+
--------
|
1609
|
+
Cancel a pending quest for the party:
|
1610
|
+
>>> response = await habitica.cancel_quest()
|
1611
|
+
>>> print(response.success) # True if the quest was successfully canceled.
|
1612
|
+
"""
|
1613
|
+
group = "party" if not group_id else str(group_id)
|
1614
|
+
url = self.url / "api/v3/groups" / group / "quests/force-start"
|
1615
|
+
|
1616
|
+
return HabiticaQuestResponse.from_json(
|
1617
|
+
await self._request("post", url=url),
|
1618
|
+
)
|
1619
|
+
|
1620
|
+
async def invite_quest(
|
1621
|
+
self,
|
1622
|
+
group_id: UUID | None = None,
|
1623
|
+
*,
|
1624
|
+
quest_key: str,
|
1625
|
+
) -> HabiticaQuestResponse:
|
1626
|
+
"""Invite members of the party or a specific group to participate in a quest.
|
1627
|
+
|
1628
|
+
Sends invitations for a quest to all eligible members of the specified group.
|
1629
|
+
The quest is started when all members accept or reject the invitation.
|
1630
|
+
|
1631
|
+
Parameters
|
1632
|
+
----------
|
1633
|
+
group_id : UUID, optional
|
1634
|
+
The UUID of the group for which the quest invitations should be sent.
|
1635
|
+
Defaults to the user's party if not specified.
|
1636
|
+
quest_key : str
|
1637
|
+
The unique key identifying the quest to invite members to.
|
1638
|
+
|
1639
|
+
Returns
|
1640
|
+
-------
|
1641
|
+
HabiticaQuestResponse
|
1642
|
+
A response object containing updated quest data of the group or party.
|
1643
|
+
|
1644
|
+
Raises
|
1645
|
+
------
|
1646
|
+
NotFoundError
|
1647
|
+
If the specified group or quest could not be found.
|
1648
|
+
aiohttp.ClientResponseError
|
1649
|
+
Raised for HTTP-related errors, such as HTTP 400 or 500 response status.
|
1650
|
+
aiohttp.ClientConnectionError
|
1651
|
+
If the connection to the API fails.
|
1652
|
+
aiohttp.ClientError
|
1653
|
+
Raised for any other exceptions encountered by `aiohttp` during the request.
|
1654
|
+
TimeoutError
|
1655
|
+
If the connection to the API times out.
|
1656
|
+
|
1657
|
+
Examples
|
1658
|
+
--------
|
1659
|
+
Send a quest invitation to the party:
|
1660
|
+
>>> response = await habitica.invite_quest(quest_key="dilatory_derby")
|
1661
|
+
>>> print(response.success) # True if invitations were successfully sent.
|
1662
|
+
|
1663
|
+
Send a quest invitation to a specific group:
|
1664
|
+
>>> group_id = UUID("12345678-1234-5678-1234-567812345678")
|
1665
|
+
>>> response = await habitica.invite_quest(group_id, quest_key="golden_knight")
|
1666
|
+
>>> print(response.success) # True if invitations were successfully sent.
|
1667
|
+
"""
|
1668
|
+
group = "party" if not group_id else str(group_id)
|
1669
|
+
url = self.url / "api/v3/groups" / group / "quests/invite" / quest_key
|
1670
|
+
|
1671
|
+
return HabiticaQuestResponse.from_json(
|
1672
|
+
await self._request("post", url=url),
|
1673
|
+
)
|
1674
|
+
|
1675
|
+
async def leave_quest(self, group_id: UUID | None = None) -> HabiticaQuestResponse:
|
1676
|
+
"""Leave the current quest from the party or a specific group.
|
1677
|
+
|
1678
|
+
Allows a user to exit an ongoing quest they are part of. This action removes
|
1679
|
+
them from the quest but does not affect its progress for other participants.
|
1680
|
+
Users who leave a quest will not contribute to its completion or receive rewards.
|
1681
|
+
|
1682
|
+
Parameters
|
1683
|
+
----------
|
1684
|
+
group_id : UUID, optional
|
1685
|
+
The UUID of the group associated with the quest the user is leaving.
|
1686
|
+
Defaults to the user's party if not specified.
|
1687
|
+
quest_key : str
|
1688
|
+
The unique key identifying the quest to invite members to.
|
1689
|
+
|
1690
|
+
Returns
|
1691
|
+
-------
|
1692
|
+
HabiticaQuestResponse
|
1693
|
+
A response object containing updated quest data of the group or party.
|
1694
|
+
|
1695
|
+
Raises
|
1696
|
+
------
|
1697
|
+
NotFoundError
|
1698
|
+
If the specified group or quest could not be found.
|
1699
|
+
aiohttp.ClientResponseError
|
1700
|
+
Raised for HTTP-related errors, such as HTTP 400 or 500 response status.
|
1701
|
+
aiohttp.ClientConnectionError
|
1702
|
+
If the connection to the API fails.
|
1703
|
+
aiohttp.ClientError
|
1704
|
+
Raised for any other exceptions encountered by `aiohttp` during the request.
|
1705
|
+
TimeoutError
|
1706
|
+
If the connection to the API times out.
|
1707
|
+
|
1708
|
+
Examples
|
1709
|
+
--------
|
1710
|
+
Leave the current quest in the user's party:
|
1711
|
+
>>> response = await habitica.leave_quest()
|
1712
|
+
>>> print(response.success) # True if the user successfully left the quest.
|
1713
|
+
|
1714
|
+
Leave the current quest in a specific group:
|
1715
|
+
>>> group_id = UUID("12345678-1234-5678-1234-567812345678")
|
1716
|
+
>>> response = await habitica.leave_quest(group_id)
|
1717
|
+
>>> print(response.success) # True if the user successfully left the quest.
|
1718
|
+
"""
|
1719
|
+
group = "party" if not group_id else str(group_id)
|
1720
|
+
url = self.url / "api/v3/groups" / group / "quests/leave"
|
1721
|
+
|
1722
|
+
return HabiticaQuestResponse.from_json(
|
1723
|
+
await self._request("post", url=url),
|
1724
|
+
)
|
1725
|
+
|
1283
1726
|
def _cache_asset(self, asset: str, asset_data: IO[bytes]) -> None:
|
1284
1727
|
"""Cache an asset and maintain the cache size limit by removing older entries.
|
1285
1728
|
|
@@ -1556,3 +1999,33 @@ class Habitica:
|
|
1556
1999
|
image.save(fp, fmt)
|
1557
2000
|
|
1558
2001
|
return user_styles
|
2002
|
+
|
2003
|
+
async def habitipy(self) -> HabitipyAsync:
|
2004
|
+
"""Create a Habitipy instance."""
|
2005
|
+
|
2006
|
+
_session = self._session
|
2007
|
+
_headers = self._headers
|
2008
|
+
loop = asyncio.get_running_loop()
|
2009
|
+
|
2010
|
+
class HAHabitipyAsync(HabitipyAsync):
|
2011
|
+
"""Closure API class to hold session."""
|
2012
|
+
|
2013
|
+
def __call__(self, **kwargs) -> Any:
|
2014
|
+
"""Pass session to habitipy."""
|
2015
|
+
return super().__call__(_session, **kwargs)
|
2016
|
+
|
2017
|
+
def _make_headers(self) -> dict[str, str]:
|
2018
|
+
"""Inject headers."""
|
2019
|
+
headers = super()._make_headers()
|
2020
|
+
headers.update(_headers)
|
2021
|
+
return headers
|
2022
|
+
|
2023
|
+
return await loop.run_in_executor(
|
2024
|
+
None,
|
2025
|
+
HAHabitipyAsync,
|
2026
|
+
{
|
2027
|
+
"url": str(self.url),
|
2028
|
+
"login": self._headers.get("X-API-USER"),
|
2029
|
+
"password": self._headers.get("X-API-KEY"),
|
2030
|
+
}, # type: ignore[var-annotated]
|
2031
|
+
)
|
habiticalib/types.py
CHANGED
@@ -591,7 +591,7 @@ class PreferencesUser:
|
|
591
591
|
webhooks: dict = field(default_factory=dict)
|
592
592
|
improvementCategories: list[str] = field(default_factory=list)
|
593
593
|
timezoneOffsetAtLastCron: int | None = None
|
594
|
-
language:
|
594
|
+
language: Language | None = None
|
595
595
|
|
596
596
|
|
597
597
|
@dataclass(kw_only=True)
|
@@ -662,13 +662,6 @@ class StatsUser:
|
|
662
662
|
Int: int | None = field(default=None, metadata=field_options(alias="int"))
|
663
663
|
|
664
664
|
|
665
|
-
field(
|
666
|
-
metadata=field_options(
|
667
|
-
deserialize=serialize_datetime,
|
668
|
-
)
|
669
|
-
)
|
670
|
-
|
671
|
-
|
672
665
|
@dataclass(kw_only=True)
|
673
666
|
class TagsUser:
|
674
667
|
"""Tags user data."""
|
@@ -777,6 +770,13 @@ class HabiticaUserResponse(HabiticaResponse):
|
|
777
770
|
data: UserData
|
778
771
|
|
779
772
|
|
773
|
+
@dataclass(kw_only=True)
|
774
|
+
class HabiticaGroupMembersResponse(HabiticaResponse):
|
775
|
+
"""Representation of a group members data response."""
|
776
|
+
|
777
|
+
data: list[UserData]
|
778
|
+
|
779
|
+
|
780
780
|
@dataclass(kw_only=True)
|
781
781
|
class CompletedBy:
|
782
782
|
"""Task group completedby data."""
|
@@ -1107,6 +1107,25 @@ class HabiticaTagResponse(HabiticaResponse, DataClassORJSONMixin):
|
|
1107
1107
|
data: TagsUser
|
1108
1108
|
|
1109
1109
|
|
1110
|
+
@dataclass(kw_only=True)
|
1111
|
+
class QuestData:
|
1112
|
+
"""Quest data."""
|
1113
|
+
|
1114
|
+
progress: ProgressQuest = field(default_factory=ProgressQuest)
|
1115
|
+
active: bool = False
|
1116
|
+
members: dict[str, bool | None]
|
1117
|
+
extra: dict | None = None
|
1118
|
+
key: str
|
1119
|
+
leader: UUID | None = None
|
1120
|
+
|
1121
|
+
|
1122
|
+
@dataclass(kw_only=True)
|
1123
|
+
class HabiticaQuestResponse(HabiticaResponse, DataClassORJSONMixin):
|
1124
|
+
"""Representation of a quest response."""
|
1125
|
+
|
1126
|
+
data: QuestData
|
1127
|
+
|
1128
|
+
|
1110
1129
|
@dataclass
|
1111
1130
|
class ChangeClassData:
|
1112
1131
|
"""Change class data."""
|
@@ -1131,6 +1150,13 @@ class HabiticaTaskOrderResponse(HabiticaResponse):
|
|
1131
1150
|
data: list[UUID] = field(default_factory=list)
|
1132
1151
|
|
1133
1152
|
|
1153
|
+
@dataclass
|
1154
|
+
class HabiticaSleepResponse(HabiticaResponse):
|
1155
|
+
"""Representation of a sleep response."""
|
1156
|
+
|
1157
|
+
data: bool
|
1158
|
+
|
1159
|
+
|
1134
1160
|
class TaskFilter(StrEnum):
|
1135
1161
|
"""Enum representing the valid types of tasks for requests."""
|
1136
1162
|
|
@@ -1187,7 +1213,7 @@ class Skill(StrEnum):
|
|
1187
1213
|
VALOROUS_PRESENCE = "valorousPresence"
|
1188
1214
|
INTIMIDATING_GAZE = "intimidate"
|
1189
1215
|
# Rogue skills
|
1190
|
-
PICKPOCKET = "
|
1216
|
+
PICKPOCKET = "pickPocket"
|
1191
1217
|
BACKSTAB = "backStab"
|
1192
1218
|
TOOLS_OF_THE_TRADE = "toolsOfTrade"
|
1193
1219
|
STEALTH = "stealth"
|
@@ -1222,3 +1248,387 @@ class TaskPriority(Enum):
|
|
1222
1248
|
EASY = 1
|
1223
1249
|
MEDIUM = 1.5
|
1224
1250
|
HARD = 2
|
1251
|
+
|
1252
|
+
|
1253
|
+
@dataclass
|
1254
|
+
class AchievmentContent:
|
1255
|
+
"""Achievment content data."""
|
1256
|
+
|
1257
|
+
icon: str
|
1258
|
+
key: str
|
1259
|
+
titleKey: str | None = None
|
1260
|
+
textKey: str | None = None
|
1261
|
+
singularTitleKey: str | None = None
|
1262
|
+
singularTextKey: str | None = None
|
1263
|
+
pluralTitleKey: str | None = None
|
1264
|
+
pluralTextKey: str | None = None
|
1265
|
+
|
1266
|
+
|
1267
|
+
@dataclass
|
1268
|
+
class AnimalColorAchievementContent:
|
1269
|
+
"""animalColorAchievement content data."""
|
1270
|
+
|
1271
|
+
color: str
|
1272
|
+
petAchievement: str
|
1273
|
+
petNotificationType: str
|
1274
|
+
mountAchievement: str
|
1275
|
+
mountNotificationType: str
|
1276
|
+
|
1277
|
+
|
1278
|
+
@dataclass
|
1279
|
+
class AnimalSetAchievementContent:
|
1280
|
+
"""animalSetAchievements content data."""
|
1281
|
+
|
1282
|
+
Type: str = field(metadata=field_options(alias="type"))
|
1283
|
+
species: list[str]
|
1284
|
+
achievementKey: str
|
1285
|
+
notificationType: str
|
1286
|
+
|
1287
|
+
|
1288
|
+
@dataclass
|
1289
|
+
class StableAchievementContent:
|
1290
|
+
"""stableAchievements content data."""
|
1291
|
+
|
1292
|
+
masterAchievement: str
|
1293
|
+
masterNotificationType: str
|
1294
|
+
|
1295
|
+
|
1296
|
+
@dataclass
|
1297
|
+
class PetSetCompleteAchievsContent:
|
1298
|
+
"""petSetCompleteAchievs content data."""
|
1299
|
+
|
1300
|
+
color: str
|
1301
|
+
petAchievement: str
|
1302
|
+
petNotificationType: str
|
1303
|
+
|
1304
|
+
|
1305
|
+
@dataclass
|
1306
|
+
class QuestBossRage:
|
1307
|
+
"""QuestBossRage content data."""
|
1308
|
+
|
1309
|
+
title: str
|
1310
|
+
description: str
|
1311
|
+
value: float
|
1312
|
+
effect: str | None = None
|
1313
|
+
healing: float | None = None
|
1314
|
+
|
1315
|
+
|
1316
|
+
@dataclass
|
1317
|
+
class QuestBoss:
|
1318
|
+
"""QuestBoss content data."""
|
1319
|
+
|
1320
|
+
name: str
|
1321
|
+
hp: float
|
1322
|
+
Str: float = field(metadata=field_options(alias="str"))
|
1323
|
+
Def: float = field(metadata=field_options(alias="def"))
|
1324
|
+
rage: QuestBossRage | None = None
|
1325
|
+
|
1326
|
+
|
1327
|
+
@dataclass
|
1328
|
+
class QuestItem:
|
1329
|
+
"""QuestItem content data."""
|
1330
|
+
|
1331
|
+
Type: str = field(metadata=field_options(alias="type"))
|
1332
|
+
key: str
|
1333
|
+
text: str
|
1334
|
+
|
1335
|
+
|
1336
|
+
@dataclass
|
1337
|
+
class QuestDrop:
|
1338
|
+
"""QuestDrop content data."""
|
1339
|
+
|
1340
|
+
gp: float
|
1341
|
+
exp: float
|
1342
|
+
items: list[QuestItem] | None = None
|
1343
|
+
|
1344
|
+
|
1345
|
+
@dataclass
|
1346
|
+
class QuestCollect:
|
1347
|
+
"""QuestCollect content data."""
|
1348
|
+
|
1349
|
+
text: str
|
1350
|
+
count: int
|
1351
|
+
|
1352
|
+
|
1353
|
+
@dataclass
|
1354
|
+
class QuestUnlockCondition:
|
1355
|
+
"""QuestUnlockCondition content data."""
|
1356
|
+
|
1357
|
+
condition: str
|
1358
|
+
text: str
|
1359
|
+
|
1360
|
+
|
1361
|
+
@dataclass
|
1362
|
+
class QuestsContent:
|
1363
|
+
"""petSetCompleteAchievs content data."""
|
1364
|
+
|
1365
|
+
text: str
|
1366
|
+
notes: str
|
1367
|
+
|
1368
|
+
completion: str
|
1369
|
+
category: str
|
1370
|
+
|
1371
|
+
drop: QuestDrop
|
1372
|
+
key: str
|
1373
|
+
goldValue: float | None = None
|
1374
|
+
value: float | None = None
|
1375
|
+
previous: str | None = None
|
1376
|
+
prereqQuests: list[str] | None = None
|
1377
|
+
collect: dict[str, QuestCollect] | None = None
|
1378
|
+
unlockCondition: QuestUnlockCondition | None = None
|
1379
|
+
boss: QuestBoss | None = None
|
1380
|
+
group: str | None = None
|
1381
|
+
|
1382
|
+
|
1383
|
+
@dataclass
|
1384
|
+
class ItemListEntry:
|
1385
|
+
"""ItemListEntry content data."""
|
1386
|
+
|
1387
|
+
localeKey: str
|
1388
|
+
isEquipment: bool
|
1389
|
+
|
1390
|
+
|
1391
|
+
@dataclass
|
1392
|
+
class ItemListContent:
|
1393
|
+
"""ItemListContent content data."""
|
1394
|
+
|
1395
|
+
weapon: ItemListEntry
|
1396
|
+
armor: ItemListEntry
|
1397
|
+
head: ItemListEntry
|
1398
|
+
shield: ItemListEntry
|
1399
|
+
back: ItemListEntry
|
1400
|
+
body: ItemListEntry
|
1401
|
+
headAccessory: ItemListEntry
|
1402
|
+
eyewear: ItemListEntry
|
1403
|
+
hatchingPotions: ItemListEntry
|
1404
|
+
premiumHatchingPotions: ItemListEntry
|
1405
|
+
eggs: ItemListEntry
|
1406
|
+
quests: ItemListEntry
|
1407
|
+
food: ItemListEntry
|
1408
|
+
Saddle: ItemListEntry
|
1409
|
+
bundles: ItemListEntry
|
1410
|
+
|
1411
|
+
|
1412
|
+
@dataclass
|
1413
|
+
class GearEntry:
|
1414
|
+
"""GearEntry content data."""
|
1415
|
+
|
1416
|
+
text: str
|
1417
|
+
notes: str
|
1418
|
+
Int: int = field(metadata=field_options(alias="int"))
|
1419
|
+
value: int
|
1420
|
+
Type: str = field(metadata=field_options(alias="type"))
|
1421
|
+
key: str
|
1422
|
+
Set: str = field(metadata=field_options(alias="set"))
|
1423
|
+
klass: str
|
1424
|
+
index: str
|
1425
|
+
Str: int = field(metadata=field_options(alias="str"))
|
1426
|
+
per: int
|
1427
|
+
con: int
|
1428
|
+
|
1429
|
+
|
1430
|
+
@dataclass
|
1431
|
+
class GearClass:
|
1432
|
+
"""GearClass content data."""
|
1433
|
+
|
1434
|
+
base: dict[str, GearEntry] | None = None
|
1435
|
+
warrior: dict[str, GearEntry] | None = None
|
1436
|
+
wizard: dict[str, GearEntry] | None = None
|
1437
|
+
rogue: dict[str, GearEntry] | None = None
|
1438
|
+
special: dict[str, GearEntry] | None = None
|
1439
|
+
armoire: dict[str, GearEntry] | None = None
|
1440
|
+
mystery: dict[str, GearEntry] | None = None
|
1441
|
+
healer: dict[str, GearEntry] | None = None
|
1442
|
+
|
1443
|
+
|
1444
|
+
@dataclass
|
1445
|
+
class GearType:
|
1446
|
+
"""GearType content data."""
|
1447
|
+
|
1448
|
+
weapon: GearClass
|
1449
|
+
armor: GearClass
|
1450
|
+
head: GearClass
|
1451
|
+
shield: GearClass
|
1452
|
+
back: GearClass
|
1453
|
+
body: GearClass
|
1454
|
+
headAccessory: GearClass
|
1455
|
+
eyewear: GearClass
|
1456
|
+
|
1457
|
+
|
1458
|
+
@dataclass
|
1459
|
+
class GearContent:
|
1460
|
+
"""GearContent content data."""
|
1461
|
+
|
1462
|
+
tree: GearType
|
1463
|
+
flat: dict[str, GearEntry]
|
1464
|
+
|
1465
|
+
|
1466
|
+
@dataclass
|
1467
|
+
class SpellEntry:
|
1468
|
+
"""SpellEntry content data."""
|
1469
|
+
|
1470
|
+
text: str
|
1471
|
+
mana: int
|
1472
|
+
target: str
|
1473
|
+
notes: str
|
1474
|
+
key: str
|
1475
|
+
previousPurchase: bool | None = None
|
1476
|
+
limited: bool | None = None
|
1477
|
+
lvl: int | None = None
|
1478
|
+
value: int | None = None
|
1479
|
+
immediateUse: bool | None = None
|
1480
|
+
purchaseType: str | None = None
|
1481
|
+
silent: bool | None = None
|
1482
|
+
|
1483
|
+
|
1484
|
+
@dataclass
|
1485
|
+
class SpellsClass:
|
1486
|
+
"""SpellsClass content data."""
|
1487
|
+
|
1488
|
+
wizard: dict[str, SpellEntry]
|
1489
|
+
warrior: dict[str, SpellEntry]
|
1490
|
+
rogue: dict[str, SpellEntry]
|
1491
|
+
healer: dict[str, SpellEntry]
|
1492
|
+
special: dict[str, SpellEntry]
|
1493
|
+
|
1494
|
+
|
1495
|
+
@dataclass
|
1496
|
+
class CarTypes:
|
1497
|
+
"""CarTypes content data."""
|
1498
|
+
|
1499
|
+
key: str
|
1500
|
+
messageOptions: int
|
1501
|
+
yearRound: bool = False
|
1502
|
+
|
1503
|
+
|
1504
|
+
@dataclass
|
1505
|
+
class SpecialItemEntry:
|
1506
|
+
"""Item content data."""
|
1507
|
+
|
1508
|
+
key: str | None = None
|
1509
|
+
text: str | None = None
|
1510
|
+
notes: str | None = None
|
1511
|
+
immediateUse: bool | None = None
|
1512
|
+
limited: bool | None = None
|
1513
|
+
mana: int | None = None
|
1514
|
+
previousPurchase: bool | None = None
|
1515
|
+
purchaseType: str | None = None
|
1516
|
+
silent: bool | None = None
|
1517
|
+
target: str | None = None
|
1518
|
+
value: int | None = None
|
1519
|
+
|
1520
|
+
|
1521
|
+
@dataclass
|
1522
|
+
class EggEntry:
|
1523
|
+
"""Egg content data."""
|
1524
|
+
|
1525
|
+
text: str | None = None
|
1526
|
+
mountText: str | None = None
|
1527
|
+
adjective: str | None = None
|
1528
|
+
value: int | None = None
|
1529
|
+
key: str | None = None
|
1530
|
+
notes: str | None = None
|
1531
|
+
|
1532
|
+
|
1533
|
+
@dataclass
|
1534
|
+
class HatchingPotionEntry:
|
1535
|
+
"""Hatching potion content data."""
|
1536
|
+
|
1537
|
+
value: int | None = None
|
1538
|
+
key: str | None = None
|
1539
|
+
text: str | None = None
|
1540
|
+
notes: str | None = None
|
1541
|
+
premium: bool | None = None
|
1542
|
+
limited: bool | None = None
|
1543
|
+
_addlNotes: str | None = None
|
1544
|
+
wacky: bool | None = None
|
1545
|
+
|
1546
|
+
|
1547
|
+
@dataclass
|
1548
|
+
class PetEntry:
|
1549
|
+
"""Pet content data."""
|
1550
|
+
|
1551
|
+
key: str | None = None
|
1552
|
+
Type: str | None = field(default=None, metadata=field_options(alias="type"))
|
1553
|
+
potion: str | None = None
|
1554
|
+
egg: str | None = None
|
1555
|
+
text: str | None = None
|
1556
|
+
|
1557
|
+
|
1558
|
+
@dataclass
|
1559
|
+
class InventoryItemEntry:
|
1560
|
+
"""Inventory item content data."""
|
1561
|
+
|
1562
|
+
text: str | None = None
|
1563
|
+
textA: str | None = None
|
1564
|
+
textThe: str | None = None
|
1565
|
+
target: str | None = None
|
1566
|
+
value: int | None = None
|
1567
|
+
key: str | None = None
|
1568
|
+
notes: str | None = None
|
1569
|
+
canDrop: bool | None = None
|
1570
|
+
|
1571
|
+
|
1572
|
+
@dataclass
|
1573
|
+
class ContentData:
|
1574
|
+
"""Content data."""
|
1575
|
+
|
1576
|
+
achievements: dict[str, AchievmentContent]
|
1577
|
+
questSeriesAchievements: dict[str, list[str]]
|
1578
|
+
animalColorAchievements: list[AnimalColorAchievementContent]
|
1579
|
+
animalSetAchievements: dict[str, AnimalSetAchievementContent]
|
1580
|
+
stableAchievements: dict[str, StableAchievementContent]
|
1581
|
+
petSetCompleteAchievs: list[PetSetCompleteAchievsContent]
|
1582
|
+
quests: dict[str, QuestsContent]
|
1583
|
+
questsByLevel: list[QuestsContent]
|
1584
|
+
userCanOwnQuestCategories: list[str]
|
1585
|
+
itemList: ItemListContent
|
1586
|
+
gear: GearContent
|
1587
|
+
spells: SpellsClass
|
1588
|
+
audioThemes: list[str]
|
1589
|
+
# mystery
|
1590
|
+
officialPinnedItems: list
|
1591
|
+
# bundles
|
1592
|
+
# potion
|
1593
|
+
# armoire
|
1594
|
+
# events
|
1595
|
+
# repeatingEvents
|
1596
|
+
classes: list[str]
|
1597
|
+
gearTypes: list[str]
|
1598
|
+
cardTypes: dict[str, CarTypes]
|
1599
|
+
special: dict[str, SpecialItemEntry]
|
1600
|
+
dropEggs: dict[str, EggEntry]
|
1601
|
+
questEggs: dict[str, EggEntry]
|
1602
|
+
eggs: dict[str, EggEntry]
|
1603
|
+
# timeTravelStable
|
1604
|
+
dropHatchingPotions: dict[str, HatchingPotionEntry]
|
1605
|
+
premiumHatchingPotions: dict[str, HatchingPotionEntry]
|
1606
|
+
wackyHatchingPotions: dict[str, HatchingPotionEntry]
|
1607
|
+
hatchingPotions: dict[str, HatchingPotionEntry]
|
1608
|
+
pets: dict[str, bool]
|
1609
|
+
premiumPets: dict[str, bool]
|
1610
|
+
questPets: dict[str, bool]
|
1611
|
+
specialPets: dict[str, str]
|
1612
|
+
wackyPets: dict[str, bool]
|
1613
|
+
petInfo: dict[str, PetEntry]
|
1614
|
+
mounts: dict[str, bool]
|
1615
|
+
premiumMounts: dict[str, bool]
|
1616
|
+
questMounts: dict[str, bool]
|
1617
|
+
specialMounts: dict[str, str]
|
1618
|
+
mountInfo: dict[str, PetEntry]
|
1619
|
+
food: dict[str, InventoryItemEntry]
|
1620
|
+
# appearances
|
1621
|
+
# backgrounds
|
1622
|
+
# backgroundsFlat
|
1623
|
+
# userDefaults
|
1624
|
+
# tasksByCategory
|
1625
|
+
# userDefaultsMobile
|
1626
|
+
# faq
|
1627
|
+
# loginIncentives
|
1628
|
+
|
1629
|
+
|
1630
|
+
@dataclass
|
1631
|
+
class HabiticaContentResponse(HabiticaResponse):
|
1632
|
+
"""Representation of a content response."""
|
1633
|
+
|
1634
|
+
data: ContentData
|
@@ -1,6 +1,6 @@
|
|
1
1
|
Metadata-Version: 2.3
|
2
2
|
Name: Habiticalib
|
3
|
-
Version: 0.
|
3
|
+
Version: 0.2.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
|
@@ -0,0 +1,11 @@
|
|
1
|
+
habiticalib/__init__.py,sha256=Mo0G1V_RKbIiAGYMWqznhOLtMxCM2UAmCqHW5JBEryw,2201
|
2
|
+
habiticalib/const.py,sha256=pqAPlZylW8FyBWg31nixggB3u9mLksdo_D0nyLJulfM,624
|
3
|
+
habiticalib/exceptions.py,sha256=oVFCGbHkVn0UpIKIPZPzXfvzs9US4R05ebdEn6cOpqM,1350
|
4
|
+
habiticalib/helpers.py,sha256=IRZLYWkDVLI0iVBgBMmvZ6L83KCUl-CnzGhUR_tP6Fg,4576
|
5
|
+
habiticalib/lib.py,sha256=woSpO1YeFv2d1BtHM1pKR1S4FmzbMnqSM0SAgQpupFU,72405
|
6
|
+
habiticalib/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
7
|
+
habiticalib/types.py,sha256=zJq3jnZNUSU0p5XX_14PpGHmxmCeuf1F_YQjFpcoMLo,42341
|
8
|
+
habiticalib-0.2.0.dist-info/METADATA,sha256=G5slvwHpL9ELZkJRjE_e8YUw4UFdNPuTEvcfC59M1Po,4185
|
9
|
+
habiticalib-0.2.0.dist-info/WHEEL,sha256=C2FUgwZgiLbznR-k0b_5k3Ai_1aASOXDss3lzCUsUug,87
|
10
|
+
habiticalib-0.2.0.dist-info/licenses/LICENSE,sha256=oIinIOSJ49l1iVIRI3XGXFWt6SF7a83kEFBAY8ORwNI,1084
|
11
|
+
habiticalib-0.2.0.dist-info/RECORD,,
|
@@ -1,11 +0,0 @@
|
|
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,,
|
File without changes
|
File without changes
|