Coverage for python/lsst/pipe/base/_dataset_handle.py: 27%
51 statements
« prev ^ index » next coverage.py v6.4.4, created at 2022-08-23 02:31 -0700
« prev ^ index » next coverage.py v6.4.4, created at 2022-08-23 02:31 -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, *, component: Optional[str] = None, parameters: Optional[dict] = None, **kwargs: dict
42 ) -> Any:
43 """Retrieves the dataset pointed to by this handle
45 This handle may be used multiple times, possibly with different
46 parameters.
48 Parameters
49 ----------
50 component : `str` or None
51 If the deferred object is a component dataset type, this parameter
52 may specify the name of the component to use in the get operation.
53 parameters : `dict` or None
54 The parameters argument will be passed to the butler get method.
55 It defaults to None. If the value is not None, this dict will
56 be merged with the parameters dict used to construct the
57 `DeferredDatasetHandle` class.
58 **kwargs
59 This argument is deprecated and only exists to support legacy
60 gen2 butler code during migration. It is completely ignored
61 and will be removed in the future.
63 Returns
64 -------
65 return : `object`
66 The dataset pointed to by this handle. This is the actual object
67 that was initially stored and not a copy. Modifying this object
68 will modify the stored object. If the stored object is `None` this
69 method always returns `None` regardless of any component request or
70 parameters.
72 Raises
73 ------
74 KeyError
75 Raised if a component or parameters are used but no storage
76 class can be found.
77 """
78 if self.inMemoryDataset is None:
79 return None
81 if self.parameters is not None:
82 mergedParameters = self.parameters.copy()
83 if parameters is not None:
84 mergedParameters.update(parameters)
85 elif parameters is not None:
86 mergedParameters = parameters
87 else:
88 mergedParameters = {}
90 if component or mergedParameters:
91 # This requires a storage class look up to locate the delegate
92 # class.
93 storageClass = self._getStorageClass()
94 inMemoryDataset = self.inMemoryDataset
96 # Parameters for derived components are applied against the
97 # composite.
98 if component in storageClass.derivedComponents:
99 storageClass.validateParameters(parameters)
101 # Process the parameters (hoping this never modified the
102 # original object).
103 inMemoryDataset = storageClass.delegate().handleParameters(inMemoryDataset, mergedParameters)
104 mergedParameters = {} # They have now been used
106 readStorageClass = storageClass.derivedComponents[component]
107 else:
108 if component:
109 readStorageClass = storageClass.components[component]
110 else:
111 readStorageClass = storageClass
112 readStorageClass.validateParameters(mergedParameters)
114 if component:
115 inMemoryDataset = storageClass.delegate().getComponent(inMemoryDataset, component)
117 if mergedParameters:
118 inMemoryDataset = readStorageClass.delegate().handleParameters(
119 inMemoryDataset, mergedParameters
120 )
122 return inMemoryDataset
123 else:
124 # If there are no parameters or component requests the object
125 # can be returned as is.
126 return self.inMemoryDataset
128 def _getStorageClass(self) -> StorageClass:
129 """Return the relevant storage class.
131 Returns
132 -------
133 storageClass : `StorageClass`
134 The storage class associated with this handle, or one derived
135 from the python type of the stored object.
137 Raises
138 ------
139 KeyError
140 Raised if the storage class could not be found.
141 """
142 factory = StorageClassFactory()
143 if self.storageClass:
144 return factory.getStorageClass(self.storageClass)
146 # Need to match python type.
147 pytype = type(self.inMemoryDataset)
148 return factory.findStorageClass(pytype)
150 inMemoryDataset: Any
151 """The object to store in this dataset handle for later retrieval.
152 """
154 storageClass: Optional[str] = None
155 """The name of the `~lsst.daf.butler.StorageClass` associated with this
156 dataset.
158 If `None`, the storage class will be looked up from the factory.
159 """
161 parameters: Optional[dict] = None
162 """Optional parameters that may be used to specify a subset of the dataset
163 to be loaded (`dict` or `None`).
164 """
166 dataId: DataCoordinate = dataclasses.field(default_factory=_default_dataId)
167 """The `~lsst.daf.butler.DataCoordinate` associated with this dataset
168 handle.
169 """