warframe-market.py 1.0.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.
- warframe_market_py-1.0.0/.github/workflows/publish.yml +41 -0
- warframe_market_py-1.0.0/.gitignore +5 -0
- warframe_market_py-1.0.0/LICENSE +21 -0
- warframe_market_py-1.0.0/PKG-INFO +10 -0
- warframe_market_py-1.0.0/README.md +32 -0
- warframe_market_py-1.0.0/pyproject.toml +27 -0
- warframe_market_py-1.0.0/requirements.txt +2 -0
- warframe_market_py-1.0.0/warframe_market/__init__.py +0 -0
- warframe_market_py-1.0.0/warframe_market/api/__init__.py +40 -0
- warframe_market_py-1.0.0/warframe_market/api/item.py +42 -0
- warframe_market_py-1.0.0/warframe_market/api/lich.py +36 -0
- warframe_market_py-1.0.0/warframe_market/api/misc.py +62 -0
- warframe_market_py-1.0.0/warframe_market/api/order.py +96 -0
- warframe_market_py-1.0.0/warframe_market/api/riven.py +29 -0
- warframe_market_py-1.0.0/warframe_market/api/sister.py +36 -0
- warframe_market_py-1.0.0/warframe_market/api/user.py +16 -0
- warframe_market_py-1.0.0/warframe_market/client.py +42 -0
- warframe_market_py-1.0.0/warframe_market/common/__init__.py +17 -0
- warframe_market_py-1.0.0/warframe_market/common/base.py +57 -0
- warframe_market_py-1.0.0/warframe_market/common/enums.py +30 -0
- warframe_market_py-1.0.0/warframe_market/common/options.py +3 -0
- warframe_market_py-1.0.0/warframe_market/models/__init__.py +0 -0
- warframe_market_py-1.0.0/warframe_market/models/achievement.py +34 -0
- warframe_market_py-1.0.0/warframe_market/models/activity.py +27 -0
- warframe_market_py-1.0.0/warframe_market/models/item.py +48 -0
- warframe_market_py-1.0.0/warframe_market/models/lich.py +63 -0
- warframe_market_py-1.0.0/warframe_market/models/location.py +23 -0
- warframe_market_py-1.0.0/warframe_market/models/mission.py +19 -0
- warframe_market_py-1.0.0/warframe_market/models/npc.py +19 -0
- warframe_market_py-1.0.0/warframe_market/models/order.py +56 -0
- warframe_market_py-1.0.0/warframe_market/models/riven.py +56 -0
- warframe_market_py-1.0.0/warframe_market/models/sister.py +63 -0
- warframe_market_py-1.0.0/warframe_market/models/user.py +61 -0
- warframe_market_py-1.0.0/warframe_market/models/user_private.py +112 -0
- warframe_market_py-1.0.0/warframe_market/utils.py +0 -0
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
name: publish
|
|
2
|
+
|
|
3
|
+
on:
|
|
4
|
+
release:
|
|
5
|
+
types: [published]
|
|
6
|
+
|
|
7
|
+
jobs:
|
|
8
|
+
test:
|
|
9
|
+
runs-on: ubuntu-latest
|
|
10
|
+
strategy:
|
|
11
|
+
matrix:
|
|
12
|
+
python-version: ["3.9", "3.10", "3.11", "3.12", "3.13"]
|
|
13
|
+
steps:
|
|
14
|
+
- uses: actions/checkout@v4
|
|
15
|
+
- name: Set up Python
|
|
16
|
+
uses: actions/setup-python@v5
|
|
17
|
+
with:
|
|
18
|
+
python-version: ${{ matrix.python-version }}
|
|
19
|
+
- name: Install Hatch
|
|
20
|
+
run: python -m pip install --upgrade hatch
|
|
21
|
+
- name: Build package
|
|
22
|
+
run: hatch build
|
|
23
|
+
|
|
24
|
+
publish:
|
|
25
|
+
needs: test
|
|
26
|
+
runs-on: ubuntu-latest
|
|
27
|
+
steps:
|
|
28
|
+
- uses: actions/checkout@v4
|
|
29
|
+
- name: Set up Python
|
|
30
|
+
uses: actions/setup-python@v5
|
|
31
|
+
with:
|
|
32
|
+
python-version: '3.9'
|
|
33
|
+
- name: Install Hatch
|
|
34
|
+
run: python -m pip install --upgrade hatch
|
|
35
|
+
- name: Build package
|
|
36
|
+
run: hatch build
|
|
37
|
+
- name: Publish to PyPI
|
|
38
|
+
env:
|
|
39
|
+
HATCH_INDEX_USER: "__token__"
|
|
40
|
+
HATCH_INDEX_AUTH: ${{ secrets.PYPI_TOKEN }}
|
|
41
|
+
run: hatch publish --yes
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2025 Aldi Filopati
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: warframe-market.py
|
|
3
|
+
Version: 1.0.0
|
|
4
|
+
Summary: An asynchronous Python wrapper for Warframe.Market API
|
|
5
|
+
Project-URL: Homepage, https://github.com/aldi-f/warframe-market.py
|
|
6
|
+
Author: aldi-f
|
|
7
|
+
License-File: LICENSE
|
|
8
|
+
Requires-Python: >=3.9
|
|
9
|
+
Requires-Dist: aiohttp==3.12.6
|
|
10
|
+
Requires-Dist: msgspec==0.19.0
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
# warframe-market.py
|
|
2
|
+
> **Warning**: This project is still in development and is not yet ready for production use.
|
|
3
|
+
|
|
4
|
+
Warframe Market API for Python
|
|
5
|
+
|
|
6
|
+
# Installation
|
|
7
|
+
```bash
|
|
8
|
+
pip install warframe-market.py
|
|
9
|
+
```
|
|
10
|
+
|
|
11
|
+
# Usage
|
|
12
|
+
```python
|
|
13
|
+
import asyncio
|
|
14
|
+
from warframe_market.client import WarframeMarketClient
|
|
15
|
+
from warframe_market.api.item import Items, Item
|
|
16
|
+
|
|
17
|
+
async def main():
|
|
18
|
+
async with WarframeMarketClient() as client:
|
|
19
|
+
# Get all items in English
|
|
20
|
+
items = await client.get(Items)
|
|
21
|
+
for item in items.data:
|
|
22
|
+
print(item.i18n["en"].name)
|
|
23
|
+
|
|
24
|
+
# Get a single item
|
|
25
|
+
item = await client.get(Item,"nova_prime_set")
|
|
26
|
+
print(item)
|
|
27
|
+
|
|
28
|
+
if __name__ == "__main__":
|
|
29
|
+
loop = asyncio.get_event_loop()
|
|
30
|
+
loop.run_until_complete(main())
|
|
31
|
+
loop.close()
|
|
32
|
+
```
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
[project]
|
|
2
|
+
name = "warframe-market.py"
|
|
3
|
+
description = "An asynchronous Python wrapper for Warframe.Market API"
|
|
4
|
+
authors = [{ name = "aldi-f" }]
|
|
5
|
+
dependencies = ["aiohttp==3.12.6", "msgspec==0.19.0"]
|
|
6
|
+
dynamic = ["version"]
|
|
7
|
+
requires-python = ">=3.9"
|
|
8
|
+
|
|
9
|
+
[project.urls]
|
|
10
|
+
Homepage = "https://github.com/aldi-f/warframe-market.py"
|
|
11
|
+
|
|
12
|
+
[build-system]
|
|
13
|
+
requires = ["hatchling", "hatch-vcs"]
|
|
14
|
+
build-backend = "hatchling.build"
|
|
15
|
+
|
|
16
|
+
[tool.hatch.metadata]
|
|
17
|
+
allow-direct-url = true
|
|
18
|
+
|
|
19
|
+
[tool.hatch.build.targets.wheel]
|
|
20
|
+
packages = ["warframe_market"]
|
|
21
|
+
|
|
22
|
+
[tool.hatch.version]
|
|
23
|
+
source = "vcs"
|
|
24
|
+
|
|
25
|
+
[tool.pyright]
|
|
26
|
+
venvPath = "."
|
|
27
|
+
venv = "venv"
|
|
File without changes
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
from .item import (
|
|
2
|
+
Items,
|
|
3
|
+
Item,
|
|
4
|
+
ItemSet,
|
|
5
|
+
)
|
|
6
|
+
from .lich import (
|
|
7
|
+
LichWeapons,
|
|
8
|
+
LichWeapon,
|
|
9
|
+
LichEphemeras,
|
|
10
|
+
LichQuirks,
|
|
11
|
+
)
|
|
12
|
+
|
|
13
|
+
from .misc import (
|
|
14
|
+
Locations,
|
|
15
|
+
Missions,
|
|
16
|
+
NPCs,
|
|
17
|
+
Versions,
|
|
18
|
+
)
|
|
19
|
+
from .order import (
|
|
20
|
+
OrdersItem,
|
|
21
|
+
OrdersItemTop,
|
|
22
|
+
OrdersUser,
|
|
23
|
+
OrderId,
|
|
24
|
+
)
|
|
25
|
+
|
|
26
|
+
from .riven import (
|
|
27
|
+
Rivens,
|
|
28
|
+
Riven,
|
|
29
|
+
RivenAttributes,
|
|
30
|
+
)
|
|
31
|
+
|
|
32
|
+
from .sister import (
|
|
33
|
+
SisterWeapons,
|
|
34
|
+
SisterWeapon,
|
|
35
|
+
SisterEphemeras,
|
|
36
|
+
SisterQuirks,
|
|
37
|
+
)
|
|
38
|
+
from .user import (
|
|
39
|
+
User,
|
|
40
|
+
)
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
import msgspec
|
|
2
|
+
from typing import List
|
|
3
|
+
from ..common.base import BaseRequest
|
|
4
|
+
from ..models.item import ItemShortModel, ItemModel
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
class Items(BaseRequest):
|
|
8
|
+
"""Get list of all tradable items"""
|
|
9
|
+
|
|
10
|
+
__endpoint__ = "/items"
|
|
11
|
+
|
|
12
|
+
data: List[ItemShortModel]
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
class Item(BaseRequest):
|
|
16
|
+
"""Get full info about one, particular item. Requires slug"""
|
|
17
|
+
|
|
18
|
+
__endpoint__ = "/item/{slug}"
|
|
19
|
+
__slug__ = True
|
|
20
|
+
|
|
21
|
+
data: ItemModel
|
|
22
|
+
|
|
23
|
+
|
|
24
|
+
class _ItemSetData(msgspec.Struct):
|
|
25
|
+
"""Internal model for ItemSet data
|
|
26
|
+
|
|
27
|
+
Attributes:
|
|
28
|
+
id (str): Unique identifier for the item set
|
|
29
|
+
items (List[ItemModel]): List of items in the set
|
|
30
|
+
"""
|
|
31
|
+
|
|
32
|
+
id: str
|
|
33
|
+
items: List[ItemModel]
|
|
34
|
+
|
|
35
|
+
|
|
36
|
+
class ItemSet(BaseRequest):
|
|
37
|
+
"""Retrieve Information on Item Sets. Requires slug"""
|
|
38
|
+
|
|
39
|
+
__endpoint__ = "/item/{slug}/set"
|
|
40
|
+
__slug__ = True
|
|
41
|
+
|
|
42
|
+
data: _ItemSetData
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
from typing import List
|
|
2
|
+
from ..common.base import BaseRequest
|
|
3
|
+
from ..models.lich import LichWeaponModel, LichEphemeraModel, LichQuirkModel
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
class LichWeapons(BaseRequest):
|
|
7
|
+
"""Get list of all tradable lich weapons"""
|
|
8
|
+
|
|
9
|
+
__endpoint__ = "/lich/weapons"
|
|
10
|
+
|
|
11
|
+
data: List[LichWeaponModel]
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
class LichWeapon(BaseRequest):
|
|
15
|
+
"""Get full info about one, particular lich weapon. Requires slug"""
|
|
16
|
+
|
|
17
|
+
__endpoint__ = "/lich/weapon/{slug}"
|
|
18
|
+
__slug__ = True
|
|
19
|
+
|
|
20
|
+
data: LichWeaponModel
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+
class LichEphemeras(BaseRequest):
|
|
24
|
+
"""Get list of all tradable lich ephemeras"""
|
|
25
|
+
|
|
26
|
+
__endpoint__ = "/lich/ephemeras"
|
|
27
|
+
|
|
28
|
+
data: List[LichEphemeraModel]
|
|
29
|
+
|
|
30
|
+
|
|
31
|
+
class LichQuirks(BaseRequest):
|
|
32
|
+
"""Get list of all tradable lich quirks"""
|
|
33
|
+
|
|
34
|
+
__endpoint__ = "/lich/quirks"
|
|
35
|
+
|
|
36
|
+
data: List[LichQuirkModel]
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
import msgspec
|
|
2
|
+
from datetime import datetime
|
|
3
|
+
from typing import List
|
|
4
|
+
from ..common.base import BaseRequest
|
|
5
|
+
from ..models.location import LocationModel
|
|
6
|
+
from ..models.npc import NpcModel
|
|
7
|
+
from ..models.mission import MissionModel
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
class _AppsData(msgspec.Struct):
|
|
11
|
+
ios: str
|
|
12
|
+
android: str
|
|
13
|
+
minIos: str
|
|
14
|
+
minAndroid: str
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
class _CollectionsData(msgspec.Struct):
|
|
18
|
+
items: str
|
|
19
|
+
rivens: str
|
|
20
|
+
liches: str
|
|
21
|
+
sisters: str
|
|
22
|
+
missions: str
|
|
23
|
+
npcs: str
|
|
24
|
+
locations: str
|
|
25
|
+
|
|
26
|
+
|
|
27
|
+
class _VersionData(msgspec.Struct):
|
|
28
|
+
apps: _AppsData
|
|
29
|
+
collections: _CollectionsData
|
|
30
|
+
updatedAt: datetime
|
|
31
|
+
|
|
32
|
+
|
|
33
|
+
class Versions(BaseRequest):
|
|
34
|
+
"""Get current API version"""
|
|
35
|
+
|
|
36
|
+
__endpoint__ = "/versions"
|
|
37
|
+
|
|
38
|
+
data: _VersionData
|
|
39
|
+
|
|
40
|
+
|
|
41
|
+
class Locations(BaseRequest):
|
|
42
|
+
"""Get list of all tradable lich weapons"""
|
|
43
|
+
|
|
44
|
+
__endpoint__ = "/locations"
|
|
45
|
+
|
|
46
|
+
data: List[LocationModel]
|
|
47
|
+
|
|
48
|
+
|
|
49
|
+
class NPCs(BaseRequest):
|
|
50
|
+
"""Get list of all NPCs"""
|
|
51
|
+
|
|
52
|
+
__endpoint__ = "/npcs"
|
|
53
|
+
|
|
54
|
+
data: List[NpcModel]
|
|
55
|
+
|
|
56
|
+
|
|
57
|
+
class Missions(BaseRequest):
|
|
58
|
+
"""Get list of all missions"""
|
|
59
|
+
|
|
60
|
+
__endpoint__ = "/missions"
|
|
61
|
+
|
|
62
|
+
data: List[MissionModel]
|
|
@@ -0,0 +1,96 @@
|
|
|
1
|
+
import msgspec
|
|
2
|
+
from typing import List
|
|
3
|
+
from ..common.base import BaseRequest
|
|
4
|
+
from ..models.order import OrderModel, OrderWithUserModel
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
class OrdersRecent(BaseRequest):
|
|
8
|
+
"""Get the most recent orders.
|
|
9
|
+
500 max, for the last 4 hours, sorted by createdAt
|
|
10
|
+
"""
|
|
11
|
+
|
|
12
|
+
__endpoint__ = "/orders/recent"
|
|
13
|
+
|
|
14
|
+
data: List[OrderWithUserModel]
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
class OrdersItem(BaseRequest):
|
|
18
|
+
"""Get a list of all orders for an item from users
|
|
19
|
+
who was online within the last 7 days.
|
|
20
|
+
|
|
21
|
+
Requires slug of the item.
|
|
22
|
+
"""
|
|
23
|
+
|
|
24
|
+
__endpoint__ = "/orders/item/{slug}"
|
|
25
|
+
__slug__ = True
|
|
26
|
+
|
|
27
|
+
data: List[OrderWithUserModel]
|
|
28
|
+
|
|
29
|
+
|
|
30
|
+
class _OrdersItemData(msgspec.Struct):
|
|
31
|
+
"""Internal model for OrdersItemTop data
|
|
32
|
+
|
|
33
|
+
Attributes:
|
|
34
|
+
buy (List[OrderWithUserModel]): List of top buy orders
|
|
35
|
+
sell (List[OrderWithUserModel]): List of top sell orders
|
|
36
|
+
"""
|
|
37
|
+
|
|
38
|
+
buy: List[OrderWithUserModel]
|
|
39
|
+
sell: List[OrderWithUserModel]
|
|
40
|
+
|
|
41
|
+
|
|
42
|
+
class OrdersItemTop(BaseRequest):
|
|
43
|
+
"""This endpoint is designed to fetch the top 5 buy
|
|
44
|
+
and top 5 sell orders for a specific item, exclusively from online users.
|
|
45
|
+
Orders are sorted by price.
|
|
46
|
+
|
|
47
|
+
Available query parameters:
|
|
48
|
+
- rank: Filter by rank (e.g., 0, 1, 2, etc.)
|
|
49
|
+
- rankLt: Filter by rank less than specified value
|
|
50
|
+
- charges: Filter by charges (e.g., 0, 1, 2, etc.)
|
|
51
|
+
- chargesLt: Filter by charges less than specified value
|
|
52
|
+
- amberStars: Filter by amber stars (e.g., 0, 1, 2, etc.)
|
|
53
|
+
- amberStarsLt: Filter by amber stars less than specified value
|
|
54
|
+
- cyanStars: Filter by cyan stars (e.g., 0, 1, 2, etc.)
|
|
55
|
+
- cyanStarsLt: Filter by cyan stars less than specified value
|
|
56
|
+
- subtype: Filter by Item subtype (e.g. "blueprint", "crafted)
|
|
57
|
+
|
|
58
|
+
Requires slug of the item.
|
|
59
|
+
"""
|
|
60
|
+
|
|
61
|
+
__endpoint__ = "/orders/item/{slug}/top"
|
|
62
|
+
__params__ = [
|
|
63
|
+
"rank",
|
|
64
|
+
"rankLt",
|
|
65
|
+
"charges",
|
|
66
|
+
"chargesLt",
|
|
67
|
+
"amberStars",
|
|
68
|
+
"amberStarsLt",
|
|
69
|
+
"cyanStars",
|
|
70
|
+
"cyanStarsLt",
|
|
71
|
+
"subtype",
|
|
72
|
+
]
|
|
73
|
+
__slug__ = True
|
|
74
|
+
|
|
75
|
+
data: _OrdersItemData
|
|
76
|
+
|
|
77
|
+
|
|
78
|
+
class OrdersUser(BaseRequest):
|
|
79
|
+
"""Getting public orders from specified user.
|
|
80
|
+
|
|
81
|
+
Requires user ID (same as slug)
|
|
82
|
+
"""
|
|
83
|
+
|
|
84
|
+
__endpoint__ = "/orders/user/{slug}"
|
|
85
|
+
__slug__ = True
|
|
86
|
+
|
|
87
|
+
data: List[OrderModel]
|
|
88
|
+
|
|
89
|
+
|
|
90
|
+
class OrderId(BaseRequest):
|
|
91
|
+
"""Get full info about one, particular order. Requires order ID (same as slug)"""
|
|
92
|
+
|
|
93
|
+
__endpoint__ = "/order/{slug}"
|
|
94
|
+
__slug__ = True
|
|
95
|
+
|
|
96
|
+
data: OrderWithUserModel
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import msgspec
|
|
2
|
+
from typing import List
|
|
3
|
+
from ..common.base import BaseRequest
|
|
4
|
+
from ..models.riven import RivenModel, RivenAttributeModel
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
class Rivens(BaseRequest):
|
|
8
|
+
"""Get list of all tradable riven items"""
|
|
9
|
+
|
|
10
|
+
__endpoint__ = "/riven/weapons"
|
|
11
|
+
|
|
12
|
+
data: List[RivenModel]
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
class Riven(BaseRequest):
|
|
16
|
+
"""Get full info about one, particular riven item. Requires slug"""
|
|
17
|
+
|
|
18
|
+
__endpoint__ = "/riven/weapon/{slug}"
|
|
19
|
+
__slug__ = True
|
|
20
|
+
|
|
21
|
+
data: RivenModel
|
|
22
|
+
|
|
23
|
+
|
|
24
|
+
class RivenAttributes(BaseRequest):
|
|
25
|
+
"""Get list of all attributes for riven weapons"""
|
|
26
|
+
|
|
27
|
+
__endpoint__ = "/riven/attributes"
|
|
28
|
+
|
|
29
|
+
data: List[RivenAttributeModel]
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
from typing import List
|
|
2
|
+
from ..common.base import BaseRequest
|
|
3
|
+
from ..models.sister import SisterWeaponModel, SisterEphemeraModel, SisterQuirkModel
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
class SisterWeapons(BaseRequest):
|
|
7
|
+
"""Get list of all tradable sister weapons"""
|
|
8
|
+
|
|
9
|
+
__endpoint__ = "/sister/weapons"
|
|
10
|
+
|
|
11
|
+
data: List[SisterWeaponModel]
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
class SisterWeapon(BaseRequest):
|
|
15
|
+
"""Get full info about one, particular sister weapon. Requires slug"""
|
|
16
|
+
|
|
17
|
+
__endpoint__ = "/sister/weapon/{slug}"
|
|
18
|
+
__slug__ = True
|
|
19
|
+
|
|
20
|
+
data: SisterWeaponModel
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+
class SisterEphemeras(BaseRequest):
|
|
24
|
+
"""Get list of all tradable sister ephemeras"""
|
|
25
|
+
|
|
26
|
+
__endpoint__ = "/sister/ephemeras"
|
|
27
|
+
|
|
28
|
+
data: List[SisterEphemeraModel]
|
|
29
|
+
|
|
30
|
+
|
|
31
|
+
class SisterQuirks(BaseRequest):
|
|
32
|
+
"""Get list of all tradable sister quirks"""
|
|
33
|
+
|
|
34
|
+
__endpoint__ = "/sister/quirks"
|
|
35
|
+
|
|
36
|
+
data: List[SisterQuirkModel]
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import msgspec
|
|
2
|
+
from typing import List
|
|
3
|
+
from ..common.base import BaseRequest
|
|
4
|
+
from ..models.user import UserModel
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
class User(BaseRequest):
|
|
8
|
+
"""Getting information about particular user
|
|
9
|
+
|
|
10
|
+
Requires user ID (same as slug)
|
|
11
|
+
"""
|
|
12
|
+
|
|
13
|
+
__endpoint__ = "/userId/{slug}"
|
|
14
|
+
__slug__ = True
|
|
15
|
+
|
|
16
|
+
data: UserModel
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
import aiohttp
|
|
2
|
+
from typing import TypeVar, Type
|
|
3
|
+
from .common import BASE_URL
|
|
4
|
+
from .common.base import BaseRequest
|
|
5
|
+
|
|
6
|
+
T = TypeVar("T", bound=BaseRequest)
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
class WarframeMarketClient:
|
|
10
|
+
"""Client for interacting with Warframe Market API."""
|
|
11
|
+
|
|
12
|
+
def __init__(self, base_url: str = BASE_URL):
|
|
13
|
+
self.base_url = base_url
|
|
14
|
+
self.response = None
|
|
15
|
+
|
|
16
|
+
async def get(self, request_class: Type[T], slug="", **kwargs) -> T:
|
|
17
|
+
"""Perform a GET request using the specified request class.
|
|
18
|
+
|
|
19
|
+
Args:
|
|
20
|
+
request_class: The request class that defines the endpoint and response type
|
|
21
|
+
slug: Optional slug to append to the endpoint URL
|
|
22
|
+
**kwargs: Additional query parameters to include in the request
|
|
23
|
+
|
|
24
|
+
Returns:
|
|
25
|
+
The parsed API response
|
|
26
|
+
"""
|
|
27
|
+
endpoint = request_class._get_endpoint(slug=slug, **kwargs)
|
|
28
|
+
url = f"{self.base_url}{endpoint}"
|
|
29
|
+
async with aiohttp.ClientSession() as session:
|
|
30
|
+
async with session.get(url) as response:
|
|
31
|
+
if response.status != 200:
|
|
32
|
+
raise Exception(f"Error {response.status}: {await response.text()}")
|
|
33
|
+
data = await response.text()
|
|
34
|
+
return request_class._decode(data)
|
|
35
|
+
|
|
36
|
+
async def __aenter__(self):
|
|
37
|
+
"""Enter async context manager."""
|
|
38
|
+
return self
|
|
39
|
+
|
|
40
|
+
async def __aexit__(self, exc_type, exc_value, traceback):
|
|
41
|
+
"""Exit async context manager."""
|
|
42
|
+
pass
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
|
|
2
|
+
BASE_URL = "https://api.warframe.market/v2"
|
|
3
|
+
BASE_STATIC_ASSETS_URL = "https://warframe.market/static/assets"
|
|
4
|
+
|
|
5
|
+
from .enums import (
|
|
6
|
+
Language,
|
|
7
|
+
Platform,
|
|
8
|
+
)
|
|
9
|
+
|
|
10
|
+
from .base import (
|
|
11
|
+
Base,
|
|
12
|
+
BaseRequest,
|
|
13
|
+
)
|
|
14
|
+
|
|
15
|
+
from .options import (
|
|
16
|
+
LanguageCode,
|
|
17
|
+
)
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
import msgspec
|
|
2
|
+
from datetime import datetime
|
|
3
|
+
from typing import TypeVar, ClassVar, Type, Optional, Any, List
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
def _dec_hook(type: Type, obj: Any) -> Any:
|
|
7
|
+
|
|
8
|
+
# Decode UTC dates
|
|
9
|
+
if isinstance(type, datetime) and isinstance(obj, str):
|
|
10
|
+
return datetime.fromisoformat(obj.strip("Z"))
|
|
11
|
+
|
|
12
|
+
# Will add more when needed
|
|
13
|
+
|
|
14
|
+
return obj
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
class Base(msgspec.Struct, kw_only=True):
|
|
18
|
+
"""Base model"""
|
|
19
|
+
|
|
20
|
+
api_version: str = msgspec.field(name="apiVersion")
|
|
21
|
+
error: Optional[Any] = None
|
|
22
|
+
|
|
23
|
+
|
|
24
|
+
T = TypeVar("T", bound=Base)
|
|
25
|
+
|
|
26
|
+
|
|
27
|
+
class BaseRequest(Base):
|
|
28
|
+
"""Base model for all Warframe Market API requests.
|
|
29
|
+
|
|
30
|
+
Attributes:
|
|
31
|
+
__endpoint__: The API endpoint for the request.
|
|
32
|
+
__params__: List of query parameters that can be used in the request.
|
|
33
|
+
__slug__: Whether the request requires a slug in the endpoint.
|
|
34
|
+
"""
|
|
35
|
+
|
|
36
|
+
__endpoint__: ClassVar[str]
|
|
37
|
+
__params__: ClassVar[List[str]] = []
|
|
38
|
+
__slug__: ClassVar[bool] = False
|
|
39
|
+
|
|
40
|
+
@classmethod
|
|
41
|
+
def _decode(cls: Type[T], response: str) -> T:
|
|
42
|
+
"""Decode the response string into a BaseResponse object."""
|
|
43
|
+
return msgspec.json.decode(response, type=cls, dec_hook=_dec_hook)
|
|
44
|
+
|
|
45
|
+
@classmethod
|
|
46
|
+
def _get_endpoint(cls, slug: Optional[str] = None, **kwargs) -> str:
|
|
47
|
+
"""Build the endpoint URL with optional slug and query parameters."""
|
|
48
|
+
endpoint = cls.__endpoint__
|
|
49
|
+
if cls.__slug__ and slug:
|
|
50
|
+
endpoint = endpoint.format(slug=slug)
|
|
51
|
+
if cls.__params__:
|
|
52
|
+
params = "&".join(
|
|
53
|
+
f"{k}={v}" for k, v in kwargs.items() if k in cls.__params__
|
|
54
|
+
)
|
|
55
|
+
if params:
|
|
56
|
+
endpoint += f"?{params}"
|
|
57
|
+
return endpoint
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
from enum import Enum
|
|
2
|
+
|
|
3
|
+
|
|
4
|
+
class Language(Enum):
|
|
5
|
+
KOREAN = "ko"
|
|
6
|
+
RUSSIAN = "ru"
|
|
7
|
+
GERMAN = "de"
|
|
8
|
+
FRENCH = "fr"
|
|
9
|
+
PORTUGUESE = "pt"
|
|
10
|
+
CHINESE_SIMPLIFIED = "zh-hans"
|
|
11
|
+
CHINESE_TRADITIONAL = "zh-hant"
|
|
12
|
+
SPANISH = "es"
|
|
13
|
+
ITALIAN = "it"
|
|
14
|
+
POLISH = "pl"
|
|
15
|
+
UKRAINIAN = "uk"
|
|
16
|
+
ENGLISH = "en"
|
|
17
|
+
|
|
18
|
+
def __str__(self):
|
|
19
|
+
return self.value
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
class Platform(Enum):
|
|
23
|
+
PC = "pc"
|
|
24
|
+
PS4 = "ps4"
|
|
25
|
+
XBOX = "xbox"
|
|
26
|
+
SWITCH = "switch"
|
|
27
|
+
MOBILE = "mobile"
|
|
28
|
+
|
|
29
|
+
def __str__(self):
|
|
30
|
+
return self.value
|
|
File without changes
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
import msgspec
|
|
2
|
+
from ..common.options import LanguageCode
|
|
3
|
+
|
|
4
|
+
|
|
5
|
+
class AchievementI18NModel(msgspec.Struct):
|
|
6
|
+
"""
|
|
7
|
+
Localized information for an achievement.
|
|
8
|
+
|
|
9
|
+
Attributes:
|
|
10
|
+
name: Localized name of the achievement
|
|
11
|
+
description: Localized description of the achievement
|
|
12
|
+
"""
|
|
13
|
+
|
|
14
|
+
name: str
|
|
15
|
+
description: str
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
class AchievementModel(msgspec.Struct):
|
|
19
|
+
"""
|
|
20
|
+
Model for site achievements.
|
|
21
|
+
|
|
22
|
+
Attributes:
|
|
23
|
+
id: Unique identifier for the achievement
|
|
24
|
+
icon: URL to the achievement's icon
|
|
25
|
+
thumb: URL to the achievement's thumbnail image
|
|
26
|
+
type: Type or category of the achievement
|
|
27
|
+
i18n: Localized text in various languages
|
|
28
|
+
"""
|
|
29
|
+
|
|
30
|
+
id: str
|
|
31
|
+
icon: str
|
|
32
|
+
thumb: str
|
|
33
|
+
type: str
|
|
34
|
+
i18n: dict[LanguageCode, AchievementI18NModel]
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
from typing import Optional
|
|
2
|
+
import msgspec
|
|
3
|
+
from enum import Enum
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
class ActivityType(str, Enum):
|
|
7
|
+
"""Types of activities a user can be engaged in."""
|
|
8
|
+
|
|
9
|
+
ON_MISSION = "on_mission"
|
|
10
|
+
DOJO = "dojo"
|
|
11
|
+
UNKNOWN = "unknown"
|
|
12
|
+
EMPTY = ""
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
class ActivityModel(msgspec.Struct):
|
|
16
|
+
"""
|
|
17
|
+
Model for user activity information.
|
|
18
|
+
|
|
19
|
+
Attributes:
|
|
20
|
+
type: Name of the activity (e.g., 'on mission', 'dojo')
|
|
21
|
+
details: Optional specifics about the activity
|
|
22
|
+
started_at: Timestamp of when the activity started
|
|
23
|
+
"""
|
|
24
|
+
|
|
25
|
+
type: ActivityType
|
|
26
|
+
details: Optional[str] = None
|
|
27
|
+
started_at: Optional[str] = msgspec.field(default=None, name="startedAt")
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
import msgspec
|
|
2
|
+
from ..common.options import LanguageCode
|
|
3
|
+
|
|
4
|
+
|
|
5
|
+
class ItemI18NModel(msgspec.Struct):
|
|
6
|
+
"""Localization data for an item."""
|
|
7
|
+
|
|
8
|
+
name: str
|
|
9
|
+
icon: str
|
|
10
|
+
thumb: str
|
|
11
|
+
description: str | None = None
|
|
12
|
+
wiki_link: str | None = msgspec.field(default=None, name="wikiLink")
|
|
13
|
+
sub_icon: str | None = msgspec.field(default=None, name="subIcon")
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
class ItemShortModel(msgspec.Struct):
|
|
17
|
+
"""Short form item data model."""
|
|
18
|
+
|
|
19
|
+
id: str
|
|
20
|
+
slug: str
|
|
21
|
+
game_ref: str = msgspec.field(name="gameRef")
|
|
22
|
+
tags: list[str] = msgspec.field(default_factory=list)
|
|
23
|
+
i18n: dict[LanguageCode, ItemI18NModel] = msgspec.field(default_factory=dict)
|
|
24
|
+
max_rank: int | None = msgspec.field(default=None, name="maxRank")
|
|
25
|
+
max_charges: int | None = msgspec.field(default=None, name="maxCharges")
|
|
26
|
+
vaulted: bool | None = None
|
|
27
|
+
ducats: int | None = None
|
|
28
|
+
amber_stars: int | None = msgspec.field(default=None, name="amberStars")
|
|
29
|
+
cyan_stars: int | None = msgspec.field(default=None, name="cyanStars")
|
|
30
|
+
base_endo: int | None = msgspec.field(default=None, name="baseEndo")
|
|
31
|
+
endo_multiplier: float | None = msgspec.field(default=None, name="endoMultiplier")
|
|
32
|
+
subtypes: list[str] = msgspec.field(default_factory=list)
|
|
33
|
+
|
|
34
|
+
|
|
35
|
+
class ItemModel(ItemShortModel):
|
|
36
|
+
"""Full item data model that extends ItemShortModel."""
|
|
37
|
+
|
|
38
|
+
tradable: bool | None = None
|
|
39
|
+
set_root: bool | None = msgspec.field(default=None, name="setRoot")
|
|
40
|
+
set_parts: list[str] | None = msgspec.field(default=None, name="setParts")
|
|
41
|
+
quantity_in_set: int | None = msgspec.field(default=None, name="quantityInSet")
|
|
42
|
+
rarity: str | None = None
|
|
43
|
+
bulk_tradable: bool | None = msgspec.field(default=None, name="bulkTradable")
|
|
44
|
+
max_amber_stars: int | None = msgspec.field(default=None, name="maxAmberStars")
|
|
45
|
+
max_cyan_stars: int | None = msgspec.field(default=None, name="maxCyanStars")
|
|
46
|
+
req_mastery_rank: int | None = msgspec.field(default=None, name="reqMasteryRank")
|
|
47
|
+
trading_tax: int | None = msgspec.field(default=None, name="tradingTax")
|
|
48
|
+
vosfor: int | None = None
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
import msgspec
|
|
2
|
+
from ..common.options import LanguageCode
|
|
3
|
+
|
|
4
|
+
|
|
5
|
+
# Lich Weapon
|
|
6
|
+
class LichWeaponI18NModel(msgspec.Struct):
|
|
7
|
+
"""Localization data for a Lich weapon."""
|
|
8
|
+
|
|
9
|
+
name: str = msgspec.field(name="itemName") # Changed to match Go struct's json tag
|
|
10
|
+
icon: str
|
|
11
|
+
thumb: str
|
|
12
|
+
wiki_link: str | None = msgspec.field(default=None, name="wikiLink")
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
class LichWeaponModel(msgspec.Struct):
|
|
16
|
+
"""Model for Kuva/Sister Lich weapons."""
|
|
17
|
+
|
|
18
|
+
id: str
|
|
19
|
+
slug: str
|
|
20
|
+
game_ref: str = msgspec.field(name="gameRef")
|
|
21
|
+
req_mastery_rank: int = msgspec.field(name="reqMasteryRank")
|
|
22
|
+
i18n: dict[LanguageCode, LichWeaponI18NModel] = msgspec.field(default_factory=dict)
|
|
23
|
+
|
|
24
|
+
|
|
25
|
+
# Lich Ephemera
|
|
26
|
+
class LichEphemeraI18NModel(msgspec.Struct):
|
|
27
|
+
"""Localization data for a Lich ephemera."""
|
|
28
|
+
|
|
29
|
+
name: str = msgspec.field(name="itemName")
|
|
30
|
+
icon: str
|
|
31
|
+
thumb: str
|
|
32
|
+
|
|
33
|
+
|
|
34
|
+
class LichEphemeraModel(msgspec.Struct):
|
|
35
|
+
"""Model for Kuva/Sister Lich ephemeras."""
|
|
36
|
+
|
|
37
|
+
id: str
|
|
38
|
+
slug: str
|
|
39
|
+
game_ref: str = msgspec.field(name="gameRef")
|
|
40
|
+
animation: str
|
|
41
|
+
element: str
|
|
42
|
+
i18n: dict[LanguageCode, LichEphemeraI18NModel] = msgspec.field(
|
|
43
|
+
default_factory=dict
|
|
44
|
+
)
|
|
45
|
+
|
|
46
|
+
|
|
47
|
+
# Lich Quirk
|
|
48
|
+
class LichQuirkI18NModel(msgspec.Struct):
|
|
49
|
+
"""Localization data for a Lich quirk."""
|
|
50
|
+
|
|
51
|
+
name: str = msgspec.field(name="itemName")
|
|
52
|
+
description: str | None = None
|
|
53
|
+
icon: str | None = None
|
|
54
|
+
thumb: str | None = None
|
|
55
|
+
|
|
56
|
+
|
|
57
|
+
class LichQuirkModel(msgspec.Struct):
|
|
58
|
+
"""Model for Kuva/Sister Lich quirks."""
|
|
59
|
+
|
|
60
|
+
id: str
|
|
61
|
+
slug: str
|
|
62
|
+
group: str | None = None
|
|
63
|
+
i18n: dict[LanguageCode, LichQuirkI18NModel] = msgspec.field(default_factory=dict)
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import msgspec
|
|
2
|
+
from ..common.options import LanguageCode
|
|
3
|
+
|
|
4
|
+
|
|
5
|
+
class LocationI18NModel(msgspec.Struct):
|
|
6
|
+
"""Localization data for a location."""
|
|
7
|
+
|
|
8
|
+
node_name: str = msgspec.field(name="nodeName")
|
|
9
|
+
icon: str
|
|
10
|
+
thumb: str
|
|
11
|
+
system_name: str | None = msgspec.field(default=None, name="systemName")
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
class LocationModel(msgspec.Struct):
|
|
15
|
+
"""Model for locations."""
|
|
16
|
+
|
|
17
|
+
id: str
|
|
18
|
+
slug: str
|
|
19
|
+
game_ref: str = msgspec.field(name="gameRef")
|
|
20
|
+
faction: str | None = None
|
|
21
|
+
min_level: int | None = msgspec.field(default=None, name="minLevel")
|
|
22
|
+
max_level: int | None = msgspec.field(default=None, name="maxLevel")
|
|
23
|
+
i18n: dict[LanguageCode, LocationI18NModel] = msgspec.field(default_factory=dict)
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import msgspec
|
|
2
|
+
from ..common.options import LanguageCode
|
|
3
|
+
|
|
4
|
+
|
|
5
|
+
class MissionI18NModel(msgspec.Struct):
|
|
6
|
+
"""Localization data for a mission."""
|
|
7
|
+
|
|
8
|
+
name: str
|
|
9
|
+
icon: str | None = None
|
|
10
|
+
thumb: str | None = None
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
class MissionModel(msgspec.Struct):
|
|
14
|
+
"""Model for missions."""
|
|
15
|
+
|
|
16
|
+
id: str
|
|
17
|
+
slug: str
|
|
18
|
+
game_ref: str = msgspec.field(name="gameRef")
|
|
19
|
+
i18n: dict[LanguageCode, MissionI18NModel] = msgspec.field(default_factory=dict)
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import msgspec
|
|
2
|
+
from ..common.options import LanguageCode
|
|
3
|
+
|
|
4
|
+
|
|
5
|
+
class NpcI18NModel(msgspec.Struct):
|
|
6
|
+
"""Localization data for an NPC."""
|
|
7
|
+
|
|
8
|
+
name: str
|
|
9
|
+
icon: str
|
|
10
|
+
thumb: str
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
class NpcModel(msgspec.Struct):
|
|
14
|
+
"""Model for NPCs."""
|
|
15
|
+
|
|
16
|
+
id: str
|
|
17
|
+
slug: str
|
|
18
|
+
game_ref: str = msgspec.field(name="gameRef")
|
|
19
|
+
i18n: dict[LanguageCode, NpcI18NModel] = msgspec.field(default_factory=dict)
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
import msgspec
|
|
2
|
+
from typing import Optional
|
|
3
|
+
|
|
4
|
+
from .user import UserShortModel
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
class OrderModel(msgspec.Struct):
|
|
8
|
+
"""
|
|
9
|
+
Model for trade orders.
|
|
10
|
+
|
|
11
|
+
Attributes:
|
|
12
|
+
id: Unique identifier of the order
|
|
13
|
+
type: Type of order ('buy' or 'sell')
|
|
14
|
+
platinum: Total platinum currency involved
|
|
15
|
+
quantity: Number of items in the order
|
|
16
|
+
per_trade: Optional items quantity per transaction
|
|
17
|
+
rank: Optional rank/level of the item
|
|
18
|
+
charges: Optional number of charges left (for requiem mods)
|
|
19
|
+
subtype: Optional specific subtype/category of the item
|
|
20
|
+
amber_stars: Optional count of amber stars (for sculpture orders)
|
|
21
|
+
cyan_stars: Optional count of cyan stars (for sculpture orders)
|
|
22
|
+
visible: Whether the order is publicly visible
|
|
23
|
+
created_at: Creation timestamp of the order
|
|
24
|
+
updated_at: Last modification timestamp
|
|
25
|
+
item_id: Unique identifier of the involved item
|
|
26
|
+
group: User-defined group for the order
|
|
27
|
+
"""
|
|
28
|
+
|
|
29
|
+
id: str
|
|
30
|
+
type: str
|
|
31
|
+
platinum: int
|
|
32
|
+
quantity: int
|
|
33
|
+
visible: bool
|
|
34
|
+
created_at: str = msgspec.field(name="createdAt")
|
|
35
|
+
updated_at: str = msgspec.field(name="updatedAt")
|
|
36
|
+
item_id: str = msgspec.field(name="itemId")
|
|
37
|
+
group: str
|
|
38
|
+
per_trade: Optional[int] = msgspec.field(default=None, name="perTrade")
|
|
39
|
+
rank: Optional[int] = None
|
|
40
|
+
charges: Optional[int] = None
|
|
41
|
+
subtype: Optional[str] = None
|
|
42
|
+
amber_stars: Optional[int] = msgspec.field(default=None, name="amberStars")
|
|
43
|
+
cyan_stars: Optional[int] = msgspec.field(default=None, name="cyanStars")
|
|
44
|
+
|
|
45
|
+
|
|
46
|
+
class OrderWithUserModel(OrderModel, kw_only=True):
|
|
47
|
+
"""
|
|
48
|
+
Model for trade orders with associated user information.
|
|
49
|
+
|
|
50
|
+
Extends the base Order model to include the user who created the order.
|
|
51
|
+
|
|
52
|
+
Additional Attributes:
|
|
53
|
+
user: Basic profile information of the order's creator
|
|
54
|
+
"""
|
|
55
|
+
|
|
56
|
+
user: UserShortModel
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
import msgspec
|
|
2
|
+
from typing import Literal
|
|
3
|
+
|
|
4
|
+
from ..common.options import LanguageCode
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
RivenType = Literal["rifle", "shotgun", "pistol", "melee", "kitgun", "zaw"]
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
class RivenI18N(msgspec.Struct):
|
|
11
|
+
"""Localization data for a Riven mod."""
|
|
12
|
+
|
|
13
|
+
name: str = msgspec.field(name="itemName")
|
|
14
|
+
icon: str
|
|
15
|
+
thumb: str
|
|
16
|
+
wiki_link: str | None = msgspec.field(default=None, name="wikiLink")
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
class RivenAttributeI18N(msgspec.Struct):
|
|
20
|
+
"""Localization data for a Riven attribute."""
|
|
21
|
+
|
|
22
|
+
name: str = msgspec.field(name="effect")
|
|
23
|
+
icon: str
|
|
24
|
+
thumb: str
|
|
25
|
+
|
|
26
|
+
|
|
27
|
+
class RivenModel(msgspec.Struct):
|
|
28
|
+
"""Model for Riven mods."""
|
|
29
|
+
|
|
30
|
+
id: str
|
|
31
|
+
slug: str
|
|
32
|
+
game_ref: str = msgspec.field(name="gameRef")
|
|
33
|
+
disposition: float
|
|
34
|
+
req_mastery_rank: int = msgspec.field(name="reqMasteryRank")
|
|
35
|
+
group: str | None = None
|
|
36
|
+
riven_type: str | None = msgspec.field(default=None, name="rivenType")
|
|
37
|
+
i18n: dict[LanguageCode, RivenI18N] = msgspec.field(default_factory=dict)
|
|
38
|
+
|
|
39
|
+
|
|
40
|
+
class RivenAttributeModel(msgspec.Struct):
|
|
41
|
+
"""Model for Riven mod attributes."""
|
|
42
|
+
|
|
43
|
+
id: str
|
|
44
|
+
slug: str
|
|
45
|
+
game_ref: str = msgspec.field(name="gameRef")
|
|
46
|
+
prefix: str
|
|
47
|
+
suffix: str
|
|
48
|
+
group: str | None = None
|
|
49
|
+
i18n: dict[LanguageCode, RivenAttributeI18N] = msgspec.field(default_factory=dict)
|
|
50
|
+
exclusive_to: list[str] | None = msgspec.field(default=None, name="exclusiveTo")
|
|
51
|
+
positive_is_negative: bool | None = msgspec.field(
|
|
52
|
+
default=None, name="positiveIsNegative"
|
|
53
|
+
)
|
|
54
|
+
unit: str | None = None
|
|
55
|
+
positive_only: bool | None = msgspec.field(default=None, name="positiveOnly")
|
|
56
|
+
negative_only: bool | None = msgspec.field(default=None, name="negativeOnly")
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
import msgspec
|
|
2
|
+
|
|
3
|
+
from ..common.options import LanguageCode
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
class SisterWeaponI18NModel(msgspec.Struct):
|
|
7
|
+
"""Localization data for a Sister weapon."""
|
|
8
|
+
|
|
9
|
+
name: str = msgspec.field(name="itemName")
|
|
10
|
+
icon: str
|
|
11
|
+
thumb: str
|
|
12
|
+
wiki_link: str | None = msgspec.field(default=None, name="wikiLink")
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
class SisterWeaponModel(msgspec.Struct):
|
|
16
|
+
"""Model for Sister weapons."""
|
|
17
|
+
|
|
18
|
+
id: str
|
|
19
|
+
slug: str
|
|
20
|
+
game_ref: str = msgspec.field(name="gameRef")
|
|
21
|
+
req_mastery_rank: int = msgspec.field(name="reqMasteryRank")
|
|
22
|
+
i18n: dict[LanguageCode, SisterWeaponI18NModel] = msgspec.field(
|
|
23
|
+
default_factory=dict
|
|
24
|
+
)
|
|
25
|
+
|
|
26
|
+
|
|
27
|
+
class SisterEphemeraI18NModel(msgspec.Struct):
|
|
28
|
+
"""Localization data for a Sister ephemera."""
|
|
29
|
+
|
|
30
|
+
name: str = msgspec.field(name="itemName")
|
|
31
|
+
icon: str
|
|
32
|
+
thumb: str
|
|
33
|
+
|
|
34
|
+
|
|
35
|
+
class SisterEphemeraModel(msgspec.Struct):
|
|
36
|
+
"""Model for Sister ephemeras."""
|
|
37
|
+
|
|
38
|
+
id: str
|
|
39
|
+
slug: str
|
|
40
|
+
game_ref: str = msgspec.field(name="gameRef")
|
|
41
|
+
animation: str
|
|
42
|
+
element: str
|
|
43
|
+
i18n: dict[LanguageCode, SisterEphemeraI18NModel] = msgspec.field(
|
|
44
|
+
default_factory=dict
|
|
45
|
+
)
|
|
46
|
+
|
|
47
|
+
|
|
48
|
+
class SisterQuirkI18NModel(msgspec.Struct):
|
|
49
|
+
"""Localization data for a Sister quirk."""
|
|
50
|
+
|
|
51
|
+
name: str = msgspec.field(name="itemName")
|
|
52
|
+
icon: str
|
|
53
|
+
thumb: str
|
|
54
|
+
description: str | None = None
|
|
55
|
+
|
|
56
|
+
|
|
57
|
+
class SisterQuirkModel(msgspec.Struct):
|
|
58
|
+
"""Model for Sister quirks."""
|
|
59
|
+
|
|
60
|
+
id: str
|
|
61
|
+
slug: str
|
|
62
|
+
group: str | None = None
|
|
63
|
+
i18n: dict[LanguageCode, SisterQuirkI18NModel] = msgspec.field(default_factory=dict)
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
import msgspec
|
|
2
|
+
from .activity import ActivityModel
|
|
3
|
+
from .achievement import AchievementModel
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
class UserShortModel(msgspec.Struct):
|
|
7
|
+
"""
|
|
8
|
+
Short form user data model.
|
|
9
|
+
|
|
10
|
+
Attributes:
|
|
11
|
+
id: Unique identifier of the user
|
|
12
|
+
ingame_name: In-game name of the user
|
|
13
|
+
avatar: Optional avatar image URL
|
|
14
|
+
reputation: Reputation score
|
|
15
|
+
locale: Preferred communication language (e.g., 'en', 'ko', 'es')
|
|
16
|
+
platform: Gaming platform used by the user
|
|
17
|
+
crossplay: Whether the user has crossplay enabled
|
|
18
|
+
status: Current status of the user
|
|
19
|
+
activity: Current activity of the user
|
|
20
|
+
last_seen: Timestamp of the user's last online presence
|
|
21
|
+
"""
|
|
22
|
+
|
|
23
|
+
id: str
|
|
24
|
+
ingame_name: str = msgspec.field(name="ingameName")
|
|
25
|
+
reputation: int
|
|
26
|
+
locale: str
|
|
27
|
+
platform: str
|
|
28
|
+
crossplay: bool
|
|
29
|
+
status: str
|
|
30
|
+
activity: ActivityModel
|
|
31
|
+
last_seen: str = msgspec.field(name="lastSeen")
|
|
32
|
+
avatar: str | None = None
|
|
33
|
+
|
|
34
|
+
|
|
35
|
+
class UserModel(UserShortModel, kw_only=True):
|
|
36
|
+
"""
|
|
37
|
+
Full user profile model that extends UserShortModel.
|
|
38
|
+
|
|
39
|
+
Additional Attributes:
|
|
40
|
+
background: Optional profile background image URL
|
|
41
|
+
about: Optional HTML-formatted user description
|
|
42
|
+
mastery_level: Optional in-game mastery level
|
|
43
|
+
achievement_showcase: List of showcased achievements
|
|
44
|
+
banned: Whether the user is currently banned
|
|
45
|
+
ban_until: Optional ban expiration timestamp
|
|
46
|
+
warned: Whether the user has been warned (mod/admin only)
|
|
47
|
+
warn_message: Optional warning message (mod/admin only)
|
|
48
|
+
ban_message: Optional ban reason (mod/admin only)
|
|
49
|
+
"""
|
|
50
|
+
|
|
51
|
+
background: str | None = None
|
|
52
|
+
about: str | None = None
|
|
53
|
+
mastery_level: int | None = msgspec.field(default=None, name="masteryLevel")
|
|
54
|
+
achievement_showcase: list[AchievementModel] = msgspec.field(
|
|
55
|
+
default_factory=list, name="achievementShowcase"
|
|
56
|
+
)
|
|
57
|
+
banned: bool | None = None
|
|
58
|
+
ban_until: str | None = msgspec.field(default=None, name="banUntil")
|
|
59
|
+
warned: bool | None = None
|
|
60
|
+
warn_message: str | None = msgspec.field(default=None, name="warnMessage")
|
|
61
|
+
ban_message: str | None = msgspec.field(default=None, name="banMessage")
|
|
@@ -0,0 +1,112 @@
|
|
|
1
|
+
import msgspec
|
|
2
|
+
from enum import Enum
|
|
3
|
+
from typing import List, Optional
|
|
4
|
+
|
|
5
|
+
from .activity import ActivityModel
|
|
6
|
+
from .achievement import AchievementModel
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
class Role(str, Enum):
|
|
10
|
+
"""User roles in the system."""
|
|
11
|
+
|
|
12
|
+
USER = "user"
|
|
13
|
+
MODERATOR = "moderator"
|
|
14
|
+
ADMIN = "admin"
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
class Tier(str, Enum):
|
|
18
|
+
"""Subscription tiers."""
|
|
19
|
+
|
|
20
|
+
NONE = "none"
|
|
21
|
+
BRONZE = "bronze"
|
|
22
|
+
SILVER = "silver"
|
|
23
|
+
GOLD = "gold"
|
|
24
|
+
DIAMOND = "diamond"
|
|
25
|
+
|
|
26
|
+
|
|
27
|
+
class LinkedAccounts(msgspec.Struct):
|
|
28
|
+
"""Model for linked external accounts."""
|
|
29
|
+
|
|
30
|
+
pass
|
|
31
|
+
|
|
32
|
+
|
|
33
|
+
class UserPrivateModel(msgspec.Struct):
|
|
34
|
+
"""
|
|
35
|
+
Private user profile with full details and sensitive information.
|
|
36
|
+
|
|
37
|
+
Attributes:
|
|
38
|
+
id: Unique identifier of the user
|
|
39
|
+
role: User's role in the system (e.g., user, moderator, admin)
|
|
40
|
+
ingame_name: In-game name of the user
|
|
41
|
+
reputation: Reputation score
|
|
42
|
+
locale: Preferred communication language (e.g., 'en', 'ko', 'es')
|
|
43
|
+
platform: Gaming platform used by the user
|
|
44
|
+
crossplay: Whether the user has crossplay enabled
|
|
45
|
+
status: Current status of the user
|
|
46
|
+
activity: Current activity of the user
|
|
47
|
+
last_seen: Timestamp of the user's last online presence
|
|
48
|
+
mastery_rank: In-game mastery rank
|
|
49
|
+
credits: User's credit balance
|
|
50
|
+
theme: User's selected theme
|
|
51
|
+
verification: Whether the user is verified
|
|
52
|
+
check_code: Verification check code
|
|
53
|
+
tier: Subscription tier of the user
|
|
54
|
+
subscription: Whether the user has an active subscription
|
|
55
|
+
linked_accounts: Linked external accounts information
|
|
56
|
+
has_email: Whether the user has an email address associated with their account
|
|
57
|
+
created_at: Account creation timestamp
|
|
58
|
+
reviews_left: Number of reviews left by the user
|
|
59
|
+
unread_messages: Count of unread messages in the user's inbox
|
|
60
|
+
avatar: Optional avatar image URL
|
|
61
|
+
achievement_showcase: List of achievements showcased by the user
|
|
62
|
+
ignore_list: List of user IDs that this user has ignored
|
|
63
|
+
about: Optional HTML-formatted user description
|
|
64
|
+
about_raw: Optional raw text version of the user's description
|
|
65
|
+
warned: Whether the user has been warned (mod/admin only)
|
|
66
|
+
warn_message: Optional warning message (mod/admin only)
|
|
67
|
+
banned: Whether the user is currently banned (mod/admin only)
|
|
68
|
+
ban_until: Optional timestamp until which the user is banned (mod/admin only)
|
|
69
|
+
ban_message: Optional reason for the ban (mod/admin only)
|
|
70
|
+
delete_in_progress: Whether the user account deletion is in progress (mod/admin only)
|
|
71
|
+
delete_at: Optional timestamp when the account deletion is scheduled (mod/admin only)
|
|
72
|
+
"""
|
|
73
|
+
|
|
74
|
+
id: str
|
|
75
|
+
role: Role
|
|
76
|
+
ingame_name: str = msgspec.field(name="ingameName")
|
|
77
|
+
reputation: int
|
|
78
|
+
locale: str
|
|
79
|
+
platform: str
|
|
80
|
+
crossplay: bool
|
|
81
|
+
status: str
|
|
82
|
+
activity: ActivityModel
|
|
83
|
+
last_seen: str = msgspec.field(name="lastSeen")
|
|
84
|
+
mastery_rank: int = msgspec.field(name="masteryRank")
|
|
85
|
+
credits: int
|
|
86
|
+
theme: str
|
|
87
|
+
verification: bool
|
|
88
|
+
check_code: str = msgspec.field(name="checkCode")
|
|
89
|
+
tier: Tier
|
|
90
|
+
subscription: bool
|
|
91
|
+
linked_accounts: LinkedAccounts = msgspec.field(name="linkedAccounts")
|
|
92
|
+
has_email: bool = msgspec.field(name="hasEmail")
|
|
93
|
+
created_at: str = msgspec.field(name="createdAt")
|
|
94
|
+
reviews_left: int = msgspec.field(name="reviewsLeft")
|
|
95
|
+
unread_messages: int = msgspec.field(name="unreadMessages")
|
|
96
|
+
# Optional fields
|
|
97
|
+
avatar: str | None = None
|
|
98
|
+
achievement_showcase: List[AchievementModel] = msgspec.field(
|
|
99
|
+
default_factory=list, name="achievementShowcase"
|
|
100
|
+
)
|
|
101
|
+
ignore_list: List[str] = msgspec.field(default_factory=list, name="ignoreList")
|
|
102
|
+
about: Optional[str] = None
|
|
103
|
+
about_raw: Optional[str] = msgspec.field(default=None, name="aboutRaw")
|
|
104
|
+
warned: Optional[bool] = None
|
|
105
|
+
warn_message: Optional[str] = msgspec.field(default=None, name="warnMessage")
|
|
106
|
+
banned: Optional[bool] = None
|
|
107
|
+
ban_until: Optional[str] = msgspec.field(default=None, name="banUntil")
|
|
108
|
+
ban_message: Optional[str] = msgspec.field(default=None, name="banMessage")
|
|
109
|
+
delete_in_progress: Optional[bool] = msgspec.field(
|
|
110
|
+
default=None, name="deleteInProgress"
|
|
111
|
+
)
|
|
112
|
+
delete_at: Optional[str] = msgspec.field(default=None, name="deleteAt")
|
|
File without changes
|