lsst-daf-butler 29.2025.3100__py3-none-any.whl → 29.2025.3200__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.
@@ -129,11 +129,6 @@ class LimitedButler(ABC):
129
129
  obj : `object`
130
130
  The dataset.
131
131
 
132
- Raises
133
- ------
134
- AmbiguousDatasetError
135
- Raised if the supplied `DatasetRef` is unresolved.
136
-
137
132
  Notes
138
133
  -----
139
134
  In a `LimitedButler` the only allowable way to specify a dataset is
@@ -326,7 +321,7 @@ class LimitedButler(ABC):
326
321
  Whether the dataset artifact exists in the datastore and can be
327
322
  retrieved.
328
323
  """
329
- return self._datastore.exists(ref)
324
+ return self.stored_many([ref])[ref]
330
325
 
331
326
  def stored_many(
332
327
  self,
@@ -39,6 +39,8 @@ from collections.abc import Callable, Collection, Mapping, Sequence, Set
39
39
  from threading import RLock
40
40
  from typing import Any
41
41
 
42
+ import pydantic
43
+
42
44
  from lsst.utils import doImportType
43
45
  from lsst.utils.classes import Singleton
44
46
  from lsst.utils.introspection import get_full_type_name
@@ -57,6 +59,18 @@ class StorageClassConfig(ConfigSubset):
57
59
  defaultConfigFile = "storageClasses.yaml"
58
60
 
59
61
 
62
+ class _StorageClassModel(pydantic.BaseModel):
63
+ """Model class used to validate storage class configuration."""
64
+
65
+ pytype: str | None = None
66
+ inheritsFrom: str | None = None
67
+ components: dict[str, str] = pydantic.Field(default_factory=dict)
68
+ derivedComponents: dict[str, str] = pydantic.Field(default_factory=dict)
69
+ parameters: list[str] = pydantic.Field(default_factory=list)
70
+ delegate: str | None = None
71
+ converters: dict[str, str] = pydantic.Field(default_factory=dict)
72
+
73
+
60
74
  class StorageClass:
61
75
  """Class describing how a label maps to a particular Python type.
62
76
 
@@ -81,17 +95,9 @@ class StorageClass:
81
95
  that python type to the valid type of this storage class.
82
96
  """
83
97
 
84
- _cls_name: str = "BaseStorageClass"
85
- _cls_components: dict[str, StorageClass] | None = None
86
- _cls_derivedComponents: dict[str, StorageClass] | None = None
87
- _cls_parameters: Set[str] | Sequence[str] | None = None
88
- _cls_delegate: str | None = None
89
- _cls_pytype: type | str | None = None
90
- _cls_converters: dict[str, str] | None = None
91
-
92
98
  def __init__(
93
99
  self,
94
- name: str | None = None,
100
+ name: str = "",
95
101
  pytype: type | str | None = None,
96
102
  components: dict[str, StorageClass] | None = None,
97
103
  derivedComponents: dict[str, StorageClass] | None = None,
@@ -99,23 +105,8 @@ class StorageClass:
99
105
  delegate: str | None = None,
100
106
  converters: dict[str, str] | None = None,
101
107
  ):
102
- if name is None:
103
- name = self._cls_name
104
- if pytype is None:
105
- pytype = self._cls_pytype
106
- if components is None:
107
- components = self._cls_components
108
- if derivedComponents is None:
109
- derivedComponents = self._cls_derivedComponents
110
- if parameters is None:
111
- parameters = self._cls_parameters
112
- if delegate is None:
113
- delegate = self._cls_delegate
114
-
115
108
  # Merge converters with class defaults.
116
109
  self._converters = {}
117
- if self._cls_converters is not None:
118
- self._converters.update(self._cls_converters)
119
110
  if converters:
120
111
  self._converters.update(converters)
121
112
 
@@ -634,7 +625,6 @@ class StorageClassFactory(metaclass=Singleton):
634
625
 
635
626
  def __init__(self, config: StorageClassConfig | str | None = None):
636
627
  self._storageClasses: dict[str, StorageClass] = {}
637
- self._configs: list[StorageClassConfig] = []
638
628
  self._lock = RLock()
639
629
 
640
630
  # Always seed with the default config
@@ -657,40 +647,15 @@ class StorageClassFactory(metaclass=Singleton):
657
647
 
658
648
  StorageClasses
659
649
  --------------
660
- {sep.join(f"{s}: {self._storageClasses[s]!r}" for s in sorted(self._storageClasses))}
650
+ {sep.join(f"{self._storageClasses[s]!r}" for s in sorted(self._storageClasses))}
661
651
  """
