pyrmute 0.2.0__py3-none-any.whl → 0.4.0__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -16,6 +16,7 @@ from .types import (
16
16
  JsonValue,
17
17
  ModelMetadata,
18
18
  ModelName,
19
+ NestedModelInfo,
19
20
  )
20
21
 
21
22
 
@@ -285,7 +286,7 @@ class SchemaManager:
285
286
  self: Self,
286
287
  name: ModelName,
287
288
  version: str | ModelVersion,
288
- ) -> list[ModelMetadata]:
289
+ ) -> list[NestedModelInfo]:
289
290
  """Get all nested models referenced by a model.
290
291
 
291
292
  Args:
@@ -293,19 +294,28 @@ class SchemaManager:
293
294
  version: Semantic version.
294
295
 
295
296
  Returns:
296
- List of (model_name, model_version) tuples for nested models.
297
+ List of NestedModelInfo.
297
298
  """
298
299
  ver = ModelVersion.parse(version) if isinstance(version, str) else version
299
300
  model = self.registry.get_model(name, ver)
300
301
 
301
- nested: list[ModelMetadata] = []
302
+ nested: list[NestedModelInfo] = []
302
303
 
303
304
  for field_info in model.model_fields.values():
304
305
  model_type = self._get_model_type_from_field(field_info)
305
- if model_type:
306
- model_info = self.registry.get_model_info(model_type)
307
- if model_info and model_info not in nested:
308
- nested.append(model_info)
306
+ if not model_type:
307
+ continue
308
+
309
+ model_info = self.registry.get_model_info(model_type)
310
+
311
+ if not model_info:
312
+ continue
313
+
314
+ name_, version_ = model_info
315
+ nested_model_info = NestedModelInfo(name=name_, version=version_)
316
+
317
+ if nested_model_info not in nested:
318
+ nested.append(nested_model_info)
309
319
 
310
320
  return nested
311
321
 
pyrmute/_version.py CHANGED
@@ -28,7 +28,7 @@ version_tuple: VERSION_TUPLE
28
28
  commit_id: COMMIT_ID
29
29
  __commit_id__: COMMIT_ID
30
30
 
31
- __version__ = version = '0.2.0'
32
- __version_tuple__ = version_tuple = (0, 2, 0)
31
+ __version__ = version = '0.4.0'
32
+ __version_tuple__ = version_tuple = (0, 4, 0)
33
33
 
34
34
  __commit_id__ = commit_id = None
@@ -2,9 +2,9 @@
2
2
 
3
3
  from collections.abc import Iterator
4
4
  from dataclasses import dataclass
5
- from typing import Self
5
+ from typing import Self, TypeAlias
6
6
 
7
- from .types import MigrationData
7
+ from .types import ModelData
8
8
 
9
9
 
10
10
  @dataclass
@@ -28,8 +28,8 @@ class MigrationTestCase:
28
28
  ... )
29
29
  """
30
30
 
31
- source: MigrationData
32
- target: MigrationData | None = None
31
+ source: ModelData
32
+ target: ModelData | None = None
33
33
  description: str = ""
34
34
 
35
35
 
@@ -55,7 +55,7 @@ class MigrationTestResult:
55
55
  """
56
56
 
57
57
  test_case: MigrationTestCase
58
- actual: MigrationData
58
+ actual: ModelData
59
59
  passed: bool
60
60
  error: str | None = None
61
61
 
@@ -159,3 +159,6 @@ class MigrationTestResults:
159
159
  f"✗ {len(self.failures)} of {total_count} test(s) failed "
160
160
  f"({passed_count} passed)"
161
161
  )
162
+
163
+
164
+ MigrationTestCases: TypeAlias = list[tuple[ModelData, ModelData] | MigrationTestCase]
pyrmute/model_manager.py CHANGED
@@ -13,6 +13,7 @@ from ._schema_manager import SchemaManager
13
13
  from .exceptions import MigrationError, ModelNotFoundError
14
14
  from .migration_testing import (
15
15
  MigrationTestCase,
16
+ MigrationTestCases,
16
17
  MigrationTestResult,
17
18
  MigrationTestResults,
18
19
  )
