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

68 statements  

« prev     ^ index     » next       coverage.py v7.3.0, created at 2023-08-23 10:31 +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 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/>. 

21 

22"""Module Defining variants for valid values used to constrain datasets in a 

23graph building query. 

24""" 

25 

26from __future__ import annotations 

27 

28__all__ = ("DatasetQueryConstraintVariant",) 

29 

30import warnings 

31from collections.abc import Iterable, Iterator 

32from typing import Protocol 

33 

34from lsst.utils.introspection import find_outside_stacklevel 

35 

36 

37class DatasetQueryConstraintVariant(Iterable, Protocol): 

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

39 constraining graph building queries based on dataset type existence. 

40 

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

42 a query. 

43 

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

45 graph building query. 

46 

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

48 in constraining a graph building query. 

49 

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

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

52 

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

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

55 it were an empty instance. 

56 

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

58 `fromExpression` class method given a valid string. 

59 """ 

60 

61 ALL: "type[_ALL]" 

62 OFF: "type[_OFF]" 

63 LIST: "type[_LIST]" 

64 

65 @classmethod 

66 def __subclasshook__(cls, subclass): 

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

68 return True 

69 return False 

70 

71 @classmethod 

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

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

74 expression. 

75 

76 Valid values are ``all`` for all inputs dataset types in pipeline, 

77 ``off`` to not consider dataset type existence as a constraint, single 

78 or comma-separated list of dataset type names. 

79 """ 

80 if not isinstance(expression, str): 

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

82 elif expression == "all": 

83 return cls.ALL 

84 elif expression == "off": 

85 return cls.OFF 

86 else: 

87 if " " in expression: 

88 warnings.warn( 

89 "Whitespace found in expression will be trimmed", 

90 RuntimeWarning, 

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

92 ) 

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

94 members = expression.split(",") 

95 return cls.LIST(members) 

96 

97 

98class _ALLMETA(DatasetQueryConstraintVariant, type(Protocol)): 

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

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

101 

102 

103class _ALL(metaclass=_ALLMETA): 

104 def __new__(cls): 

105 return cls 

106 

107 

108class _OFFMETA(DatasetQueryConstraintVariant, type(Protocol)): 

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

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

111 

112 

113class _OFF(metaclass=_OFFMETA): 

114 def __new__(cls): 

115 return cls 

116 

117 

118class _LISTMETA(type(Protocol)): 

119 def __iter__(self): # noqa: N804 

120 return iter(tuple()) 

121 

122 def __len__(self): # noqa: N804 

123 return 0 

124 

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

126 if isinstance(o, self): 

127 return True 

128 return super().__eq__(o) 

129 

130 

131class _LIST(DatasetQueryConstraintVariant, metaclass=_LISTMETA): 

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

133 self.members = list(members) 

134 

135 def __len__(self) -> int: 

136 return len(self.members) 

137 

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

139 return iter(self.members) 

140 

141 def __repr__(self) -> str: 

142 return repr(self.members) 

143 

144 def __str__(self) -> str: 

145 return str(self.members) 

146 

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

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

149 return self.members == o.members 

150 return super().__eq__(o) 

151 

152 

153def suppressInit(self): 

154 raise NotImplementedError( 

155 "DatasetQueryConstraintVariants cannot be directly instantiated. " 

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

157 ) 

158 

159 

160DatasetQueryConstraintVariant.__init__ = suppressInit 

161DatasetQueryConstraintVariant.ALL = _ALL 

162DatasetQueryConstraintVariant.OFF = _OFF 

163DatasetQueryConstraintVariant.LIST = _LIST