662
652
 
663
- def __contains__(self, storageClassOrName: StorageClass | str) -> bool:
664
- """Indicate whether the storage class exists in the factory.
665
-
666
- Parameters
667
- ----------
668
- storageClassOrName : `str` or `StorageClass`
669
- If `str` is given existence of the named StorageClass
670
- in the factory is checked. If `StorageClass` is given
671
- existence and equality are checked.
672
-
673
- Returns
674
- -------
675
- in : `bool`
676
- True if the supplied string is present, or if the supplied
677
- `StorageClass` is present and identical.
678
-
679
- Notes
680
- -----
681
- The two different checks (one for "key" and one for "value") based on
682
- the type of the given argument mean that it is possible for
683
- StorageClass.name to be in the factory but StorageClass to not be
684
- in the factory.
685
- """
653
+ def __contains__(self, storageClassOrName: object) -> bool:
686
654
  with self._lock:
687
655
  if isinstance(storageClassOrName, str):
688
656
  return storageClassOrName in self._storageClasses
689
- elif (
690
- isinstance(storageClassOrName, StorageClass)
691
- and storageClassOrName.name in self._storageClasses
692
- ):
693
- return storageClassOrName == self._storageClasses[storageClassOrName.name]
657
+ elif isinstance(storageClassOrName, StorageClass):
658
+ return storageClassOrName.name in self._storageClasses
694
659
  return False
695
660
 
696
661
  def addFromConfig(self, config: StorageClassConfig | Config | str) -> None:
@@ -708,68 +673,54 @@ StorageClasses
708
673
  # components or parents before their classes are defined
709
674
  # we have a helper function that we can call recursively
710
675
  # to extract definitions from the configuration.
711
- def processStorageClass(name: str, _sconfig: StorageClassConfig, msg: str = "") -> None:
712
- # Maybe we've already processed this through recursion
676
+ def processStorageClass(name: str, _sconfig: StorageClassConfig, msg: str = "") -> StorageClass:
677
+ # This might have already been processed through recursion, or
678
+ # already present in the factory.
713
679
  if name not in _sconfig:
714
- return
715
- info = _sconfig.pop(name)
716
-
717
- # Always create the storage class so we can ensure that
718
- # we are not trying to overwrite with a different definition
719
- components = None
720
-
721
- # Extract scalar items from dict that are needed for
722
- # StorageClass Constructor
723
- storageClassKwargs = {k: info[k] for k in ("pytype", "delegate", "parameters") if k in info}
724
-
725
- if "converters" in info:
726
- storageClassKwargs["converters"] = info["converters"].toDict()
727
-
728
- for compName in ("components", "derivedComponents"):
729
- if compName not in info:
730
- continue
731
- components = {}
732
- for cname, ctype in info[compName].items():
733
- if ctype not in self:
734
- processStorageClass(ctype, sconfig, msg)
735
- components[cname] = self.getStorageClass(ctype)
736
-
737
- # Fill in other items
738
- storageClassKwargs[compName] = components
739
-
740
- # Create the new storage class and register it
741
- baseClass = None
742
- if "inheritsFrom" in info:
743
- baseName = info["inheritsFrom"]
744
-
745
- # The inheritsFrom feature requires that the storage class
746
- # being inherited from is itself a subclass of StorageClass
747
- # that was created with makeNewStorageClass. If it was made
748
- # and registered with a simple StorageClass constructor it
749
- # cannot be used here and we try to recreate it.
750
- if baseName in self:
751
- baseClass = type(self.getStorageClass(baseName))
752
- if baseClass is StorageClass:
753
- log.warning(
754
- "Storage class %s is requested to inherit from %s but that storage class "
755
- "has not been defined to be a subclass of StorageClass and so can not "
756
- "be used. Attempting to recreate parent class from current configuration.",
757
- name,
758
- baseName,
759
- )
760
- processStorageClass(baseName, sconfig, msg)
761
- else:
762
- processStorageClass(baseName, sconfig, msg)
763
- baseClass = type(self.getStorageClass(baseName))
764
- if baseClass is StorageClass:
765
- raise TypeError(
766
- f"Configuration for storage class {name} requests to inherit from "
767
- f" storage class {baseName} but that class is not defined correctly."
768
- )
769
-
770
- newStorageClassType = self.makeNewStorageClass(name, baseClass, **storageClassKwargs)
771
- newStorageClass = newStorageClassType()
772
- self.registerStorageClass(newStorageClass, msg=msg)
680
+ return self.getStorageClass(name)
681
+ try:
682
+ model = _StorageClassModel.model_validate(_sconfig.pop(name))
683
+ except Exception as err:
684
+ err.add_note(msg)
685
+ raise
686
+ components: dict[str, StorageClass] = {}
687
+ derivedComponents: dict[str, StorageClass] = {}
688
+ parameters: set[str] = set()
689
+ delegate: str | None = None
690
+ converters: dict[str, str] = {}
691
+ if model.inheritsFrom is not None:
692
+ base = processStorageClass(model.inheritsFrom, _sconfig, msg + f"; processing base of {name}")
693
+ pytype = base._pytypeName
694
+ components.update(base.components)
695
+ derivedComponents.update(base.derivedComponents)
696
+ parameters.update(base.parameters)
697
+ delegate = base._delegateClassName
698
+ converters.update(base.converters)
699
+ if model.pytype is not None:
700
+ pytype = model.pytype
701
+ for k, v in model.components.items():
702
+ components[k] = processStorageClass(
703
+ v, _sconfig, msg + f"; processing component {k} of {name}"
704
+ )
705
+ for k, v in model.derivedComponents.items():
706
+ derivedComponents[k] = processStorageClass(
707
+ v, _sconfig, msg + f"; processing derivedCmponent {k} of {name}"
708
+ )
709
+ parameters.update(model.parameters)
710
+ if model.delegate is not None:
711
+ delegate = model.delegate
712
+ converters.update(model.converters)
713
+ result = StorageClass(
714
+ name=name,
715
+ pytype=pytype,
716
+ components=components,
717
+ derivedComponents=derivedComponents,
718
+ parameters=parameters,
719
+ delegate=delegate,
720
+ converters=converters,
721
+ )
722
+ self.registerStorageClass(result, msg=msg)
723
+ return result
773
724
 