@@ -22,9 +23,9 @@ from .types import (
22
23
  DecoratedBaseModel,
23
24
  JsonSchema,
24
25
  JsonSchemaGenerator,
25
- MigrationData,
26
26
  MigrationFunc,
27
- ModelMetadata,
27
+ ModelData,
28
+ NestedModelInfo,
28
29
  )
29
30
 
30
31
 
@@ -55,7 +56,7 @@ class ModelManager:
55
56
  >>>
56
57
  >>> # Define migration between versions
57
58
  >>> @manager.migration("User", "1.0.0", "2.0.0")
58
- ... def migrate(data: MigrationData) -> MigrationData:
59
+ ... def migrate(data: ModelData) -> ModelData:
59
60
  ... return {**data, "email": "unknown@example.com"}
60
61
  >>>
61
62
  >>> # Migrate legacy data
@@ -91,9 +92,9 @@ class ModelManager:
91
92
 
92
93
  def __init__(self: Self) -> None:
93
94
  """Initialize the versioned model manager."""
94
- self.registry = Registry()
95
- self.migration_manager = MigrationManager(self.registry)
96
- self.schema_manager = SchemaManager(self.registry)
95
+ self._registry = Registry()
96
+ self._migration_manager = MigrationManager(self._registry)
97
+ self._schema_manager = SchemaManager(self._registry)
97
98
 
