1 # Copyright (c) 2023 Cisco and/or its affiliates.
2 # Licensed under the Apache License, Version 2.0 (the "License");
3 # you may not use this file except in compliance with the License.
4 # You may obtain a copy of the License at:
6 # http://www.apache.org/licenses/LICENSE-2.0
8 # Unless required by applicable law or agreed to in writing, software
9 # distributed under the License is distributed on an "AS IS" BASIS,
10 # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
11 # See the License for the specific language governing permissions and
12 # limitations under the License.
14 """Module defining SearchGoalTuple class."""
16 from collections.abc import Iterator
17 from dataclasses import dataclass
18 from typing import Tuple
20 from .search_goal import SearchGoal
23 @dataclass(frozen=True)
24 class SearchGoalTuple:
25 """Container class holding multiple search goals.
27 Just a convenience for checking their number and types.
30 goals: Tuple[SearchGoal, ...]
31 """Goals extracted from user-provided Iterable of search goals."""
33 def __post_init__(self) -> None:
34 """Check type and number of search goals.
36 :raises ValueError: If there are no goals.
37 :raises TypeError: If a goal is not a SearchGoal.
39 super().__setattr__("goals", tuple(self.goals))
41 raise ValueError(f"Cannot be empty: {self.goals}")
42 for goal in self.goals:
43 if not isinstance(goal, SearchGoal):
44 raise TypeError(f"Must be a SearchGoal instance: {goal}")
45 copied = list(self.goals)
46 deduplicated = set(self.goals)
48 if goal not in deduplicated:
49 raise ValueError(f"Duplicate goal: {goal}")
50 deduplicated.remove(goal)
52 raise ValueError(f"Error processing goals: {deduplicated}")
54 def __iter__(self) -> Iterator[SearchGoal]:
55 """Enable itertion over goals.
57 :returns: Iterator iteratinc over contained goals.
58 :rtype: Iterator[SearchGoal]
60 return iter(self.goals)