valentina-python-client 2.4.2__tar.gz → 2.5.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.
Files changed (84) hide show
  1. {valentina_python_client-2.4.2 → valentina_python_client-2.5.0}/PKG-INFO +1 -1
  2. {valentina_python_client-2.4.2 → valentina_python_client-2.5.0}/pyproject.toml +1 -1
  3. {valentina_python_client-2.4.2 → valentina_python_client-2.5.0}/src/vclient/__init__.py +1 -1
  4. {valentina_python_client-2.4.2 → valentina_python_client-2.5.0}/src/vclient/_sync/services/base.py +35 -8
  5. {valentina_python_client-2.4.2 → valentina_python_client-2.5.0}/src/vclient/_sync/services/character_blueprint.py +38 -3
  6. {valentina_python_client-2.4.2 → valentina_python_client-2.5.0}/src/vclient/_sync/services/dictionary.py +6 -2
  7. {valentina_python_client-2.4.2 → valentina_python_client-2.5.0}/src/vclient/constants.py +3 -0
  8. {valentina_python_client-2.4.2 → valentina_python_client-2.5.0}/src/vclient/services/base.py +25 -5
  9. {valentina_python_client-2.4.2 → valentina_python_client-2.5.0}/src/vclient/services/character_blueprint.py +25 -0
  10. {valentina_python_client-2.4.2 → valentina_python_client-2.5.0}/src/vclient/services/dictionary.py +4 -2
  11. {valentina_python_client-2.4.2 → valentina_python_client-2.5.0}/LICENSE +0 -0
  12. {valentina_python_client-2.4.2 → valentina_python_client-2.5.0}/README.md +0 -0
  13. {valentina_python_client-2.4.2 → valentina_python_client-2.5.0}/src/vclient/_codegen.py +0 -0
  14. {valentina_python_client-2.4.2 → valentina_python_client-2.5.0}/src/vclient/_sync/__init__.py +0 -0
  15. {valentina_python_client-2.4.2 → valentina_python_client-2.5.0}/src/vclient/_sync/client.py +0 -0
  16. {valentina_python_client-2.4.2 → valentina_python_client-2.5.0}/src/vclient/_sync/registry.py +0 -0
  17. {valentina_python_client-2.4.2 → valentina_python_client-2.5.0}/src/vclient/_sync/services/__init__.py +0 -0
  18. {valentina_python_client-2.4.2 → valentina_python_client-2.5.0}/src/vclient/_sync/services/_audit_params.py +0 -0
  19. {valentina_python_client-2.4.2 → valentina_python_client-2.5.0}/src/vclient/_sync/services/campaign_book_chapters.py +0 -0
  20. {valentina_python_client-2.4.2 → valentina_python_client-2.5.0}/src/vclient/_sync/services/campaign_books.py +0 -0
  21. {valentina_python_client-2.4.2 → valentina_python_client-2.5.0}/src/vclient/_sync/services/campaigns.py +0 -0
  22. {valentina_python_client-2.4.2 → valentina_python_client-2.5.0}/src/vclient/_sync/services/character_autogen.py +0 -0
  23. {valentina_python_client-2.4.2 → valentina_python_client-2.5.0}/src/vclient/_sync/services/character_traits.py +0 -0
  24. {valentina_python_client-2.4.2 → valentina_python_client-2.5.0}/src/vclient/_sync/services/characters.py +0 -0
  25. {valentina_python_client-2.4.2 → valentina_python_client-2.5.0}/src/vclient/_sync/services/companies.py +0 -0
  26. {valentina_python_client-2.4.2 → valentina_python_client-2.5.0}/src/vclient/_sync/services/developers.py +0 -0
  27. {valentina_python_client-2.4.2 → valentina_python_client-2.5.0}/src/vclient/_sync/services/dicerolls.py +0 -0
  28. {valentina_python_client-2.4.2 → valentina_python_client-2.5.0}/src/vclient/_sync/services/global_admin.py +0 -0
  29. {valentina_python_client-2.4.2 → valentina_python_client-2.5.0}/src/vclient/_sync/services/options.py +0 -0
  30. {valentina_python_client-2.4.2 → valentina_python_client-2.5.0}/src/vclient/_sync/services/system.py +0 -0
  31. {valentina_python_client-2.4.2 → valentina_python_client-2.5.0}/src/vclient/_sync/services/user_lookup.py +0 -0
  32. {valentina_python_client-2.4.2 → valentina_python_client-2.5.0}/src/vclient/_sync/services/user_self_registration.py +0 -0
  33. {valentina_python_client-2.4.2 → valentina_python_client-2.5.0}/src/vclient/_sync/services/users.py +0 -0
  34. {valentina_python_client-2.4.2 → valentina_python_client-2.5.0}/src/vclient/_sync/testing/__init__.py +0 -0
  35. {valentina_python_client-2.4.2 → valentina_python_client-2.5.0}/src/vclient/_sync/testing/_client.py +0 -0
  36. {valentina_python_client-2.4.2 → valentina_python_client-2.5.0}/src/vclient/client.py +0 -0
  37. {valentina_python_client-2.4.2 → valentina_python_client-2.5.0}/src/vclient/config.py +0 -0
  38. {valentina_python_client-2.4.2 → valentina_python_client-2.5.0}/src/vclient/endpoints.py +0 -0
  39. {valentina_python_client-2.4.2 → valentina_python_client-2.5.0}/src/vclient/exceptions.py +0 -0
  40. {valentina_python_client-2.4.2 → valentina_python_client-2.5.0}/src/vclient/models/__init__.py +0 -0
  41. {valentina_python_client-2.4.2 → valentina_python_client-2.5.0}/src/vclient/models/audit_logs.py +0 -0
  42. {valentina_python_client-2.4.2 → valentina_python_client-2.5.0}/src/vclient/models/books.py +0 -0
  43. {valentina_python_client-2.4.2 → valentina_python_client-2.5.0}/src/vclient/models/campaigns.py +0 -0
  44. {valentina_python_client-2.4.2 → valentina_python_client-2.5.0}/src/vclient/models/chapters.py +0 -0
  45. {valentina_python_client-2.4.2 → valentina_python_client-2.5.0}/src/vclient/models/character_autogen.py +0 -0
  46. {valentina_python_client-2.4.2 → valentina_python_client-2.5.0}/src/vclient/models/character_blueprint.py +0 -0
  47. {valentina_python_client-2.4.2 → valentina_python_client-2.5.0}/src/vclient/models/character_trait.py +0 -0
  48. {valentina_python_client-2.4.2 → valentina_python_client-2.5.0}/src/vclient/models/characters.py +0 -0
  49. {valentina_python_client-2.4.2 → valentina_python_client-2.5.0}/src/vclient/models/companies.py +0 -0
  50. {valentina_python_client-2.4.2 → valentina_python_client-2.5.0}/src/vclient/models/developers.py +0 -0
  51. {valentina_python_client-2.4.2 → valentina_python_client-2.5.0}/src/vclient/models/diceroll.py +0 -0
  52. {valentina_python_client-2.4.2 → valentina_python_client-2.5.0}/src/vclient/models/dictionary.py +0 -0
  53. {valentina_python_client-2.4.2 → valentina_python_client-2.5.0}/src/vclient/models/full_sheet.py +0 -0
  54. {valentina_python_client-2.4.2 → valentina_python_client-2.5.0}/src/vclient/models/global_admin.py +0 -0
  55. {valentina_python_client-2.4.2 → valentina_python_client-2.5.0}/src/vclient/models/pagination.py +0 -0
  56. {valentina_python_client-2.4.2 → valentina_python_client-2.5.0}/src/vclient/models/shared.py +0 -0
  57. {valentina_python_client-2.4.2 → valentina_python_client-2.5.0}/src/vclient/models/system.py +0 -0
  58. {valentina_python_client-2.4.2 → valentina_python_client-2.5.0}/src/vclient/models/user_lookup.py +0 -0
  59. {valentina_python_client-2.4.2 → valentina_python_client-2.5.0}/src/vclient/models/users.py +0 -0
  60. {valentina_python_client-2.4.2 → valentina_python_client-2.5.0}/src/vclient/py.typed +0 -0
  61. {valentina_python_client-2.4.2 → valentina_python_client-2.5.0}/src/vclient/registry.py +0 -0
  62. {valentina_python_client-2.4.2 → valentina_python_client-2.5.0}/src/vclient/services/__init__.py +0 -0
  63. {valentina_python_client-2.4.2 → valentina_python_client-2.5.0}/src/vclient/services/_audit_params.py +0 -0
  64. {valentina_python_client-2.4.2 → valentina_python_client-2.5.0}/src/vclient/services/campaign_book_chapters.py +0 -0
  65. {valentina_python_client-2.4.2 → valentina_python_client-2.5.0}/src/vclient/services/campaign_books.py +0 -0
  66. {valentina_python_client-2.4.2 → valentina_python_client-2.5.0}/src/vclient/services/campaigns.py +0 -0
  67. {valentina_python_client-2.4.2 → valentina_python_client-2.5.0}/src/vclient/services/character_autogen.py +0 -0
  68. {valentina_python_client-2.4.2 → valentina_python_client-2.5.0}/src/vclient/services/character_traits.py +0 -0
  69. {valentina_python_client-2.4.2 → valentina_python_client-2.5.0}/src/vclient/services/characters.py +0 -0
  70. {valentina_python_client-2.4.2 → valentina_python_client-2.5.0}/src/vclient/services/companies.py +0 -0
  71. {valentina_python_client-2.4.2 → valentina_python_client-2.5.0}/src/vclient/services/developers.py +0 -0
  72. {valentina_python_client-2.4.2 → valentina_python_client-2.5.0}/src/vclient/services/dicerolls.py +0 -0
  73. {valentina_python_client-2.4.2 → valentina_python_client-2.5.0}/src/vclient/services/global_admin.py +0 -0
  74. {valentina_python_client-2.4.2 → valentina_python_client-2.5.0}/src/vclient/services/options.py +0 -0
  75. {valentina_python_client-2.4.2 → valentina_python_client-2.5.0}/src/vclient/services/system.py +0 -0
  76. {valentina_python_client-2.4.2 → valentina_python_client-2.5.0}/src/vclient/services/user_lookup.py +0 -0
  77. {valentina_python_client-2.4.2 → valentina_python_client-2.5.0}/src/vclient/services/user_self_registration.py +0 -0
  78. {valentina_python_client-2.4.2 → valentina_python_client-2.5.0}/src/vclient/services/users.py +0 -0
  79. {valentina_python_client-2.4.2 → valentina_python_client-2.5.0}/src/vclient/testing/__init__.py +0 -0
  80. {valentina_python_client-2.4.2 → valentina_python_client-2.5.0}/src/vclient/testing/_client.py +0 -0
  81. {valentina_python_client-2.4.2 → valentina_python_client-2.5.0}/src/vclient/testing/_factories.py +0 -0
  82. {valentina_python_client-2.4.2 → valentina_python_client-2.5.0}/src/vclient/testing/_router.py +0 -0
  83. {valentina_python_client-2.4.2 → valentina_python_client-2.5.0}/src/vclient/testing/_routes.py +0 -0
  84. {valentina_python_client-2.4.2 → valentina_python_client-2.5.0}/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: 2.4.2
