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

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. 

33 

34.. hint:: 

35 

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 

40 

41from pyTooling.Decorators import export 

42from pyTooling.MetaClasses import ExtendedType 

43 

44 

45T = TypeVar("T") 

46 

47 

48@export 

49class CallByRefParam(Generic[T], metaclass=ExtendedType, slots=True): 

50 """ 

51 Implements a *call-by-reference* parameter. 

52 

53 .. seealso:: 

54 

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 """ 

60 

61 Value: T #: internal value 

62 

63 def __init__(self, value: Nullable[T] = None) -> None: 

64 """Constructs a *call-by-reference* object for any type. 

65 

66 :param value: The value to be set as an initial value. 

67 """ 

68 self.Value = value 

69 

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. 

72 

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 

78 

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. 

83 

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 

91 

92 def __ne__(self, other) -> bool: 

93 """ 

94 Compare a CallByRefParam wrapped value with another instances (CallbyRefParam) or non-wrapped value for inequality. 

95 

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 

103 

104 # Type conversion operators 

105 def __repr__(self) -> str: 

106 """ 

107 Returns the wrapped object's string representation. 

108 

109 :returns: The string representation of the wrapped value. 

110 """ 

111 return repr(self.Value) 

112 

113 def __str__(self) -> str: 

114 """ 

115 Returns the wrapped object's string equivalent. 

116 

117 :returns: The string equivalent of the wrapped value. 

118 """ 

119 return str(self.Value) 

120 

121 

122@export 

123class CallByRefBoolParam(CallByRefParam): 

124 """A special *call-by-reference* implementation for boolean reference types.""" 

125 

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. 

130 

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 

143 

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. 

147 

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 

160 

161 # Type conversion operators 

162 def __bool__(self) -> bool: 

163 """ 

164 Type conversion to :class:`bool`. 

165 

166 :returns: The wrapped value. 

167 """ 

168 return self.Value 

169 

170 def __int__(self) -> int: 

171 """ 

172 Type conversion to :class:`int`. 

173 

174 :returns: The integer representation of the wrapped boolean value. 

175 """ 

176 return int(self.Value) 

177 

178 

179@export 

180class CallByRefIntParam(CallByRefParam): 

181 """A special *call-by-reference* implementation for integer reference types.""" 

182 

183 # Unary operators 

184 def __neg__(self) -> int: 

185 """Negate: -self.""" 

186 return -self.Value 

187 

188 def __pos__(self) -> int: 

189 """Positive: +self.""" 

190 return +self.Value 

191 

192 def __invert__(self) -> int: 

193 """Invert: ~self.""" 

194 return ~self.Value 

195 

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 

205 

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 

214 

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 

223 

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 

234 

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 

244 

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 

254 

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 

264 

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 

273 

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 

282 

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 

291 

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 

300 

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 

309 

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 

318 

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 

329 

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 

339 

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 

349 

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 

359 

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 

369 

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 

379 

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 

389 

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. 

394 

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 

407 

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. 

411 

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 

424 

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. 

428 

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 

441 

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. 

445 

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 

458 

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. 

462 

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 

475 

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. 

479 

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 

492 

493 # Type conversion operators 

494 def __bool__(self) -> bool: 

495 """ 

496 Type conversion to :class:`bool`. 

497 

498 :returns: The boolean representation of the wrapped integer value. 

499 """ 

500 return bool(self.Value) 

501 

502 def __int__(self) -> int: 

503 """ 

504 Type conversion to :class:`int`. 

505 

506 :returns: The wrapped value.""" 

507 return self.Value 

508 

509 def __float__(self) -> float: 

510 """ 

511 Type conversion to :class:`float`. 

512 

513 :returns: The float representation of the wrapped integer value. 

514 """ 

515 return float(self.Value)