774
725
  # In case there is a problem, construct a context message for any
775
726
  # error reporting.
@@ -778,68 +729,9 @@ StorageClasses
778
729
  log.debug("Adding definitions from config %s", ", ".join(files))
779
730
 
780
731
  with self._lock:
781
- self._configs.append(sconfig)
782
732
  for name in list(sconfig.keys()):
783
733
  processStorageClass(name, sconfig, context)
784
734
 
785
- @staticmethod
786
- def makeNewStorageClass(
787
- name: str, baseClass: type[StorageClass] | None = StorageClass, **kwargs: Any
788
- ) -> type[StorageClass]:
789
- """Create a new Python class as a subclass of `StorageClass`.
790
-
791
- Parameters
792
- ----------
793
- name : `str`
794
- Name to use for this class.
795
- baseClass : `type`, optional
796
- Base class for this `StorageClass`. Must be either `StorageClass`
797
- or a subclass of `StorageClass`. If `None`, `StorageClass` will
798
- be used.
799
- **kwargs
800
- Additional parameter values to use as defaults for this class.
801
- This can include ``components``, ``parameters``,
802
- ``derivedComponents``, and ``converters``.
803
-
804
- Returns
805
- -------
806
- newtype : `type` subclass of `StorageClass`
807
- Newly created Python type.
808
- """
809
- if baseClass is None:
810
- baseClass = StorageClass
811
- if not issubclass(baseClass, StorageClass):
812
- raise ValueError(f"Base class must be a StorageClass not {baseClass}")
813
-
814
- # convert the arguments to use different internal names
815
- clsargs = {f"_cls_{k}": v for k, v in kwargs.items() if v is not None}
816
- clsargs["_cls_name"] = name
817
-
818
- # Some container items need to merge with the base class values
819
- # so that a child can inherit but override one bit.
820
- # lists (which you get from configs) are treated as sets for this to
821
- # work consistently.
822
- for k in ("components", "parameters", "derivedComponents", "converters"):
823
- classKey = f"_cls_{k}"
824
- if classKey in clsargs:
825
- baseValue = getattr(baseClass, classKey, None)
826
- if baseValue is not None:
827
- currentValue = clsargs[classKey]
828
- if isinstance(currentValue, dict):
829
- newValue = baseValue.copy()
830
- else:
831
- newValue = set(baseValue)
832
- newValue.update(currentValue)
833
- clsargs[classKey] = newValue
834
-
835
- # If we have parameters they should be a frozen set so that the
836
- # parameters in the class can not be modified.
837
- pk = "_cls_parameters"
838
- if pk in clsargs:
839
- clsargs[pk] = frozenset(clsargs[pk])
840
-
841
- return type(f"StorageClass{name}", (baseClass,), clsargs)
842
-
843
735
  def getStorageClass(self, storageClassName: str) -> StorageClass:
844
736
  """Get a StorageClass instance associated with the supplied name.
845
737
 
@@ -111,6 +111,28 @@ class DatastoreRecordData:
111
111
  """Opaque table data, indexed by dataset ID and grouped by opaque table
112
112
  name."""
113
113
 
114
+ @staticmethod
115
+ def merge_mappings(*args: Mapping[str, DatastoreRecordData]) -> dict[str, DatastoreRecordData]:
116
+ """Merge mappings of datastore record data.
117
+
118
+ Parameters
119
+ ----------
120
+ *args : `~collections.abc.Mapping` [ `str`, `DatastoreRecordData` ]
121
+ Mappings of record data, keyed by datastore name.
122
+
123
+ Returns
124
+ -------
125
+ merged : `~collections.abc.Mapping` [ `str`, `DatastoreRecordData` ]
126
+ Merged mapping of record data, keyed by datastore name.
127
+ """
128
+ result: dict[str, DatastoreRecordData] = {}
129
+ for arg in args:
130
+ for datastore_name, record_data in arg.items():
131
+ if datastore_name not in result:
132
+ result[datastore_name] = DatastoreRecordData()
133
+ result[datastore_name].update(record_data)
134
+ return result
135
+
114
136
  def update(self, other: DatastoreRecordData) -> None:
115
137
  """Update contents of this instance with data from another instance.
116
138
 
@@ -32,7 +32,7 @@ __all__ = ("SerializedStoredFileInfo", "StoredDatastoreItemInfo", "StoredFileInf
32
32
  import inspect
33
33
  from collections.abc import Iterable, Mapping
34
34
  from dataclasses import dataclass
35
- from typing import TYPE_CHECKING, Any, ClassVar
35
+ from typing import TYPE_CHECKING, Any
36
36
 
37
37
  import pydantic
38
38
 
@@ -209,8 +209,6 @@ class StoredFileInfo(StoredDatastoreItemInfo):
209
209
  compatibility, it remains a positional argument with no default).
210
210
  """
211
211
 
212
- storageClassFactory: ClassVar[StorageClassFactory] = StorageClassFactory()
213
-
214
212
  def __init__(
215
213
  self,
216
214
  formatter: FormatterParameter,
@@ -268,7 +266,7 @@ class StoredFileInfo(StoredDatastoreItemInfo):
268
266
  @property
269
267
  def storageClass(self) -> StorageClass:
270
268
  """Storage class associated with this dataset."""
271
- return self.storageClassFactory.getStorageClass(self.storage_class_name)
269
+ return StorageClassFactory().getStorageClass(self.storage_class_name)
272
270
 
273
271
  def rebase(self, ref: DatasetRef) -> StoredFileInfo:
274
272
  """Return a copy of the record suitable for a specified reference.
@@ -753,7 +753,6 @@ class SerializableDimensionData(pydantic.RootModel):
753
753
  ]
754
754
 
755
755
 
756
- @dataclasses.dataclass
757
756
  class DimensionDataAttacher:
758
757
  """A helper class for attaching dimension records to data IDs.
759
758
 
@@ -786,7 +785,7 @@ class DimensionDataAttacher:
786
785
  dimensions: DimensionGroup | None = None,
787
786
  ):
788
787
  self.records = {record_set.element.name: record_set for record_set in records}
789
- self.deserializers = {}
788
+ self.deserializers: dict[str, DimensionRecordSetDeserializer] = {}
790
789
  for deserializer in deserializers:
791
790
  self.deserializers[deserializer.element.name] = deserializer
792
791
  if deserializer.element.name not in self.records:
@@ -851,6 +850,54 @@ class DimensionDataAttacher:
851
850
 
852
851
  return [r.data_id.expanded(r.done) for r in records]
853
852
 
853
+ def serialized(
854
+ self, *, ignore: Iterable[str] = (), ignore_cached: bool = False, include_skypix: bool = False
855
+ ) -> SerializableDimensionData:
856
+ """Serialize all dimension data in this attacher, with deduplication
857
+ across fully- and partially-deserialized records.
858
+
859
+ Parameters
860
+ ----------
861
+ ignore : `~collections.abc.Iterable` [ `str` ], optional
862
+ Names of dimension elements that should not be serialized.
863
+ ignore_cached : `bool`, optional
864
+ If `True`, ignore all dimension elements for which
865
+ `DimensionElement.is_cached` is `True`.
866
+ include_skypix : `bool`, optional
867
+ If `True`, include skypix dimensions. These are ignored by default
868
+ because they can always be recomputed from their IDs on-the-fly.
869
+
870
+ Returns
871
+ -------
872
+ serialized : `SerializedDimensionData`
873
+ Serialized dimension records.
874
+ """
875
+ from ._skypix import SkyPixDimension
876
+
877
+ ignore = set(ignore)
878
+ result = SerializableDimensionData()
879
+ for record_set in self.records.values():
880
+ if record_set.element.name in ignore:
881
+ continue
882
+ if not include_skypix and isinstance(record_set.element, SkyPixDimension):
883
+ continue
884
+ if ignore_cached and record_set.element.is_cached:
885
+ continue
886
+ serialized_records: dict[tuple[DataIdValue, ...], SerializedKeyValueDimensionRecord] = {}
887
+ if (deserializer := self.deserializers.get(record_set.element.name)) is not None:
888
+ for key, value in deserializer._mapping.items():
889
+ serialized_record = list(key)
890
+ serialized_record.extend(value)
891
+ serialized_records[key] = serialized_record
892
+ for key, record in record_set._by_required_values.items():
893
+ if key not in serialized_records:
894
+ serialized_records[key] = record.serialize_key_value()
895
+ result.root[record_set.element.name] = list(serialized_records.values())
896
+ if self.cache is not None and not ignore_cached:
897
+ for record_set in self.cache.values():
898
+ result.root[record_set.element.name] = record_set.serialize_records()
899
+ return result
900
+
854
901
 
855
902
  @dataclasses.dataclass
856
903
  class _InProgressRecordDicts:
@@ -147,12 +147,7 @@ def _addFullStorageClass(butler: Butler, name: str, formatter: str, **kwargs: An
147
147
  previously found in the repository.
148
148
  """
149
149
  storageRegistry = butler._datastore.storageClassFactory
150
-
151
- # Use the special constructor to allow a subclass of storage class
152
- # to be created. This allows other test storage classes to inherit from
153
- # this one.
154
- storage_type = storageRegistry.makeNewStorageClass(name, None, **kwargs)
155
- storage = storage_type()
150
+ storage = StorageClass(name, **kwargs)
156
151
  try:
157
152
  storageRegistry.registerStorageClass(storage)
158
153
  except ValueError:
@@ -1,2 +1,2 @@
1
1
  __all__ = ["__version__"]
2
- __version__ = "29.2025.3100"
2
+ __version__ = "29.2025.3200"
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: lsst-daf-butler
3
- Version: 29.2025.3100
3
+ Version: 29.2025.3200
4
4
  Summary: An abstraction layer for reading and writing astronomical data to datastores.
5
5
  Author-email: Rubin Observatory Data Management <dm-admin@lists.lsst.org>
6
6
  License: BSD 3-Clause License
@@ -25,14 +25,14 @@ lsst/daf/butler/_file_dataset.py,sha256=KF_o5zi01L0gK4t_Ncb3BSbCTiyf9zmwwTpWoNga
25
25
  lsst/daf/butler/_file_descriptor.py,sha256=PIYT9O2NRbNndtI2rMXfx7tP6nUcTnd9fxFVsq-Hu1s,3841
26
26
  lsst/daf/butler/_formatter.py,sha256=BZTpbAwATykj6Omz4pl5f5SdI_Qa0rWxhSUk1G4_UIc,83156
27
27
  lsst/daf/butler/_labeled_butler_factory.py,sha256=vsh5rcdX0ZeVfDeC9eLWxRNy5KYz8W-bFN5WrRICcEY,8593
28
- lsst/daf/butler/_limited_butler.py,sha256=1Us3SXtqgZzZS95FcSLsAMjyiBKxoSlAGWFEWrq29bY,16819
28
+ lsst/daf/butler/_limited_butler.py,sha256=85na5IWR3nRRWEgMcuy-lY46FPrxBRqsvgEMEnZoOkQ,16696
29
29
  lsst/daf/butler/_location.py,sha256=oX-AKZeSdToeKBxvB6y-pxLMiFwF-3nz3YleH5SiA3A,10451
