LSST Applications g00274db5b6+edbf708997,g00d0e8bbd7+edbf708997,g199a45376c+5137f08352,g1fd858c14a+1d4b6db739,g262e1987ae+f4d9505c4f,g29ae962dfc+7156fb1a53,g2cef7863aa+73c82f25e4,g35bb328faa+edbf708997,g3e17d7035e+5b3adc59f5,g3fd5ace14f+852fa6fbcb,g47891489e3+6dc8069a4c,g53246c7159+edbf708997,g64539dfbff+9f17e571f4,g67b6fd64d1+6dc8069a4c,g74acd417e5+ae494d68d9,g786e29fd12+af89c03590,g7ae74a0b1c+a25e60b391,g7aefaa3e3d+536efcc10a,g7cc15d900a+d121454f8d,g87389fa792+a4172ec7da,g89139ef638+6dc8069a4c,g8d7436a09f+28c28d8d6d,g8ea07a8fe4+db21c37724,g92c671f44c+9f17e571f4,g98df359435+b2e6376b13,g99af87f6a8+b0f4ad7b8d,gac66b60396+966efe6077,gb88ae4c679+7dec8f19df,gbaa8f7a6c5+38b34f4976,gbf99507273+edbf708997,gc24b5d6ed1+9f17e571f4,gca7fc764a6+6dc8069a4c,gcc769fe2a4+97d0256649,gd7ef33dd92+6dc8069a4c,gdab6d2f7ff+ae494d68d9,gdbb4c4dda9+9f17e571f4,ge410e46f29+6dc8069a4c,geaed405ab2+e194be0d2b,w.2025.47
LSST Data Management Base Package
Loading...
Searching...
No Matches
migration.py
Go to the documentation of this file.
1from __future__ import annotations
2
3from typing import Callable, ClassVar
4
5__all__ = ["MigrationError", "MigrationRegistry", "migration"]
6
7Migrator = Callable[[dict], dict]
8
9PRE_SCHEMA = "0.0.0"
10
11
12class MigrationError(Exception):
13 """Custom error for migration issues."""
14
15 pass
16
17
19 """Manages migration of data between different schema versions."""
20
21 registry: ClassVar[dict[tuple[str, str], Migrator]] = {}
22 current: ClassVar[dict[str, str]] = {}
23
24 @staticmethod
25 def register(type_name: str, from_version: str, migrator: Migrator) -> None:
26 """Register a migration function from one version to another."""
27 MigrationRegistry.registry[(type_name, from_version)] = migrator
28
29 @staticmethod
30 def set_current(data_type: str, version: str) -> None:
31 """Set the current version for a given data type."""
32 MigrationRegistry.current[data_type] = version
33
34 @staticmethod
35 def migrate(data_type: str, data: dict) -> dict:
36 """Migrate data to the current schema version.
37
38 Parameters
39 ----------
40 data :
41 The data to migrate. Must contain 'type' and 'version' keys.
42
43 Returns
44 -------
45 result :
46 The migrated data.
47 """
48 if "version" not in data:
49 # Unversioned data is pre-schema and is considered to be
50 # version "0.0.0" for backwards compatibility.
51 data["version"] = PRE_SCHEMA
52
53 from_version = data["version"]
54
55 if data_type not in MigrationRegistry.current:
56 raise ValueError(f"No current version set for data type '{data_type}'.")
57
58 to_version = MigrationRegistry.current[data_type]
59
60 # Keep track of seen versions to avoid infinite loops
61 seen: set[tuple[str, str]] = set()
62
63 while from_version != to_version:
64 key = (data_type, from_version)
65 if key not in MigrationRegistry.registry or key in seen:
66 raise MigrationError(
67 f"No migration path from version '{from_version}' for type '{data_type}'."
68 )
69
70 migrator = MigrationRegistry.registry[key]
71 data = migrator(data)
72 from_version = data["version"]
73
74 return data
75
76
77def migration(type_name: str, from_version: str) -> Callable[[Migrator], Migrator]:
78 """Decorator to register a migration step.
79
80 Parameters
81 ----------
82 type_name :
83 The type of data being migrated.
84 from_version :
85 The version the migrator converts from.
86
87 Returns
88 -------
89 result :
90 The decorator that registers the migration function.
91 """
92
93 def decorator(func: Migrator) -> Migrator:
94 MigrationRegistry.register(type_name, from_version, func)
95 return func
96
97 return decorator
None register(str type_name, str from_version, Migrator migrator)
Definition migration.py:25
dict migrate(str data_type, dict data)
Definition migration.py:35
None set_current(str data_type, str version)
Definition migration.py:30