98
99
  def model(
99
100
  self: Self,
@@ -129,7 +130,7 @@ class ModelManager:
129
130
  ... class CityV1(BaseModel):
130
131
  ... city: City
131
132
  """
132
- return self.registry.register(
133
+ return self._registry.register(
133
134
  name, version, schema_generator, enable_ref, backward_compatible
134
135
  )
135
136
 
@@ -149,11 +150,11 @@ class ModelManager:
149
150
  Returns:
150
151
  Decorator function for migration function.
151
152
  """
152
- return self.migration_manager.register_migration(name, from_version, to_version)
153
+ return self._migration_manager.register_migration(
154
+ name, from_version, to_version
155
+ )
153
156
 
154
- def get(
155
- self: Self, name: str, version: str | ModelVersion | None = None
156
- ) -> type[BaseModel]:
157
+ def get(self: Self, name: str, version: str | ModelVersion) -> type[BaseModel]:
157
158
  """Get a model by name and version.
158
159
 
159
160
  Args:
@@ -163,9 +164,18 @@ class ModelManager:
163
164
  Returns:
164
165
  Model class.
165
166
  """
166
- if version is None:
167
- return self.registry.get_latest(name)
168
- return self.registry.get_model(name, version)
167
+ return self._registry.get_model(name, version)
168
+
169
+ def get_latest(self: Self, name: str) -> type[BaseModel]:
170
+ """Get the latest version of a model by name.
171
+
172
+ Args:
173
+ name: Name of the model.
174
+
175
+ Returns:
176
+ Model class.
177
+ """
178
+ return self._registry.get_latest(name)
169
179
 
170
180
  def has_migration_path(
171
181
  self: Self,
@@ -200,14 +210,14 @@ class ModelManager:
200
210
  else to_version
201
211
  )
202
212
  try:
203
- self.migration_manager.validate_migration_path(name, from_ver, to_ver)
213
+ self._migration_manager.validate_migration_path(name, from_ver, to_ver)
204
214
  return True
205
215
  except (KeyError, ModelNotFoundError, MigrationError):
206
216
  return False
207
217
 
208
218
  def validate_data(
209
219
  self: Self,
210
- data: MigrationData,
220
+ data: ModelData,
211
221
  name: str,
212
222
  version: str | ModelVersion,
213
223
  ) -> bool:
@@ -241,7 +251,7 @@ class ModelManager:
241
251
 
242
252
  def migrate(
243
253
  self: Self,
244
- data: MigrationData,
254
+ data: ModelData,
245
255
  name: str,
246
256
  from_version: str | ModelVersion,
247
257
  to_version: str | ModelVersion,
@@ -263,11 +273,11 @@ class ModelManager:
263
273
 
264
274
  def migrate_data(
265
275
  self: Self,
266
- data: MigrationData,
276
+ data: ModelData,
267
277
  name: str,
268
278
  from_version: str | ModelVersion,
269
279
  to_version: str | ModelVersion,
270
- ) -> MigrationData:
280
+ ) -> ModelData:
271
281
  """Migrate data between versions.
272
282
 
273
283
  Args:
@@ -279,11 +289,11 @@ class ModelManager:
279
289
  Returns:
280
290
  Raw migrated dictionary.
281
291
  """
282
- return self.migration_manager.migrate(data, name, from_version, to_version)
292
+ return self._migration_manager.migrate(data, name, from_version, to_version)
283
293
 
284
294
  def migrate_batch( # noqa: PLR0913
285
295
  self: Self,
286
- data_list: Iterable[MigrationData],
296
+ data_list: Iterable[ModelData],
287
297
  name: str,
288
298
  from_version: str | ModelVersion,
289
299
  to_version: str | ModelVersion,
@@ -341,14 +351,14 @@ class ModelManager:
341
351
 
342
352
  def migrate_batch_data( # noqa: PLR0913
343
353
  self: Self,
344
- data_list: Iterable[MigrationData],
354
+ data_list: Iterable[ModelData],
345
355
  name: str,
346
356
  from_version: str | ModelVersion,
347
357
  to_version: str | ModelVersion,
348
358
  parallel: bool = False,
349
359
  max_workers: int | None = None,
350
360
  use_processes: bool = False,
351
- ) -> list[MigrationData]:
361
+ ) -> list[ModelData]:
352
362
  """Migrate multiple data items between versions, returning raw dictionaries.
353
363
 
354
364
  Args:
@@ -393,7 +403,7 @@ class ModelManager:
393
403
 
394
404
  def migrate_batch_streaming(
395
405
  self: Self,
396
- data_list: Iterable[MigrationData],
406
+ data_list: Iterable[ModelData],
397
407
  name: str,
398
408
  from_version: str | ModelVersion,
399
409
  to_version: str | ModelVersion,
@@ -439,12 +449,12 @@ class ModelManager:
439
449
 
440
450
  def migrate_batch_data_streaming(
441
451
  self: Self,
442
- data_list: Iterable[MigrationData],
452
+ data_list: Iterable[ModelData],
443
453
  name: str,
444
454
  from_version: str | ModelVersion,
445
455
  to_version: str | ModelVersion,
446
456
  chunk_size: int = 100,
447
- ) -> Iterable[MigrationData]:
457
+ ) -> Iterable[ModelData]:
448
458
  """Migrate data in chunks, yielding raw dictionaries as they complete.
449
459
 
450
460
  Useful for large datasets where you want to start processing results before all
@@ -548,7 +558,7 @@ class ModelManager:
548
558
  Returns:
549
559
  JSON schema dictionary.
550
560
  """
551
- return self.schema_manager.get_schema(name, version, **kwargs)
561
+ return self._schema_manager.get_schema(name, version, **kwargs)
552
562
 
553
563
  def list_models(self: Self) -> list[str]:
554
564
  """Get list of all registered models.
@@ -556,7 +566,7 @@ class ModelManager:
556
566
  Returns:
557
567
  List of model names.
558
568
  """
559
- return self.registry.list_models()
569
+ return self._registry.list_models()
560
570
 
561
571
  def list_versions(self: Self, name: str) -> list[ModelVersion]:
562
572
  """Get all versions for a model.
@@ -567,7 +577,7 @@ class ModelManager:
567
577
  Returns:
568
578
  Sorted list of versions.
569
579
  """
570
- return self.registry.get_versions(name)
580
+ return self._registry.get_versions(name)
571
581
 
572
582
  def dump_schemas(
573
583
  self: Self,
@@ -582,7 +592,8 @@ class ModelManager:
582
592
  output_dir: Directory path for output.
583
593
  indent: JSON indentation level.
584
594
  separate_definitions: If True, create separate schema files for nested
585
- models and use $ref to reference them.
595
+ models and use $ref to reference them. Only applies to models with
596
+ 'enable_ref=True'.
586
597
  ref_template: Template for $ref URLs when separate_definitions=True.
587
598
  Defaults to relative file references if not provided.
588
599
 
@@ -600,46 +611,15 @@ class ModelManager:
600
611
  ... ref_template="https://example.com/schemas/{model}_v{version}.json"
601
612
  ... )
602
613
  """
603
- self.schema_manager.dump_schemas(
614
+ self._schema_manager.dump_schemas(
604
615
  output_dir, indent, separate_definitions, ref_template
605
616
  )
606
617
 
607
- def dump_schemas_with_refs(
608
- self: Self,
609
- output_dir: str | Path,
610
- ref_template: str | None = None,
611
- indent: int = 2,
612
- ) -> None:
613
- """Export schemas with separate files for nested models.
614
-
615
- This is a convenience method that calls dump_schemas with
616
- separate_definitions=True.
617
-
618
- Args:
619
- output_dir: Directory path for output.
620
- ref_template: Template for $ref URLs. Supports {model} and {version}
621
- placeholders. Defaults to relative file refs.
622
- indent: JSON indentation level.
623
-
624
- Example:
625
- >>> # Relative file references (default)
626
- >>> manager.dump_schemas_with_refs("schemas/")
627
- >>>
628
- >>> # Absolute URL references
629
- >>> manager.dump_schemas_with_refs(
630
- ... "schemas/",
631
- ... ref_template="https://example.com/schemas/{model}_v{version}.json"
632
- ... )
633
- """
634
- self.schema_manager.dump_schemas(
635
- output_dir, indent, separate_definitions=True, ref_template=ref_template
636
- )
637
-
638
618
  def get_nested_models(
639
619
  self: Self,
640
620
  name: str,
641
621
  version: str | ModelVersion,
642
- ) -> list[ModelMetadata]:
622
+ ) -> list[NestedModelInfo]:
643
623
  """Get all nested models used by a model.
644
624
 
645
625
  Args:
@@ -647,16 +627,16 @@ class ModelManager:
647
627
  version: Semantic version.
648
628
 
649
629
  Returns:
650
- List of (model_name, version) tuples for nested models.
630
+ List of NestedModelInfo.
651
631
  """
652
- return self.schema_manager.get_nested_models(name, version)
632
+ return self._schema_manager.get_nested_models(name, version)
653
633
 
654
634
  def test_migration(
655
635
  self: Self,
656
636
  name: str,
657
637
  from_version: str | ModelVersion,
658
638
  to_version: str | ModelVersion,
659
- test_cases: list[tuple[MigrationData, MigrationData] | MigrationTestCase],
639
+ test_cases: MigrationTestCases,
660
640
  ) -> MigrationTestResults:
661
641
  """Test a migration with multiple test cases.
662
642
 
pyrmute/types.py CHANGED
@@ -3,6 +3,7 @@
3
3
  from __future__ import annotations
4
4
 
5
5
  from collections.abc import Callable
6
+ from dataclasses import dataclass
6
7
  from typing import Any, TypeAlias, TypeVar
7
8
 
8
9
  from pydantic import BaseModel
@@ -19,13 +20,19 @@ JsonSchemaDefinitions: TypeAlias = dict[str, JsonValue]
19
20
  JsonSchemaGenerator: TypeAlias = Callable[[type[BaseModel]], JsonSchema]
20
21
  SchemaGenerators: TypeAlias = dict[ModelVersion, JsonSchemaGenerator]
21
22
 
22
- MigrationData: TypeAlias = dict[str, Any]
23
- MigrationFunc: TypeAlias = Callable[[MigrationData], MigrationData]
24
-
25
-
23
+ ModelData: TypeAlias = dict[str, Any]
24
+ MigrationFunc: TypeAlias = Callable[[ModelData], ModelData]
26
25
  MigrationKey: TypeAlias = tuple[ModelVersion, ModelVersion]
27
26
  MigrationMap: TypeAlias = dict[MigrationKey, MigrationFunc]
28
27
 
29
28
  ModelName: TypeAlias = str
30
29
  ModelMetadata: TypeAlias = tuple[ModelName, ModelVersion]
31
30
  VersionedModels: TypeAlias = dict[ModelVersion, type[BaseModel]]
31
+
32
+
33
+ @dataclass
34
+ class NestedModelInfo:
35
+ """Contains information about nested models."""
36
+
37
+ name: str
38
+ version: ModelVersion