Coverage for pyTooling / CLIAbstraction / BooleanFlag.py: 97%
59 statements
« prev ^ index » next coverage.py v7.13.1, created at 2026-01-08 23:46 +0000
« prev ^ index » next coverage.py v7.13.1, created at 2026-01-08 23:46 +0000
1# ==================================================================================================================== #
2# _____ _ _ ____ _ ___ _ _ _ _ _ #
3# _ __ _ |_ _|__ ___ | (_)_ __ __ _ / ___| | |_ _| / \ | |__ ___| |_ _ __ __ _ ___| |_(_) ___ _ __ #
4# | '_ \| | | || |/ _ \ / _ \| | | '_ \ / _` || | | | | | / _ \ | '_ \/ __| __| '__/ _` |/ __| __| |/ _ \| '_ \ #
5# | |_) | |_| || | (_) | (_) | | | | | | (_| || |___| |___ | | / ___ \| |_) \__ \ |_| | | (_| | (__| |_| | (_) | | | | #
6# | .__/ \__, ||_|\___/ \___/|_|_|_| |_|\__, (_)____|_____|___/_/ \_\_.__/|___/\__|_| \__,_|\___|\__|_|\___/|_| |_| #
7# |_| |___/ |___/ #
8# ==================================================================================================================== #
9# Authors: #
10# Patrick Lehmann #
11# #
12# License: #
13# ==================================================================================================================== #
14# Copyright 2017-2026 Patrick Lehmann - Bötzingen, Germany #
15# Copyright 2014-2016 Technische Universität Dresden - Germany, Chair of VLSI-Design, Diagnostics and Architecture #
16# #
17# Licensed under the Apache License, Version 2.0 (the "License"); #
18# you may not use this file except in compliance with the License. #
19# You may obtain a copy of the License at #
20# #
21# http://www.apache.org/licenses/LICENSE-2.0 #
22# #
23# Unless required by applicable law or agreed to in writing, software #
24# distributed under the License is distributed on an "AS IS" BASIS, #
25# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. #
26# See the License for the specific language governing permissions and #
27# limitations under the License. #
28# #
29# SPDX-License-Identifier: Apache-2.0 #
30# ==================================================================================================================== #
31#
32"""
33Boolean flags are arguments with a name and different pattern for a positive (``True``) and negative (``False``) value.
35.. seealso::
37 * For simple flags. |br|
38 |rarr| :mod:`~pyTooling.CLIAbstraction.Flag`
39 * For flags with a value. |br|
40 |rarr| :mod:`~pyTooling.CLIAbstraction.ValuedFlag`
41 * For flags that have an optional value. |br|
42 |rarr| :mod:`~pyTooling.CLIAbstraction.NamedOptionalValuedFlag`
43"""
44from typing import ClassVar, Union, Iterable, Any, Optional as Nullable, Self
46try:
47 from pyTooling.Decorators import export
48 from pyTooling.CLIAbstraction.Argument import NamedArgument, ValuedArgument
49except (ImportError, ModuleNotFoundError): # pragma: no cover
50 print("[pyTooling.Versioning] Could not import from 'pyTooling.*'!")
52 try:
53 from Decorators import export
54 from CLIAbstraction.Argument import NamedArgument, ValuedArgument
55 except (ImportError, ModuleNotFoundError) as ex: # pragma: no cover
56 print("[pyTooling.Versioning] Could not import directly!")
57 raise ex
60@export
61class BooleanFlag(NamedArgument, ValuedArgument):
62 """
63 Class and base-class for all BooleanFlag classes, which represents a flag argument with different pattern for an
64 enabled/positive (``True``) or disabled/negative (``False``) state.
66 When deriving a subclass from an abstract BooleanFlag class, the parameters ``pattern`` and ``falsePattern`` are
67 expected.
69 **Example:**
71 * True: ``with-checks``
72 * False: ``without-checks``
73 """
75 _falsePattern: ClassVar[str]
77 def __init_subclass__(cls, *args: Any, name: Nullable[str] = None, pattern: str = "with-{0}", falsePattern: str = "without-{0}", **kwargs: Any) -> None:
78 """
79 This method is called when a class is derived.
81 :param args: Any positional arguments.
82 :param pattern: This pattern is used to format an argument when the value is ``True``. |br|
83 Default: ``"with-{0}"``.
84 :param falsePattern: This pattern is used to format an argument when the value is ``False``. |br|
85 Default: ``"without-{0}"``.
86 :param kwargs: Any keyword argument.
87 """
88 kwargs["name"] = name
89 kwargs["pattern"] = pattern
90 super().__init_subclass__(*args, **kwargs)
91 del kwargs["name"]
92 del kwargs["pattern"]
93 ValuedArgument.__init_subclass__(*args, **kwargs)
95 cls._falsePattern = falsePattern
97 # TODO: the whole class should be marked as abstract
98 # TODO: a decorator should solve the issue and overwrite the __new__ method with that code
99 def __new__(cls, *args: Any, **kwargs: Any) -> Self:
100 """
101 Check if this class was directly instantiated without being derived to a subclass. If so, raise an error.
103 :param args: Any positional arguments.
104 :param kwargs: Any keyword arguments.
105 :raises TypeError: When this class gets directly instantiated without being derived to a subclass.
106 """
107 if cls is BooleanFlag:
108 raise TypeError(f"Class '{cls.__name__}' is abstract.")
109 return super().__new__(cls, *args, **kwargs)
111 def __init__(self, value: bool) -> None:
112 """Initializes a BooleanFlag instance.
114 :param value: Initial value set for this argument instance.
115 """
116 ValuedArgument.__init__(self, value)
118 def AsArgument(self) -> Union[str, Iterable[str]]:
119 """Convert this argument instance to a string representation with proper escaping using the matching pattern based
120 on the internal name and value.
122 :return: Formatted argument.
123 :raises ValueError: If internal name is None.
124 """
125 if self._name is None: 125 ↛ 126line 125 didn't jump to line 126 because the condition on line 125 was never true
126 raise ValueError(f"Internal value '_name' is None.")
128 pattern = self._pattern if self._value is True else self._falsePattern
129 return pattern.format(self._name)
132@export
133class ShortBooleanFlag(BooleanFlag, pattern="-with-{0}", falsePattern="-without-{0}"):
134 """Represents a :py:class:`BooleanFlag` with a single dash.
136 **Example:**
138 * True: ``-with-checks``
139 * False: ``-without-checks``
140 """
142 def __init_subclass__(cls, *args: Any, name: Nullable[str] = None, pattern: str = "-with-{0}", falsePattern: str = "-without-{0}", **kwargs: Any) -> None:
143 """
144 This method is called when a class is derived.
146 :param args: Any positional arguments.
147 :param pattern: This pattern is used to format an argument when the value is ``True``. |br|
148 Default: ``"-with-{0}"``.
149 :param falsePattern: This pattern is used to format an argument when the value is ``False``. |br|
150 Default: ``"-without-{0}"``.
151 :param kwargs: Any keyword argument.
152 """
153 kwargs["name"] = name
154 kwargs["pattern"] = pattern
155 kwargs["falsePattern"] = falsePattern
156 super().__init_subclass__(*args, **kwargs)
158 # TODO: the whole class should be marked as abstract
159 # TODO: a decorator should solve the issue and overwrite the __new__ method with that code
160 def __new__(cls, *args: Any, **kwargs: Any) -> Self:
161 """
162 Check if this class was directly instantiated without being derived to a subclass. If so, raise an error.
164 :param args: Any positional arguments.
165 :param kwargs: Any keyword arguments.
166 :raises TypeError: When this class gets directly instantiated without being derived to a subclass.
167 """
168 if cls is ShortBooleanFlag:
169 raise TypeError(f"Class '{cls.__name__}' is abstract.")
170 return super().__new__(cls, *args, **kwargs)
173@export
174class LongBooleanFlag(BooleanFlag, pattern="--with-{0}", falsePattern="--without-{0}"):
175 """Represents a :py:class:`BooleanFlag` with a double dash.
177 **Example:**
179 * True: ``--with-checks``
180 * False: ``--without-checks``
181 """
183 def __init_subclass__(cls, *args: Any, name: Nullable[str] = None, pattern: str = "--with-{0}", falsePattern: str = "--without-{0}", **kwargs: Any) -> None:
184 """
185 This method is called when a class is derived.
187 :param args: Any positional arguments.
188 :param pattern: This pattern is used to format an argument when the value is ``True``. |br|
189 Default: ``"--with-{0}"``.
190 :param falsePattern: This pattern is used to format an argument when the value is ``False``. |br|
191 Default: ``"--without-{0}"``.
192 :param kwargs: Any keyword argument.
193 """
194 kwargs["name"] = name
195 kwargs["pattern"] = pattern
196 kwargs["falsePattern"] = falsePattern
197 super().__init_subclass__(*args, **kwargs)
199 # TODO: the whole class should be marked as abstract
200 # TODO: a decorator should solve the issue and overwrite the __new__ method with that code
201 def __new__(cls, *args: Any, **kwargs: Any) -> Self:
202 """
203 Check if this class was directly instantiated without being derived to a subclass. If so, raise an error.
205 :param args: Any positional arguments.
206 :param kwargs: Any keyword arguments.
207 :raises TypeError: When this class gets directly instantiated without being derived to a subclass.
208 """
209 if cls is LongBooleanFlag:
210 raise TypeError(f"Class '{cls.__name__}' is abstract.")
211 return super().__new__(cls, *args, **kwargs)
214@export
215class WindowsBooleanFlag(BooleanFlag, pattern="/with-{0}", falsePattern="/without-{0}"):
216 """Represents a :py:class:`BooleanFlag` with a slash.
218 **Example:**
220 * True: ``/with-checks``
221 * False: ``/without-checks``
222 """
224 def __init_subclass__(cls, *args: Any, name: Nullable[str] = None, pattern: str = "/with-{0}", falsePattern: str = "/without-{0}", **kwargs: Any) -> None:
225 """
226 This method is called when a class is derived.
228 :param args: Any positional arguments.
229 :param pattern: This pattern is used to format an argument when the value is ``True``. |br|
230 Default: ``"/with-{0}"``.
231 :param falsePattern: This pattern is used to format an argument when the value is ``False``. |br|
232 Default: ``"/without-{0}"``.
233 :param kwargs: Any keyword argument.
234 """
235 kwargs["name"] = name
236 kwargs["pattern"] = pattern
237 kwargs["falsePattern"] = falsePattern
238 super().__init_subclass__(*args, **kwargs)
240 # TODO: the whole class should be marked as abstract
241 # TODO: a decorator should solve the issue and overwrite the __new__ method with that code
242 def __new__(cls, *args: Any, **kwargs: Any) -> Self:
243 """
244 Check if this class was directly instantiated without being derived to a subclass. If so, raise an error.
246 :param args: Any positional arguments.
247 :param kwargs: Any keyword arguments.
248 :raises TypeError: When this class gets directly instantiated without being derived to a subclass.
249 """
250 if cls is WindowsBooleanFlag:
251 raise TypeError(f"Class '{cls.__name__}' is abstract.")
252 return super().__new__(cls, *args, **kwargs)