3
+ Version: 2.5.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>
@@ -16,7 +16,7 @@
16
16
  name = "valentina-python-client"
17
17
  readme = "README.md"
18
18
  requires-python = ">=3.13"
19
- version = "2.4.2"
19
+ version = "2.5.0"
20
20
 
21
21
  [project.optional-dependencies]
22
22
  testing = ["polyfactory>=3.3.0"]
@@ -116,4 +116,4 @@ __all__ = (
116
116
  "users_service",
117
117
  )
118
118
 
119
- __version__ = "2.4.2"
119
+ __version__ = "2.5.0"
@@ -592,20 +592,23 @@ class SyncBaseService:
592
592
  limit: int = DEFAULT_PAGE_LIMIT,
593
593
  offset: int = 0,
594
594
  params: dict[str, Any] | None = None,
595
+ max_limit: int = MAX_PAGE_LIMIT,
595
596
  ) -> PaginatedResponse[dict[str, Any]]:
596
597
  """Make a paginated GET request.
597
598
 
598
599
  Args:
599
600
  path: API endpoint path.
600
- limit: Maximum number of items to return (0-100, default 10).
601
+ limit: Maximum number of items to return (default 10).
601
602
  offset: Number of items to skip from the beginning (default 0).
602
603
  params: Additional query parameters.
604
+ max_limit: Upper bound the limit is clamped to (default 100). Reference/catalog
605
+ endpoints pass a higher bound (MAX_REFERENCE_PAGE_LIMIT).
603
606
 
604
607
  Returns:
605
608
  A PaginatedResponse containing the items and pagination metadata.
606
609
  """
