valentina-python-client 1.3.0__tar.gz → 1.3.1__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-1.3.0 → valentina_python_client-1.3.1}/PKG-INFO +12 -12
- {valentina_python_client-1.3.0 → valentina_python_client-1.3.1}/README.md +11 -11
- {valentina_python_client-1.3.0 → valentina_python_client-1.3.1}/pyproject.toml +1 -21
- {valentina_python_client-1.3.0 → valentina_python_client-1.3.1}/src/vclient/__init__.py +1 -1
- {valentina_python_client-1.3.0 → valentina_python_client-1.3.1}/src/vclient/client.py +2 -5
- {valentina_python_client-1.3.0 → valentina_python_client-1.3.1}/src/vclient/models/campaigns.py +6 -5
- {valentina_python_client-1.3.0 → valentina_python_client-1.3.1}/src/vclient/models/characters.py +33 -24
- {valentina_python_client-1.3.0 → valentina_python_client-1.3.1}/src/vclient/models/companies.py +4 -3
- {valentina_python_client-1.3.0 → valentina_python_client-1.3.1}/src/vclient/models/shared.py +3 -3
- {valentina_python_client-1.3.0 → valentina_python_client-1.3.1}/src/vclient/models/users.py +5 -4
- {valentina_python_client-1.3.0 → valentina_python_client-1.3.1}/src/vclient/services/base.py +11 -66
- {valentina_python_client-1.3.0 → valentina_python_client-1.3.1}/LICENSE +0 -0
- {valentina_python_client-1.3.0 → valentina_python_client-1.3.1}/src/vclient/config.py +0 -0
- {valentina_python_client-1.3.0 → valentina_python_client-1.3.1}/src/vclient/constants.py +0 -0
- {valentina_python_client-1.3.0 → valentina_python_client-1.3.1}/src/vclient/endpoints.py +0 -0
- {valentina_python_client-1.3.0 → valentina_python_client-1.3.1}/src/vclient/exceptions.py +0 -0
- {valentina_python_client-1.3.0 → valentina_python_client-1.3.1}/src/vclient/models/__init__.py +0 -0
- {valentina_python_client-1.3.0 → valentina_python_client-1.3.1}/src/vclient/models/books.py +0 -0
- {valentina_python_client-1.3.0 → valentina_python_client-1.3.1}/src/vclient/models/chapters.py +0 -0
- {valentina_python_client-1.3.0 → valentina_python_client-1.3.1}/src/vclient/models/character_autogen.py +0 -0
- {valentina_python_client-1.3.0 → valentina_python_client-1.3.1}/src/vclient/models/character_blueprint.py +0 -0
- {valentina_python_client-1.3.0 → valentina_python_client-1.3.1}/src/vclient/models/character_trait.py +0 -0
- {valentina_python_client-1.3.0 → valentina_python_client-1.3.1}/src/vclient/models/developers.py +0 -0
- {valentina_python_client-1.3.0 → valentina_python_client-1.3.1}/src/vclient/models/diceroll.py +0 -0
- {valentina_python_client-1.3.0 → valentina_python_client-1.3.1}/src/vclient/models/dictionary.py +0 -0
- {valentina_python_client-1.3.0 → valentina_python_client-1.3.1}/src/vclient/models/global_admin.py +0 -0
- {valentina_python_client-1.3.0 → valentina_python_client-1.3.1}/src/vclient/models/pagination.py +0 -0
- {valentina_python_client-1.3.0 → valentina_python_client-1.3.1}/src/vclient/models/system.py +0 -0
- {valentina_python_client-1.3.0 → valentina_python_client-1.3.1}/src/vclient/py.typed +0 -0
- {valentina_python_client-1.3.0 → valentina_python_client-1.3.1}/src/vclient/registry.py +0 -0
- {valentina_python_client-1.3.0 → valentina_python_client-1.3.1}/src/vclient/services/__init__.py +0 -0
- {valentina_python_client-1.3.0 → valentina_python_client-1.3.1}/src/vclient/services/campaign_book_chapters.py +0 -0
- {valentina_python_client-1.3.0 → valentina_python_client-1.3.1}/src/vclient/services/campaign_books.py +0 -0
- {valentina_python_client-1.3.0 → valentina_python_client-1.3.1}/src/vclient/services/campaigns.py +0 -0
- {valentina_python_client-1.3.0 → valentina_python_client-1.3.1}/src/vclient/services/character_autogen.py +0 -0
- {valentina_python_client-1.3.0 → valentina_python_client-1.3.1}/src/vclient/services/character_blueprint.py +0 -0
- {valentina_python_client-1.3.0 → valentina_python_client-1.3.1}/src/vclient/services/character_traits.py +0 -0
- {valentina_python_client-1.3.0 → valentina_python_client-1.3.1}/src/vclient/services/characters.py +0 -0
- {valentina_python_client-1.3.0 → valentina_python_client-1.3.1}/src/vclient/services/companies.py +0 -0
- {valentina_python_client-1.3.0 → valentina_python_client-1.3.1}/src/vclient/services/developers.py +0 -0
- {valentina_python_client-1.3.0 → valentina_python_client-1.3.1}/src/vclient/services/dicerolls.py +0 -0
- {valentina_python_client-1.3.0 → valentina_python_client-1.3.1}/src/vclient/services/dictionary.py +0 -0
- {valentina_python_client-1.3.0 → valentina_python_client-1.3.1}/src/vclient/services/global_admin.py +0 -0
- {valentina_python_client-1.3.0 → valentina_python_client-1.3.1}/src/vclient/services/options.py +0 -0
- {valentina_python_client-1.3.0 → valentina_python_client-1.3.1}/src/vclient/services/system.py +0 -0
- {valentina_python_client-1.3.0 → valentina_python_client-1.3.1}/src/vclient/services/users.py +0 -0
- {valentina_python_client-1.3.0 → valentina_python_client-1.3.1}/src/vclient/validate_constants.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.3
|
|
2
2
|
Name: valentina-python-client
|
|
3
|
-
Version: 1.3.
|
|
3
|
+
Version: 1.3.1
|
|
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>
|
|
@@ -30,13 +30,13 @@ Async Python client library for accessing the Valentina Noir API.
|
|
|
30
30
|
|
|
31
31
|
## Features
|
|
32
32
|
|
|
33
|
-
-
|
|
34
|
-
-
|
|
35
|
-
-
|
|
36
|
-
-
|
|
37
|
-
-
|
|
38
|
-
-
|
|
39
|
-
-
|
|
33
|
+
- **Async-first design** - Built on httpx for efficient async HTTP operations
|
|
34
|
+
- **Type-safe** - Full type hints with Pydantic models for request/response validation
|
|
35
|
+
- **Convenient factory pattern** - Create a client once, access services from anywhere
|
|
36
|
+
- **Automatic pagination** - Stream through large datasets with `iter_all()` or fetch everything with `list_all()`
|
|
37
|
+
- **Robust error handling** - Specific exception types for different error conditions
|
|
38
|
+
- **Idempotency support** - Optional automatic idempotency keys for safe retries
|
|
39
|
+
- **Rate limit handling** - Built-in support for automatic rate limit retries
|
|
40
40
|
|
|
41
41
|
This client is a supported and up-to-date reference implementation for the Valentina Noir API. The full documentation for is available at https://docs.valentina-noir.com/python-api-client/.
|
|
42
42
|
|
|
@@ -62,12 +62,12 @@ The script reads configuration from (highest precedence first):
|
|
|
62
62
|
|
|
63
63
|
1. CLI arguments (`--api-url`, `--api-key`, `--company-id`)
|
|
64
64
|
2. System environment variables (`VALENTINA_CLIENT_BASE_URL`, `VALENTINA_CLIENT_API_KEY`, `VALENTINA_CLIENT_DEFAULT_COMPANY_ID`)
|
|
65
|
-
3. A `.env.
|
|
65
|
+
3. A `.env.secret` file in the project root
|
|
66
66
|
|
|
67
67
|
Exit codes: `0` = all constants match, `1` = mismatches found, `2` = missing configuration.
|
|
68
68
|
|
|
69
69
|
## Resources
|
|
70
70
|
|
|
71
|
-
-
|
|
72
|
-
-
|
|
73
|
-
-
|
|
71
|
+
- [Full Client Documentation](https://docs.valentina-noir.com/python-api-client/)
|
|
72
|
+
- [API Concepts](https://docs.valentina-noir.com/concepts/)
|
|
73
|
+
- [API Reference](https://api.valentina-noir.com/docs)
|
|
@@ -4,13 +4,13 @@ Async Python client library for accessing the Valentina Noir API.
|
|
|
4
4
|
|
|
5
5
|
## Features
|
|
6
6
|
|
|
7
|
-
-
|
|
8
|
-
-
|
|
9
|
-
-
|
|
10
|
-
-
|
|
11
|
-
-
|
|
12
|
-
-
|
|
13
|
-
-
|
|
7
|
+
- **Async-first design** - Built on httpx for efficient async HTTP operations
|
|
8
|
+
- **Type-safe** - Full type hints with Pydantic models for request/response validation
|
|
9
|
+
- **Convenient factory pattern** - Create a client once, access services from anywhere
|
|
10
|
+
- **Automatic pagination** - Stream through large datasets with `iter_all()` or fetch everything with `list_all()`
|
|
11
|
+
- **Robust error handling** - Specific exception types for different error conditions
|
|
12
|
+
- **Idempotency support** - Optional automatic idempotency keys for safe retries
|
|
13
|
+
- **Rate limit handling** - Built-in support for automatic rate limit retries
|
|
14
14
|
|
|
15
15
|
This client is a supported and up-to-date reference implementation for the Valentina Noir API. The full documentation for is available at https://docs.valentina-noir.com/python-api-client/.
|
|
16
16
|
|
|
@@ -36,12 +36,12 @@ The script reads configuration from (highest precedence first):
|
|
|
36
36
|
|
|
37
37
|
1. CLI arguments (`--api-url`, `--api-key`, `--company-id`)
|
|
38
38
|
2. System environment variables (`VALENTINA_CLIENT_BASE_URL`, `VALENTINA_CLIENT_API_KEY`, `VALENTINA_CLIENT_DEFAULT_COMPANY_ID`)
|
|
39
|
-
3. A `.env.
|
|
39
|
+
3. A `.env.secret` file in the project root
|
|
40
40
|
|
|
41
41
|
Exit codes: `0` = all constants match, `1` = mismatches found, `2` = missing configuration.
|
|
42
42
|
|
|
43
43
|
## Resources
|
|
44
44
|
|
|
45
|
-
-
|
|
46
|
-
-
|
|
47
|
-
-
|
|
45
|
+
- [Full Client Documentation](https://docs.valentina-noir.com/python-api-client/)
|
|
46
|
+
- [API Concepts](https://docs.valentina-noir.com/concepts/)
|
|
47
|
+
- [API Reference](https://api.valentina-noir.com/docs)
|
|
@@ -10,7 +10,7 @@
|
|
|
10
10
|
name = "valentina-python-client"
|
|
11
11
|
readme = "README.md"
|
|
12
12
|
requires-python = ">=3.13"
|
|
13
|
-
version = "1.3.
|
|
13
|
+
version = "1.3.1"
|
|
14
14
|
|
|
15
15
|
[project.urls]
|
|
16
16
|
Homepage = "https://docs.valentina-noir.com/python-api-client/"
|
|
@@ -80,26 +80,6 @@
|
|
|
80
80
|
[tool.coverage.xml]
|
|
81
81
|
output = ".cache/coverage.xml"
|
|
82
82
|
|
|
83
|
-
[tool.mypy] # https://mypy.readthedocs.io/en/latest/config_file.html
|
|
84
|
-
cache_dir = ".cache/mypy"
|
|
85
|
-
disallow_any_unimported = false
|
|
86
|
-
disallow_subclassing_any = false
|
|
87
|
-
disallow_untyped_decorators = false
|
|
88
|
-
disallow_untyped_defs = true
|
|
89
|
-
exclude = ['duties.py', 'tests/']
|
|
90
|
-
follow_imports = "normal"
|
|
91
|
-
ignore_missing_imports = true
|
|
92
|
-
junit_xml = ".cache/mypy.xml"
|
|
93
|
-
no_implicit_optional = true
|
|
94
|
-
pretty = false
|
|
95
|
-
show_column_numbers = true
|
|
96
|
-
show_error_codes = true
|
|
97
|
-
show_error_context = true
|
|
98
|
-
strict_optional = false
|
|
99
|
-
warn_redundant_casts = true
|
|
100
|
-
warn_unreachable = true
|
|
101
|
-
warn_unused_ignores = true
|
|
102
|
-
|
|
103
83
|
[tool.pytest.ini_options]
|
|
104
84
|
|
|
105
85
|
addopts = "--color=yes --doctest-modules --strict-config --strict-markers -n auto --dist loadfile"
|
|
@@ -160,10 +160,7 @@ class VClient:
|
|
|
160
160
|
base_url=self._config.base_url,
|
|
161
161
|
timeout=self._config.timeout,
|
|
162
162
|
max_retries=self._config.max_retries,
|
|
163
|
-
).
|
|
164
|
-
"Initialize VClient (base_url={base_url})",
|
|
165
|
-
base_url=self._config.base_url,
|
|
166
|
-
)
|
|
163
|
+
).info("Initialize VClient")
|
|
167
164
|
|
|
168
165
|
def _create_http_client(self) -> httpx.AsyncClient:
|
|
169
166
|
"""Create and configure the HTTP client."""
|
|
@@ -204,7 +201,7 @@ class VClient:
|
|
|
204
201
|
"""Close the HTTP client and release resources."""
|
|
205
202
|
from vclient.registry import clear_default_client
|
|
206
203
|
|
|
207
|
-
logger.bind(base_url=self._config.base_url).
|
|
204
|
+
logger.bind(base_url=self._config.base_url).info("Close VClient")
|
|
208
205
|
await self._http.aclose()
|
|
209
206
|
clear_default_client(self)
|
|
210
207
|
|
{valentina_python_client-1.3.0 → valentina_python_client-1.3.1}/src/vclient/models/campaigns.py
RENAMED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
"""Pydantic models for Campaign API responses and requests."""
|
|
2
2
|
|
|
3
3
|
from datetime import datetime
|
|
4
|
+
from typing import Annotated
|
|
4
5
|
|
|
5
6
|
from pydantic import BaseModel, Field
|
|
6
7
|
|
|
@@ -39,7 +40,7 @@ class CampaignCreate(BaseModel):
|
|
|
39
40
|
"""
|
|
40
41
|
|
|
41
42
|
name: str = Field(min_length=3, max_length=50)
|
|
42
|
-
description: str | None =
|
|
43
|
+
description: Annotated[str, Field(min_length=3)] | None = None
|
|
43
44
|
desperation: int = Field(default=0, ge=0, le=5)
|
|
44
45
|
danger: int = Field(default=0, ge=0, le=5)
|
|
45
46
|
|
|
@@ -50,10 +51,10 @@ class CampaignUpdate(BaseModel):
|
|
|
50
51
|
Only include fields that need to be changed; omitted fields remain unchanged.
|
|
51
52
|
"""
|
|
52
53
|
|
|
53
|
-
name: str
|
|
54
|
-
description: str | None =
|
|
55
|
-
desperation: int
|
|
56
|
-
danger: int
|
|
54
|
+
name: Annotated[str, Field(min_length=3, max_length=50)] | None = None
|
|
55
|
+
description: Annotated[str, Field(min_length=3)] | None = None
|
|
56
|
+
desperation: Annotated[int, Field(ge=0, le=5)] | None = None
|
|
57
|
+
danger: Annotated[int, Field(ge=0, le=5)] | None = None
|
|
57
58
|
|
|
58
59
|
|
|
59
60
|
__all__ = [
|
{valentina_python_client-1.3.0 → valentina_python_client-1.3.1}/src/vclient/models/characters.py
RENAMED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
"""Pydantic models for Character API responses and requests."""
|
|
2
2
|
|
|
3
3
|
from datetime import datetime
|
|
4
|
+
from typing import Annotated
|
|
4
5
|
|
|
5
6
|
from pydantic import BaseModel, Field
|
|
6
7
|
|
|
@@ -155,20 +156,22 @@ class Character(BaseModel):
|
|
|
155
156
|
# Identity
|
|
156
157
|
name_first: str = Field(..., min_length=3, description="Character's first name.")
|
|
157
158
|
name_last: str = Field(..., min_length=3, description="Character's last name.")
|
|
158
|
-
name_nick: str | None = Field(
|
|
159
|
-
default=None,
|
|
159
|
+
name_nick: Annotated[str, Field(min_length=3, max_length=50)] | None = Field(
|
|
160
|
+
default=None, description="Character's nickname."
|
|
160
161
|
)
|
|
161
162
|
name: str = Field(..., description="Character's display name.")
|
|
162
163
|
name_full: str = Field(..., description="Character's full name.")
|
|
163
164
|
|
|
164
165
|
# Biography
|
|
165
166
|
age: int | None = Field(default=None, description="Character's age.")
|
|
166
|
-
biography: str | None = Field(
|
|
167
|
-
|
|
168
|
-
default=None, min_length=3, max_length=50, description="Character's demeanor."
|
|
167
|
+
biography: Annotated[str, Field(min_length=3)] | None = Field(
|
|
168
|
+
default=None, description="Character biography."
|
|
169
169
|
)
|
|
170
|
-
|
|
171
|
-
default=None,
|
|
170
|
+
demeanor: Annotated[str, Field(min_length=3, max_length=50)] | None = Field(
|
|
171
|
+
default=None, description="Character's demeanor."
|
|
172
|
+
)
|
|
173
|
+
nature: Annotated[str, Field(min_length=3, max_length=50)] | None = Field(
|
|
174
|
+
default=None, description="Character's nature."
|
|
172
175
|
)
|
|
173
176
|
concept_id: str | None = Field(default=None, description="ID of the character concept.")
|
|
174
177
|
|
|
@@ -220,16 +223,18 @@ class CharacterCreate(BaseModel):
|
|
|
220
223
|
|
|
221
224
|
# Optional fields
|
|
222
225
|
type: CharacterType | None = Field(default=None, description="Character type.")
|
|
223
|
-
name_nick: str | None = Field(
|
|
224
|
-
default=None,
|
|
226
|
+
name_nick: Annotated[str, Field(min_length=3, max_length=50)] | None = Field(
|
|
227
|
+
default=None, description="Character's nickname."
|
|
225
228
|
)
|
|
226
229
|
age: int | None = Field(default=None, description="Character's age.")
|
|
227
|
-
biography: str | None = Field(
|
|
228
|
-
|
|
229
|
-
|
|
230
|
+
biography: Annotated[str, Field(min_length=3)] | None = Field(
|
|
231
|
+
default=None, description="Character biography."
|
|
232
|
+
)
|
|
233
|
+
demeanor: Annotated[str, Field(min_length=3, max_length=50)] | None = Field(
|
|
234
|
+
default=None, description="Character's demeanor."
|
|
230
235
|
)
|
|
231
|
-
nature: str | None = Field(
|
|
232
|
-
default=None,
|
|
236
|
+
nature: Annotated[str, Field(min_length=3, max_length=50)] | None = Field(
|
|
237
|
+
default=None, description="Character's nature."
|
|
233
238
|
)
|
|
234
239
|
concept_id: str | None = Field(default=None, description="ID of the character concept.")
|
|
235
240
|
user_player_id: str | None = Field(
|
|
@@ -263,21 +268,25 @@ class CharacterUpdate(BaseModel):
|
|
|
263
268
|
game_version: GameVersion | None = None
|
|
264
269
|
status: CharacterStatus | None = None
|
|
265
270
|
|
|
266
|
-
name_first: str | None = Field(
|
|
267
|
-
default=None,
|
|
271
|
+
name_first: Annotated[str, Field(min_length=3)] | None = Field(
|
|
272
|
+
default=None, description="Character's first name."
|
|
268
273
|
)
|
|
269
|
-
name_last: str | None = Field(
|
|
270
|
-
|
|
271
|
-
|
|
274
|
+
name_last: Annotated[str, Field(min_length=3)] | None = Field(
|
|
275
|
+
default=None, description="Character's last name."
|
|
276
|
+
)
|
|
277
|
+
name_nick: Annotated[str, Field(min_length=3, max_length=50)] | None = Field(
|
|
278
|
+
default=None, description="Character's nickname."
|
|
272
279
|
)
|
|
273
280
|
|
|
274
281
|
age: int | None = None
|
|
275
|
-
biography: str | None = Field(
|
|
276
|
-
|
|
277
|
-
|
|
282
|
+
biography: Annotated[str, Field(min_length=3)] | None = Field(
|
|
283
|
+
default=None, description="Character biography."
|
|
284
|
+
)
|
|
285
|
+
demeanor: Annotated[str, Field(min_length=3, max_length=50)] | None = Field(
|
|
286
|
+
default=None, description="Character's demeanor."
|
|
278
287
|
)
|
|
279
|
-
nature: str | None = Field(
|
|
280
|
-
default=None,
|
|
288
|
+
nature: Annotated[str, Field(min_length=3, max_length=50)] | None = Field(
|
|
289
|
+
default=None, description="Character's nature."
|
|
281
290
|
)
|
|
282
291
|
concept_id: str | None = Field(default=None, description="ID of the character concept.")
|
|
283
292
|
|
{valentina_python_client-1.3.0 → valentina_python_client-1.3.1}/src/vclient/models/companies.py
RENAMED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
"""Pydantic models for Company API responses."""
|
|
2
2
|
|
|
3
3
|
from datetime import datetime
|
|
4
|
+
from typing import Annotated
|
|
4
5
|
|
|
5
6
|
from pydantic import BaseModel, Field
|
|
6
7
|
|
|
@@ -77,7 +78,7 @@ class CompanyCreate(BaseModel):
|
|
|
77
78
|
|
|
78
79
|
name: str = Field(min_length=3, max_length=50)
|
|
79
80
|
email: str
|
|
80
|
-
description: str | None =
|
|
81
|
+
description: Annotated[str, Field(min_length=3)] | None = None
|
|
81
82
|
settings: CompanySettings | None = None
|
|
82
83
|
|
|
83
84
|
|
|
@@ -87,9 +88,9 @@ class CompanyUpdate(BaseModel):
|
|
|
87
88
|
Only include fields that need to be changed; omitted fields remain unchanged.
|
|
88
89
|
"""
|
|
89
90
|
|
|
90
|
-
name: str
|
|
91
|
+
name: Annotated[str, Field(min_length=3, max_length=50)] | None = None
|
|
91
92
|
email: str | None = None
|
|
92
|
-
description: str | None =
|
|
93
|
+
description: Annotated[str, Field(min_length=3)] | None = None
|
|
93
94
|
settings: CompanySettings | None = None
|
|
94
95
|
|
|
95
96
|
|
{valentina_python_client-1.3.0 → valentina_python_client-1.3.1}/src/vclient/models/shared.py
RENAMED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
"""Shared Pydantic models used across multiple services."""
|
|
2
2
|
|
|
3
3
|
from datetime import datetime
|
|
4
|
-
from typing import Any
|
|
4
|
+
from typing import Annotated, Any
|
|
5
5
|
|
|
6
6
|
from pydantic import BaseModel, Field
|
|
7
7
|
|
|
@@ -84,8 +84,8 @@ class NoteUpdate(BaseModel):
|
|
|
84
84
|
Only include fields that need to be changed; omitted fields remain unchanged.
|
|
85
85
|
"""
|
|
86
86
|
|
|
87
|
-
title: str
|
|
88
|
-
content: str | None =
|
|
87
|
+
title: Annotated[str, Field(min_length=3, max_length=50)] | None = None
|
|
88
|
+
content: Annotated[str, Field(min_length=3)] | None = None
|
|
89
89
|
|
|
90
90
|
|
|
91
91
|
# -----------------------------------------------------------------------------
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
"""Pydantic models for User API responses and requests."""
|
|
2
2
|
|
|
3
3
|
from datetime import datetime
|
|
4
|
+
from typing import Annotated
|
|
4
5
|
|
|
5
6
|
from pydantic import BaseModel, Field
|
|
6
7
|
|
|
@@ -89,7 +90,7 @@ class UserUpdate(BaseModel):
|
|
|
89
90
|
Only include fields that need to be changed; omitted fields remain unchanged.
|
|
90
91
|
"""
|
|
91
92
|
|
|
92
|
-
name: str
|
|
93
|
+
name: Annotated[str, Field(min_length=3, max_length=50)] | None = None
|
|
93
94
|
email: str | None = None
|
|
94
95
|
role: UserRole | None = None
|
|
95
96
|
discord_profile: DiscordProfile | None = None
|
|
@@ -124,7 +125,7 @@ class QuickrollCreate(BaseModel):
|
|
|
124
125
|
"""
|
|
125
126
|
|
|
126
127
|
name: str = Field(min_length=3, max_length=50)
|
|
127
|
-
description: str | None =
|
|
128
|
+
description: Annotated[str, Field(min_length=3)] | None = None
|
|
128
129
|
trait_ids: list[str] = Field(default_factory=list)
|
|
129
130
|
|
|
130
131
|
|
|
@@ -134,8 +135,8 @@ class QuickrollUpdate(BaseModel):
|
|
|
134
135
|
Only include fields that need to be changed; omitted fields remain unchanged.
|
|
135
136
|
"""
|
|
136
137
|
|
|
137
|
-
name: str
|
|
138
|
-
description: str | None =
|
|
138
|
+
name: Annotated[str, Field(min_length=3, max_length=50)] | None = None
|
|
139
|
+
description: Annotated[str, Field(min_length=3)] | None = None
|
|
139
140
|
trait_ids: list[str] | None = None
|
|
140
141
|
|
|
141
142
|
|
{valentina_python_client-1.3.0 → valentina_python_client-1.3.1}/src/vclient/services/base.py
RENAMED
|
@@ -173,7 +173,7 @@ class BaseService:
|
|
|
173
173
|
retry_statuses = config.retry_statuses
|
|
174
174
|
request_logger = logger.bind(method=method, url=path)
|
|
175
175
|
|
|
176
|
-
request_logger.debug("Send
|
|
176
|
+
request_logger.debug("Send request")
|
|
177
177
|
|
|
178
178
|
last_error: RateLimitError | ServerError | None = None
|
|
179
179
|
|
|
@@ -199,14 +199,7 @@ class BaseService:
|
|
|
199
199
|
attempt=attempt + 1,
|
|
200
200
|
max_attempts=max_attempts,
|
|
201
201
|
delay=delay,
|
|
202
|
-
).warning(
|
|
203
|
-
"Retry {method} {url} after {error_type} (attempt {attempt}/{max_attempts})",
|
|
204
|
-
method=method,
|
|
205
|
-
url=path,
|
|
206
|
-
error_type=error_type,
|
|
207
|
-
attempt=attempt + 1,
|
|
208
|
-
max_attempts=max_attempts,
|
|
209
|
-
)
|
|
202
|
+
).warning("Retry after network error")
|
|
210
203
|
await asyncio.sleep(delay)
|
|
211
204
|
continue
|
|
212
205
|
|
|
@@ -217,13 +210,7 @@ class BaseService:
|
|
|
217
210
|
request_logger.bind(
|
|
218
211
|
status=response.status_code,
|
|
219
212
|
elapsed_ms=elapsed_ms,
|
|
220
|
-
).debug(
|
|
221
|
-
"Receive {status} from {method} {url} ({elapsed_ms}ms)",
|
|
222
|
-
status=response.status_code,
|
|
223
|
-
method=method,
|
|
224
|
-
url=path,
|
|
225
|
-
elapsed_ms=f"{elapsed_ms:.0f}",
|
|
226
|
-
)
|
|
213
|
+
).debug("Receive response")
|
|
227
214
|
return response # noqa: TRY300
|
|
228
215
|
except RateLimitError as e:
|
|
229
216
|
last_error = e
|
|
@@ -236,14 +223,7 @@ class BaseService:
|
|
|
236
223
|
attempt=attempt + 1,
|
|
237
224
|
max_attempts=max_attempts,
|
|
238
225
|
delay=delay,
|
|
239
|
-
).warning(
|
|
240
|
-
"Retry {method} {url} after rate limit (attempt {attempt}/{max_attempts}, delay {delay}s)",
|
|
241
|
-
method=method,
|
|
242
|
-
url=path,
|
|
243
|
-
attempt=attempt + 1,
|
|
244
|
-
max_attempts=max_attempts,
|
|
245
|
-
delay=f"{delay:.1f}",
|
|
246
|
-
)
|
|
226
|
+
).warning("Retry after rate limit")
|
|
247
227
|
await asyncio.sleep(delay)
|
|
248
228
|
except ServerError as e:
|
|
249
229
|
if e.status_code not in retry_statuses or not self._is_retryable_method(
|
|
@@ -262,24 +242,11 @@ class BaseService:
|
|
|
262
242
|
attempt=attempt + 1,
|
|
263
243
|
max_attempts=max_attempts,
|
|
264
244
|
delay=delay,
|
|
265
|
-
).warning(
|
|
266
|
-
"Retry {method} {url} after {status} error (attempt {attempt}/{max_attempts}, delay {delay}s)",
|
|
267
|
-
method=method,
|
|
268
|
-
url=path,
|
|
269
|
-
status=e.status_code,
|
|
270
|
-
attempt=attempt + 1,
|
|
271
|
-
max_attempts=max_attempts,
|
|
272
|
-
delay=f"{delay:.1f}",
|
|
273
|
-
)
|
|
245
|
+
).warning("Retry after server error")
|
|
274
246
|
await asyncio.sleep(delay)
|
|
275
247
|
|
|
276
248
|
if last_error is not None:
|
|
277
|
-
request_logger.bind(attempts=max_attempts).error(
|
|
278
|
-
"Exhaust retries for {method} {url} after {attempts} attempts",
|
|
279
|
-
method=method,
|
|
280
|
-
url=path,
|
|
281
|
-
attempts=max_attempts,
|
|
282
|
-
)
|
|
249
|
+
request_logger.bind(attempts=max_attempts).error("Exhaust retries")
|
|
283
250
|
raise last_error
|
|
284
251
|
|
|
285
252
|
msg = "Unexpected state: no response or error"
|
|
@@ -324,45 +291,23 @@ class BaseService:
|
|
|
324
291
|
)
|
|
325
292
|
|
|
326
293
|
if status_code == 401: # noqa: PLR2004
|
|
327
|
-
error_logger.error(
|
|
328
|
-
"Fail authentication for {method} {url} ({status})",
|
|
329
|
-
method=method,
|
|
330
|
-
url=url,
|
|
331
|
-
status=status_code,
|
|
332
|
-
)
|
|
294
|
+
error_logger.error("Fail authentication")
|
|
333
295
|
raise AuthenticationError(message, status_code, response_data)
|
|
334
296
|
|
|
335
297
|
if status_code == 403: # noqa: PLR2004
|
|
336
|
-
error_logger.error(
|
|
337
|
-
"Deny authorization for {method} {url} ({status})",
|
|
338
|
-
method=method,
|
|
339
|
-
url=url,
|
|
340
|
-
status=status_code,
|
|
341
|
-
)
|
|
298
|
+
error_logger.error("Deny authorization")
|
|
342
299
|
raise AuthorizationError(message, status_code, response_data)
|
|
343
300
|
|
|
344
301
|
if status_code == 404: # noqa: PLR2004
|
|
345
|
-
error_logger.debug(
|
|
346
|
-
"Return 404 for {method} {url}",
|
|
347
|
-
method=method,
|
|
348
|
-
url=url,
|
|
349
|
-
)
|
|
302
|
+
error_logger.debug("Return 404")
|
|
350
303
|
raise NotFoundError(message, status_code, response_data)
|
|
351
304
|
|
|
352
305
|
if status_code == 400: # noqa: PLR2004
|
|
353
|
-
error_logger.warning(
|
|
354
|
-
"Reject {method} {url} with validation error",
|
|
355
|
-
method=method,
|
|
356
|
-
url=url,
|
|
357
|
-
)
|
|
306
|
+
error_logger.warning("Reject with validation error")
|
|
358
307
|
raise ValidationError(message, status_code, response_data)
|
|
359
308
|
|
|
360
309
|
if status_code == 409: # noqa: PLR2004
|
|
361
|
-
error_logger.warning(
|
|
362
|
-
"Return 409 conflict for {method} {url}",
|
|
363
|
-
method=method,
|
|
364
|
-
url=url,
|
|
365
|
-
)
|
|
310
|
+
error_logger.warning("Return 409 conflict")
|
|
366
311
|
raise ConflictError(message, status_code, response_data)
|
|
367
312
|
|
|
368
313
|
if HTTP_500_INTERNAL_SERVER_ERROR <= status_code < HTTP_600_UPPER_BOUND:
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{valentina_python_client-1.3.0 → valentina_python_client-1.3.1}/src/vclient/models/__init__.py
RENAMED
|
File without changes
|
|
File without changes
|
{valentina_python_client-1.3.0 → valentina_python_client-1.3.1}/src/vclient/models/chapters.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{valentina_python_client-1.3.0 → valentina_python_client-1.3.1}/src/vclient/models/developers.py
RENAMED
|
File without changes
|
{valentina_python_client-1.3.0 → valentina_python_client-1.3.1}/src/vclient/models/diceroll.py
RENAMED
|
File without changes
|
{valentina_python_client-1.3.0 → valentina_python_client-1.3.1}/src/vclient/models/dictionary.py
RENAMED
|
File without changes
|
{valentina_python_client-1.3.0 → valentina_python_client-1.3.1}/src/vclient/models/global_admin.py
RENAMED
|
File without changes
|
{valentina_python_client-1.3.0 → valentina_python_client-1.3.1}/src/vclient/models/pagination.py
RENAMED
|
File without changes
|
{valentina_python_client-1.3.0 → valentina_python_client-1.3.1}/src/vclient/models/system.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
{valentina_python_client-1.3.0 → valentina_python_client-1.3.1}/src/vclient/services/__init__.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
{valentina_python_client-1.3.0 → valentina_python_client-1.3.1}/src/vclient/services/campaigns.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{valentina_python_client-1.3.0 → valentina_python_client-1.3.1}/src/vclient/services/characters.py
RENAMED
|
File without changes
|
{valentina_python_client-1.3.0 → valentina_python_client-1.3.1}/src/vclient/services/companies.py
RENAMED
|
File without changes
|
{valentina_python_client-1.3.0 → valentina_python_client-1.3.1}/src/vclient/services/developers.py
RENAMED
|
File without changes
|
{valentina_python_client-1.3.0 → valentina_python_client-1.3.1}/src/vclient/services/dicerolls.py
RENAMED
|
File without changes
|
{valentina_python_client-1.3.0 → valentina_python_client-1.3.1}/src/vclient/services/dictionary.py
RENAMED
|
File without changes
|
{valentina_python_client-1.3.0 → valentina_python_client-1.3.1}/src/vclient/services/global_admin.py
RENAMED
|
File without changes
|
{valentina_python_client-1.3.0 → valentina_python_client-1.3.1}/src/vclient/services/options.py
RENAMED
|
File without changes
|
{valentina_python_client-1.3.0 → valentina_python_client-1.3.1}/src/vclient/services/system.py
RENAMED
|
File without changes
|
{valentina_python_client-1.3.0 → valentina_python_client-1.3.1}/src/vclient/services/users.py
RENAMED
|
File without changes
|
{valentina_python_client-1.3.0 → valentina_python_client-1.3.1}/src/vclient/validate_constants.py
RENAMED
|
File without changes
|