Coverage for pyTooling/Warning/__init__.py: 100%
32 statements
« prev ^ index » next coverage.py v7.8.0, created at 2025-04-25 22:22 +0000
« prev ^ index » next coverage.py v7.8.0, created at 2025-04-25 22:22 +0000
1# ==================================================================================================================== #
2# _____ _ _ __ __ _ #
3# _ __ _ |_ _|__ ___ | (_)_ __ __ \ \ / /_ _ _ __ _ __ (_)_ __ __ _ #
4# | '_ \| | | || |/ _ \ / _ \| | | '_ \ / _` \ \ /\ / / _` | '__| '_ \| | '_ \ / _` | #
5# | |_) | |_| || | (_) | (_) | | | | | | (_| |\ V V / (_| | | | | | | | | | | (_| | #
6# | .__/ \__, ||_|\___/ \___/|_|_|_| |_|\__, (_)_/\_/ \__,_|_| |_| |_|_|_| |_|\__, | #
7# |_| |___/ |___/ |___/ #
8# ==================================================================================================================== #
9# Authors: #
10# Patrick Lehmann #
11# #
12# License: #
13# ==================================================================================================================== #
14# Copyright 2025-2025 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"""
32A solution to send warnings like exceptions to a handler in the upper part of the call-stack.
34.. hint:: See :ref:`high-level help <WARNING>` for explanations and usage examples.
35"""
36from builtins import Warning as _Warning
38from inspect import currentframe
39from typing import List, Callable, Optional as Nullable
41try:
42 from pyTooling.Decorators import export
43except ModuleNotFoundError: # pragma: no cover
44 print("[pyTooling.Common] Could not import from 'pyTooling.*'!")
46 try:
47 from Decorators import export
48 except ModuleNotFoundError as ex: # pragma: no cover
49 print("[pyTooling.Common] Could not import directly!")
50 raise ex
53@export
54class WarningCollector:
55 _warnings: Nullable[List]
56 _handler: Nullable[Callable[[_Warning], bool]]
58 def __init__(self, warnings: Nullable[List] = None, handler: Nullable[Callable[[_Warning], bool]] = None):
59 self._warnings = warnings
60 self._handler = handler
62 def __enter__(self) -> 'WarningCollector': # -> Self: needs Python 3.11
63 return self
65 def __exit__(self, exc_type, exc_val, exc_tb):
66 pass
68 def AddWarning(self, warning: _Warning) -> bool:
69 if self._warnings is not None:
70 self._warnings.append(warning)
71 if self._handler is not None:
72 return self._handler(warning)
74 return False
76 @classmethod
77 def Raise(cls, warning: _Warning) -> None:
78 frame = currentframe()
79 while frame := frame.f_back:
80 for localValue in reversed(frame.f_locals.values()):
81 if isinstance(localValue, cls):
82 if localValue.AddWarning(warning):
83 raise Exception(f"Warning: {warning}") from warning
84 return
85 else:
86 raise Exception(f"Unhandled warning: {warning}") from warning