607
610
  request_params = {
608
- "limit": min(max(limit, 0), MAX_PAGE_LIMIT),
611
+ "limit": min(max(limit, 0), max_limit),
609
612
  "offset": max(offset, 0),
610
613
  **(params or {}),
611
614
  }
@@ -620,20 +623,25 @@ class SyncBaseService:
620
623
  limit: int = DEFAULT_PAGE_LIMIT,
621
624
  offset: int = 0,
622
625
  params: dict[str, Any] | None = None,
626
+ max_limit: int = MAX_PAGE_LIMIT,
623
627
  ) -> PaginatedResponse[T]:
624
628
  """Make a paginated GET request and parse items into the given model class.
625
629
 
626
630
  Args:
627
631
  path: API endpoint path.
628
632
  model_class: Pydantic model class to validate each item into.
629
- limit: Maximum number of items to return (0-100, default 10).
633
+ limit: Maximum number of items to return (default 10).
630
634
  offset: Number of items to skip from the beginning (default 0).
631
635
  params: Additional query parameters.
636
+ max_limit: Upper bound the limit is clamped to (default 100). Reference/catalog
637
+ endpoints pass a higher bound (MAX_REFERENCE_PAGE_LIMIT).
632
638
 
633
639
  Returns:
634
640
  A PaginatedResponse containing validated model instances.
635
641
  """
636
- response = self._get_paginated(path, limit=limit, offset=offset, params=params)
642
+ response = self._get_paginated(
643
+ path, limit=limit, offset=offset, params=params, max_limit=max_limit
644
+ )
637
645
  return PaginatedResponse(
638
646
  items=[model_class.model_validate(item) for item in response.items],
639
647
  limit=response.limit,
@@ -642,7 +650,12 @@ class SyncBaseService:
642
650
  )
643
651
 
644
652
  def _iter_all_pages(
645
- self, path: str, *, limit: int = MAX_PAGE_LIMIT, params: dict[str, Any] | None = None
653
+ self,
654
+ path: str,
655
+ *,
656
+ limit: int = MAX_PAGE_LIMIT,
657
+ params: dict[str, Any] | None = None,
658
+ max_limit: int = MAX_PAGE_LIMIT,
646
659
  ) -> Iterator[dict[str, Any]]:
647
660
  """Iterate through all pages of a paginated endpoint.
648
661
 
@@ -653,6 +666,8 @@ class SyncBaseService:
653
666
  path: API endpoint path.
654
667
  limit: Items per page (default 100 for efficiency).
655
668
  params: Additional query parameters.
669
+ max_limit: Upper bound the per-page limit is clamped to (default 100).
670
+ Reference/catalog endpoints pass a higher bound (MAX_REFERENCE_PAGE_LIMIT).
656
671
 
657
672
  Yields:
658
673
  Individual items from the paginated response.
@@ -665,7 +680,9 @@ class SyncBaseService:
665
680
  """
666
681
  offset = 0
667
682
  while True:
668
- page = self._get_paginated(path, limit=limit, offset=offset, params=params)
683
+ page = self._get_paginated(
684
+ path, limit=limit, offset=offset, params=params, max_limit=max_limit
685
+ )
669
686
  for item in page.items:
