Coverage for pyTooling / CallByRef / __init__.py: 90%
239 statements
« prev ^ index » next coverage.py v7.13.4, created at 2026-02-20 22:29 +0000
« prev ^ index » next coverage.py v7.13.4, created at 2026-02-20 22: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# #
16# Licensed under the Apache License, Version 2.0 (the "License"); #
17# you may not use this file except in compliance with the License. #
18# You may obtain a copy of the License at #
19# #
20# http://www.apache.org/licenses/LICENSE-2.0 #
21# #
22# Unless required by applicable law or agreed to in writing, software #
23# distributed under the License is distributed on an "AS IS" BASIS, #
24# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. #
25# See the License for the specific language governing permissions and #
26# limitations under the License. #
27# #
28# SPDX-License-Identifier: Apache-2.0 #
29# ==================================================================================================================== #
30#
31"""
32Auxiliary classes to implement call-by-reference.
34.. hint::
36 See :ref:`high-level help <COMMON/CallByRef>` for explanations and usage examples.
37"""
38from decimal import Decimal
39from typing import Any, Generic, TypeVar, Optional as Nullable
41from pyTooling.Decorators import export
42from pyTooling.MetaClasses import ExtendedType
45T = TypeVar("T")
48@export
49class CallByRefParam(Generic[T], metaclass=ExtendedType, slots=True):
50 """
51 Implements a *call-by-reference* parameter.
53 .. seealso::
55 * :class:`CallByRefBoolParam` |br|
56 |rarr| A special *call-by-reference* implementation for boolean reference types.
57 * :class:`CallByRefIntParam` |br|
58 |rarr| A special *call-by-reference* implementation for integer reference types.
59 """
61 Value: T #: internal value
63 def __init__(self, value: Nullable[T] = None) -> None:
64 """Constructs a *call-by-reference* object for any type.
66 :param value: The value to be set as an initial value.
67 """
68 self.Value = value
70 def __ilshift__(self, other: T) -> 'CallByRefParam[T]': # Starting with Python 3.11+, use typing.Self as return type
71 """Assigns a value to the *call-by-reference* object.
73 :param other: The value to be assigned to this *call-by-reference* object.
74 :returns: Itself.
75 """
76 self.Value = other
77 return self
79 # binary operators - comparison
80 def __eq__(self, other: Any) -> bool:
81 """
82 Compare a CallByRefParam wrapped value with another instances (CallbyRefParam) or non-wrapped value for equality.
84 :param other: Parameter to compare against.
85 :returns: ``True``, if both values are equal.
86 """
87 if isinstance(other, CallByRefParam): 87 ↛ 88line 87 didn't jump to line 88 because the condition on line 87 was never true
88 return self.Value == other.Value
89 else:
90 return self.Value == other
92 def __ne__(self, other) -> bool:
93 """
94 Compare a CallByRefParam wrapped value with another instances (CallbyRefParam) or non-wrapped value for inequality.
96 :param other: Parameter to compare against.
97 :returns: ``True``, if both values are unequal.
98 """
99 if isinstance(other, CallByRefParam): 99 ↛ 100line 99 didn't jump to line 100 because the condition on line 99 was never true
100 return self.Value != other.Value
101 else:
102 return self.Value != other
104 # Type conversion operators
105 def __repr__(self) -> str:
106 """
107 Returns the wrapped object's string representation.
109 :returns: The string representation of the wrapped value.
110 """
111 return repr(self.Value)
113 def __str__(self) -> str:
114 """
115 Returns the wrapped object's string equivalent.
117 :returns: The string equivalent of the wrapped value.
118 """
119 return str(self.Value)
122@export
123class CallByRefBoolParam(CallByRefParam):
124 """A special *call-by-reference* implementation for boolean reference types."""
126 # Binary operators - comparison
127 def __eq__(self, other: Any) -> bool:
128 """
129 Compare a CallByRefBoolParam wrapped boolean value with another instances (CallByRefBoolParam) or non-wrapped boolean value for equality.
131 :param other: Parameter to compare against.
132 :returns: ``True``, if both values are equal.
133 :raises TypeError: If parameter ``other`` is not of type :class:`bool` or :class:`CallByRefBoolParam`.
134 """
135 if isinstance(other, bool):
136 return self.Value == other
137 elif isinstance(other, CallByRefBoolParam): 137 ↛ 138line 137 didn't jump to line 138 because the condition on line 137 was never true
138 return self.Value == other.Value
139 else:
140 ex = TypeError(f"Second operand of type '{other.__class__.__name__}' is not supported by == operator.")
141 ex.add_note("Supported types for second operand: bool, CallByRefBoolParam")
142 raise ex
144 def __ne__(self, other) -> bool:
145 """
146 Compare a CallByRefBoolParam wrapped boolean value with another instances (CallByRefBoolParam) or non-wrapped boolean value for inequality.
148 :param other: Parameter to compare against.
149 :returns: ``True``, if both values are unequal.
150 :raises TypeError: If parameter ``other`` is not of type :class:`bool` or :class:`CallByRefBoolParam`.
151 """
152 if isinstance(other, bool):
153 return self.Value != other
154 elif isinstance(other, CallByRefBoolParam): 154 ↛ 155line 154 didn't jump to line 155 because the condition on line 154 was never true
155 return self.Value != other.Value
156 else:
157 ex = TypeError(f"Second operand of type '{other.__class__.__name__}' is not supported by != operator.")
158 ex.add_note(f"Supported types for second operand: bool, CallByRefBoolParam")
159 raise ex
161 # Type conversion operators
162 def __bool__(self) -> bool:
163 """
164 Type conversion to :class:`bool`.
166 :returns: The wrapped value.
167 """
168 return self.Value
170 def __int__(self) -> int:
171 """
172 Type conversion to :class:`int`.
174 :returns: The integer representation of the wrapped boolean value.
175 """
176 return int(self.Value)
179@export
180class CallByRefIntParam(CallByRefParam):
181 """A special *call-by-reference* implementation for integer reference types."""
183 # Unary operators
184 def __neg__(self) -> int:
185 """Negate: -self."""
186 return -self.Value
188 def __pos__(self) -> int:
189 """Positive: +self."""
190 return +self.Value
192 def __invert__(self) -> int:
193 """Invert: ~self."""
194 return ~self.Value
196 # Binary operators - logical
197 def __and__(self, other: Any) -> int:
198 """And: self & other."""
199 if isinstance(other, int):
200 return self.Value & other
201 else:
202 ex = TypeError(f"Second operand of type '{other.__class__.__name__}' is not supported by and operator.")
203 ex.add_note(f"Supported types for second operand: int")
204 raise ex
206 def __or__(self, other: Any) -> int:
207 """Or: self | other."""
208 if isinstance(other, int):
209 return self.Value | other
210 else:
211 ex = TypeError(f"Second operand of type '{other.__class__.__name__}' is not supported by or operator.")
212 ex.add_note(f"Supported types for second operand: int")
213 raise ex
215 def __xor__(self, other: Any) -> int:
216 """Xor: self ^ other."""
217 if isinstance(other, int):
218 return self.Value ^ other
219 else:
220 ex = TypeError(f"Second operand of type '{other.__class__.__name__}' is not supported by xor operator.")
221 ex.add_note(f"Supported types for second operand: int")
222 raise ex
224 # Binary inplace operators
225 def __iand__(self, other: Any) -> 'CallByRefIntParam': # Starting with Python 3.11+, use typing.Self as return type
226 """Inplace and: self &= other."""
227 if isinstance(other, int):
228 self.Value &= other
229 return self
230 else:
231 ex = TypeError(f"Second operand of type '{other.__class__.__name__}' is not supported by &= operator.")
232 ex.add_note(f"Supported types for second operand: int")
233 raise ex
235 def __ior__(self, other: Any) -> 'CallByRefIntParam': # Starting with Python 3.11+, use typing.Self as return type
236 r"""Inplace or: self \|= other."""
237 if isinstance(other, int):
238 self.Value |= other
239 return self
240 else:
241 ex = TypeError(f"Second operand of type '{other.__class__.__name__}' is not supported by |= operator.")
242 ex.add_note(f"Supported types for second operand: int")
243 raise ex
245 def __ixor__(self, other: Any) -> 'CallByRefIntParam': # Starting with Python 3.11+, use typing.Self as return type
246 r"""Inplace or: self \|= other."""
247 if isinstance(other, int):
248 self.Value ^= other
249 return self
250 else:
251 ex = TypeError(f"Second operand of type '{other.__class__.__name__}' is not supported by ^= operator.")
252 ex.add_note(f"Supported types for second operand: int")
253 raise ex
255 # Binary operators - arithmetic
256 def __add__(self, other: Any) -> int:
257 """Addition: self + other."""
258 if isinstance(other, int):
259 return self.Value + other
260 else:
261 ex = TypeError(f"Second operand of type '{other.__class__.__name__}' is not supported by + operator.")
262 ex.add_note(f"Supported types for second operand: int")
263 raise ex
265 def __sub__(self, other: Any) -> int:
266 """Subtraction: self - other."""
267 if isinstance(other, int):
268 return self.Value - other
269 else:
270 ex = TypeError(f"Second operand of type '{other.__class__.__name__}' is not supported by - operator.")
271 ex.add_note(f"Supported types for second operand: int")
272 raise ex
274 def __truediv__(self, other: Any) -> int:
275 """Division: self / other."""
276 if isinstance(other, int):
277 return self.Value / other
278 else:
279 ex = TypeError(f"Second operand of type '{other.__class__.__name__}' is not supported by / operator.")
280 ex.add_note(f"Supported types for second operand: int")
281 raise ex
283 def __floordiv__(self, other: Any) -> int:
284 """Floor division: self // other."""
285 if isinstance(other, int):
286 return self.Value // other
287 else:
288 ex = TypeError(f"Second operand of type '{other.__class__.__name__}' is not supported by // operator.")
289 ex.add_note(f"Supported types for second operand: int")
290 raise ex
292 def __mul__(self, other: Any) -> int:
293 """Multiplication: self * other."""
294 if isinstance(other, int):
295 return self.Value * other
296 else:
297 ex = TypeError(f"Second operand of type '{other.__class__.__name__}' is not supported by * operator.")
298 ex.add_note(f"Supported types for second operand: int")
299 raise ex
301 def __mod__(self, other: Any) -> int:
302 """Modulo: self % other."""
303 if isinstance(other, int):
304 return self.Value % other
305 else:
306 ex = TypeError(f"Second operand of type '{other.__class__.__name__}' is not supported by % operator.")
307 ex.add_note(f"Supported types for second operand: int")
308 raise ex
310 def __pow__(self, other: Any) -> int:
311 """Power: self ** other."""
312 if isinstance(other, int):
313 return self.Value ** other
314 else:
315 ex = TypeError(f"Second operand of type '{other.__class__.__name__}' is not supported by ** operator.")
316 ex.add_note(f"Supported types for second operand: int")
317 raise ex
319 # Binary inplace operators - arithmetic
320 def __iadd__(self, other: Any) -> 'CallByRefIntParam':
321 """Addition: self += other."""
322 if isinstance(other, int):
323 self.Value += other
324 return self
325 else:
326 ex = TypeError(f"Second operand of type '{other.__class__.__name__}' is not supported by xor operator.")
327 ex.add_note(f"Supported types for second operand: int")
328 raise ex
330 def __isub__(self, other: Any) -> 'CallByRefIntParam':
331 """Subtraction: self -= other."""
332 if isinstance(other, int):
333 self.Value -= other
334 return self
335 else:
336 ex = TypeError(f"Second operand of type '{other.__class__.__name__}' is not supported by xor operator.")
337 ex.add_note(f"Supported types for second operand: int")
338 raise ex
340 def __idiv__(self, other: Any) -> 'CallByRefIntParam':
341 """Division: self /= other."""
342 if isinstance(other, int):
343 self.Value /= other
344 return self
345 else:
346 ex = TypeError(f"Second operand of type '{other.__class__.__name__}' is not supported by xor operator.")
347 ex.add_note(f"Supported types for second operand: int")
348 raise ex
350 def __ifloordiv__(self, other: Any) -> 'CallByRefIntParam':
351 """Floor division: self // other."""
352 if isinstance(other, int):
353 self.Value //= other
354 return self
355 else:
356 ex = TypeError(f"Second operand of type '{other.__class__.__name__}' is not supported by xor operator.")
357 ex.add_note(f"Supported types for second operand: int")
358 raise ex
360 def __imul__(self, other: Any) -> 'CallByRefIntParam':
361 r"""Multiplication: self \*= other."""
362 if isinstance(other, int):
363 self.Value *= other
364 return self
365 else:
366 ex = TypeError(f"Second operand of type '{other.__class__.__name__}' is not supported by xor operator.")
367 ex.add_note(f"Supported types for second operand: int")
368 raise ex
370 def __imod__(self, other: Any) -> 'CallByRefIntParam':
371 """Modulo: self %= other."""
372 if isinstance(other, int):
373 self.Value %= other
374 return self
375 else:
376 ex = TypeError(f"Second operand of type '{other.__class__.__name__}' is not supported by xor operator.")
377 ex.add_note(f"Supported types for second operand: int")
378 raise ex
380 def __ipow__(self, other: Any) -> 'CallByRefIntParam':
381 r"""Power: self \*\*= other."""
382 if isinstance(other, int):
383 self.Value **= other
384 return self
385 else:
386 ex = TypeError(f"Second operand of type '{other.__class__.__name__}' is not supported by xor operator.")
387 ex.add_note(f"Supported types for second operand: int")
388 raise ex
390 # Binary operators - comparison
391 def __eq__(self, other: Any) -> bool:
392 """
393 Compare a CallByRefIntParam wrapped integer value with another instances (CallByRefIntParam) or non-wrapped integer value for equality.
395 :param other: Parameter to compare against.
396 :returns: ``True``, if both values are equal.
397 :raises TypeError: If parameter ``other`` is not of type :class:`int`, :class:`float`, :class:`complex`, :class:`Decimal` or :class:`CallByRefParam`.
398 """
399 if isinstance(other, (int, float, complex, Decimal)) and not isinstance(other, bool):
400 return self.Value == other
401 elif isinstance(other, CallByRefIntParam): 401 ↛ 402line 401 didn't jump to line 402 because the condition on line 401 was never true
402 return self.Value == other.Value
403 else:
404 ex = TypeError(f"Second operand of type '{other.__class__.__name__}' is not supported by == operator.")
405 ex.add_note(f"Supported types for second operand: int, float, complex, Decimal, CallByRefIntParam")
406 raise ex
408 def __ne__(self, other) -> bool:
409 """
410 Compare a CallByRefIntParam wrapped integer value with another instances (CallByRefIntParam) or non-wrapped integer value for inequality.
412 :param other: Parameter to compare against.
413 :returns: ``True``, if both values are unequal.
414 :raises TypeError: If parameter ``other`` is not of type :class:`int`, :class:`float`, :class:`complex`, :class:`Decimal` or :class:`CallByRefParam`.
415 """
416 if isinstance(other, (int, float, complex, Decimal)) and not isinstance(other, bool):
417 return self.Value != other
418 elif isinstance(other, CallByRefIntParam): 418 ↛ 419line 418 didn't jump to line 419 because the condition on line 418 was never true
419 return self.Value != other.Value
420 else:
421 ex = TypeError(f"Second operand of type '{other.__class__.__name__}' is not supported by != operator.")
422 ex.add_note(f"Supported types for second operand: int, float, complex, Decimal, CallByRefIntParam")
423 raise ex
425 def __lt__(self, other: Any) -> bool:
426 """
427 Compare a CallByRefIntParam wrapped integer value with another instances (CallByRefIntParam) or non-wrapped integer value for less-than.
429 :param other: Parameter to compare against.
430 :returns: ``True``, if the wrapped value is less than the other value.
431 :raises TypeError: If parameter ``other`` is not of type :class:`int`, :class:`float`, :class:`complex`, :class:`Decimal` or :class:`CallByRefParam`.
432 """
433 if isinstance(other, (int, float, complex, Decimal)) and not isinstance(other, bool):
434 return self.Value < other
435 elif isinstance(other, CallByRefIntParam): 435 ↛ 436line 435 didn't jump to line 436 because the condition on line 435 was never true
436 return self.Value < other.Value
437 else:
438 ex = TypeError(f"Second operand of type '{other.__class__.__name__}' is not supported by < operator.")
439 ex.add_note(f"Supported types for second operand: int, float, complex, Decimal, CallByRefIntParam")
440 raise ex
442 def __le__(self, other: Any) -> bool:
443 """
444 Compare a CallByRefIntParam wrapped integer value with another instances (CallByRefIntParam) or non-wrapped integer value for less-than-or-equal.
446 :param other: Parameter to compare against.
447 :returns: ``True``, if the wrapped value is less than or equal the other value.
448 :raises TypeError: If parameter ``other`` is not of type :class:`int`, :class:`float`, :class:`complex`, :class:`Decimal` or :class:`CallByRefParam`.
449 """
450 if isinstance(other, (int, float, complex, Decimal)) and not isinstance(other, bool):
451 return self.Value <= other
452 elif isinstance(other, CallByRefIntParam): 452 ↛ 453line 452 didn't jump to line 453 because the condition on line 452 was never true
453 return self.Value <= other.Value
454 else:
455 ex = TypeError(f"Second operand of type '{other.__class__.__name__}' is not supported by <= operator.")
456 ex.add_note(f"Supported types for second operand: int, float, complex, Decimal, CallByRefIntParam")
457 raise ex
459 def __gt__(self, other: Any) -> bool:
460 """
461 Compare a CallByRefIntParam wrapped integer value with another instances (CallByRefIntParam) or non-wrapped integer value for geater-than.
463 :param other: Parameter to compare against.
464 :returns: ``True``, if the wrapped value is greater than the other value.
465 :raises TypeError: If parameter ``other`` is not of type :class:`int`, :class:`float`, :class:`complex`, :class:`Decimal` or :class:`CallByRefParam`.
466 """
467 if isinstance(other, (int, float, complex, Decimal)) and not isinstance(other, bool):
468 return self.Value > other
469 elif isinstance(other, CallByRefIntParam): 469 ↛ 470line 469 didn't jump to line 470 because the condition on line 469 was never true
470 return self.Value > other.Value
471 else:
472 ex = TypeError(f"Second operand of type '{other.__class__.__name__}' is not supported by > operator.")
473 ex.add_note(f"Supported types for second operand: int, float, complex, Decimal, CallByRefIntParam")
474 raise ex
476 def __ge__(self, other: Any) -> bool:
477 """
478 Compare a CallByRefIntParam wrapped integer value with another instances (CallByRefIntParam) or non-wrapped integer value for greater-than-or-equal.
480 :param other: Parameter to compare against.
481 :returns: ``True``, if the wrapped value is greater than or equal the other value.
482 :raises TypeError: If parameter ``other`` is not of type :class:`int`, :class:`float`, :class:`complex`, :class:`Decimal` or :class:`CallByRefParam`.
483 """
484 if isinstance(other, (int, float, complex, Decimal)) and not isinstance(other, bool):
485 return self.Value >= other
486 elif isinstance(other, CallByRefIntParam): 486 ↛ 487line 486 didn't jump to line 487 because the condition on line 486 was never true
487 return self.Value >= other.Value
488 else:
489 ex = TypeError(f"Second operand of type '{other.__class__.__name__}' is not supported by >= operator.")
490 ex.add_note(f"Supported types for second operand: int, float, complex, Decimal, CallByRefIntParam")
491 raise ex
493 # Type conversion operators
494 def __bool__(self) -> bool:
495 """
496 Type conversion to :class:`bool`.
498 :returns: The boolean representation of the wrapped integer value.
499 """
500 return bool(self.Value)
502 def __int__(self) -> int:
503 """
504 Type conversion to :class:`int`.
506 :returns: The wrapped value."""
507 return self.Value
509 def __float__(self) -> float:
510 """
511 Type conversion to :class:`float`.
513 :returns: The float representation of the wrapped integer value.
514 """
515 return float(self.Value)