valentina-python-client 3.2.0__tar.gz → 3.4.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.
- {valentina_python_client-3.2.0 → valentina_python_client-3.4.0}/PKG-INFO +5 -4
- valentina_python_client-3.4.0/pyproject.toml +244 -0
- valentina_python_client-3.2.0/pyproject.toml → valentina_python_client-3.4.0/pyproject.toml.orig +20 -17
- {valentina_python_client-3.2.0 → valentina_python_client-3.4.0}/src/vclient/__init__.py +2 -2
- {valentina_python_client-3.2.0 → valentina_python_client-3.4.0}/src/vclient/_sync/services/campaigns.py +7 -3
- {valentina_python_client-3.2.0 → valentina_python_client-3.4.0}/src/vclient/_sync/services/character_traits.py +227 -3
- {valentina_python_client-3.2.0 → valentina_python_client-3.4.0}/src/vclient/_sync/services/characters.py +103 -3
- {valentina_python_client-3.2.0 → valentina_python_client-3.4.0}/src/vclient/_sync/services/options.py +7 -2
- {valentina_python_client-3.2.0 → valentina_python_client-3.4.0}/src/vclient/constants.py +5 -0
- {valentina_python_client-3.2.0 → valentina_python_client-3.4.0}/src/vclient/endpoints.py +6 -0
- {valentina_python_client-3.2.0 → valentina_python_client-3.4.0}/src/vclient/exceptions.py +3 -1
- {valentina_python_client-3.2.0 → valentina_python_client-3.4.0}/src/vclient/models/__init__.py +26 -0
- {valentina_python_client-3.2.0 → valentina_python_client-3.4.0}/src/vclient/models/campaigns.py +4 -1
- valentina_python_client-3.4.0/src/vclient/models/character_trait.py +286 -0
- {valentina_python_client-3.2.0 → valentina_python_client-3.4.0}/src/vclient/models/characters.py +18 -2
- {valentina_python_client-3.2.0 → valentina_python_client-3.4.0}/src/vclient/models/companies.py +3 -0
- {valentina_python_client-3.2.0 → valentina_python_client-3.4.0}/src/vclient/models/dictionary.py +5 -0
- {valentina_python_client-3.2.0 → valentina_python_client-3.4.0}/src/vclient/models/shared.py +29 -1
- {valentina_python_client-3.2.0 → valentina_python_client-3.4.0}/src/vclient/services/campaigns.py +9 -2
- {valentina_python_client-3.2.0 → valentina_python_client-3.4.0}/src/vclient/services/character_traits.py +244 -3
- {valentina_python_client-3.2.0 → valentina_python_client-3.4.0}/src/vclient/services/characters.py +112 -2
- {valentina_python_client-3.2.0 → valentina_python_client-3.4.0}/src/vclient/services/options.py +7 -2
- {valentina_python_client-3.2.0 → valentina_python_client-3.4.0}/src/vclient/testing/__init__.py +10 -0
- {valentina_python_client-3.2.0 → valentina_python_client-3.4.0}/src/vclient/testing/_factories.py +132 -6
- {valentina_python_client-3.2.0 → valentina_python_client-3.4.0}/src/vclient/testing/_router.py +17 -2
- {valentina_python_client-3.2.0 → valentina_python_client-3.4.0}/src/vclient/testing/_routes.py +26 -0
- {valentina_python_client-3.2.0 → valentina_python_client-3.4.0}/src/vclient/validate_constants.py +3 -0
- valentina_python_client-3.2.0/src/vclient/models/character_trait.py +0 -116
- {valentina_python_client-3.2.0 → valentina_python_client-3.4.0}/LICENSE +0 -0
- {valentina_python_client-3.2.0 → valentina_python_client-3.4.0}/README.md +0 -0
- {valentina_python_client-3.2.0 → valentina_python_client-3.4.0}/src/vclient/_codegen.py +0 -0
- {valentina_python_client-3.2.0 → valentina_python_client-3.4.0}/src/vclient/_sync/__init__.py +0 -0
- {valentina_python_client-3.2.0 → valentina_python_client-3.4.0}/src/vclient/_sync/client.py +0 -0
- {valentina_python_client-3.2.0 → valentina_python_client-3.4.0}/src/vclient/_sync/registry.py +0 -0
- {valentina_python_client-3.2.0 → valentina_python_client-3.4.0}/src/vclient/_sync/services/__init__.py +0 -0
- {valentina_python_client-3.2.0 → valentina_python_client-3.4.0}/src/vclient/_sync/services/_audit_params.py +0 -0
- {valentina_python_client-3.2.0 → valentina_python_client-3.4.0}/src/vclient/_sync/services/base.py +0 -0
- {valentina_python_client-3.2.0 → valentina_python_client-3.4.0}/src/vclient/_sync/services/campaign_book_chapters.py +0 -0
- {valentina_python_client-3.2.0 → valentina_python_client-3.4.0}/src/vclient/_sync/services/campaign_books.py +0 -0
- {valentina_python_client-3.2.0 → valentina_python_client-3.4.0}/src/vclient/_sync/services/character_autogen.py +0 -0
- {valentina_python_client-3.2.0 → valentina_python_client-3.4.0}/src/vclient/_sync/services/character_blueprint.py +0 -0
- {valentina_python_client-3.2.0 → valentina_python_client-3.4.0}/src/vclient/_sync/services/companies.py +0 -0
- {valentina_python_client-3.2.0 → valentina_python_client-3.4.0}/src/vclient/_sync/services/developers.py +0 -0
- {valentina_python_client-3.2.0 → valentina_python_client-3.4.0}/src/vclient/_sync/services/dicerolls.py +0 -0
- {valentina_python_client-3.2.0 → valentina_python_client-3.4.0}/src/vclient/_sync/services/dictionary.py +0 -0
- {valentina_python_client-3.2.0 → valentina_python_client-3.4.0}/src/vclient/_sync/services/global_admin.py +0 -0
- {valentina_python_client-3.2.0 → valentina_python_client-3.4.0}/src/vclient/_sync/services/identity.py +0 -0
- {valentina_python_client-3.2.0 → valentina_python_client-3.4.0}/src/vclient/_sync/services/system.py +0 -0
- {valentina_python_client-3.2.0 → valentina_python_client-3.4.0}/src/vclient/_sync/services/user_lookup.py +0 -0
- {valentina_python_client-3.2.0 → valentina_python_client-3.4.0}/src/vclient/_sync/services/users.py +0 -0
- {valentina_python_client-3.2.0 → valentina_python_client-3.4.0}/src/vclient/_sync/testing/__init__.py +0 -0
- {valentina_python_client-3.2.0 → valentina_python_client-3.4.0}/src/vclient/_sync/testing/_client.py +0 -0
- {valentina_python_client-3.2.0 → valentina_python_client-3.4.0}/src/vclient/client.py +0 -0
- {valentina_python_client-3.2.0 → valentina_python_client-3.4.0}/src/vclient/config.py +0 -0
- {valentina_python_client-3.2.0 → valentina_python_client-3.4.0}/src/vclient/models/audit_logs.py +0 -0
- {valentina_python_client-3.2.0 → valentina_python_client-3.4.0}/src/vclient/models/books.py +0 -0
- {valentina_python_client-3.2.0 → valentina_python_client-3.4.0}/src/vclient/models/chapters.py +0 -0
- {valentina_python_client-3.2.0 → valentina_python_client-3.4.0}/src/vclient/models/character_autogen.py +0 -0
- {valentina_python_client-3.2.0 → valentina_python_client-3.4.0}/src/vclient/models/character_blueprint.py +0 -0
- {valentina_python_client-3.2.0 → valentina_python_client-3.4.0}/src/vclient/models/developers.py +0 -0
- {valentina_python_client-3.2.0 → valentina_python_client-3.4.0}/src/vclient/models/diceroll.py +0 -0
- {valentina_python_client-3.2.0 → valentina_python_client-3.4.0}/src/vclient/models/full_sheet.py +0 -0
- {valentina_python_client-3.2.0 → valentina_python_client-3.4.0}/src/vclient/models/global_admin.py +0 -0
- {valentina_python_client-3.2.0 → valentina_python_client-3.4.0}/src/vclient/models/pagination.py +0 -0
- {valentina_python_client-3.2.0 → valentina_python_client-3.4.0}/src/vclient/models/system.py +0 -0
- {valentina_python_client-3.2.0 → valentina_python_client-3.4.0}/src/vclient/models/user_lookup.py +0 -0
- {valentina_python_client-3.2.0 → valentina_python_client-3.4.0}/src/vclient/models/users.py +0 -0
- {valentina_python_client-3.2.0 → valentina_python_client-3.4.0}/src/vclient/py.typed +0 -0
- {valentina_python_client-3.2.0 → valentina_python_client-3.4.0}/src/vclient/registry.py +0 -0
- {valentina_python_client-3.2.0 → valentina_python_client-3.4.0}/src/vclient/services/__init__.py +0 -0
- {valentina_python_client-3.2.0 → valentina_python_client-3.4.0}/src/vclient/services/_audit_params.py +0 -0
- {valentina_python_client-3.2.0 → valentina_python_client-3.4.0}/src/vclient/services/base.py +0 -0
- {valentina_python_client-3.2.0 → valentina_python_client-3.4.0}/src/vclient/services/campaign_book_chapters.py +0 -0
- {valentina_python_client-3.2.0 → valentina_python_client-3.4.0}/src/vclient/services/campaign_books.py +0 -0
- {valentina_python_client-3.2.0 → valentina_python_client-3.4.0}/src/vclient/services/character_autogen.py +0 -0
- {valentina_python_client-3.2.0 → valentina_python_client-3.4.0}/src/vclient/services/character_blueprint.py +0 -0
- {valentina_python_client-3.2.0 → valentina_python_client-3.4.0}/src/vclient/services/companies.py +0 -0
- {valentina_python_client-3.2.0 → valentina_python_client-3.4.0}/src/vclient/services/developers.py +0 -0
- {valentina_python_client-3.2.0 → valentina_python_client-3.4.0}/src/vclient/services/dicerolls.py +0 -0
- {valentina_python_client-3.2.0 → valentina_python_client-3.4.0}/src/vclient/services/dictionary.py +0 -0
- {valentina_python_client-3.2.0 → valentina_python_client-3.4.0}/src/vclient/services/global_admin.py +0 -0
- {valentina_python_client-3.2.0 → valentina_python_client-3.4.0}/src/vclient/services/identity.py +0 -0
- {valentina_python_client-3.2.0 → valentina_python_client-3.4.0}/src/vclient/services/system.py +0 -0
- {valentina_python_client-3.2.0 → valentina_python_client-3.4.0}/src/vclient/services/user_lookup.py +0 -0
- {valentina_python_client-3.2.0 → valentina_python_client-3.4.0}/src/vclient/services/users.py +0 -0
- {valentina_python_client-3.2.0 → valentina_python_client-3.4.0}/src/vclient/testing/_client.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.3
|
|
2
2
|
Name: valentina-python-client
|
|
3
|
-
Version: 3.
|
|
3
|
+
Version: 3.4.0
|
|
4
4
|
Summary: Async Python client library for the Valentina Noir API
|
|
5
5
|
Author: Nate Landau
|
|
6
6
|
Author-email: Nate Landau <github@natenate.org>
|
|
@@ -15,11 +15,12 @@ License: MIT License
|
|
|
15
15
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
|
16
16
|
Classifier: Programming Language :: Python :: 3.13
|
|
17
17
|
Classifier: Programming Language :: Python :: 3.14
|
|
18
|
-
|
|
19
|
-
Requires-Dist:
|
|
18
|
+
Classifier: Programming Language :: Python :: 3.15
|
|
19
|
+
Requires-Dist: anyio>=4.15.1,<5.0.0
|
|
20
|
+
Requires-Dist: httpx2>=2.13.1
|
|
20
21
|
Requires-Dist: loguru>=0.7.3
|
|
21
22
|
Requires-Dist: polyfactory>=3.3.0,<4.0.0
|
|
22
|
-
Requires-Dist: pydantic[email]>=2.
|
|
23
|
+
Requires-Dist: pydantic[email]>=2.14.1,<3.0.0
|
|
23
24
|
Requires-Dist: polyfactory>=3.3.0 ; extra == 'testing'
|
|
24
25
|
Requires-Python: >=3.13
|
|
25
26
|
Project-URL: Homepage, https://docs.valentina-noir.com/python-api-client/
|
|
@@ -0,0 +1,244 @@
|
|
|
1
|
+
[project]
|
|
2
|
+
classifiers = [
|
|
3
|
+
"Programming Language :: Python :: 3.13",
|
|
4
|
+
"Programming Language :: Python :: 3.14",
|
|
5
|
+
"Programming Language :: Python :: 3.15",
|
|
6
|
+
]
|
|
7
|
+
dependencies = [
|
|
8
|
+
"anyio>=4.15.1,<5.0.0",
|
|
9
|
+
"httpx2>=2.13.1",
|
|
10
|
+
"loguru>=0.7.3",
|
|
11
|
+
"polyfactory>=3.3.0, <4.0.0",
|
|
12
|
+
"pydantic[email]>=2.14.1,<3.0.0",
|
|
13
|
+
]
|
|
14
|
+
description = "Async Python client library for the Valentina Noir API"
|
|
15
|
+
name = "valentina-python-client"
|
|
16
|
+
readme = "README.md"
|
|
17
|
+
requires-python = ">=3.13"
|
|
18
|
+
version = "3.4.0"
|
|
19
|
+
|
|
20
|
+
[[project.authors]]
|
|
21
|
+
name = "Nate Landau"
|
|
22
|
+
email = "github@natenate.org"
|
|
23
|
+
|
|
24
|
+
[project.license]
|
|
25
|
+
file = "LICENSE"
|
|
26
|
+
|
|
27
|
+
[project.optional-dependencies]
|
|
28
|
+
testing = ["polyfactory>=3.3.0"]
|
|
29
|
+
|
|
30
|
+
[project.urls]
|
|
31
|
+
Homepage = "https://docs.valentina-noir.com/python-api-client/"
|
|
32
|
+
Repository = "https://github.com/natelandau/valentina-python-client"
|
|
33
|
+
|
|
34
|
+
[build-system]
|
|
35
|
+
build-backend = "uv_build"
|
|
36
|
+
requires = ["uv_build>=0.13.0,<0.14"]
|
|
37
|
+
|
|
38
|
+
[tool.uv.build-backend]
|
|
39
|
+
module-name = "vclient"
|
|
40
|
+
|
|
41
|
+
[tool.commitizen]
|
|
42
|
+
bump_message = "bump(release): v$current_version → v$new_version"
|
|
43
|
+
changelog_merge_prerelease = true
|
|
44
|
+
tag_format = "v$version"
|
|
45
|
+
update_changelog_on_bump = true
|
|
46
|
+
version_files = ["src/vclient/__init__.py:__version__"]
|
|
47
|
+
version_provider = "uv"
|
|
48
|
+
|
|
49
|
+
[tool.coverage.report]
|
|
50
|
+
exclude_lines = [
|
|
51
|
+
"def __repr__",
|
|
52
|
+
'except [\w\s\._]+ as .*:',
|
|
53
|
+
"if TYPE_CHECKING",
|
|
54
|
+
"pragma: no cover",
|
|
55
|
+
"raise Abort",
|
|
56
|
+
"raise Exit",
|
|
57
|
+
]
|
|
58
|
+
fail_under = 0
|
|
59
|
+
precision = 1
|
|
60
|
+
show_missing = true
|
|
61
|
+
skip_covered = true
|
|
62
|
+
skip_empty = true
|
|
63
|
+
|
|
64
|
+
[tool.coverage.run]
|
|
65
|
+
branch = true
|
|
66
|
+
command_line = "--module pytest"
|
|
67
|
+
data_file = ".cache/coverage"
|
|
68
|
+
omit = ["tests/*"]
|
|
69
|
+
source = ["src"]
|
|
70
|
+
|
|
71
|
+
[tool.coverage.xml]
|
|
72
|
+
output = ".cache/coverage.xml"
|
|
73
|
+
|
|
74
|
+
[tool.pytest.ini_options]
|
|
75
|
+
addopts = "--color=yes --doctest-modules --strict-config --strict-markers -n auto --dist loadfile"
|
|
76
|
+
cache_dir = ".cache/pytest"
|
|
77
|
+
filterwarnings = [
|
|
78
|
+
"error",
|
|
79
|
+
"ignore:.*Pydantic.*:UserWarning",
|
|
80
|
+
"ignore::DeprecationWarning:",
|
|
81
|
+
]
|
|
82
|
+
markers = ["serial"]
|
|
83
|
+
testpaths = ["tests"]
|
|
84
|
+
xfail_strict = true
|
|
85
|
+
|
|
86
|
+
[tool.ruff]
|
|
87
|
+
exclude = [
|
|
88
|
+
".cache",
|
|
89
|
+
".dev",
|
|
90
|
+
".git",
|
|
91
|
+
".venv",
|
|
92
|
+
".worktrees",
|
|
93
|
+
"_build",
|
|
94
|
+
"_site",
|
|
95
|
+
"build",
|
|
96
|
+
"dist",
|
|
97
|
+
]
|
|
98
|
+
fix = true
|
|
99
|
+
line-length = 100
|
|
100
|
+
output-format = "grouped"
|
|
101
|
+
src = [
|
|
102
|
+
"src",
|
|
103
|
+
"tests",
|
|
104
|
+
]
|
|
105
|
+
target-version = "py313"
|
|
106
|
+
|
|
107
|
+
[tool.ruff.lint]
|
|
108
|
+
ignore = [
|
|
109
|
+
"ANN002",
|
|
110
|
+
"ANN003",
|
|
111
|
+
"ANN204",
|
|
112
|
+
"ANN401",
|
|
113
|
+
"B006",
|
|
114
|
+
"B008",
|
|
115
|
+
"COM812",
|
|
116
|
+
"CPY001",
|
|
117
|
+
"D107",
|
|
118
|
+
"E501",
|
|
119
|
+
"PLC0415",
|
|
120
|
+
"E711",
|
|
121
|
+
"E712",
|
|
122
|
+
"FIX002",
|
|
123
|
+
"S311",
|
|
124
|
+
"TD001",
|
|
125
|
+
"TD002",
|
|
126
|
+
"TD003",
|
|
127
|
+
]
|
|
128
|
+
select = ["ALL"]
|
|
129
|
+
unfixable = [
|
|
130
|
+
"ERA001",
|
|
131
|
+
"F401",
|
|
132
|
+
"F841",
|
|
133
|
+
]
|
|
134
|
+
|
|
135
|
+
[tool.ruff.lint.per-file-ignores]
|
|
136
|
+
"src/vclient/_sync/**" = [
|
|
137
|
+
"C416",
|
|
138
|
+
"C901",
|
|
139
|
+
"D",
|
|
140
|
+
"E501",
|
|
141
|
+
"ERA001",
|
|
142
|
+
"PLR0913",
|
|
143
|
+
"PLR2004",
|
|
144
|
+
"PLW0603",
|
|
145
|
+
"SLF001",
|
|
146
|
+
"TRY300",
|
|
147
|
+
"UP028",
|
|
148
|
+
]
|
|
149
|
+
"scripts/*.py" = [
|
|
150
|
+
"INP001",
|
|
151
|
+
"T201",
|
|
152
|
+
]
|
|
153
|
+
"src/vclient/services/*.py" = ["PLR0913"]
|
|
154
|
+
"src/vclient/validate_constants.py" = ["T201"]
|
|
155
|
+
"tests/**/*.py" = [
|
|
156
|
+
"A002",
|
|
157
|
+
"A003",
|
|
158
|
+
"ANN001",
|
|
159
|
+
"ANN002",
|
|
160
|
+
"ANN003",
|
|
161
|
+
"ANN201",
|
|
162
|
+
"ARG001",
|
|
163
|
+
"ARG002",
|
|
164
|
+
"ARG005",
|
|
165
|
+
"D102",
|
|
166
|
+
"ERA001",
|
|
167
|
+
"F403",
|
|
168
|
+
"F405",
|
|
169
|
+
"FBT001",
|
|
170
|
+
"PGH003",
|
|
171
|
+
"PLC0415",
|
|
172
|
+
"PLR0913",
|
|
173
|
+
"PLR0917",
|
|
174
|
+
"PLR2004",
|
|
175
|
+
"PT011",
|
|
176
|
+
"S101",
|
|
177
|
+
"SLF001",
|
|
178
|
+
"W292",
|
|
179
|
+
]
|
|
180
|
+
|
|
181
|
+
[tool.ruff.lint.mccabe]
|
|
182
|
+
max-complexity = 10
|
|
183
|
+
|
|
184
|
+
[tool.ruff.lint.isort]
|
|
185
|
+
combine-as-imports = true
|
|
186
|
+
|
|
187
|
+
[tool.ruff.lint.pydocstyle]
|
|
188
|
+
convention = "google"
|
|
189
|
+
|
|
190
|
+
[tool.ruff.lint.pylint]
|
|
191
|
+
max-args = 6
|
|
192
|
+
|
|
193
|
+
[tool.ruff.format]
|
|
194
|
+
exclude = ["src/vclient/_sync"]
|
|
195
|
+
indent-style = "space"
|
|
196
|
+
line-ending = "auto"
|
|
197
|
+
quote-style = "double"
|
|
198
|
+
skip-magic-trailing-comma = false
|
|
199
|
+
|
|
200
|
+
[tool.vulture]
|
|
201
|
+
exclude = [
|
|
202
|
+
"duties.py",
|
|
203
|
+
"scripts/",
|
|
204
|
+
"tests/",
|
|
205
|
+
"tmp/",
|
|
206
|
+
]
|
|
207
|
+
ignore_decorators = []
|
|
208
|
+
ignore_names = []
|
|
209
|
+
make_whitelist = false
|
|
210
|
+
min_confidence = 100
|
|
211
|
+
paths = ["src/"]
|
|
212
|
+
sort_by_size = true
|
|
213
|
+
verbose = false
|
|
214
|
+
|
|
215
|
+
[tool.ty.terminal]
|
|
216
|
+
error-on-warning = true
|
|
217
|
+
|
|
218
|
+
[dependency-groups]
|
|
219
|
+
dev = [
|
|
220
|
+
"commitizen>=4.19.2",
|
|
221
|
+
"coverage>=7.16.2",
|
|
222
|
+
"duty>=1.10.1",
|
|
223
|
+
"gate-cache>=0.6.0",
|
|
224
|
+
"httpx>=0.28.1",
|
|
225
|
+
"prek>=0.5.5",
|
|
226
|
+
"pytest-anyio>=0.0.0",
|
|
227
|
+
"pytest-clarity>=1.0.1",
|
|
228
|
+
"pytest-cov>=7.1.0",
|
|
229
|
+
"pytest-devtools>=1.3.0",
|
|
230
|
+
"pytest-httpx2>=1.0.0",
|
|
231
|
+
"pytest-mock>=3.16.0",
|
|
232
|
+
"pytest-repeat>=0.9.4",
|
|
233
|
+
"pytest-sugar>=1.1.1",
|
|
234
|
+
"pytest-xdist>=3.8.0",
|
|
235
|
+
"pytest>=9.1.1",
|
|
236
|
+
"respx>=0.23.1",
|
|
237
|
+
"ruff>=0.17.0",
|
|
238
|
+
"shellcheck-py>=0.11.0.1",
|
|
239
|
+
"ty>=0.0.86",
|
|
240
|
+
"typos>=1.51.1",
|
|
241
|
+
"vulture>=2.16",
|
|
242
|
+
"yamllint>=1.38.0",
|
|
243
|
+
]
|
|
244
|
+
docs = ["zensical>=0.0.70"]
|
valentina_python_client-3.2.0/pyproject.toml → valentina_python_client-3.4.0/pyproject.toml.orig
RENAMED
|
@@ -3,20 +3,21 @@
|
|
|
3
3
|
classifiers = [
|
|
4
4
|
"Programming Language :: Python :: 3.13",
|
|
5
5
|
"Programming Language :: Python :: 3.14",
|
|
6
|
+
"Programming Language :: Python :: 3.15",
|
|
6
7
|
]
|
|
7
8
|
dependencies = [
|
|
8
|
-
"anyio>=4.
|
|
9
|
-
"httpx2>=2.
|
|
9
|
+
"anyio>=4.15.1,<5.0.0",
|
|
10
|
+
"httpx2>=2.13.1",
|
|
10
11
|
"loguru>=0.7.3",
|
|
11
12
|
"polyfactory>=3.3.0, <4.0.0",
|
|
12
|
-
"pydantic[email]>=2.
|
|
13
|
+
"pydantic[email]>=2.14.1,<3.0.0",
|
|
13
14
|
]
|
|
14
15
|
description = "Async Python client library for the Valentina Noir API"
|
|
15
16
|
license = { file = "LICENSE" }
|
|
16
17
|
name = "valentina-python-client"
|
|
17
18
|
readme = "README.md"
|
|
18
19
|
requires-python = ">=3.13"
|
|
19
|
-
version = "3.
|
|
20
|
+
version = "3.4.0"
|
|
20
21
|
|
|
21
22
|
[project.optional-dependencies]
|
|
22
23
|
testing = ["polyfactory>=3.3.0"]
|
|
@@ -27,37 +28,38 @@
|
|
|
27
28
|
|
|
28
29
|
[build-system]
|
|
29
30
|
build-backend = "uv_build"
|
|
30
|
-
requires = ["uv_build>=0.
|
|
31
|
+
requires = ["uv_build>=0.13.0,<0.14"]
|
|
31
32
|
|
|
32
33
|
[tool.uv.build-backend]
|
|
33
34
|
module-name = "vclient"
|
|
34
35
|
|
|
35
36
|
[dependency-groups]
|
|
36
37
|
dev = [
|
|
37
|
-
"commitizen>=4.
|
|
38
|
-
"coverage>=7.
|
|
39
|
-
"duty>=1.
|
|
38
|
+
"commitizen>=4.19.2",
|
|
39
|
+
"coverage>=7.16.2",
|
|
40
|
+
"duty>=1.10.1",
|
|
41
|
+
"gate-cache>=0.6.0",
|
|
40
42
|
"httpx>=0.28.1",
|
|
41
|
-
"prek>=0.
|
|
43
|
+
"prek>=0.5.5",
|
|
42
44
|
"pytest-anyio>=0.0.0",
|
|
43
45
|
"pytest-clarity>=1.0.1",
|
|
44
46
|
"pytest-cov>=7.1.0",
|
|
45
|
-
"pytest-devtools>=1.
|
|
47
|
+
"pytest-devtools>=1.3.0",
|
|
46
48
|
"pytest-httpx2>=1.0.0",
|
|
47
|
-
"pytest-mock>=3.
|
|
49
|
+
"pytest-mock>=3.16.0",
|
|
48
50
|
"pytest-repeat>=0.9.4",
|
|
49
51
|
"pytest-sugar>=1.1.1",
|
|
50
52
|
"pytest-xdist>=3.8.0",
|
|
51
53
|
"pytest>=9.1.1",
|
|
52
54
|
"respx>=0.23.1",
|
|
53
|
-
"ruff>=0.
|
|
55
|
+
"ruff>=0.17.0",
|
|
54
56
|
"shellcheck-py>=0.11.0.1",
|
|
55
|
-
"ty>=0.0.
|
|
56
|
-
"typos>=1.
|
|
57
|
+
"ty>=0.0.86",
|
|
58
|
+
"typos>=1.51.1",
|
|
57
59
|
"vulture>=2.16",
|
|
58
60
|
"yamllint>=1.38.0",
|
|
59
|
-
|
|
60
|
-
docs = ["zensical>=0.0.
|
|
61
|
+
]
|
|
62
|
+
docs = ["zensical>=0.0.70"]
|
|
61
63
|
|
|
62
64
|
[tool.commitizen]
|
|
63
65
|
bump_message = "bump(release): v$current_version → v$new_version"
|
|
@@ -168,7 +170,8 @@
|
|
|
168
170
|
"FBT001", # Boolean-typed positional argument in function definition
|
|
169
171
|
"PGH003", # Use specific rule codes when ignoring type issues
|
|
170
172
|
"PLC0415", # Imports should be at top of file
|
|
171
|
-
"PLR0913",
|
|
173
|
+
"PLR0913", # Too many positional arguments
|
|
174
|
+
"PLR0917", # Too many positional arguments
|
|
172
175
|
"PLR2004",
|
|
173
176
|
"PT011", # set the `match` parameter or use a more specific exception
|
|
174
177
|
"S101",
|
|
@@ -31,7 +31,7 @@ _logger.add(
|
|
|
31
31
|
# Forward TRACE too (e.g. the "Send request" line) and let the consumer's
|
|
32
32
|
# stdlib logging level decide what to show; the sink must not pre-filter it.
|
|
33
33
|
level="TRACE",
|
|
34
|
-
filter=lambda record: record["name"].startswith("vclient"),
|
|
34
|
+
filter=lambda record: record["name"].startswith("vclient"), # ty: ignore[unresolved-attribute]
|
|
35
35
|
)
|
|
36
36
|
|
|
37
37
|
_logger.disable("vclient")
|
|
@@ -116,4 +116,4 @@ __all__ = (
|
|
|
116
116
|
"users_service",
|
|
117
117
|
)
|
|
118
118
|
|
|
119
|
-
__version__ = "3.
|
|
119
|
+
__version__ = "3.4.0"
|
|
@@ -127,6 +127,7 @@ class SyncCampaignsService(SyncBaseService):
|
|
|
127
127
|
request: A CampaignCreate model, OR pass fields as keyword arguments.
|
|
128
128
|
**kwargs: Fields for CampaignCreate if request is not provided.
|
|
129
129
|
Accepts: name (str, required), description (str | None),
|
|
130
|
+
in_game_date (datetime.date | None, ISO 8601 calendar date),
|
|
130
131
|
desperation (int, default 0), danger (int, default 0).
|
|
131
132
|
|
|
132
133
|
Returns:
|
|
@@ -154,7 +155,8 @@ class SyncCampaignsService(SyncBaseService):
|
|
|
154
155
|
request: A CampaignUpdate model, OR pass fields as keyword arguments.
|
|
155
156
|
**kwargs: Fields for CampaignUpdate if request is not provided.
|
|
156
157
|
Accepts: name (str | None), description (str | None),
|
|
157
|
-
|
|
158
|
+
in_game_date (datetime.date | None, ISO 8601 calendar date;
|
|
159
|
+
pass None to clear it), desperation (int | None), danger (int | None).
|
|
158
160
|
|
|
159
161
|
Returns:
|
|
160
162
|
The updated Campaign object.
|
|
@@ -166,9 +168,11 @@ class SyncCampaignsService(SyncBaseService):
|
|
|
166
168
|
ValidationError: If the request data is invalid.
|
|
167
169
|
"""
|
|
168
170
|
body = request if request is not None else self._validate_request(CampaignUpdate, **kwargs)
|
|
171
|
+
payload = body.model_dump(exclude_none=True, exclude_unset=True, mode="json")
|
|
172
|
+
if "in_game_date" in body.model_fields_set and body.in_game_date is None:
|
|
173
|
+
payload["in_game_date"] = None
|
|
169
174
|
response = self._patch(
|
|
170
|
-
self._format_endpoint(Endpoints.CAMPAIGN, campaign_id=campaign_id),
|
|
171
|
-
json=body.model_dump(exclude_none=True, exclude_unset=True, mode="json"),
|
|
175
|
+
self._format_endpoint(Endpoints.CAMPAIGN, campaign_id=campaign_id), json=payload
|
|
172
176
|
)
|
|
173
177
|
return Campaign.model_validate(response.json())
|
|
174
178
|
|
|
@@ -5,15 +5,21 @@ from collections.abc import Iterator
|
|
|
5
5
|
from typing import TYPE_CHECKING
|
|
6
6
|
|
|
7
7
|
from vclient._sync.services.base import SyncBaseService
|
|
8
|
-
from vclient.constants import DEFAULT_PAGE_LIMIT, TraitModifyCurrency
|
|
8
|
+
from vclient.constants import DEFAULT_PAGE_LIMIT, DamageType, TrackerAction, TraitModifyCurrency
|
|
9
9
|
from vclient.endpoints import Endpoints
|
|
10
10
|
from vclient.models import (
|
|
11
|
+
_TRACKER_ADAPTER,
|
|
11
12
|
BulkAssignTraitResponse,
|
|
12
13
|
CharacterTrait,
|
|
13
14
|
CharacterTraitAdd,
|
|
15
|
+
CharacterTraitSpecialtyCreate,
|
|
16
|
+
CharacterTraitSpecialtyUpdate,
|
|
14
17
|
CharacterTraitValueOptionsResponse,
|
|
15
18
|
PaginatedResponse,
|
|
19
|
+
Tracker,
|
|
20
|
+
TrackerStateSet,
|
|
16
21
|
TraitCreate,
|
|
22
|
+
_TrackerAction,
|
|
17
23
|
_TraitModify,
|
|
18
24
|
)
|
|
19
25
|
|
|
@@ -140,6 +146,8 @@ class SyncCharacterTraitsService(SyncBaseService):
|
|
|
140
146
|
def delete(self, character_trait_id: str, currency: TraitModifyCurrency | None = None) -> None:
|
|
141
147
|
"""Delete a character trait.
|
|
142
148
|
|
|
149
|
+
Any specialties on the trait are removed with it and the cost of each is refunded.
|
|
150
|
+
|
|
143
151
|
Args:
|
|
144
152
|
character_trait_id: The ID of the trait to delete.
|
|
145
153
|
currency: The currency to use to recoup the cost of the trait.
|
|
@@ -152,6 +160,8 @@ class SyncCharacterTraitsService(SyncBaseService):
|
|
|
152
160
|
AuthorizationError: If you don't have access to the character.
|
|
153
161
|
RequestValidationError: If the input parameters fail client-side validation.
|
|
154
162
|
ValidationError: If the request data is invalid.
|
|
163
|
+
ConflictError: If recouping ``XP`` or ``STARTING_POINTS`` and another request
|
|
164
|
+
changed the trait's value first. Refetch the trait and retry.
|
|
155
165
|
"""
|
|
156
166
|
params: dict[str, str | int] = {}
|
|
157
167
|
if currency is not None:
|
|
@@ -177,6 +187,8 @@ class SyncCharacterTraitsService(SyncBaseService):
|
|
|
177
187
|
AuthorizationError: If you don't have access to the character.
|
|
178
188
|
RequestValidationError: If the input parameters fail client-side validation.
|
|
179
189
|
ValidationError: If the request data is invalid.
|
|
190
|
+
ConflictError: If paying with ``XP`` or ``STARTING_POINTS`` and another request
|
|
191
|
+
changed the trait's value first. Refetch the trait and retry.
|
|
180
192
|
"""
|
|
181
193
|
body = self._validate_request(
|
|
182
194
|
CharacterTraitAdd, trait_id=trait_id, value=value, currency=currency
|
|
@@ -222,8 +234,16 @@ class SyncCharacterTraitsService(SyncBaseService):
|
|
|
222
234
|
**kwargs: Fields for TraitCreate if request is not provided.
|
|
223
235
|
Required: name (str), category_id (str), currency (TraitModifyCurrency).
|
|
224
236
|
Optional: description (str | None), max_value (int), min_value (int),
|
|
225
|
-
show_when_zero (bool),
|
|
226
|
-
upgrade_cost (int | None)
|
|
237
|
+
show_when_zero (bool), is_rollable (bool, default True),
|
|
238
|
+
initial_cost (int | None), upgrade_cost (int | None),
|
|
239
|
+
count_based_cost_multiplier (int | None).
|
|
240
|
+
|
|
241
|
+
Returns:
|
|
242
|
+
The newly created CharacterTrait object.
|
|
243
|
+
|
|
244
|
+
Raises:
|
|
245
|
+
ConflictError: If paying with ``XP`` or ``STARTING_POINTS`` and another request
|
|
246
|
+
changed the trait's value first. Refetch the trait and retry.
|
|
227
247
|
"""
|
|
228
248
|
body = request if request is not None else self._validate_request(TraitCreate, **kwargs)
|
|
229
249
|
response = self._post(
|
|
@@ -259,10 +279,20 @@ class SyncCharacterTraitsService(SyncBaseService):
|
|
|
259
279
|
) -> CharacterTrait:
|
|
260
280
|
"""Change the value of a character trait.
|
|
261
281
|
|
|
282
|
+
Lowering an ability to ``0`` also removes its specialties and refunds the cost of
|
|
283
|
+
each. The value change and the refunds are applied together or not at all.
|
|
284
|
+
|
|
262
285
|
Args:
|
|
263
286
|
character_trait_id: The ID of the trait to change the value of.
|
|
264
287
|
new_value: The new value of the trait.
|
|
265
288
|
currency: The currency to use for the modification.
|
|
289
|
+
|
|
290
|
+
Returns:
|
|
291
|
+
The updated CharacterTrait object.
|
|
292
|
+
|
|
293
|
+
Raises:
|
|
294
|
+
ConflictError: If another request changed the trait's value after this request
|
|
295
|
+
read it. Nothing is spent or refunded. Refetch the trait and retry.
|
|
266
296
|
"""
|
|
267
297
|
body = self._validate_request(_TraitModify, target_value=new_value, currency=currency)
|
|
268
298
|
response = self._put(
|
|
@@ -272,3 +302,197 @@ class SyncCharacterTraitsService(SyncBaseService):
|
|
|
272
302
|
json=body.model_dump(exclude_none=True, exclude_unset=True, mode="json"),
|
|
273
303
|
)
|
|
274
304
|
return CharacterTrait.model_validate(response.json())
|
|
305
|
+
|
|
306
|
+
def add_specialty(
|
|
307
|
+
self, character_trait_id: str, name: str, currency: TraitModifyCurrency = "NO_COST"
|
|
308
|
+
) -> CharacterTrait:
|
|
309
|
+
"""Add a specialty to an ability trait.
|
|
310
|
+
|
|
311
|
+
Specialties are only available on abilities with a value of 1 or higher. When the
|
|
312
|
+
company's ``specialty_xp_cost_enabled`` setting is on, a specialty paid with ``XP``
|
|
313
|
+
or ``STARTING_POINTS`` costs 3 points, and ``NO_COST`` follows the company's
|
|
314
|
+
``permission_free_trait_changes`` setting. When the setting is off, specialties are free.
|
|
315
|
+
|
|
316
|
+
Args:
|
|
317
|
+
character_trait_id: The ID of the ability trait.
|
|
318
|
+
name: The specialty name (3-50 characters), unique on the trait ignoring case.
|
|
319
|
+
currency: The currency to use to pay for the specialty.
|
|
320
|
+
|
|
321
|
+
Returns:
|
|
322
|
+
The updated CharacterTrait object, including its specialties.
|
|
323
|
+
|
|
324
|
+
Raises:
|
|
325
|
+
NotFoundError: If the trait does not exist.
|
|
326
|
+
AuthorizationError: If you don't have access to the character.
|
|
327
|
+
RequestValidationError: If the input parameters fail client-side validation.
|
|
328
|
+
ValidationError: If the trait is not an ability, has a value of 0, already has a
|
|
329
|
+
specialty with this name, the character cannot afford the cost, or an
|
|
330
|
+
``NPC`` or ``STORYTELLER`` character pays with anything but ``NO_COST``.
|
|
331
|
+
"""
|
|
332
|
+
body = self._validate_request(CharacterTraitSpecialtyCreate, name=name, currency=currency)
|
|
333
|
+
response = self._post(
|
|
334
|
+
self._format_endpoint(
|
|
335
|
+
Endpoints.CHARACTER_TRAIT_SPECIALTIES, character_trait_id=character_trait_id
|
|
336
|
+
),
|
|
337
|
+
json=body.model_dump(exclude_none=True, mode="json"),
|
|
338
|
+
)
|
|
339
|
+
return CharacterTrait.model_validate(response.json())
|
|
340
|
+
|
|
341
|
+
def update_specialty(
|
|
342
|
+
self, character_trait_id: str, specialty_id: str, name: str
|
|
343
|
+
) -> CharacterTrait:
|
|
344
|
+
"""Rename a specialty on an ability trait.
|
|
345
|
+
|
|
346
|
+
Renaming never changes the cost paid or the currency used.
|
|
347
|
+
|
|
348
|
+
Args:
|
|
349
|
+
character_trait_id: The ID of the ability trait.
|
|
350
|
+
specialty_id: The ID of the specialty to rename.
|
|
351
|
+
name: The new specialty name (3-50 characters), unique on the trait ignoring case.
|
|
352
|
+
|
|
353
|
+
Returns:
|
|
354
|
+
The updated CharacterTrait object, including its specialties.
|
|
355
|
+
|
|
356
|
+
Raises:
|
|
357
|
+
NotFoundError: If the trait or specialty does not exist, or the specialty
|
|
358
|
+
belongs to a different trait.
|
|
359
|
+
AuthorizationError: If you don't have access to the character.
|
|
360
|
+
RequestValidationError: If the input parameters fail client-side validation.
|
|
361
|
+
ValidationError: If the trait already has a specialty with this name.
|
|
362
|
+
"""
|
|
363
|
+
body = self._validate_request(CharacterTraitSpecialtyUpdate, name=name)
|
|
364
|
+
response = self._patch(
|
|
365
|
+
self._format_endpoint(
|
|
366
|
+
Endpoints.CHARACTER_TRAIT_SPECIALTY,
|
|
367
|
+
character_trait_id=character_trait_id,
|
|
368
|
+
specialty_id=specialty_id,
|
|
369
|
+
),
|
|
370
|
+
json=body.model_dump(exclude_none=True, mode="json"),
|
|
371
|
+
)
|
|
372
|
+
return CharacterTrait.model_validate(response.json())
|
|
373
|
+
|
|
374
|
+
def delete_specialty(self, character_trait_id: str, specialty_id: str) -> None:
|
|
375
|
+
"""Remove a specialty from an ability trait.
|
|
376
|
+
|
|
377
|
+
The cost paid is refunded in the currency used to buy it. An ``XP`` refund follows
|
|
378
|
+
the company's ``permission_recoup_xp`` setting; starting points are always refunded.
|
|
379
|
+
|
|
380
|
+
Args:
|
|
381
|
+
character_trait_id: The ID of the ability trait.
|
|
382
|
+
specialty_id: The ID of the specialty to remove.
|
|
383
|
+
|
|
384
|
+
Returns:
|
|
385
|
+
None
|
|
386
|
+
|
|
387
|
+
Raises:
|
|
388
|
+
NotFoundError: If the trait or specialty does not exist, or the specialty
|
|
389
|
+
belongs to a different trait.
|
|
390
|
+
AuthorizationError: If you don't have access to the character.
|
|
391
|
+
"""
|
|
392
|
+
self._delete(
|
|
393
|
+
self._format_endpoint(
|
|
394
|
+
Endpoints.CHARACTER_TRAIT_SPECIALTY,
|
|
395
|
+
character_trait_id=character_trait_id,
|
|
396
|
+
specialty_id=specialty_id,
|
|
397
|
+
)
|
|
398
|
+
)
|
|
399
|
+
|
|
400
|
+
def get_tracker(self, character_trait_id: str) -> Tracker:
|
|
401
|
+
"""Get the in-play tracker state of a character trait.
|
|
402
|
+
|
|
403
|
+
The same object appears as ``CharacterTrait.tracker``. Use this to refresh one
|
|
404
|
+
tracker without fetching the whole trait.
|
|
405
|
+
|
|
406
|
+
Args:
|
|
407
|
+
character_trait_id: The ID of the character trait.
|
|
408
|
+
|
|
409
|
+
Returns:
|
|
410
|
+
A CounterTracker, DamageTracker, or StainsTracker. Switch on ``type``.
|
|
411
|
+
|
|
412
|
+
Raises:
|
|
413
|
+
NotFoundError: If the trait has no tracker for the character's game version.
|
|
414
|
+
AuthorizationError: If you don't have access to the character.
|
|
415
|
+
"""
|
|
416
|
+
response = self._get(
|
|
417
|
+
self._format_endpoint(
|
|
418
|
+
Endpoints.CHARACTER_TRAIT_TRACKER, character_trait_id=character_trait_id
|
|
419
|
+
)
|
|
420
|
+
)
|
|
421
|
+
return _TRACKER_ADAPTER.validate_python(response.json())
|
|
422
|
+
|
|
423
|
+
def set_tracker(
|
|
424
|
+
self, character_trait_id: str, request: TrackerStateSet | None = None, **kwargs
|
|
425
|
+
) -> Tracker:
|
|
426
|
+
"""Replace the full state of a trait tracker, such as to correct a mistake.
|
|
427
|
+
|
|
428
|
+
Send only the fields for the tracker's type: ``current`` for counters (required),
|
|
429
|
+
``superficial`` and ``aggravated`` for damage tracks, ``stains`` for stains. Omitted
|
|
430
|
+
fields reset to 0, so an empty request clears a damage or stains tracker. Use
|
|
431
|
+
``apply_tracker_action`` for in-play changes instead.
|
|
432
|
+
|
|
433
|
+
Args:
|
|
434
|
+
character_trait_id: The ID of the character trait.
|
|
435
|
+
request: A TrackerStateSet model, OR pass fields as keyword arguments.
|
|
436
|
+
**kwargs: Fields for TrackerStateSet if request is not provided.
|
|
437
|
+
Accepts: current, superficial, aggravated, stains (int >= 0).
|
|
438
|
+
|
|
439
|
+
Returns:
|
|
440
|
+
The updated tracker.
|
|
441
|
+
|
|
442
|
+
Raises:
|
|
443
|
+
NotFoundError: If the trait has no tracker for the character's game version.
|
|
444
|
+
AuthorizationError: If you are not the character's player or a storyteller.
|
|
445
|
+
RequestValidationError: If a value is negative.
|
|
446
|
+
ValidationError: If a field does not fit the tracker type, a counter has no
|
|
447
|
+
``current``, or a value exceeds the tracker size.
|
|
448
|
+
"""
|
|
449
|
+
body = request if request is not None else self._validate_request(TrackerStateSet, **kwargs)
|
|
450
|
+
response = self._put(
|
|
451
|
+
self._format_endpoint(
|
|
452
|
+
Endpoints.CHARACTER_TRAIT_TRACKER, character_trait_id=character_trait_id
|
|
453
|
+
),
|
|
454
|
+
json=body.model_dump(exclude_none=True, mode="json"),
|
|
455
|
+
)
|
|
456
|
+
return _TRACKER_ADAPTER.validate_python(response.json())
|
|
457
|
+
|
|
458
|
+
def apply_tracker_action(
|
|
459
|
+
self,
|
|
460
|
+
character_trait_id: str,
|
|
461
|
+
action: TrackerAction,
|
|
462
|
+
*,
|
|
463
|
+
amount: int = 1,
|
|
464
|
+
damage_type: DamageType | None = None,
|
|
465
|
+
) -> Tracker:
|
|
466
|
+
"""Apply one in-play action to a trait tracker, such as spending Willpower.
|
|
467
|
+
|
|
468
|
+
The server applies the game rules for the character's game version. Which actions
|
|
469
|
+
and damage types fit each tracker is listed in ``characters.TrackerRules`` from
|
|
470
|
+
``options.get_options()``. A STAINS response reports overflow into Willpower in
|
|
471
|
+
``willpower_damage_applied``.
|
|
472
|
+
|
|
473
|
+
Args:
|
|
474
|
+
character_trait_id: The ID of the character trait.
|
|
475
|
+
action: The action to apply.
|
|
476
|
+
amount: How many points to apply. Must be at least 1.
|
|
477
|
+
damage_type: The damage type for ``damage`` and ``heal`` on damage tracks.
|
|
478
|
+
|
|
479
|
+
Returns:
|
|
480
|
+
The updated tracker.
|
|
481
|
+
|
|
482
|
+
Raises:
|
|
483
|
+
NotFoundError: If the trait has no tracker for the character's game version.
|
|
484
|
+
AuthorizationError: If you are not the character's player or a storyteller.
|
|
485
|
+
RequestValidationError: If ``amount`` is less than 1.
|
|
486
|
+
ValidationError: If the action or damage type does not fit the tracker, a
|
|
487
|
+
damage type is missing or not allowed, or a spend exceeds the current value.
|
|
488
|
+
"""
|
|
489
|
+
body = self._validate_request(
|
|
490
|
+
_TrackerAction, action=action, amount=amount, damage_type=damage_type
|
|
491
|
+
)
|
|
492
|
+
response = self._post(
|
|
493
|
+
self._format_endpoint(
|
|
494
|
+
Endpoints.CHARACTER_TRAIT_TRACKER_ACTIONS, character_trait_id=character_trait_id
|
|
495
|
+
),
|
|
496
|
+
json=body.model_dump(exclude_none=True, mode="json"),
|
|
497
|
+
)
|
|
498
|
+
return _TRACKER_ADAPTER.validate_python(response.json())
|