670
687
  yield item
671
688
  if not page.has_more:
@@ -673,7 +690,12 @@ class SyncBaseService:
673
690
  offset = page.next_offset
674
691
 
675
692
  def _get_all(
676
- self, path: str, *, limit: int = MAX_PAGE_LIMIT, params: dict[str, Any] | None = None
693
+ self,
694
+ path: str,
695
+ *,
696
+ limit: int = MAX_PAGE_LIMIT,
697
+ params: dict[str, Any] | None = None,
698
+ max_limit: int = MAX_PAGE_LIMIT,
677
699
  ) -> list[dict[str, Any]]:
678
700
  """Fetch all items from a paginated endpoint.
679
701
 
@@ -685,8 +707,13 @@ class SyncBaseService:
685
707
  path: API endpoint path.
686
708
  limit: Items per page (default 100 for efficiency).
687
709
  params: Additional query parameters.
710
+ max_limit: Upper bound the per-page limit is clamped to (default 100).
711
+ Reference/catalog endpoints pass a higher bound (MAX_REFERENCE_PAGE_LIMIT).
688
712
 
689
713
  Returns:
690
714
  A list of all items from all pages.
691
715
  """
692
- return [item for item in self._iter_all_pages(path, limit=limit, params=params)]
716
+ return [
717
+ item
718
+ for item in self._iter_all_pages(path, limit=limit, params=params, max_limit=max_limit)
719
+ ]
@@ -5,7 +5,13 @@ 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, BlueprintTraitOrderBy, CharacterClass, GameVersion
8
+ from vclient.constants import (
9
+ DEFAULT_PAGE_LIMIT,
10
+ MAX_REFERENCE_PAGE_LIMIT,
11
+ BlueprintTraitOrderBy,
12
+ CharacterClass,
13
+ GameVersion,
14
+ )
9
15
  from vclient.endpoints import Endpoints
10
16
  from vclient.models import (
11
17
  CharacterConcept,
@@ -58,6 +64,7 @@ class SyncCharacterBlueprintService(SyncBaseService):
58
64
  SheetSection,
59
65
  limit=limit,
60
66
  offset=offset,
67
+ max_limit=MAX_REFERENCE_PAGE_LIMIT,
61
68
  params=self._build_params(game_version=game_version, character_class=character_class),
62
69
  )
63
70
 
@@ -84,6 +91,8 @@ class SyncCharacterBlueprintService(SyncBaseService):
84
91
  """Iterate through all character blueprint sections."""
85
92
  for section in self._iter_all_pages(
86
93
  self._format_endpoint(Endpoints.BLUEPRINT_SECTIONS),
94
+ limit=MAX_REFERENCE_PAGE_LIMIT,
95
+ max_limit=MAX_REFERENCE_PAGE_LIMIT,
87
96
  params=self._build_params(game_version=game_version, character_class=character_class),
88
97
  ):
89
98
  yield SheetSection.model_validate(section)
@@ -110,6 +119,7 @@ class SyncCharacterBlueprintService(SyncBaseService):
110
119
  TraitCategory,
111
120
  limit=limit,
112
121
  offset=offset,
122
+ max_limit=MAX_REFERENCE_PAGE_LIMIT,
113
123
  params=self._build_params(
114
124
  game_version=game_version, section_id=section_id, character_class=character_class
115
125
  ),
@@ -140,6 +150,8 @@ class SyncCharacterBlueprintService(SyncBaseService):
140
150
  """Iterate through all character blueprint categories."""
