Coverage for pyTooling/CLIAbstraction/KeyValueFlag.py: 88%
66 statements
« prev ^ index » next coverage.py v7.15.4, created at 2026-08-22 21:29 +0000
« prev ^ index » next coverage.py v7.15.4, created at 2026-08-22 21:29 +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"""
33Flag arguments represent simple boolean values by being present or absent.
35.. seealso::
37 :mod:`~pyTooling.CLIAbstraction.BooleanFlag`
38 |rarr| For flags with a different pattern based on the boolean value itself.
39 :mod:`~pyTooling.CLIAbstraction.ValuedFlag`
40 |rarr| For flags with a value.
41 :class:`~pyTooling.CLIAbstraction.OptionalValuedFlag.OptionalValuedFlag`
42 |rarr| For flags that have an optional value.
43"""
44from typing import Union, Iterable, cast, Any, Optional as Nullable
45from pyTooling.Decorators import export
46from pyTooling.MetaClasses import abstractclass
47from pyTooling.Common import getFullyQualifiedName
48from pyTooling.CLIAbstraction.Argument import NamedAndValuedArgument
51@export
52@abstractclass
53class NamedKeyValuePairsArgument(NamedAndValuedArgument[str], pattern="{0}{1}={2}"):
54 """
55 Class and base-class for all KeyValueFlag classes, which represents a flag argument with key and value
56 (key-value-pairs).
58 An optional valued flag is a flag name followed by a value. The default delimiter sign is equal (``=``). Name and
59 value are passed as one argument to the executable even if the delimiter sign is a whitespace character. If the value
60 is None, no delimiter sign and value is passed.
62 **Example:**
64 * ``-gWidth=100``
65 """
67 def __init_subclass__(cls, *args: Any, name: Nullable[str] = None, pattern: str = "{0}{1}={2}", **kwargs: Any) -> None:
68 """
69 This method is called when a class is derived.
71 :param args: Any positional arguments.
72 :param name: Optional, name of the CLI argument.
73 :param pattern: Optional, this pattern is used to format an argument. |br|
74 Default: ``"{0}{1}={2}"``.
75 :param kwargs: Any keyword argument.
76 """
77 kwargs["name"] = name
78 kwargs["pattern"] = pattern
79 super().__init_subclass__(*args, **kwargs)
81 def __init__(self, keyValuePairs: dict[str, str]) -> None:
82 """
83 Initialize the argument with a mapping of key-value-pairs, each rendered as its own command line element.
85 :param keyValuePairs: Key-value-pairs of the argument.
86 :raises TypeError: If a key or a value is not a string.
87 """
88 super().__init__({})
90 for key, value in keyValuePairs.items():
91 if not isinstance(key, str): 91 ↛ 92line 91 didn't jump to line 92 because the condition on line 91 was never true
92 ex = TypeError(f"Parameter 'keyValuePairs' contains a pair, where the key is not of type 'str'.")
93 ex.add_note(f"Got type '{getFullyQualifiedName(key)}'.")
94 raise ex
95 elif not isinstance(value, str): 95 ↛ 96line 95 didn't jump to line 96 because the condition on line 95 was never true
96 ex = TypeError(f"Parameter 'keyValuePairs' contains a pair, where the value is not of type 'str'.")
97 ex.add_note(f"Got type '{getFullyQualifiedName(value)}'.")
98 raise ex
100 self._value[key] = value
102 @property
103 def Value(self) -> dict[str, str]:
104 """
105 Property to access the internal key-value-pairs (:attr:`_value`).
107 .. note:: On assignment, the dictionary object is not replaced, but cleared and then reused by adding the given
108 pairs.
110 :returns: Internal dictionary of key-value-pairs.
111 :raises TypeError: If an assigned pair has a key or a value which is not of type string.
112 """
113 return self._value
115 @Value.setter
116 def Value(self, keyValuePairs: dict[str, str]) -> None:
117 innerDict = cast(dict[str, str], self._value)
118 innerDict.clear()
119 for key, value in keyValuePairs.items():
120 if not isinstance(key, str):
121 ex = TypeError(f"Parameter 'keyValuePairs' contains a pair, where the key is not of type 'str'.")
122 ex.add_note(f"Got type '{getFullyQualifiedName(key)}'.")
123 raise ex
124 elif not isinstance(value, str):
125 ex = TypeError(f"Parameter 'keyValuePairs' contains a pair, where the value is not of type 'str'.")
126 ex.add_note(f"Got type '{getFullyQualifiedName(value)}'.")
127 raise ex
129 innerDict[key] = value
131 def AsArgument(self) -> Union[str, Iterable[str]]:
132 """
133 Convert this argument instance to a string representation with proper escaping using the matching pattern based on
134 the internal name.
136 :returns: Formatted argument.
137 :raises ValueError: If internal name is None.
138 """
139 if self._name is None: 139 ↛ 140line 139 didn't jump to line 140 because the condition on line 139 was never true
140 raise ValueError(f"Internal value '_name' is None.")
142 return [self._pattern.format(self._name, key, value) for key, value in self._value.items()]
145@export
146@abstractclass
147class ShortKeyValueFlag(NamedKeyValuePairsArgument, pattern="-{0}{1}={2}"):
148 """
149 Represents a :py:class:`NamedKeyValueFlagArgument` with a single dash in front of the switch name.
151 **Example:**
153 * ``-DDEBUG=TRUE``
154 """
156 def __init_subclass__(cls, *args: Any, name: Nullable[str] = None, pattern: str = "-{0}{1}={2}", **kwargs: Any) -> None:
157 """
158 This method is called when a class is derived.
160 :param args: Any positional arguments.
161 :param name: Optional, name of the CLI argument.
162 :param pattern: Optional, this pattern is used to format an argument. |br|
163 Default: ``"-{0}{1}={2}"``.
164 :param kwargs: Any keyword argument.
165 """
166 kwargs["name"] = name
167 kwargs["pattern"] = pattern
168 super().__init_subclass__(*args, **kwargs)
171@export
172@abstractclass
173class LongKeyValueFlag(NamedKeyValuePairsArgument, pattern="--{0}{1}={2}"):
174 """
175 Represents a :py:class:`NamedKeyValueFlagArgument` with a double dash in front of the switch name.
177 **Example:**
179 * ``--DDEBUG=TRUE``
180 """
182 def __init_subclass__(cls, *args: Any, name: Nullable[str] = None, pattern: str = "--{0}{1}={2}", **kwargs: Any) -> None:
183 """
184 This method is called when a class is derived.
186 :param args: Any positional arguments.
187 :param name: Optional, name of the CLI argument.
188 :param pattern: Optional, this pattern is used to format an argument. |br|
189 Default: ``"--{0}{1}={2}"``.
190 :param kwargs: Any keyword argument.
191 """
192 kwargs["name"] = name
193 kwargs["pattern"] = pattern
194 super().__init_subclass__(*args, **kwargs)
197@export
198@abstractclass
199class WindowsKeyValueFlag(NamedKeyValuePairsArgument, pattern="/{0}:{1}={2}"):
200 """
201 Represents a :py:class:`NamedKeyValueFlagArgument` with a double dash in front of the switch name.
203 **Example:**
205 * ``--DDEBUG=TRUE``
206 """
208 def __init_subclass__(cls, *args: Any, name: Nullable[str] = None, pattern: str = "/{0}:{1}={2}", **kwargs: Any) -> None:
209 """
210 This method is called when a class is derived.
212 :param args: Any positional arguments.
213 :param name: Optional, name of the CLI argument.
214 :param pattern: Optional, this pattern is used to format an argument. |br|
215 Default: ``"/{0}:{1}={2}"``.
216 :param kwargs: Any keyword argument.
217 """
218 kwargs["name"] = name
219 kwargs["pattern"] = pattern
220 super().__init_subclass__(*args, **kwargs)