30
30
  lsst/daf/butler/_named.py,sha256=-AvkTP5JIsCwj5tAmZO8epoRoF1_dGuz2aC0ItLg7-M,19541
31
31
  lsst/daf/butler/_quantum.py,sha256=xqWk2mHLydf4VWpRTCR74eBjApESuaTb46_iOdLKFDo,25575
32
32
  lsst/daf/butler/_quantum_backed.py,sha256=tvOB2kY8QMZKV98fQPjd8e6_1iW9oJtbdJT3xTCihz4,36476
33
33
  lsst/daf/butler/_query_all_datasets.py,sha256=Ev5LHI3Mq9a3XEB9bccX4n70EDQ6OVHhKqeHoThIkz8,7135
34
34
  lsst/daf/butler/_registry_shim.py,sha256=M15HOHpQTUPFfA7oPCnDw-IlmG0BrjZWu3KBfpAnoL8,14420
35
- lsst/daf/butler/_storage_class.py,sha256=NETjM3gQTUp83RplD5e6jJuGsPEiKeuNP-axqd7pgvA,37684
35
+ lsst/daf/butler/_storage_class.py,sha256=p74C-_QjYbcVFm6SdS0RYa_Gjmz9sJJ3JAA98llisdc,32997
36
36
  lsst/daf/butler/_storage_class_delegate.py,sha256=0fpDwQILeP0TcXP1W147Va4rX3qZhAyFpFkq6vrf6fo,16324
37
37
  lsst/daf/butler/_timespan.py,sha256=t0FTm5rAJQ1xEGNJ2UqsOSH_TYvKJk-70l7FSeAIdmY,23685
38
38
  lsst/daf/butler/_topology.py,sha256=TkPCLE_Rr_wkK6iOJcWeUP-wIkJkeQzPEl5-P8rqvHw,6323
@@ -52,7 +52,7 @@ lsst/daf/butler/repo_relocation.py,sha256=Ivhx2xU4slc53Z6RExhNnquMr2Hx-S8h62emml
52
52
  lsst/daf/butler/time_utils.py,sha256=MVTfOFI2xt3IeA46pa-fWY2kJRwSzaQyq1uzeUABcTM,11805
53
53
  lsst/daf/butler/timespan_database_representation.py,sha256=MWDusjIQIL2RH1CDpWSW5sYvdHCJKzAfpg1rm1DfgEU,24302
54
54
  lsst/daf/butler/utils.py,sha256=5u50COK5z4u31grOhmQF7mFz55biNLOvSMRdQjEdsjo,5140
55
- lsst/daf/butler/version.py,sha256=ieqM-HeyuKM3_4zduaocPJMVYG02uci4CjCfGX5PncI,55
55
+ lsst/daf/butler/version.py,sha256=5kA_2hRyFYLCSuDYZQBSx1jsWCdezZbf05_1pktQdgw,55
56
56
  lsst/daf/butler/_utilities/__init__.py,sha256=vLzPZYAJ-9r1cnqsP64MVpFgSw2166yOpq0iPMSdAvw,1298
57
57
  lsst/daf/butler/_utilities/locked_object.py,sha256=3RQf0Ish55mfQAfBy3V4Tfnfq5Q7-cxrwTlQMUhrIno,1931
58
58
  lsst/daf/butler/_utilities/named_locks.py,sha256=Zj_u1rZELaiWec3wJfkgmGD_YiZMLVxbMQmdbbVgk5E,2286
@@ -95,8 +95,8 @@ lsst/daf/butler/datastore/composites.py,sha256=NZ7rBK5yH-hrtpqZxC8d49UwwQqWZlEmm
95
95
  lsst/daf/butler/datastore/constraints.py,sha256=OcUXuXZq1UBnuQqq8U7Hp3Ezqu0RBN8pIo93BEq7lyI,5921
96
96
  lsst/daf/butler/datastore/file_templates.py,sha256=xnb4ZheW6NqeCE__vkIvLF91d57nhfcX3ynGWI0rX_0,35095
97
97
  lsst/daf/butler/datastore/generic_base.py,sha256=C15FN1fDVxs-XjeDc1hw5un3MMMVIaZN4QdFbjqQ168,5176
