From c4b18378d69ea0971779dae48c9d4df7538f3be2 Mon Sep 17 00:00:00 2001 From: fourdim Date: Sun, 2 Nov 2025 15:14:47 -0500 Subject: [PATCH 1/6] Support exclude in coredumpy.patch_except --- README.md | 2 ++ src/coredumpy/except_hook.py | 19 ++++++++++++++++--- tests/test_basic.py | 18 ++++++++++++++++++ 3 files changed, 36 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index 3332439..41eb1e2 100644 --- a/README.md +++ b/README.md @@ -49,6 +49,8 @@ Or you can patch explicitly in your code and execute the script/module as usual import coredumpy # Create a dump in "./dumps" when there's an unhandled exception coredumpy.patch_except(directory='./dumps') +# Create a dump in "./dumps" only when exceptions other than KeyboardInterrupt occur +coredumpy.patch_except(directory="./dumps", exclude=[KeyboardInterrupt]) # Create a dump in "./dumps" when there's a unittest failure/error coredumpy.patch_unittest(directory='./dumps') # Create a dump in "./dumps" when there's a pytest failure/error diff --git a/src/coredumpy/except_hook.py b/src/coredumpy/except_hook.py index e6fbbd9..0c97d73 100644 --- a/src/coredumpy/except_hook.py +++ b/src/coredumpy/except_hook.py @@ -4,16 +4,16 @@ import sys import traceback -from typing import Callable, Optional, Union +from typing import Callable, Optional, Union, Iterable, Type from .coredumpy import dump - _original_excepthook = sys.excepthook def patch_except(path: Optional[Union[str, Callable[[], str]]] = None, - directory: Optional[str] = None): + directory: Optional[str] = None, + exclude: Optional[Iterable[Type[BaseException]]] = None): """ Patch the excepthook to dump the frame stack when an unhandled exception occurs. @param path: @@ -21,7 +21,16 @@ def patch_except(path: Optional[Union[str, Callable[[], str]]] = None, if not specified, the default filename will be used @param directory: The directory to save the dump file, only works when path is not specified. + @param exclude: + A list of exception types to exclude from dumping. If an exception is in this list, + it will not be dumped and the original excepthook will be called instead. """ + if exclude is not None: + _exclude = tuple(exclude) + if any(not issubclass(excCls, BaseException) for excCls in _exclude): + raise TypeError('Expect `exclude` to be BaseException subclasses.') + else: + _exclude = tuple() def _get_description(type, value, tb): side_count = (70 - len(type.__qualname__) - 2) // 2 @@ -30,6 +39,10 @@ def _get_description(type, value, tb): ''.join(traceback.format_exception(type, value, tb)).strip()]) def _excepthook(type, value, tb): + if isinstance(type, _exclude): + _original_excepthook(type, value, tb) + return + while tb.tb_next: tb = tb.tb_next diff --git a/tests/test_basic.py b/tests/test_basic.py index d4a1337..89f213f 100644 --- a/tests/test_basic.py +++ b/tests/test_basic.py @@ -209,6 +209,24 @@ def g(arg): self.assertIn("return 1 / arg", stdout) self.assertIn("0", stdout) + def test_except_exclude(self): + script = """ + import coredumpy + coredumpy.patch_except(path='coredumpy_dump', exclude=[KeyboardInterrupt]) + raise KeyboardInterrupt + """ + stdout, stderr = self.run_script(script, expected_returncode=-2) + self.assertIn("KeyboardInterrupt", stderr) + self.assertNotIn("Your frame stack is dumped", stdout) + + def test_except_exclude_sanity(self): + script = """ + import coredumpy + coredumpy.patch_except(path='coredumpy_dump', exclude=[int]) + """ + _, stderr = self.run_script(script, expected_returncode=1) + self.assertIn("TypeError:", stderr) + def test_cli(self): script = """ def g(arg): From 72cc049374ac40c06d0c7968e231724f4a0bfb69 Mon Sep 17 00:00:00 2001 From: fourdim Date: Sun, 2 Nov 2025 15:34:25 -0500 Subject: [PATCH 2/6] revert: back to value --- src/coredumpy/except_hook.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/coredumpy/except_hook.py b/src/coredumpy/except_hook.py index 0c97d73..b88db78 100644 --- a/src/coredumpy/except_hook.py +++ b/src/coredumpy/except_hook.py @@ -39,7 +39,7 @@ def _get_description(type, value, tb): ''.join(traceback.format_exception(type, value, tb)).strip()]) def _excepthook(type, value, tb): - if isinstance(type, _exclude): + if isinstance(value, _exclude): _original_excepthook(type, value, tb) return From 8931f0719da29b007fbd5e8786061dfb0c9fb65a Mon Sep 17 00:00:00 2001 From: fourdim Date: Sun, 2 Nov 2025 16:04:15 -0500 Subject: [PATCH 3/6] fix: use platform independent CustomError instead --- tests/test_basic.py | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/tests/test_basic.py b/tests/test_basic.py index 89f213f..3d30c86 100644 --- a/tests/test_basic.py +++ b/tests/test_basic.py @@ -212,11 +212,13 @@ def g(arg): def test_except_exclude(self): script = """ import coredumpy - coredumpy.patch_except(path='coredumpy_dump', exclude=[KeyboardInterrupt]) - raise KeyboardInterrupt + class CustomError(Exception): + pass + coredumpy.patch_except(path='coredumpy_dump', exclude=[CustomError]) + raise CustomError """ - stdout, stderr = self.run_script(script, expected_returncode=-2) - self.assertIn("KeyboardInterrupt", stderr) + stdout, stderr = self.run_script(script, expected_returncode=1) + self.assertIn("CustomError", stderr) self.assertNotIn("Your frame stack is dumped", stdout) def test_except_exclude_sanity(self): From 69ccd2c8cfb11f6ba4b1bdb694f1c4cc4ccd870b Mon Sep 17 00:00:00 2001 From: fourdim Date: Sun, 2 Nov 2025 16:17:03 -0500 Subject: [PATCH 4/6] fix: use value error --- tests/test_basic.py | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/tests/test_basic.py b/tests/test_basic.py index 3d30c86..e182e19 100644 --- a/tests/test_basic.py +++ b/tests/test_basic.py @@ -212,10 +212,8 @@ def g(arg): def test_except_exclude(self): script = """ import coredumpy - class CustomError(Exception): - pass - coredumpy.patch_except(path='coredumpy_dump', exclude=[CustomError]) - raise CustomError + coredumpy.patch_except(path='coredumpy_dump', exclude=[ValueError]) + raise ValueError """ stdout, stderr = self.run_script(script, expected_returncode=1) self.assertIn("CustomError", stderr) From 770dc6ec4e3dc37e410b85aebab6d623d71f12f5 Mon Sep 17 00:00:00 2001 From: fourdim Date: Sun, 2 Nov 2025 16:36:22 -0500 Subject: [PATCH 5/6] fix: again --- tests/test_basic.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/test_basic.py b/tests/test_basic.py index e182e19..fefe602 100644 --- a/tests/test_basic.py +++ b/tests/test_basic.py @@ -216,7 +216,7 @@ def test_except_exclude(self): raise ValueError """ stdout, stderr = self.run_script(script, expected_returncode=1) - self.assertIn("CustomError", stderr) + self.assertIn("ValueError", stderr) self.assertNotIn("Your frame stack is dumped", stdout) def test_except_exclude_sanity(self): From 10cbefa487ec7465a8a0073e743db614fc21f65a Mon Sep 17 00:00:00 2001 From: fourdim Date: Sun, 2 Nov 2025 17:35:20 -0500 Subject: [PATCH 6/6] revert: bring back the empty line --- src/coredumpy/except_hook.py | 1 + 1 file changed, 1 insertion(+) diff --git a/src/coredumpy/except_hook.py b/src/coredumpy/except_hook.py index b88db78..4dc45e2 100644 --- a/src/coredumpy/except_hook.py +++ b/src/coredumpy/except_hook.py @@ -8,6 +8,7 @@ from .coredumpy import dump + _original_excepthook = sys.excepthook