Skip to content
This repository was archived by the owner on Nov 2, 2022. It is now read-only.

add API to generate leaf exception from exceptongroup #13

Closed
wants to merge 4 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions exceptiongroup/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

from ._version import __version__

__all__ = ["ExceptionGroup", "split", "catch"]
__all__ = ["ExceptionGroup", "split", "catch", "leaf_exceptions"]


class ExceptionGroup(BaseException):
Expand Down Expand Up @@ -64,4 +64,4 @@ def __repr__(self):


from . import _monkeypatch
from ._tools import split, catch
from ._tools import split, catch, leaf_exceptions
40 changes: 39 additions & 1 deletion exceptiongroup/_tests/test_tools.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
from collections.abc import Iterable
import pytest
from exceptiongroup import ExceptionGroup, split

from exceptiongroup import ExceptionGroup, split, leaf_exceptions


def raise_error(err):
Expand Down Expand Up @@ -117,3 +119,39 @@ def test_split_and_check_attributes_same():
assert unmatched.__cause__ is new_group.__cause__
assert unmatched.__context__ is new_group.__context__
assert unmatched.__suppress_context__ is new_group.__suppress_context__


def test_leaf_exceptions_iterable():
group = ExceptionGroup("error", [RuntimeError("error1")], ["error1"])
result = leaf_exceptions(group)
assert isinstance(result, Iterable)


def test_leaf_exceptions_values():
leaf_error1 = RuntimeError("Error1")
leaf_error2 = RuntimeError("Error2")
group = ExceptionGroup(
"error", [leaf_error1, leaf_error2], ["Error1", "Error2"]
)
result = list(leaf_exceptions(group))
assert result == [leaf_error1, leaf_error2]

# test for exception group which contains nested group
group = ExceptionGroup(
"error",
[leaf_error1, ExceptionGroup("Error2", [leaf_error2], ["Error2"])],
["Error1", "Error2"],
)
result = list(leaf_exceptions(group))
assert result == [leaf_error1, leaf_error2]


def test_leaf_exceptions_with_bare_exception():
error1 = RuntimeError("Error1")
result = list(leaf_exceptions(error1))
assert result == [error1]


def test_leaf_exception_with_non_exception_object():
with pytest.raises(TypeError):
list(leaf_exceptions(None))
31 changes: 31 additions & 0 deletions exceptiongroup/_tools.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,37 @@
from . import ExceptionGroup


def leaf_exceptions(exc):
""" Iterate and extract sub exceptions from given exception.
When sub exceptions is also ExceptionGroup, it will iterate the
ExceptionGroup's sub-exceptions recursively.

Args:
exc (BaseException): Exception object we want to extract.
Returns:
An iterable of BaseException object.

Examples:
error1 = RuntimeError("Error1")
error2 = RuntimeError("Error2")
group = ExceptionGroup(
"errorGroup",
[error1, error2],
["Error1", "Error2"]
)
assert list(leaf_exceptions(group)) == [error1, error2]
"""
if not isinstance(exc, BaseException):
raise TypeError(
"Argument `exc` should be an instance of BaseException."
)
if isinstance(exc, ExceptionGroup):
for subexc in exc.exceptions:
yield from leaf_exceptions(subexc)
else:
yield exc


def split(exc_type, exc, *, match=None):
""" splits the exception into one half (matched) representing all the parts of
the exception that match the predicate, and another half (not matched)
Expand Down