Coverage for python/lsst/pipe/base/_datasetQueryConstraints.py: 50%

74 statements  

« prev     ^ index     » next       coverage.py v7.5.0, created at 2024-04-27 10:12 +0000

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 software is dual licensed under the GNU General Public License and also 

10# under a 3-clause BSD license. Recipients may choose which of these licenses 

11# to use; please see the files gpl-3.0.txt and/or bsd_license.txt, 

12# respectively. If you choose the GPL option then the following text applies 

13# (but note that there is still no warranty even if you opt for BSD instead): 

14# 

15# This program is free software: you can redistribute it and/or modify 

16# it under the terms of the GNU General Public License as published by 

17# the Free Software Foundation, either version 3 of the License, or 

18# (at your option) any later version. 

19# 

20# This program is distributed in the hope that it will be useful, 

21# but WITHOUT ANY WARRANTY; without even the implied warranty of 

22# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 

23# GNU General Public License for more details. 

24# 

25# You should have received a copy of the GNU General Public License 

26# along with this program. If not, see <http://www.gnu.org/licenses/>. 

27 

28"""Symbols defined in this package should be imported from 

29`all_dimensions_quantum_graph_builder` instead; it only appears in the docs 

30due to limitations in Sphinx. 

31""" 

32 

33from __future__ import annotations 

34 

35__all__ = ("DatasetQueryConstraintVariant",) 

36 

37import sys 

38import warnings 

39from collections.abc import Iterable, Iterator 

40from typing import Protocol 

41 

42from lsst.utils.introspection import find_outside_stacklevel 

43 

44 

45class DatasetQueryConstraintVariant(Iterable, Protocol): 

46 """Base for all the valid variants for controlling 

47 constraining graph building queries based on dataset type existence. 

48 

49 ALL variant corresponds to using all input dataset types to constrain 

50 a query. 

51 

52 OFF variant corresponds to not using any dataset types to constrain a 

53 graph building query. 

54 

55 LIST variant should be used when one or more specific names should be used 

56 in constraining a graph building query. 

57 

58 Normally the ALL and OFF variants are used as as Singletons, attempting to 

59 instantiate them (i.e. ALL()) will return in singleton class itself. 

60 

61 LIST is used as a constructor to the contents (i.e. List(['a', 'b'])). 

62 Using the LIST variant directly as a singleton will behave the same as if 

63 it were an empty instance. 

64 

65 Variants can be directly used, or automatically be selected by using the 

66 `fromExpression` class method given a valid string. 

67 """ 

68 

69 ALL: "type[_ALL]" 

70 OFF: "type[_OFF]" 

71 LIST: "type[_LIST]" 

72 

73 @classmethod 

74 def __subclasshook__(cls, subclass): 

75 if subclass == cls.ALL or subclass == cls.OFF or subclass == cls.LIST: 

76 return True 

77 return False 

78 

79 @classmethod 

80 def fromExpression(cls, expression: str) -> "DatasetQueryConstraintVariant": 

81 """Select and return the correct Variant that corresponds to the input 

82 expression. 

83 

84 Parameters 

85 ---------- 

86 expression : `str` 

87 Input expression. Valid values are ``all`` for all inputs dataset 

88 types in pipeline, ``off`` to not consider dataset type existence 

89 as a constraint, single or comma-separated list of dataset type 

90 names. 

91 

92 Returns 

93 ------- 

94 variant : `DatasetQueryConstraintVariant` 

95 Correct variant for this expression. 

96 """ 

97 if not isinstance(expression, str): 

98 raise ValueError("Expression must be a string") 

99 elif expression == "all": 

100 return cls.ALL 

101 elif expression == "off": 

102 return cls.OFF 

103 else: 

104 if " " in expression: 

105 warnings.warn( 

106 "Whitespace found in expression will be trimmed", 

107 RuntimeWarning, 

108 stacklevel=find_outside_stacklevel("lsst.pipe.base"), 

109 ) 

110 expression = expression.replace(" ", "") 

111 members = expression.split(",") 

112 return cls.LIST(members) 

113 

114 

115if sys.version_info.minor < 12: 115 ↛ 119line 115 didn't jump to line 119, because the condition on line 115 was never false

116 MetaMeta = type 

117else: 

118 

119 class MetaMeta(type(Protocol)): 

120 def __init__(cls, *args, **kwargs): 

121 # Note: this prepends an *extra* cls to type's argument list 

122 return super().__init__(cls, *args, **kwargs) 

123 

124 

125class _ALLMETA(DatasetQueryConstraintVariant, type(Protocol), metaclass=MetaMeta): 

126 def __iter__(self) -> Iterator: # noqa: N804 

127 raise NotImplementedError("This variant cannot be iterated") 

128 

129 

130class _ALL(metaclass=_ALLMETA): 

131 def __new__(cls): 

132 return cls 

133 

134 

135class _OFFMETA(DatasetQueryConstraintVariant, type(Protocol), metaclass=MetaMeta): 

136 def __iter__(self) -> Iterator: # noqa: N804 

137 raise NotImplementedError("This variant cannot be iterated") 

138 

139 

140class _OFF(metaclass=_OFFMETA): 

141 def __new__(cls): 

142 return cls 

143 

144 

145class _LISTMETA(type(Protocol), metaclass=MetaMeta): 

146 def __iter__(self): # noqa: N804 

147 return iter(tuple()) 

148 

149 def __len__(self): # noqa: N804 

150 return 0 

151 

152 def __eq__(self, o: object) -> bool: # noqa: N804 

153 if isinstance(o, self): 

154 return True 

155 return super().__eq__(o) 

156 

157 

158class _LIST(DatasetQueryConstraintVariant, metaclass=_LISTMETA): 

159 def __init__(self, members: Iterable[str]): 

160 self.members = list(members) 

161 

162 def __len__(self) -> int: 

163 return len(self.members) 

164 

165 def __iter__(self) -> Iterable[str]: 

166 return iter(self.members) 

167 

168 def __repr__(self) -> str: 

169 return repr(self.members) 

170 

171 def __str__(self) -> str: 

172 return str(self.members) 

173 

174 def __eq__(self, o: object) -> bool: 

175 if isinstance(o, type(self)): 

176 return self.members == o.members 

177 return super().__eq__(o) 

178 

179 

180def suppressInit(self): 

181 raise NotImplementedError( 

182 "DatasetQueryConstraintVariants cannot be directly instantiated. " 

183 "Please use the variants or the fromExpression class method" 

184 ) 

185 

186 

187DatasetQueryConstraintVariant.__init__ = suppressInit 

188DatasetQueryConstraintVariant.ALL = _ALL 

189DatasetQueryConstraintVariant.OFF = _OFF 

190DatasetQueryConstraintVariant.LIST = _LIST