Coverage for python/lsst/pipe/base/_dataset_handle.py: 26%
55 statements
« prev ^ index » next coverage.py v6.4.2, created at 2022-08-03 02:43 -0700
« prev ^ index » next coverage.py v6.4.2, created at 2022-08-03 02:43 -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
29from lsst.utils.introspection import get_full_type_name
32# Use an empty dataID as a default.
33def _default_dataId() -> DataCoordinate:
34 return DataCoordinate.makeEmpty(DimensionUniverse())
37@dataclasses.dataclass(frozen=True)
38class InMemoryDatasetHandle:
39 """An in-memory version of a `~lsst.daf.butler.DeferredDatasetHandle`."""
41 def get(
42 self, *, component: Optional[str] = None, parameters: Optional[dict] = None, **kwargs: dict
43 ) -> Any:
44 """Retrieves the dataset pointed to by this handle
46 This handle may be used multiple times, possibly with different
47 parameters.
49 Parameters
50 ----------
51 component : `str` or None
52 If the deferred object is a component dataset type, this parameter
53 may specify the name of the component to use in the get operation.
54 parameters : `dict` or None
55 The parameters argument will be passed to the butler get method.
56 It defaults to None. If the value is not None, this dict will
57 be merged with the parameters dict used to construct the
58 `DeferredDatasetHandle` class.
59 **kwargs
60 This argument is deprecated and only exists to support legacy
61 gen2 butler code during migration. It is completely ignored
62 and will be removed in the future.
64 Returns
65 -------
66 return : `object`
67 The dataset pointed to by this handle. This is the actual object
68 that was initially stored and not a copy. Modifying this object
69 will modify the stored object. If the stored object is `None` this
70 method always returns `None` regardless of any component request or
71 parameters.
72 """
73 if self.inMemoryDataset is None:
74 return None
76 if self.parameters is not None:
77 mergedParameters = self.parameters.copy()
78 if parameters is not None:
79 mergedParameters.update(parameters)
80 elif parameters is not None:
81 mergedParameters = parameters
82 else:
83 mergedParameters = {}
85 if component or mergedParameters:
86 # This requires a storage class look up to locate the delegate
87 # class.
88 storageClass = self._getStorageClass()
89 inMemoryDataset = self.inMemoryDataset
91 # Parameters for derived components are applied against the
92 # composite.
93 if component in storageClass.derivedComponents:
94 storageClass.validateParameters(parameters)
96 # Process the parameters (hoping this never modified the
97 # original object).
98 inMemoryDataset = storageClass.delegate().handleParameters(inMemoryDataset, mergedParameters)
99 mergedParameters = {} # They have now been used
101 readStorageClass = storageClass.derivedComponents[component]
102 else:
103 if component:
104 readStorageClass = storageClass.components[component]
105 else:
106 readStorageClass = storageClass
107 readStorageClass.validateParameters(mergedParameters)
109 if component:
110 inMemoryDataset = storageClass.delegate().getComponent(inMemoryDataset, component)
112 if mergedParameters:
113 inMemoryDataset = readStorageClass.delegate().handleParameters(
114 inMemoryDataset, mergedParameters
115 )
117 return inMemoryDataset
118 else:
119 # If there are no parameters or component requests the object
120 # can be returned as is.
121 return self.inMemoryDataset
123 def _getStorageClass(self) -> StorageClass:
124 factory = StorageClassFactory()
125 if self.storageClass:
126 return factory.getStorageClass(self.storageClass)
128 # Need to match python type.
129 pytype = type(self.inMemoryDataset)
130 for storageClass in factory.values():
131 # It is possible for a single python type to refer to multiple
132 # storage classes such that this could be quite fragile.
133 if storageClass.is_type(pytype):
134 return storageClass
136 raise ValueError(
137 "Unable to find a StorageClass with associated with type "
138 f"{get_full_type_name(self.inMemoryDataset)}"
139 )
141 inMemoryDataset: Any
142 """The object to store in this dataset handle for later retrieval.
143 """
145 storageClass: Optional[str] = None
146 """The name of the `~lsst.daf.butler.StorageClass` associated with this
147 dataset.
149 If `None`, the storage class will be looked up from the factory.
150 """
152 parameters: Optional[dict] = None
153 """Optional parameters that may be used to specify a subset of the dataset
154 to be loaded (`dict` or `None`).
155 """
157 dataId: DataCoordinate = dataclasses.field(default_factory=_default_dataId)
158 """The `~lsst.daf.butler.DataCoordinate` associated with this dataset
159 handle.
160 """