Coverage for pyTooling / CallByRef / __init__.py: 90%
240 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# #
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
41try:
42 from pyTooling.Decorators import export
43 from pyTooling.MetaClasses import ExtendedType
44except (ImportError, ModuleNotFoundError): # pragma: no cover
45 print("[pyTooling.CallByRef] Could not import from 'pyTooling.*'!")
47 try:
48 from Decorators import export
49 from MetaClasses import ExtendedType
50 except (ImportError, ModuleNotFoundError) as ex: # pragma: no cover
51 print("[pyTooling.CallByRef] Could not import directly!")
52 raise ex
55T = TypeVar("T")
58@export
59class CallByRefParam(Generic[T], metaclass=ExtendedType, slots=True):
60 """
61 Implements a *call-by-reference* parameter.
63 .. seealso::
65 * :class:`CallByRefBoolParam` |br|
66 |rarr| A special *call-by-reference* implementation for boolean reference types.
67 * :class:`CallByRefIntParam` |br|
68 |rarr| A special *call-by-reference* implementation for integer reference types.
69 """
71 Value: T #: internal value
73 def __init__(self, value: Nullable[T] = None) -> None:
74 """Constructs a *call-by-reference* object for any type.
76 :param value: The value to be set as an initial value.
77 """
78 self.Value = value
80 def __ilshift__(self, other: T) -> 'CallByRefParam[T]': # Starting with Python 3.11+, use typing.Self as return type
81 """Assigns a value to the *call-by-reference* object.
83 :param other: The value to be assigned to this *call-by-reference* object.
84 :returns: Itself.
85 """
86 self.Value = other
87 return self
89 # binary operators - comparison
90 def __eq__(self, other: Any) -> bool:
91 """
92 Compare a CallByRefParam wrapped value with another instances (CallbyRefParam) or non-wrapped value for equality.
94 :param other: Parameter to compare against.
95 :returns: ``True``, if both values are equal.
96 """
97 if isinstance(other, CallByRefParam): 97 ↛ 98line 97 didn't jump to line 98 because the condition on line 97 was never true
98 return self.Value == other.Value
99 else:
100 return self.Value == other
102 def __ne__(self, other) -> bool:
103 """
104 Compare a CallByRefParam wrapped value with another instances (CallbyRefParam) or non-wrapped value for inequality.
106 :param other: Parameter to compare against.
107 :returns: ``True``, if both values are unequal.
108 """
109 if isinstance(other, CallByRefParam): 109 ↛ 110line 109 didn't jump to line 110 because the condition on line 109 was never true
110 return self.Value != other.Value
111 else:
112 return self.Value != other
114 # Type conversion operators
115 def __repr__(self) -> str:
116 """
117 Returns the wrapped object's string representation.
119 :returns: The string representation of the wrapped value.
120 """
121 return repr(self.Value)
123 def __str__(self) -> str:
124 """
125 Returns the wrapped object's string equivalent.
127 :returns: The string equivalent of the wrapped value.
128 """
129 return str(self.Value)
132@export
133class CallByRefBoolParam(CallByRefParam):
134 """A special *call-by-reference* implementation for boolean reference types."""
136 # Binary operators - comparison
137 def __eq__(self, other: Any) -> bool:
138 """
139 Compare a CallByRefBoolParam wrapped boolean value with another instances (CallByRefBoolParam) or non-wrapped boolean value for equality.
141 :param other: Parameter to compare against.
142 :returns: ``True``, if both values are equal.
143 :raises TypeError: If parameter ``other`` is not of type :class:`bool` or :class:`CallByRefBoolParam`.
144 """
145 if isinstance(other, bool):
146 return self.Value == other
147 elif isinstance(other, CallByRefBoolParam): 147 ↛ 148line 147 didn't jump to line 148 because the condition on line 147 was never true
148 return self.Value == other.Value
149 else:
150 ex = TypeError(f"Second operand of type '{other.__class__.__name__}' is not supported by == operator.")
151 ex.add_note("Supported types for second operand: bool, CallByRefBoolParam")
152 raise ex
154 def __ne__(self, other) -> bool:
155 """
156 Compare a CallByRefBoolParam wrapped boolean value with another instances (CallByRefBoolParam) or non-wrapped boolean value for inequality.
158 :param other: Parameter to compare against.
159 :returns: ``True``, if both values are unequal.
160 :raises TypeError: If parameter ``other`` is not of type :class:`bool` or :class:`CallByRefBoolParam`.
161 """
162 if isinstance(other, bool):
163 return self.Value != other
164 elif isinstance(other, CallByRefBoolParam): 164 ↛ 165line 164 didn't jump to line 165 because the condition on line 164 was never true
165 return self.Value != other.Value
166 else:
167 ex = TypeError(f"Second operand of type '{other.__class__.__name__}' is not supported by != operator.")
168 ex.add_note(f"Supported types for second operand: bool, CallByRefBoolParam")
169 raise ex
171 # Type conversion operators
172 def __bool__(self) -> bool:
173 """
174 Type conversion to :class:`bool`.
176 :returns: The wrapped value.
177 """
178 return self.Value
180 def __int__(self) -> int:
181 """
182 Type conversion to :class:`int`.
184 :returns: The integer representation of the wrapped boolean value.
185 """
186 return int(self.Value)
189@export
190class CallByRefIntParam(CallByRefParam):
191 """A special *call-by-reference* implementation for integer reference types."""
193 # Unary operators
194 def __neg__(self) -> int:
195 """Negate: -self."""
196 return -self.Value
198 def __pos__(self) -> int:
199 """Positive: +self."""
200 return +self.Value
202 def __invert__(self) -> int:
203 """Invert: ~self."""
204 return ~self.Value
206 # Binary operators - logical
207 def __and__(self, other: Any) -> int:
208 """And: self & other."""
209 if isinstance(other, int):
210 return self.Value & other
211 else:
212 ex = TypeError(f"Second operand of type '{other.__class__.__name__}' is not supported by and operator.")
213 ex.add_note(f"Supported types for second operand: int")
214 raise ex
216 def __or__(self, other: Any) -> int:
217 """Or: self | other."""
218 if isinstance(other, int):
219 return self.Value | other
220 else:
221 ex = TypeError(f"Second operand of type '{other.__class__.__name__}' is not supported by or operator.")
222 ex.add_note(f"Supported types for second operand: int")
223 raise ex
225 def __xor__(self, other: Any) -> int:
226 """Xor: self ^ other."""
227 if isinstance(other, int):
228 return self.Value ^ other
229 else:
230 ex = TypeError(f"Second operand of type '{other.__class__.__name__}' is not supported by xor operator.")
231 ex.add_note(f"Supported types for second operand: int")
232 raise ex
234 # Binary inplace operators
235 def __iand__(self, other: Any) -> 'CallByRefIntParam': # Starting with Python 3.11+, use typing.Self as return type
236 """Inplace and: 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 __ior__(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 def __ixor__(self, other: Any) -> 'CallByRefIntParam': # Starting with Python 3.11+, use typing.Self as return type
256 r"""Inplace or: self \|= other."""
257 if isinstance(other, int):
258 self.Value ^= other
259 return self
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 # Binary operators - arithmetic
266 def __add__(self, other: Any) -> int:
267 """Addition: self + other."""
268 if isinstance(other, int):
269 return self.Value + other
270 else:
271 ex = TypeError(f"Second operand of type '{other.__class__.__name__}' is not supported by + operator.")
272 ex.add_note(f"Supported types for second operand: int")
273 raise ex
275 def __sub__(self, other: Any) -> int:
276 """Subtraction: self - other."""
277 if isinstance(other, int):
278 return self.Value - other
279 else:
280 ex = TypeError(f"Second operand of type '{other.__class__.__name__}' is not supported by - operator.")
281 ex.add_note(f"Supported types for second operand: int")
282 raise ex
284 def __truediv__(self, other: Any) -> int:
285 """Division: self / other."""
286 if isinstance(other, int):
287 return self.Value / other
288 else:
289 ex = TypeError(f"Second operand of type '{other.__class__.__name__}' is not supported by / operator.")
290 ex.add_note(f"Supported types for second operand: int")
291 raise ex
293 def __floordiv__(self, other: Any) -> int:
294 """Floor division: self // other."""
295 if isinstance(other, int):
296 return self.Value // other
297 else:
298 ex = TypeError(f"Second operand of type '{other.__class__.__name__}' is not supported by // operator.")
299 ex.add_note(f"Supported types for second operand: int")
300 raise ex
302 def __mul__(self, other: Any) -> int:
303 """Multiplication: self * other."""
304 if isinstance(other, int):
305 return self.Value * other
306 else:
307 ex = TypeError(f"Second operand of type '{other.__class__.__name__}' is not supported by * operator.")
308 ex.add_note(f"Supported types for second operand: int")
309 raise ex
311 def __mod__(self, other: Any) -> int:
312 """Modulo: self % other."""
313 if isinstance(other, int):
314 return self.Value % other
315 else:
316 ex = TypeError(f"Second operand of type '{other.__class__.__name__}' is not supported by % operator.")
317 ex.add_note(f"Supported types for second operand: int")
318 raise ex
320 def __pow__(self, other: Any) -> int:
321 """Power: self ** other."""
322 if isinstance(other, int):
323 return self.Value ** other
324 else:
325 ex = TypeError(f"Second operand of type '{other.__class__.__name__}' is not supported by ** operator.")
326 ex.add_note(f"Supported types for second operand: int")
327 raise ex
329 # Binary inplace operators - arithmetic
330 def __iadd__(self, other: Any) -> 'CallByRefIntParam':
331 """Addition: 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 __isub__(self, other: Any) -> 'CallByRefIntParam':
341 """Subtraction: 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 __idiv__(self, other: Any) -> 'CallByRefIntParam':
351 """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 __ifloordiv__(self, other: Any) -> 'CallByRefIntParam':
361 """Floor division: 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 __imul__(self, other: Any) -> 'CallByRefIntParam':
371 r"""Multiplication: 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 __imod__(self, other: Any) -> 'CallByRefIntParam':
381 """Modulo: 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 def __ipow__(self, other: Any) -> 'CallByRefIntParam':
391 r"""Power: self \*\*= other."""
392 if isinstance(other, int):
393 self.Value **= other
394 return self
395 else:
396 ex = TypeError(f"Second operand of type '{other.__class__.__name__}' is not supported by xor operator.")
397 ex.add_note(f"Supported types for second operand: int")
398 raise ex
400 # Binary operators - comparison
401 def __eq__(self, other: Any) -> bool:
402 """
403 Compare a CallByRefIntParam wrapped integer value with another instances (CallByRefIntParam) or non-wrapped integer value for equality.
405 :param other: Parameter to compare against.
406 :returns: ``True``, if both values are equal.
407 :raises TypeError: If parameter ``other`` is not of type :class:`int`, :class:`float`, :class:`complex`, :class:`Decimal` or :class:`CallByRefParam`.
408 """
409 if isinstance(other, (int, float, complex, Decimal)) and not isinstance(other, bool):
410 return self.Value == other
411 elif isinstance(other, CallByRefIntParam): 411 ↛ 412line 411 didn't jump to line 412 because the condition on line 411 was never true
412 return self.Value == other.Value
413 else:
414 ex = TypeError(f"Second operand of type '{other.__class__.__name__}' is not supported by == operator.")
415 ex.add_note(f"Supported types for second operand: int, float, complex, Decimal, CallByRefIntParam")
416 raise ex
418 def __ne__(self, other) -> bool:
419 """
420 Compare a CallByRefIntParam wrapped integer value with another instances (CallByRefIntParam) or non-wrapped integer value for inequality.
422 :param other: Parameter to compare against.
423 :returns: ``True``, if both values are unequal.
424 :raises TypeError: If parameter ``other`` is not of type :class:`int`, :class:`float`, :class:`complex`, :class:`Decimal` or :class:`CallByRefParam`.
425 """
426 if isinstance(other, (int, float, complex, Decimal)) and not isinstance(other, bool):
427 return self.Value != other
428 elif isinstance(other, CallByRefIntParam): 428 ↛ 429line 428 didn't jump to line 429 because the condition on line 428 was never true
429 return self.Value != other.Value
430 else:
431 ex = TypeError(f"Second operand of type '{other.__class__.__name__}' is not supported by != operator.")
432 ex.add_note(f"Supported types for second operand: int, float, complex, Decimal, CallByRefIntParam")
433 raise ex
435 def __lt__(self, other: Any) -> bool:
436 """
437 Compare a CallByRefIntParam wrapped integer value with another instances (CallByRefIntParam) or non-wrapped integer value for less-than.
439 :param other: Parameter to compare against.
440 :returns: ``True``, if the wrapped value is less than the other value.
441 :raises TypeError: If parameter ``other`` is not of type :class:`int`, :class:`float`, :class:`complex`, :class:`Decimal` or :class:`CallByRefParam`.
442 """
443 if isinstance(other, (int, float, complex, Decimal)) and not isinstance(other, bool):
444 return self.Value < other
445 elif isinstance(other, CallByRefIntParam): 445 ↛ 446line 445 didn't jump to line 446 because the condition on line 445 was never true
446 return self.Value < other.Value
447 else:
448 ex = TypeError(f"Second operand of type '{other.__class__.__name__}' is not supported by < operator.")
449 ex.add_note(f"Supported types for second operand: int, float, complex, Decimal, CallByRefIntParam")
450 raise ex
452 def __le__(self, other: Any) -> bool:
453 """
454 Compare a CallByRefIntParam wrapped integer value with another instances (CallByRefIntParam) or non-wrapped integer value for less-than-or-equal.
456 :param other: Parameter to compare against.
457 :returns: ``True``, if the wrapped value is less than or equal the other value.
458 :raises TypeError: If parameter ``other`` is not of type :class:`int`, :class:`float`, :class:`complex`, :class:`Decimal` or :class:`CallByRefParam`.
459 """
460 if isinstance(other, (int, float, complex, Decimal)) and not isinstance(other, bool):
461 return self.Value <= other
462 elif isinstance(other, CallByRefIntParam): 462 ↛ 463line 462 didn't jump to line 463 because the condition on line 462 was never true
463 return self.Value <= other.Value
464 else:
465 ex = TypeError(f"Second operand of type '{other.__class__.__name__}' is not supported by <= operator.")
466 ex.add_note(f"Supported types for second operand: int, float, complex, Decimal, CallByRefIntParam")
467 raise ex
469 def __gt__(self, other: Any) -> bool:
470 """
471 Compare a CallByRefIntParam wrapped integer value with another instances (CallByRefIntParam) or non-wrapped integer value for geater-than.
473 :param other: Parameter to compare against.
474 :returns: ``True``, if the wrapped value is greater than the other value.
475 :raises TypeError: If parameter ``other`` is not of type :class:`int`, :class:`float`, :class:`complex`, :class:`Decimal` or :class:`CallByRefParam`.
476 """
477 if isinstance(other, (int, float, complex, Decimal)) and not isinstance(other, bool):
478 return self.Value > other
479 elif isinstance(other, CallByRefIntParam): 479 ↛ 480line 479 didn't jump to line 480 because the condition on line 479 was never true
480 return self.Value > other.Value
481 else:
482 ex = TypeError(f"Second operand of type '{other.__class__.__name__}' is not supported by > operator.")
483 ex.add_note(f"Supported types for second operand: int, float, complex, Decimal, CallByRefIntParam")
484 raise ex
486 def __ge__(self, other: Any) -> bool:
487 """
488 Compare a CallByRefIntParam wrapped integer value with another instances (CallByRefIntParam) or non-wrapped integer value for greater-than-or-equal.
490 :param other: Parameter to compare against.
491 :returns: ``True``, if the wrapped value is greater than or equal the other value.
492 :raises TypeError: If parameter ``other`` is not of type :class:`int`, :class:`float`, :class:`complex`, :class:`Decimal` or :class:`CallByRefParam`.
493 """
494 if isinstance(other, (int, float, complex, Decimal)) and not isinstance(other, bool):
495 return self.Value >= other
496 elif isinstance(other, CallByRefIntParam): 496 ↛ 497line 496 didn't jump to line 497 because the condition on line 496 was never true
497 return self.Value >= other.Value
498 else:
499 ex = TypeError(f"Second operand of type '{other.__class__.__name__}' is not supported by >= operator.")
500 ex.add_note(f"Supported types for second operand: int, float, complex, Decimal, CallByRefIntParam")
501 raise ex
503 # Type conversion operators
504 def __bool__(self) -> bool:
505 """
506 Type conversion to :class:`bool`.
508 :returns: The boolean representation of the wrapped integer value.
509 """
510 return bool(self.Value)
512 def __int__(self) -> int:
513 """
514 Type conversion to :class:`int`.
516 :returns: The wrapped value."""
517 return self.Value
519 def __float__(self) -> float:
520 """
521 Type conversion to :class:`float`.
523 :returns: The float representation of the wrapped integer value.
524 """
525 return float(self.Value)