98
- lsst/daf/butler/datastore/record_data.py,sha256=Jvv2Gpfcr43w97Ub4PT4N0fQQcqPni-wWYv3zMBZZCg,9556
99
- lsst/daf/butler/datastore/stored_file_info.py,sha256=3GzTeCxvRS3kEE_8GUyqz3qTsp1EgW2Ciy8cMqdJWjU,15931
98
+ lsst/daf/butler/datastore/record_data.py,sha256=dhku1kCG0WCeYeWOq9m0Euq02pa96XDF5W9nD_ZEe8k,10428
99
+ lsst/daf/butler/datastore/stored_file_info.py,sha256=s_9LsLZgIF7TwjiXEXgNPz3OaaRiUyzmf5SOdJ1elhk,15838
100
100
  lsst/daf/butler/datastores/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
101
101
  lsst/daf/butler/datastores/chainedDatastore.py,sha256=0KWzBzUyUpd9wy4e6zPcJdNIr53Fl1eut__38jRUm-E,55468
102
102
  lsst/daf/butler/datastores/fileDatastore.py,sha256=QC1zRPbD4ID8KPSgar3ttvnAsOscDexT7lMvf15I9HE,135991
@@ -116,7 +116,7 @@ lsst/daf/butler/dimensions/_elements.py,sha256=3Hn884mHbxz6H2KkMm-SFitEG_eHVRivU
116
116
  lsst/daf/butler/dimensions/_governor.py,sha256=En0Ar_uBuUnuKG1IACbyaZ7FRwf234zI5IEjwIQmMHw,5963
117
117
  lsst/daf/butler/dimensions/_group.py,sha256=GNKRmWwH4eiakGtzJPcwinVH57GSW86WRPNZ92erRx8,22833
118
118
  lsst/daf/butler/dimensions/_packer.py,sha256=yfgw7gXMSkPC59Kr51X6Isi8j6ihxqoR1OO2xPnd8FY,6461
119
- lsst/daf/butler/dimensions/_record_set.py,sha256=agiAZcAxueb1gqOf4723xXrQlXJ-MZI8-mh8gzvslJ8,38107
119
+ lsst/daf/butler/dimensions/_record_set.py,sha256=IEH2dBxPTn56eHjOsyaneNjqeVv4VgqM6Z4_NiGBfNY,40454
120
120
  lsst/daf/butler/dimensions/_record_table.py,sha256=b1ijXQlnXH1N8rdiAV4C4GlDmOsBbWGuzob8Gv0mtII,9733
121
121
  lsst/daf/butler/dimensions/_records.py,sha256=QX8XxiHRhRKFkUO3CvoDpe_8KGGyt3nyl08ifxUWwVs,24677
122
122
  lsst/daf/butler/dimensions/_schema.py,sha256=DOuhmI98f3yuvasFFATJCFrx6cjQSx4o2kyLioMbHlU,18507
@@ -320,7 +320,7 @@ lsst/daf/butler/script/transferDatasets.py,sha256=VPTiooLgpMkHWelTHCCvOYccr6OCPk
320
320
  lsst/daf/butler/tests/__init__.py,sha256=JPCjf2ppCcTqC8pDpo5O-RNKlDlMqzql_rdQ41NUses,1506
321
321
  lsst/daf/butler/tests/_datasetsHelper.py,sha256=LH1ZPuzSpRijAPtAiwBoSZZPzI-aSaHN3FU93AtJ6JI,8288
322
322
  lsst/daf/butler/tests/_dummyRegistry.py,sha256=CowulEeirnWwSJf-AnutvOLvGSr3ITgShlYj9f_IuYk,9509
323
- lsst/daf/butler/tests/_examplePythonTypes.py,sha256=OkKf8e16T4xSBVjN05qvfrukowqJ6BICTmQZZFdskaI,13508
323
+ lsst/daf/butler/tests/_examplePythonTypes.py,sha256=oKuKhFkyipD7XCojlQR7D9xPyq6YS9nkB-U4_l07BIM,13281
324
324
  lsst/daf/butler/tests/_testRepo.py,sha256=MVkQwXJ5vI86--Npa7SDHRblpJC5pig6vpGxv-dgGvE,23755
325
325
  lsst/daf/butler/tests/butler_queries.py,sha256=DYEOZUHkv2T58CWydlfKozEddwCfwLMD_txW3nEQZsI,121629
326
326
  lsst/daf/butler/tests/cliCmdTestBase.py,sha256=6SsDIIttbvwi9TX7jkaPa8VuTvzO17hL6WGAm_T6uxM,6994