141
151
  for category in self._iter_all_pages(
142
152
  self._format_endpoint(Endpoints.BLUEPRINT_CATEGORIES),
153
+ limit=MAX_REFERENCE_PAGE_LIMIT,
154
+ max_limit=MAX_REFERENCE_PAGE_LIMIT,
143
155
  params=self._build_params(
144
156
  game_version=game_version, section_id=section_id, character_class=character_class
145
157
  ),
@@ -168,6 +180,7 @@ class SyncCharacterBlueprintService(SyncBaseService):
168
180
  TraitSubcategory,
169
181
  limit=limit,
170
182
  offset=offset,
183
+ max_limit=MAX_REFERENCE_PAGE_LIMIT,
171
184
  params=self._build_params(
172
185
  game_version=game_version, category_id=category_id, character_class=character_class
173
186
  ),
@@ -198,6 +211,8 @@ class SyncCharacterBlueprintService(SyncBaseService):
198
211
  """Iterate through all character blueprint subcategories."""
199
212
  for subcategory in self._iter_all_pages(
200
213
  self._format_endpoint(Endpoints.BLUEPRINT_SUBCATEGORIES),
214
+ limit=MAX_REFERENCE_PAGE_LIMIT,
215
+ max_limit=MAX_REFERENCE_PAGE_LIMIT,
201
216
  params=self._build_params(
202
217
  game_version=game_version, category_id=category_id, character_class=character_class
203
218
  ),
@@ -232,6 +247,7 @@ class SyncCharacterBlueprintService(SyncBaseService):
232
247
  Trait,
233
248
  limit=limit,
234
249
  offset=offset,
250
+ max_limit=MAX_REFERENCE_PAGE_LIMIT,
235
251
  params=self._build_params(
236
252
  character_class=character_class,
237
253
  category_id=category_id,
@@ -282,6 +298,8 @@ class SyncCharacterBlueprintService(SyncBaseService):
282
298
  """Iterate through all character blueprint traits."""
283
299
  for trait in self._iter_all_pages(
284
300
  self._format_endpoint(Endpoints.BLUEPRINT_TRAITS),
301
+ limit=MAX_REFERENCE_PAGE_LIMIT,
302
+ max_limit=MAX_REFERENCE_PAGE_LIMIT,
285
303
  params=self._build_params(
286
304
  character_class=character_class,
287
305
  category_id=category_id,
@@ -306,7 +324,11 @@ class SyncCharacterBlueprintService(SyncBaseService):
306
324
  ) -> PaginatedResponse[CharacterConcept]:
307
325
  """Get a paginated page of character concepts."""
308
326
  return self._get_paginated_as(
309
- self._format_endpoint(Endpoints.CONCEPTS), CharacterConcept, limit=limit, offset=offset
327
+ self._format_endpoint(Endpoints.CONCEPTS),
328
+ CharacterConcept,
329
+ limit=limit,
330
+ offset=offset,
331
+ max_limit=MAX_REFERENCE_PAGE_LIMIT,
310
332
  )
311
333
 
312
334
  def list_all_concepts(self) -> list[CharacterConcept]:
@@ -315,7 +337,11 @@ class SyncCharacterBlueprintService(SyncBaseService):
315
337
 
316
338
  def iter_all_concepts(self) -> Iterator[CharacterConcept]:
317
339
  """Iterate through all character concepts."""
318
- for concept in self._iter_all_pages(self._format_endpoint(Endpoints.CONCEPTS)):
340
+ for concept in self._iter_all_pages(
341
+ self._format_endpoint(Endpoints.CONCEPTS),
342
+ limit=MAX_REFERENCE_PAGE_LIMIT,
343
+ max_limit=MAX_REFERENCE_PAGE_LIMIT,
344
+ ):
319
345
  yield CharacterConcept.model_validate(concept)
320
346
 
321
347
  def get_concept(self, *, concept_id: str) -> CharacterConcept:
@@ -336,6 +362,7 @@ class SyncCharacterBlueprintService(SyncBaseService):
336
362
  VampireClan,
337
363
  limit=limit,
338
364
  offset=offset,
365
+ max_limit=MAX_REFERENCE_PAGE_LIMIT,
339
366
  params=self._build_params(game_version=game_version),
340
367
  )
341
368
 
@@ -351,6 +378,8 @@ class SyncCharacterBlueprintService(SyncBaseService):
351
378
  """Iterate through all vampire clans."""
352
379
  for clan in self._iter_all_pages(
353
380
  self._format_endpoint(Endpoints.VAMPIRE_CLANS),
381
+ limit=MAX_REFERENCE_PAGE_LIMIT,
382
+ max_limit=MAX_REFERENCE_PAGE_LIMIT,
354
383
  params=self._build_params(game_version=game_version),
355
384
  ):
356
385
  yield VampireClan.model_validate(clan)
@@ -375,6 +404,7 @@ class SyncCharacterBlueprintService(SyncBaseService):
375
404
  WerewolfAuspice,
376
405
  limit=limit,
377
406
  offset=offset,
407
+ max_limit=MAX_REFERENCE_PAGE_LIMIT,
378
408
  params=self._build_params(game_version=game_version),
379
409
  )
380
410
 
@@ -390,6 +420,8 @@ class SyncCharacterBlueprintService(SyncBaseService):
390
420
  """Iterate through all werewolf auspices."""
391
421
  for auspice in self._iter_all_pages(
392
422
  self._format_endpoint(Endpoints.WEREWOLF_AUSPICES),
423
+ limit=MAX_REFERENCE_PAGE_LIMIT,
424
+ max_limit=MAX_REFERENCE_PAGE_LIMIT,
393
425
  params=self._build_params(game_version=game_version),
394
426
  ):
395
427
  yield WerewolfAuspice.model_validate(auspice)
@@ -416,6 +448,7 @@ class SyncCharacterBlueprintService(SyncBaseService):
416
448
  WerewolfTribe,
417
449
  limit=limit,
418
450
  offset=offset,
451
+ max_limit=MAX_REFERENCE_PAGE_LIMIT,
419
452
  params=self._build_params(game_version=game_version),
420
453
  )
421
454
 
@@ -431,6 +464,8 @@ class SyncCharacterBlueprintService(SyncBaseService):
431
464
  """Iterate through all werewolf tribes."""
432
465
  for tribe in self._iter_all_pages(
433
466
  self._format_endpoint(Endpoints.WEREWOLF_TRIBES),
467
+ limit=MAX_REFERENCE_PAGE_LIMIT,
468
+ max_limit=MAX_REFERENCE_PAGE_LIMIT,
434
469
  params=self._build_params(game_version=game_version),
435
470
  ):
436
471
  yield WerewolfTribe.model_validate(tribe)
@@ -5,7 +5,7 @@ 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
8
+ from vclient.constants import DEFAULT_PAGE_LIMIT, MAX_REFERENCE_PAGE_LIMIT
9
9
  from vclient.endpoints import Endpoints
10
10
  from vclient.models import (
11
11
  DictionaryTerm,
@@ -48,6 +48,7 @@ class SyncDictionaryService(SyncBaseService):
48
48
  DictionaryTerm,
49
49
  limit=limit,
50
50
  offset=offset,
51
+ max_limit=MAX_REFERENCE_PAGE_LIMIT,
51
52
  params=self._build_params(term=term),
52
53
  )
53
54
 
@@ -55,11 +56,14 @@ class SyncDictionaryService(SyncBaseService):
55
56
  """Retrieve all dictionary terms."""
56
57
  return [term for term in self.iter_all(term=term)]
57
58
 
58
- def iter_all(self, *, term: str | None = None, limit: int = 100) -> Iterator[DictionaryTerm]:
59
+ def iter_all(
60
+ self, *, term: str | None = None, limit: int = MAX_REFERENCE_PAGE_LIMIT
61
+ ) -> Iterator[DictionaryTerm]:
59
62
  """Iterate through all dictionary terms."""
60
63
  for item in self._iter_all_pages(
61
64
  self._format_endpoint(Endpoints.DICTIONARY_TERMS),
62
65
  limit=limit,
66
+ max_limit=MAX_REFERENCE_PAGE_LIMIT,
63
67
  params=self._build_params(term=term),
64
68
  ):
65
69
  yield DictionaryTerm.model_validate(item)
@@ -20,6 +20,9 @@ IDEMPOTENT_HTTP_METHODS: frozenset[str] = frozenset({"GET", "PUT", "DELETE"})
20
20
  # Pagination defaults
21
21
  DEFAULT_PAGE_LIMIT = 10
22
22
  MAX_PAGE_LIMIT = 100
23
+ # Reference/catalog list endpoints serve bounded seed data and allow fetching a
24
+ # full catalog in one request, so they accept a higher per-request limit.
25
+ MAX_REFERENCE_PAGE_LIMIT = 1000
23
26
 
24
27
  # Server log tail defaults
25
28
  DEFAULT_LOG_TAIL_LIMIT = 100
@@ -667,20 +667,23 @@ class BaseService:
667
667
  limit: int = DEFAULT_PAGE_LIMIT,
668
668
  offset: int = 0,
669
669
  params: dict[str, Any] | None = None,
670
+ max_limit: int = MAX_PAGE_LIMIT,
670
671
  ) -> PaginatedResponse[dict[str, Any]]:
671
672
  """Make a paginated GET request.
672
673
 
673
674
  Args:
674
675
  path: API endpoint path.
675
- limit: Maximum number of items to return (0-100, default 10).
676
+ limit: Maximum number of items to return (default 10).
676
677
  offset: Number of items to skip from the beginning (default 0).
677
678
  params: Additional query parameters.
679
+ max_limit: Upper bound the limit is clamped to (default 100). Reference/catalog
680
+ endpoints pass a higher bound (MAX_REFERENCE_PAGE_LIMIT).
678
681
 
679
682
  Returns:
680
683
  A PaginatedResponse containing the items and pagination metadata.
681
684
  """
682
685
  request_params = {
683
- "limit": min(max(limit, 0), MAX_PAGE_LIMIT), # Clamp to valid range
686
+ "limit": min(max(limit, 0), max_limit), # Clamp to valid range
684
687
  "offset": max(offset, 0),
685
688
  **(params or {}),
686
689
  }
@@ -696,20 +699,25 @@ class BaseService:
696
699
  limit: int = DEFAULT_PAGE_LIMIT,
697
700
  offset: int = 0,
698
701
  params: dict[str, Any] | None = None,
702
+ max_limit: int = MAX_PAGE_LIMIT,
699
703
  ) -> PaginatedResponse[T]:
700
704
  """Make a paginated GET request and parse items into the given model class.
701
705
 
702
706
  Args:
703
707
  path: API endpoint path.
704
708
  model_class: Pydantic model class to validate each item into.
705
- limit: Maximum number of items to return (0-100, default 10).
709
+ limit: Maximum number of items to return (default 10).
706
710
  offset: Number of items to skip from the beginning (default 0).
707
711
  params: Additional query parameters.
712
+ max_limit: Upper bound the limit is clamped to (default 100). Reference/catalog
713
+ endpoints pass a higher bound (MAX_REFERENCE_PAGE_LIMIT).
708
714
 
709
715
  Returns:
710
716
  A PaginatedResponse containing validated model instances.
711
717
  """
712
- response = await self._get_paginated(path, limit=limit, offset=offset, params=params)
718
+ response = await self._get_paginated(
719
+ path, limit=limit, offset=offset, params=params, max_limit=max_limit
720
+ )
713
721
  return PaginatedResponse(
714
722
  items=[model_class.model_validate(item) for item in response.items],
715
723
  limit=response.limit,
@@ -723,6 +731,7 @@ class BaseService:
723
731
  *,
724
732
  limit: int = MAX_PAGE_LIMIT,
725
733
  params: dict[str, Any] | None = None,
734
+ max_limit: int = MAX_PAGE_LIMIT,
726
735
  ) -> AsyncIterator[dict[str, Any]]:
