Coverage for python/lsst/pipe/base/_dataset_handle.py: 22%
61 statements
« prev ^ index » next coverage.py v6.5.0, created at 2022-12-06 02:02 -0800
« prev ^ index » next coverage.py v6.5.0, created at 2022-12-06 02:02 -0800
1# This file is part of pipe_base.
2#
3# Developed for the LSST Data Management System.
4# This product includes software developed by the LSST Project
5# (http://www.lsst.org).
6# See the COPYRIGHT file at the top-level directory of this distribution
7# for details of code ownership.
8#
9# This program is free software: you can redistribute it and/or modify
10# it under the terms of the GNU General Public License as published by
11# the Free Software Foundation, either version 3 of the License, or
12# (at your option) any later version.
13#
14# This program is distributed in the hope that it will be useful,
15# but WITHOUT ANY WARRANTY; without even the implied warranty of
16# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17# GNU General Public License for more details.
18#
19# You should have received a copy of the GNU General Public License
20# along with this program. If not, see <http://www.gnu.org/licenses/>.
21from __future__ import annotations
23__all__ = ["InMemoryDatasetHandle"]
25import dataclasses
26from typing import Any, Optional
28from lsst.daf.butler import DataCoordinate, DimensionUniverse, StorageClass, StorageClassFactory
31# Use an empty dataID as a default.
32def _default_dataId() -> DataCoordinate:
33 return DataCoordinate.makeEmpty(DimensionUniverse())
36@dataclasses.dataclass(frozen=True)
37class InMemoryDatasetHandle:
38 """An in-memory version of a `~lsst.daf.butler.DeferredDatasetHandle`."""
40 def get(
41 self,
42 *,
43 component: Optional[str] = None,
44 parameters: Optional[dict] = None,
45 storageClass: str | StorageClass | None = None,
46 **kwargs: dict,
47 ) -> Any:
48 """Retrieves the dataset pointed to by this handle
50 This handle may be used multiple times, possibly with different
51 parameters.
53 Parameters
54 ----------
55 component : `str` or None
56 If the deferred object is a component dataset type, this parameter
57 may specify the name of the component to use in the get operation.
58 parameters : `dict` or None
59 The parameters argument will be passed to the butler get method.
60 It defaults to None. If the value is not None, this dict will
61 be merged with the parameters dict used to construct the
62 `DeferredDatasetHandle` class.
63 storageClass : `StorageClass` or `str`, optional
64 The storage class to be used to override the Python type
65 returned by this method. By default the returned type matches
66 the type stored. Specifying a read `StorageClass` can force a
67 different type to be returned.
68 This type must be compatible with the original type.
69 **kwargs
70 This argument is deprecated and only exists to support legacy
71 gen2 butler code during migration. It is completely ignored
72 and will be removed in the future.
74 Returns
75 -------
76 return : `object`
77 The dataset pointed to by this handle. This is the actual object
78 that was initially stored and not a copy. Modifying this object
79 will modify the stored object. If the stored object is `None` this
80 method always returns `None` regardless of any component request or
81 parameters.
83 Raises
84 ------
85 KeyError
86 Raised if a component or parameters are used but no storage
87 class can be found.
88 """
89 if self.inMemoryDataset is None:
90 return None
92 if self.parameters is not None:
93 mergedParameters = self.parameters.copy()
94 if parameters is not None:
95 mergedParameters.update(parameters)
96 elif parameters is not None:
97 mergedParameters = parameters
98 else:
99 mergedParameters = {}
101 returnStorageClass: StorageClass | None = None
102 if storageClass:
103 if isinstance(storageClass, str):
104 factory = StorageClassFactory()
105 returnStorageClass = factory.getStorageClass(storageClass)
106 else:
107 returnStorageClass = storageClass
109 if component or mergedParameters:
110 # This requires a storage class look up to locate the delegate
111 # class.
112 thisStorageClass = self._getStorageClass()
113 inMemoryDataset = self.inMemoryDataset
115 # Parameters for derived components are applied against the
116 # composite.
117 if component in thisStorageClass.derivedComponents:
118 thisStorageClass.validateParameters(parameters)
120 # Process the parameters (hoping this never modified the
121 # original object).
122 inMemoryDataset = thisStorageClass.delegate().handleParameters(
123 inMemoryDataset, mergedParameters
124 )
125 mergedParameters = {} # They have now been used
127 readStorageClass = thisStorageClass.derivedComponents[component]
128 else:
129 if component:
130 readStorageClass = thisStorageClass.components[component]
131 else:
132 readStorageClass = thisStorageClass
133 readStorageClass.validateParameters(mergedParameters)
135 if component:
136 inMemoryDataset = thisStorageClass.delegate().getComponent(inMemoryDataset, component)
138 if mergedParameters:
139 inMemoryDataset = readStorageClass.delegate().handleParameters(
140 inMemoryDataset, mergedParameters
141 )
142 if returnStorageClass:
143 return returnStorageClass.coerce_type(inMemoryDataset)
144 return inMemoryDataset
145 else:
146 # If there are no parameters or component requests the object
147 # can be returned as is, but possibly with conversion.
148 if returnStorageClass:
149 return returnStorageClass.coerce_type(self.inMemoryDataset)
150 return self.inMemoryDataset
152 def _getStorageClass(self) -> StorageClass:
153 """Return the relevant storage class.
155 Returns
156 -------
157 storageClass : `StorageClass`
158 The storage class associated with this handle, or one derived
159 from the python type of the stored object.
161 Raises
162 ------
163 KeyError
164 Raised if the storage class could not be found.
165 """
166 factory = StorageClassFactory()
167 if self.storageClass:
168 return factory.getStorageClass(self.storageClass)
170 # Need to match python type.
171 pytype = type(self.inMemoryDataset)
172 return factory.findStorageClass(pytype)
174 inMemoryDataset: Any
175 """The object to store in this dataset handle for later retrieval.
176 """
178 storageClass: Optional[str] = None
179 """The name of the `~lsst.daf.butler.StorageClass` associated with this
180 dataset.
182 If `None`, the storage class will be looked up from the factory.
183 """
185 parameters: Optional[dict] = None
186 """Optional parameters that may be used to specify a subset of the dataset
187 to be loaded (`dict` or `None`).
188 """
190 dataId: DataCoordinate = dataclasses.field(default_factory=_default_dataId)
191 """The `~lsst.daf.butler.DataCoordinate` associated with this dataset
192 handle.
193 """