From d6d07de525bd813905e5c69def4cb46f9fd634bf Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Piotr=20Ma=C5=9Blanka?= <piotr.maslanka@henrietta.com.pl> Date: Fri, 6 Dec 2024 14:39:37 +0100 Subject: [PATCH] 2.26.5 --- CHANGELOG.md | 5 +++++ docs/instrumentation/traceback.rst | 4 +++- satella/__init__.py | 2 +- satella/coding/generators.py | 7 +++++-- satella/coding/iterators.py | 11 ++++++++--- satella/instrumentation/__init__.py | 4 ++-- satella/instrumentation/trace_back/__init__.py | 4 ++-- satella/instrumentation/trace_back/trace_back.py | 7 +++++++ tests/test_instrumentation/test_trace_back.py | 9 ++++++++- 9 files changed, 41 insertions(+), 12 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 3f59686c..71cbabf2 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,8 @@ +# v2.26.5 + +* added `get_current_traceback` and fixed `RunActionAfterGeneratorCompletes` and `run_when_iterator_completes` default + exception handling plus better docs + # v2.26.4 * `run_when_iterator_completes` and `RunActionAfterGeneratorCompletes` will now support exceptions diff --git a/docs/instrumentation/traceback.rst b/docs/instrumentation/traceback.rst index 1e5f3420..274092bb 100644 --- a/docs/instrumentation/traceback.rst +++ b/docs/instrumentation/traceback.rst @@ -57,10 +57,12 @@ Alternatively, you can pass a `<frame>` object to Traceback, in order to seriali .. autoclass:: satella.instrumentation.GenerationPolicy :members: -There's a helper function as well +There's some helper function as well .. autofunction:: satella.instrumentation.frame_from_traceback +.. autofunction:: satella.instrumentation.get_current_traceback + Dumping all stack frames ------------------------ diff --git a/satella/__init__.py b/satella/__init__.py index 7ee03739..e7cf032b 100644 --- a/satella/__init__.py +++ b/satella/__init__.py @@ -1 +1 @@ -__version__ = '2.26.4' +__version__ = '2.26.5' diff --git a/satella/coding/generators.py b/satella/coding/generators.py index b95ba6ec..33d20ee7 100644 --- a/satella/coding/generators.py +++ b/satella/coding/generators.py @@ -20,7 +20,6 @@ class RunActionAfterGeneratorCompletes(tp.Generator, metaclass=ABCMeta): :param generator: generator to watch for :param args: arguments to invoke action_to_run with :param call_despite_closed: :meth:`action_to_run` will be called even if the generator is closed - :param call_on_exception: callable/1 with exception instance if generator somehow fails :param kwargs: keyword arguments to invoke action_to_run with """ self.closed = False @@ -73,7 +72,11 @@ class RunActionAfterGeneratorCompletes(tp.Generator, metaclass=ABCMeta): """This will run when this generator completes. Override it.""" def call_on_exception(self, exc: Exception): - """This will run when this generator throws any exception. Override it.""" + """ + This will run when this generator throws any exception inside it's __next__() or send(). You can reraise + it (which is the default behavior if you do not override this). + """ + raise exc def run_when_generator_completes(gen: tp.Generator, call_on_done: tp.Callable, diff --git a/satella/coding/iterators.py b/satella/coding/iterators.py index 3532dc06..3dd82cf5 100644 --- a/satella/coding/iterators.py +++ b/satella/coding/iterators.py @@ -138,19 +138,24 @@ class hint_with_length: return self.length -def run_when_iterator_completes(iterator: tp.Iterator, func_to_run: tp.Callable, do_exception=lambda e: None, +def run_when_iterator_completes(iterator: tp.Iterator, func_to_run: tp.Callable, do_exception=None, *args, **kwargs): """ Schedule a function to be called when an iterator completes. :param iterator: iterator to use - :param func_to_run: function to run afterwards - :param do_exception: a callable to call with the exception instance if generator fails at some point + :param func_to_run: function to run afterwards, but only if there were no exceptions or they were swallowed by + do_exception. + :param do_exception: a callable to call with the exception instance if generator fails at some point. Note that + if this doesn't re-raise the exception, it will be swallowed. Default behaviour is just to + re-raise it. :param args: arguments to pass to the function :param kwargs: keyword arguments to pass to the function """ try: yield from iterator except Exception as e: + if do_exception is None: + raise do_exception(e) func_to_run(*args, **kwargs) diff --git a/satella/instrumentation/__init__.py b/satella/instrumentation/__init__.py index b317921d..3cc7b435 100644 --- a/satella/instrumentation/__init__.py +++ b/satella/instrumentation/__init__.py @@ -1,6 +1,6 @@ from .dump_frames_on import install_dump_frames_on, dump_frames_on from .trace_back import Traceback, GenerationPolicy, StackFrame, StoredVariableValue, \ - frame_from_traceback + frame_from_traceback, get_current_traceback __all__ = ['install_dump_frames_on', 'Traceback', 'GenerationPolicy', 'StoredVariableValue', - 'StackFrame', 'frame_from_traceback', 'dump_frames_on'] + 'StackFrame', 'frame_from_traceback', 'dump_frames_on', 'get_current_traceback'] diff --git a/satella/instrumentation/trace_back/__init__.py b/satella/instrumentation/trace_back/__init__.py index 2f892b75..8be05678 100644 --- a/satella/instrumentation/trace_back/__init__.py +++ b/satella/instrumentation/trace_back/__init__.py @@ -1,5 +1,5 @@ from .classes import GenerationPolicy, StackFrame, StoredVariableValue -from .trace_back import Traceback, frame_from_traceback +from .trace_back import Traceback, frame_from_traceback, get_current_traceback __all__ = ['GenerationPolicy', 'StoredVariableValue', 'StackFrame', 'Traceback', - 'frame_from_traceback'] + 'frame_from_traceback', 'get_current_traceback'] diff --git a/satella/instrumentation/trace_back/trace_back.py b/satella/instrumentation/trace_back/trace_back.py index bd65862b..758d5c8f 100644 --- a/satella/instrumentation/trace_back/trace_back.py +++ b/satella/instrumentation/trace_back/trace_back.py @@ -148,3 +148,10 @@ class Traceback(JSONAble): except BaseException as e: output.write( u'*** %s: repr unavailable (due to locally raised %s)\n' % (name, repr(e))) + + +def get_current_traceback() -> str: + """ + A shorthand form for :code:`Traceback().pretty_format()`. + """ + return Traceback().pretty_format() diff --git a/tests/test_instrumentation/test_trace_back.py b/tests/test_instrumentation/test_trace_back.py index 5121649f..36bf8e57 100644 --- a/tests/test_instrumentation/test_trace_back.py +++ b/tests/test_instrumentation/test_trace_back.py @@ -3,10 +3,17 @@ import pickle import sys import unittest -from satella.instrumentation import Traceback +from satella.instrumentation import Traceback, get_current_traceback class TestTraceback(unittest.TestCase): + def test_get_current_traceback(self): + try: + a = 1 / 0 + except ZeroDivisionError: + tb = get_current_traceback() + self.assertIn('ZeroDivisionError', tb) + def test_no_exc(self): tb = Traceback() byte = io.BytesIO() -- GitLab