Coverage for python/lsst/pipe/base/pipeline_graph/_task_subsets.py: 60%

37 statements  

« prev     ^ index     » next       coverage.py v7.3.2, created at 2023-10-11 09:32 +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/>. 

27from __future__ import annotations 

28 

29__all__ = ("TaskSubset",) 

30 

31from collections.abc import Iterator, MutableSet 

32 

33import networkx 

34import networkx.algorithms.boundary 

35 

36from ._exceptions import PipelineGraphError 

37from ._nodes import NodeKey, NodeType 

38 

39 

40class TaskSubset(MutableSet[str]): 

41 """A specialized set that represents a labeles subset of the tasks in a 

42 pipeline graph. 

43 

44 Instances of this class should never be constructed directly; they should 

45 only be accessed via the `PipelineGraph.task_subsets` attribute and created 

46 by the `PipelineGraph.add_task_subset` method. 

47 

48 Parameters 

49 ---------- 

50 parent_xgraph : `networkx.DiGraph` 

51 Parent networkx graph that this subgraph is part of. 

52 label : `str` 

53 Label associated with this subset of the pipeline. 

54 members : `set` [ `str` ] 

55 Labels of the tasks that are members of this subset. 

56 description : `str`, optional 

57 Description string associated with this labeled subset. 

58 

59 Notes 

60 ----- 

61 Iteration order is arbitrary, even when the parent pipeline graph is 

62 ordered (there is no guarantee that an ordering of the tasks in the graph 

63 implies a consistent ordering of subsets). 

64 """ 

65 

66 def __init__( 

67 self, 

68 parent_xgraph: networkx.DiGraph, 

69 label: str, 

70 members: set[str], 

71 description: str, 

72 ): 

73 self._parent_xgraph = parent_xgraph 

74 self._label = label 

75 self._members = members 

76 self._description = description 

77 

78 @property 

79 def label(self) -> str: 

80 """Label associated with this subset of the pipeline.""" 

81 return self._label 

82 

83 @property 

84 def description(self) -> str: 

85 """Description string associated with this labeled subset.""" 

86 return self._description 

87 

88 @description.setter 

89 def description(self, value: str) -> None: 

90 # Docstring in getter. 

91 self._description = value 

92 

93 def __repr__(self) -> str: 

94 return f"{self.label}: {self.description!r}, tasks={{{', '.join(iter(self))}}}" 

95 

96 def __contains__(self, key: object) -> bool: 

97 return key in self._members 

98 

99 def __len__(self) -> int: 

100 return len(self._members) 

101 

102 def __iter__(self) -> Iterator[str]: 

103 return iter(self._members) 

104 

105 def add(self, task_label: str) -> None: 

106 """Add a new task to this subset. 

107 

108 Parameters 

109 ---------- 

110 task_label : `str` 

111 Label for the task. Must already be present in the parent pipeline 

112 graph. 

113 """ 

114 key = NodeKey(NodeType.TASK, task_label) 

115 if key not in self._parent_xgraph: 

116 raise PipelineGraphError(f"{task_label!r} is not a task in the parent pipeline.") 

117 self._members.add(key.name) 

118 

119 def discard(self, task_label: str) -> None: 

120 """Remove a task from the subset if it is present. 

121 

122 Parameters 

123 ---------- 

124 task_label : `str` 

125 Label for the task. Must already be present in the parent pipeline 

126 graph. 

127 """ 

128 self._members.discard(task_label)