Coverage for klayout_pex/util/multiple_choice.py: 70%
27 statements
« prev ^ index » next coverage.py v7.6.9, created at 2024-12-17 17:24 +0000
« prev ^ index » next coverage.py v7.6.9, created at 2024-12-17 17:24 +0000
1#
2# --------------------------------------------------------------------------------
3# SPDX-FileCopyrightText: 2024 Martin Jan Köhler and Harald Pretl
4# Johannes Kepler University, Institute for Integrated Circuits.
5#
6# This file is part of KPEX
7# (see https://github.com/martinjankoehler/klayout-pex).
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# SPDX-License-Identifier: GPL-3.0-or-later
22# --------------------------------------------------------------------------------
23#
24from __future__ import annotations
25from typing import *
28class MultipleChoicePattern:
29 def __init__(self, pattern: str):
30 """
31 Multiple Choice pattern, allows blacklisting and whitelisting.
32 For example, given a list of dielectric, let the user decide which of them to include or exclude.
33 Allowed patterns:
34 - all (default): complete list of choices included
35 - none: no choices included at all
36 - +dielname: include choice named 'dielname'
37 - -dielname: exclude choice named 'dielname'
38 Examples:
39 - all,-nild5,-nild6
40 - include all dielectrics except nild5 and nild6
41 - none,+nild5,+capild
42 - include only dielectrics named nild5 and capild
43 """
44 self.pattern = pattern
46 components = pattern.split(sep=',')
47 components = [c.lower().strip() for c in components]
48 self.has_all = 'all' in components
49 self.has_none = 'none' in components
50 self.included = [c[1:] for c in components if c.startswith('+')]
51 self.excluded = [c[1:] for c in components if c.startswith('-')]
52 if self.has_none and self.has_all:
53 raise ValueError("Multiple choice pattern can't have both subpatterns all and none")
54 if self.has_none and len(self.excluded) >= 1:
55 raise ValueError("Multiple choice pattern based on none can only have inclusive (+) subpatterns")
56 if self.has_all and len(self.included) >= 1:
57 raise ValueError("Multiple choice pattern based on all can only have exclusive (-) subpatterns")
59 def filter(self, choices: List[str]) -> List[str]:
60 if self.has_all:
61 return [c for c in choices if c not in self.excluded]
62 return [c for c in choices if c in self.included]
64 def is_included(self, choice: str) -> bool:
65 if self.has_none:
66 return choice in self.included
67 if self.has_all:
68 return choice not in self.excluded
69 return False