Coverage for python/lsst/pipe/base/_dataset_handle.py: 22%
61 statements
« prev ^ index » next coverage.py v6.5.0, created at 2023-03-31 02:59 -0700
« prev ^ index » next coverage.py v6.5.0, created at 2023-03-31 02:59 -0700
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 ) -> Any:
47 """Retrieves the dataset pointed to by this handle
49 This handle may be used multiple times, possibly with different
50 parameters.
52 Parameters
53 ----------
54 component : `str` or None
55 If the deferred object is a component dataset type, this parameter
56 may specify the name of the component to use in the get operation.
57 parameters : `dict` or None
58 The parameters argument will be passed to the butler get method.
59 It defaults to None. If the value is not None, this dict will
60 be merged with the parameters dict used to construct the
61 `DeferredDatasetHandle` class.
62 storageClass : `StorageClass` or `str`, optional
63 The storage class to be used to override the Python type
64 returned by this method. By default the returned type matches
65 the type stored. Specifying a read `StorageClass` can force a
66 different type to be returned.
67 This type must be compatible with the original type.
69 Returns
70 -------
71 return : `object`
72 The dataset pointed to by this handle. This is the actual object
73 that was initially stored and not a copy. Modifying this object
74 will modify the stored object. If the stored object is `None` this
75 method always returns `None` regardless of any component request or
76 parameters.
78 Raises
79 ------
80 KeyError
81 Raised if a component or parameters are used but no storage
82 class can be found.
83 """
84 if self.inMemoryDataset is None:
85 return None
87 if self.parameters is not None:
88 mergedParameters = self.parameters.copy()
89 if parameters is not None:
90 mergedParameters.update(parameters)
91 elif parameters is not None:
92 mergedParameters = parameters
93 else:
94 mergedParameters = {}
96 returnStorageClass: StorageClass | None = None
97 if storageClass:
98 if isinstance(storageClass, str):
99 factory = StorageClassFactory()
100 returnStorageClass = factory.getStorageClass(storageClass)
101 else:
102 returnStorageClass = storageClass
104 if component or mergedParameters:
105 # This requires a storage class look up to locate the delegate
106 # class.
107 thisStorageClass = self._getStorageClass()
108 inMemoryDataset = self.inMemoryDataset
110 # Parameters for derived components are applied against the
111 # composite.
112 if component in thisStorageClass.derivedComponents:
113 thisStorageClass.validateParameters(parameters)
115 # Process the parameters (hoping this never modified the
116 # original object).
117 inMemoryDataset = thisStorageClass.delegate().handleParameters(
118 inMemoryDataset, mergedParameters
119 )
120 mergedParameters = {} # They have now been used
122 readStorageClass = thisStorageClass.derivedComponents[component]
123 else:
124 if component:
125 readStorageClass = thisStorageClass.components[component]
126 else:
127 readStorageClass = thisStorageClass
128 readStorageClass.validateParameters(mergedParameters)
130 if component:
131 inMemoryDataset = thisStorageClass.delegate().getComponent(inMemoryDataset, component)
133 if mergedParameters:
134 inMemoryDataset = readStorageClass.delegate().handleParameters(
135 inMemoryDataset, mergedParameters
136 )
137 if returnStorageClass:
138 return returnStorageClass.coerce_type(inMemoryDataset)
139 return inMemoryDataset
140 else:
141 # If there are no parameters or component requests the object
142 # can be returned as is, but possibly with conversion.
143 if returnStorageClass:
144 return returnStorageClass.coerce_type(self.inMemoryDataset)
145 return self.inMemoryDataset
147 def _getStorageClass(self) -> StorageClass:
148 """Return the relevant storage class.
150 Returns
151 -------
152 storageClass : `StorageClass`
153 The storage class associated with this handle, or one derived
154 from the python type of the stored object.
156 Raises
157 ------
158 KeyError
159 Raised if the storage class could not be found.
160 """
161 factory = StorageClassFactory()
162 if self.storageClass:
163 return factory.getStorageClass(self.storageClass)
165 # Need to match python type.
166 pytype = type(self.inMemoryDataset)
167 return factory.findStorageClass(pytype)
169 inMemoryDataset: Any
170 """The object to store in this dataset handle for later retrieval.
171 """
173 storageClass: Optional[str] = None
174 """The name of the `~lsst.daf.butler.StorageClass` associated with this
175 dataset.
177 If `None`, the storage class will be looked up from the factory.
178 """
180 parameters: Optional[dict] = None
181 """Optional parameters that may be used to specify a subset of the dataset
182 to be loaded (`dict` or `None`).
183 """
185 dataId: DataCoordinate = dataclasses.field(default_factory=_default_dataId)
186 """The `~lsst.daf.butler.DataCoordinate` associated with this dataset
187 handle.
188 """