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

74 statements  

« prev     ^ index     » next       coverage.py v7.4.2, created at 2024-02-21 10:57 +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"""Module Defining variants for valid values used to constrain datasets in a 

29graph building query. 

30""" 

31 

32from __future__ import annotations 

33 

34__all__ = ("DatasetQueryConstraintVariant",) 

35 

36import sys 

37import warnings 

38from collections.abc import Iterable, Iterator 

39from typing import Protocol 

40 

41from lsst.utils.introspection import find_outside_stacklevel 

42 

43 

44class DatasetQueryConstraintVariant(Iterable, Protocol): 

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

46 constraining graph building queries based on dataset type existence. 

47 

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

49 a query. 

50 

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

52 graph building query. 

53 

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

55 in constraining a graph building query. 

56 

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

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

59 

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

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

62 it were an empty instance. 

63 

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

65 `fromExpression` class method given a valid string. 

66 """ 

67 

68 ALL: "type[_ALL]" 

69 OFF: "type[_OFF]" 

70 LIST: "type[_LIST]" 

71 

72 @classmethod 

73 def __subclasshook__(cls, subclass): 

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

75 return True 

76 return False 

77 

78 @classmethod 

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

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

81 expression. 

82 

83 Parameters 

84 ---------- 

85 expression : `str` 

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

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

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

89 names. 

90 

91 Returns 

92 ------- 

93 variant : `DatasetQueryConstraintVariant` 

94 Correct variant for this expression. 

95 """ 

96 if not isinstance(expression, str): 

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

98 elif expression == "all": 

99 return cls.ALL 

100 elif expression == "off": 

101 return cls.OFF 

102 else: 

103 if " " in expression: 

104 warnings.warn( 

105 "Whitespace found in expression will be trimmed", 

106 RuntimeWarning, 

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

108 ) 

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

110 members = expression.split(",") 

111 return cls.LIST(members) 

112 

113 

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

115 MetaMeta = type 

116else: 

117 

118 class MetaMeta(type(Protocol)): 

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

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

121 

122 

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

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

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

126 

127 

128class _ALL(metaclass=_ALLMETA): 

129 def __new__(cls): 

130 return cls 

131 

132 

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

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

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

136 

137 

138class _OFF(metaclass=_OFFMETA): 

139 def __new__(cls): 

140 return cls 

141 

142 

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

144 def __iter__(self): # noqa: N804 

145 return iter(tuple()) 

146 

147 def __len__(self): # noqa: N804 

148 return 0 

149 

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

151 if isinstance(o, self): 

152 return True 

153 return super().__eq__(o) 

154 

155 

156class _LIST(DatasetQueryConstraintVariant, metaclass=_LISTMETA): 

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

158 self.members = list(members) 

159 

160 def __len__(self) -> int: 

161 return len(self.members) 

162 

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

164 return iter(self.members) 

165 

166 def __repr__(self) -> str: 

167 return repr(self.members) 

168 

169 def __str__(self) -> str: 

170 return str(self.members) 

171 

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

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

174 return self.members == o.members 

175 return super().__eq__(o) 

176 

177 

178def suppressInit(self): 

179 raise NotImplementedError( 

180 "DatasetQueryConstraintVariants cannot be directly instantiated. " 

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

182 ) 

183 

184 

185DatasetQueryConstraintVariant.__init__ = suppressInit 

186DatasetQueryConstraintVariant.ALL = _ALL 

187DatasetQueryConstraintVariant.OFF = _OFF 

188DatasetQueryConstraintVariant.LIST = _LIST