727
736
  """Iterate through all pages of a paginated endpoint.
728
737
 
@@ -733,6 +742,8 @@ class BaseService:
733
742
  path: API endpoint path.
734
743
  limit: Items per page (default 100 for efficiency).
735
744
  params: Additional query parameters.
745
+ max_limit: Upper bound the per-page limit is clamped to (default 100).
746
+ Reference/catalog endpoints pass a higher bound (MAX_REFERENCE_PAGE_LIMIT).
736
747
 
737
748
  Yields:
738
749
  Individual items from the paginated response.
@@ -751,6 +762,7 @@ class BaseService:
751
762
  limit=limit,
752
763
  offset=offset,
753
764
  params=params,
765
+ max_limit=max_limit,
754
766
  )
755
767
 
756
768
  for item in page.items:
@@ -767,6 +779,7 @@ class BaseService:
767
779
  *,
768
780
  limit: int = MAX_PAGE_LIMIT,
769
781
  params: dict[str, Any] | None = None,
782
+ max_limit: int = MAX_PAGE_LIMIT,
770
783
  ) -> list[dict[str, Any]]:
771
784
  """Fetch all items from a paginated endpoint.
772
785
 
@@ -778,8 +791,15 @@ class BaseService:
778
791
  path: API endpoint path.
779
792
  limit: Items per page (default 100 for efficiency).
780
793
  params: Additional query parameters.
794
+ max_limit: Upper bound the per-page limit is clamped to (default 100).
795
+ Reference/catalog endpoints pass a higher bound (MAX_REFERENCE_PAGE_LIMIT).
781
796
 
782
797
  Returns:
783
798
  A list of all items from all pages.