@@ -347,13 +347,13 @@ lsst/daf/butler/transfers/__init__.py,sha256=M1YcFszSkNB5hB2pZwwGXqbJE2dKt4YXDin
347
347
  lsst/daf/butler/transfers/_context.py,sha256=1oOlKWj53bjcVioOIzRNPZSC_Q0dLDI_R4syI9gMOkg,16938
348
348
  lsst/daf/butler/transfers/_interfaces.py,sha256=Ia1NqcFR5E-Ik4zsXEe2fuMtNCJj5Yfe_gVHLTBtJDw,7490
349
349
  lsst/daf/butler/transfers/_yaml.py,sha256=w_0GmrueuHVLfOfAXGHFBbWAl18tX6eSElbTC-2jRoc,32632
350
- lsst_daf_butler-29.2025.3100.dist-info/licenses/COPYRIGHT,sha256=k1Vq0-Be_K-puaeW4UZnckPjksEL-MJh4XKiWcjMxJE,312
351
- lsst_daf_butler-29.2025.3100.dist-info/licenses/LICENSE,sha256=pRExkS03v0MQW-neNfIcaSL6aiAnoLxYgtZoFzQ6zkM,232
352
- lsst_daf_butler-29.2025.3100.dist-info/licenses/bsd_license.txt,sha256=7MIcv8QRX9guUtqPSBDMPz2SnZ5swI-xZMqm_VDSfxY,1606
353
- lsst_daf_butler-29.2025.3100.dist-info/licenses/gpl-v3.0.txt,sha256=OXLcl0T2SZ8Pmy2_dmlvKuetivmyPd5m1q-Gyd-zaYY,35149
354
- lsst_daf_butler-29.2025.3100.dist-info/METADATA,sha256=8ZJylGDdQyCuwwuA3tyCExlwR0XTFTan7nxPFmE3KF4,3265
355
- lsst_daf_butler-29.2025.3100.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
356
- lsst_daf_butler-29.2025.3100.dist-info/entry_points.txt,sha256=XsRxyTK3c-jGlKVuVnbpch3gtaO0lAA_fS3i2NGS5rw,59
357
- lsst_daf_butler-29.2025.3100.dist-info/top_level.txt,sha256=eUWiOuVVm9wwTrnAgiJT6tp6HQHXxIhj2QSZ7NYZH80,5
358
- lsst_daf_butler-29.2025.3100.dist-info/zip-safe,sha256=AbpHGcgLb-kRsJGnwFEktk7uzpZOCcBY74-YBdrKVGs,1
359
- lsst_daf_butler-29.2025.3100.dist-info/RECORD,,
350
+ lsst_daf_butler-29.2025.3200.dist-info/licenses/COPYRIGHT,sha256=k1Vq0-Be_K-puaeW4UZnckPjksEL-MJh4XKiWcjMxJE,312
351
+ lsst_daf_butler-29.2025.3200.dist-info/licenses/LICENSE,sha256=pRExkS03v0MQW-neNfIcaSL6aiAnoLxYgtZoFzQ6zkM,232
352
+ lsst_daf_butler-29.2025.3200.dist-info/licenses/bsd_license.txt,sha256=7MIcv8QRX9guUtqPSBDMPz2SnZ5swI-xZMqm_VDSfxY,1606
353
+ lsst_daf_butler-29.2025.3200.dist-info/licenses/gpl-v3.0.txt,sha256=OXLcl0T2SZ8Pmy2_dmlvKuetivmyPd5m1q-Gyd-zaYY,35149
354
+ lsst_daf_butler-29.2025.3200.dist-info/METADATA,sha256=EKxNPWN4-EBJsVSYYnLginCjq8YLfqjt2sRDy_SZoRI,3265
355
+ lsst_daf_butler-29.2025.3200.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
356
+ lsst_daf_butler-29.2025.3200.dist-info/entry_points.txt,sha256=XsRxyTK3c-jGlKVuVnbpch3gtaO0lAA_fS3i2NGS5rw,59
357
+ lsst_daf_butler-29.2025.3200.dist-info/top_level.txt,sha256=eUWiOuVVm9wwTrnAgiJT6tp6HQHXxIhj2QSZ7NYZH80,5
358
+ lsst_daf_butler-29.2025.3200.dist-info/zip-safe,sha256=AbpHGcgLb-kRsJGnwFEktk7uzpZOCcBY74-YBdrKVGs,1
359
+ lsst_daf_butler-29.2025.3200.dist-info/RECORD,,