784
799
  """
785
- return [item async for item in self._iter_all_pages(path, limit=limit, params=params)]
800
+ return [
801
+ item
802
+ async for item in self._iter_all_pages(
803
+ path, limit=limit, params=params, max_limit=max_limit
804
+ )
805
+ ]
@@ -5,6 +5,7 @@ from typing import TYPE_CHECKING
5
5
 
6
6
  from vclient.constants import (
7
7
  DEFAULT_PAGE_LIMIT,
8
+ MAX_REFERENCE_PAGE_LIMIT,
8
9
  BlueprintTraitOrderBy,
9
10
  CharacterClass,
10
11
  GameVersion,
@@ -65,6 +66,7 @@ class CharacterBlueprintService(BaseService):
65
66
  SheetSection,
66
67
  limit=limit,
67
68
  offset=offset,
69
+ max_limit=MAX_REFERENCE_PAGE_LIMIT,
68
70
  params=self._build_params(game_version=game_version, character_class=character_class),
69
71
  )
70
72
 
@@ -91,6 +93,8 @@ class CharacterBlueprintService(BaseService):
91
93
  """Iterate through all character blueprint sections."""
92
94
  async for section in self._iter_all_pages(
93
95
  self._format_endpoint(Endpoints.BLUEPRINT_SECTIONS),
96
+ limit=MAX_REFERENCE_PAGE_LIMIT,
97
+ max_limit=MAX_REFERENCE_PAGE_LIMIT,
94
98
  params=self._build_params(game_version=game_version, character_class=character_class),
95
99
  ):
96
100
  yield SheetSection.model_validate(section)
@@ -122,6 +126,7 @@ class CharacterBlueprintService(BaseService):
122
126
  TraitCategory,
123
127
  limit=limit,
124
128
  offset=offset,
129
+ max_limit=MAX_REFERENCE_PAGE_LIMIT,
125
130
  params=self._build_params(
126
131
  game_version=game_version,
127
132
  section_id=section_id,
@@ -156,6 +161,8 @@ class CharacterBlueprintService(BaseService):
156
161
  """Iterate through all character blueprint categories."""
157
162
  async for category in self._iter_all_pages(
158
163
  self._format_endpoint(Endpoints.BLUEPRINT_CATEGORIES),
164
+ limit=MAX_REFERENCE_PAGE_LIMIT,
165
+ max_limit=MAX_REFERENCE_PAGE_LIMIT,
159
166
  params=self._build_params(
160
167
  game_version=game_version,
161
168
  section_id=section_id,
@@ -191,6 +198,7 @@ class CharacterBlueprintService(BaseService):
191
198
  TraitSubcategory,
192
199
  limit=limit,
193
200
  offset=offset,
201
+ max_limit=MAX_REFERENCE_PAGE_LIMIT,
194
202
  params=self._build_params(
195
203
  game_version=game_version,
196
204
  category_id=category_id,
@@ -225,6 +233,8 @@ class CharacterBlueprintService(BaseService):
225
233
  """Iterate through all character blueprint subcategories."""
226
234
  async for subcategory in self._iter_all_pages(
227
235
  self._format_endpoint(Endpoints.BLUEPRINT_SUBCATEGORIES),
236
+ limit=MAX_REFERENCE_PAGE_LIMIT,
237
+ max_limit=MAX_REFERENCE_PAGE_LIMIT,
228
238
  params=self._build_params(
229
239
  game_version=game_version,
230
240
  category_id=category_id,
@@ -264,6 +274,7 @@ class CharacterBlueprintService(BaseService):
264
274
  Trait,
265
275
  limit=limit,
266
276
  offset=offset,
277
+ max_limit=MAX_REFERENCE_PAGE_LIMIT,
267
278
  params=self._build_params(
268
279
  character_class=character_class,
269
280
  category_id=category_id,
@@ -314,6 +325,8 @@ class CharacterBlueprintService(BaseService):
314
325
  """Iterate through all character blueprint traits."""
315
326
  async for trait in self._iter_all_pages(
316
327
  self._format_endpoint(Endpoints.BLUEPRINT_TRAITS),
328
+ limit=MAX_REFERENCE_PAGE_LIMIT,
329
+ max_limit=MAX_REFERENCE_PAGE_LIMIT,
317
330
  params=self._build_params(
318
331
  character_class=character_class,
319
332
  category_id=category_id,
@@ -347,6 +360,7 @@ class CharacterBlueprintService(BaseService):
347
360
  CharacterConcept,
348
361
  limit=limit,
349
362
  offset=offset,
363
+ max_limit=MAX_REFERENCE_PAGE_LIMIT,
350
364
  )
351
365
 
352
366
  async def list_all_concepts(self) -> list[CharacterConcept]:
@@ -357,6 +371,8 @@ class CharacterBlueprintService(BaseService):
357
371
  """Iterate through all character concepts."""
358
372
  async for concept in self._iter_all_pages(
359
373
  self._format_endpoint(Endpoints.CONCEPTS),
374
+ limit=MAX_REFERENCE_PAGE_LIMIT,
375
+ max_limit=MAX_REFERENCE_PAGE_LIMIT,
360
376
  ):
361
377
  yield CharacterConcept.model_validate(concept)
362
378
 
@@ -383,6 +399,7 @@ class CharacterBlueprintService(BaseService):
383
399
  VampireClan,
384
400
  limit=limit,
385
401
  offset=offset,
402
+ max_limit=MAX_REFERENCE_PAGE_LIMIT,
386
403
  params=self._build_params(game_version=game_version),
387
404
  )
388
405
 
@@ -398,6 +415,8 @@ class CharacterBlueprintService(BaseService):
398
415
  """Iterate through all vampire clans."""
399
416
  async for clan in self._iter_all_pages(
400
417
  self._format_endpoint(Endpoints.VAMPIRE_CLANS),
418
+ limit=MAX_REFERENCE_PAGE_LIMIT,
419
+ max_limit=MAX_REFERENCE_PAGE_LIMIT,
401
420
  params=self._build_params(game_version=game_version),
402
421
  ):
403
422
  yield VampireClan.model_validate(clan)
@@ -425,6 +444,7 @@ class CharacterBlueprintService(BaseService):
425
444
  WerewolfAuspice,
426
445
  limit=limit,
427
446
  offset=offset,
447
+ max_limit=MAX_REFERENCE_PAGE_LIMIT,
428
448
  params=self._build_params(game_version=game_version),
429
449
  )
430
450
 
@@ -442,6 +462,8 @@ class CharacterBlueprintService(BaseService):
442
462
  """Iterate through all werewolf auspices."""
443
463
  async for auspice in self._iter_all_pages(
444
464
  self._format_endpoint(Endpoints.WEREWOLF_AUSPICES),
465
+ limit=MAX_REFERENCE_PAGE_LIMIT,
466
+ max_limit=MAX_REFERENCE_PAGE_LIMIT,
445
467
  params=self._build_params(game_version=game_version),
446
468
  ):
447
469
  yield WerewolfAuspice.model_validate(auspice)
@@ -471,6 +493,7 @@ class CharacterBlueprintService(BaseService):
471
493
  WerewolfTribe,
472
494
  limit=limit,
473
495
  offset=offset,
496
+ max_limit=MAX_REFERENCE_PAGE_LIMIT,
474
497
  params=self._build_params(game_version=game_version),
475
498
  )
476
499
 
@@ -486,6 +509,8 @@ class CharacterBlueprintService(BaseService):
486
509
  """Iterate through all werewolf tribes."""
487
510
  async for tribe in self._iter_all_pages(
488
511
  self._format_endpoint(Endpoints.WEREWOLF_TRIBES),
512
+ limit=MAX_REFERENCE_PAGE_LIMIT,
513
+ max_limit=MAX_REFERENCE_PAGE_LIMIT,
489
514
  params=self._build_params(game_version=game_version),
490
515
  ):
491
516
  yield WerewolfTribe.model_validate(tribe)
@@ -3,7 +3,7 @@
3
3
  from collections.abc import AsyncIterator
4
4
  from typing import TYPE_CHECKING
5
5
 
6
- from vclient.constants import DEFAULT_PAGE_LIMIT
6
+ from vclient.constants import DEFAULT_PAGE_LIMIT, MAX_REFERENCE_PAGE_LIMIT
7
7
  from vclient.endpoints import Endpoints
8
8
  from vclient.models import (
9
9
  DictionaryTerm,
@@ -53,6 +53,7 @@ class DictionaryService(BaseService):
53
53
  DictionaryTerm,
54
54
  limit=limit,
55
55
  offset=offset,
56
+ max_limit=MAX_REFERENCE_PAGE_LIMIT,
56
57
  params=self._build_params(term=term),
57
58
  )
58
59
 
@@ -61,12 +62,13 @@ class DictionaryService(BaseService):
61
62
  return [term async for term in self.iter_all(term=term)]
62
63
 
63
64
  async def iter_all(
64
- self, *, term: str | None = None, limit: int = 100
65
+ self, *, term: str | None = None, limit: int = MAX_REFERENCE_PAGE_LIMIT
65
66
  ) -> AsyncIterator[DictionaryTerm]:
66
67
  """Iterate through all dictionary terms."""
67
68
  async for item in self._iter_all_pages(
68
69
  self._format_endpoint(Endpoints.DICTIONARY_TERMS),
69
70
  limit=limit,
71
+ max_limit=MAX_REFERENCE_PAGE_LIMIT,
70
72
  params=self._build_params(term=term),
71
73
  ):
72
74
  yield DictionaryTerm.model_validate(item)