Example #1
0
def test_catch_nested_group():
    value_runtime_errors = []
    zero_division_errors = []
    with catch(
        {
            (ValueError, RuntimeError): value_runtime_errors.append,
            ZeroDivisionError: zero_division_errors.append,
        }
    ):
        nested_group = ExceptionGroup(
            "nested", [RuntimeError("bar"), ZeroDivisionError()]
        )
        raise ExceptionGroup("booboo", [ValueError("foo"), nested_group])

    assert len(value_runtime_errors) == 1
    exceptions = value_runtime_errors[0].exceptions
    assert isinstance(exceptions[0], ValueError)
    assert isinstance(exceptions[1], ExceptionGroup)
    assert isinstance(exceptions[1].exceptions[0], RuntimeError)

    assert len(zero_division_errors) == 1
    assert isinstance(zero_division_errors[0], ExceptionGroup)
    assert isinstance(zero_division_errors[0].exceptions[0], ExceptionGroup)
    assert isinstance(
        zero_division_errors[0].exceptions[0].exceptions[0], ZeroDivisionError
    )
    def test_bad_EG_construction__bad_excs_sequence(self):
        MSG = r"second argument \(exceptions\) must be a sequence"
        with self.assertRaisesRegex(TypeError, MSG):
            ExceptionGroup("errors not sequence", {ValueError(42)})
        with self.assertRaisesRegex(TypeError, MSG):
            ExceptionGroup("eg", None)

        MSG = r"second argument \(exceptions\) must be a non-empty sequence"
        with self.assertRaisesRegex(ValueError, MSG):
            ExceptionGroup("eg", [])
def test_catch_nested_group():
    value_runtime_errors = []
    zero_division_errors = []
    try:
        nested_group = ExceptionGroup(
            "nested", [RuntimeError("bar"), ZeroDivisionError()]
        )
        raise ExceptionGroup("booboo", [ValueError("foo"), nested_group])
    except* (ValueError, RuntimeError) as exc:
        value_runtime_errors.append(exc)
    def test_fields_are_readonly(self):
        eg = ExceptionGroup("eg", [TypeError(1), OSError(2)])

        self.assertEqual(type(eg.exceptions), tuple)

        eg.message
        with self.assertRaises(AttributeError):
            eg.message = "new msg"

        eg.exceptions
        with self.assertRaises(AttributeError):
            eg.exceptions = [OSError("xyz")]
    def test_bad_EG_construction__too_few_args(self):
        if sys.version_info >= (3, 11):
            MSG = (
                r"BaseExceptionGroup.__new__\(\) takes exactly 2 arguments \(1 given\)"
            )
        else:
            MSG = (r"__new__\(\) missing 1 required positional argument: "
                   r"'_ExceptionGroup__exceptions'")

        with self.assertRaisesRegex(TypeError, MSG):
            ExceptionGroup("no errors")
        with self.assertRaisesRegex(TypeError, MSG):
            ExceptionGroup([ValueError("no msg")])
def test_exception_group_when_members_are_not_exceptions():
    with pytest.raises(TypeError):
        ExceptionGroup(
            "error",
            [RuntimeError("RuntimeError"), "error2"],
            ["RuntimeError", "error2"],
        )
def test_split_and_check_attributes_same():
    try:
        raise_error(RuntimeError("RuntimeError"))
    except Exception as e:
        run_error = e

    try:
        raise_error(ValueError("ValueError"))
    except Exception as e:
        val_error = e

    group = ExceptionGroup("ErrorGroup", [run_error, val_error],
                           ["RuntimeError", "ValueError"])
    # go and check __traceback__, __cause__ attributes
    try:
        raise_error_from_another(group, RuntimeError("Cause"))
    except BaseException as e:
        new_group = e

    matched, unmatched = split(RuntimeError, group)
    assert matched.__traceback__ is new_group.__traceback__
    assert matched.__cause__ is new_group.__cause__
    assert matched.__context__ is new_group.__context__
    assert matched.__suppress_context__ is new_group.__suppress_context__
    assert unmatched.__traceback__ is new_group.__traceback__
    assert unmatched.__cause__ is new_group.__cause__
    assert unmatched.__context__ is new_group.__context__
    assert unmatched.__suppress_context__ is new_group.__suppress_context__
def create_simple_eg():
    excs = []
    try:
        try:
            raise MemoryError("context and cause for ValueError(1)")
        except MemoryError as e:
            raise ValueError(1) from e
    except ValueError as e:
        excs.append(e)

    try:
        try:
            raise OSError("context for TypeError")
        except OSError:
            raise TypeError(int)
    except TypeError as e:
        excs.append(e)

    try:
        try:
            raise ImportError("context for ValueError(2)")
        except ImportError:
            raise ValueError(2)
    except ValueError as e:
        excs.append(e)

    try:
        raise ExceptionGroup("simple eg", excs)
    except ExceptionGroup as e:
        return e
 def level1(i):
     excs = []
     for f, arg in [(raiseVE, i), (raiseTE, int), (raiseVE, i + 1)]:
         try:
             f(arg)
         except Exception as e:
             excs.append(e)
     raise ExceptionGroup("msg1", excs)
def test_repr():
    group = BaseExceptionGroup("foo", [ValueError(1), KeyboardInterrupt()])
    assert repr(group) == (
        "BaseExceptionGroup('foo', [ValueError(1), KeyboardInterrupt()])"
    )

    group = ExceptionGroup("foo", [ValueError(1), RuntimeError("bar")])
    assert repr(group) == "ExceptionGroup('foo', [ValueError(1), RuntimeError('bar')])"
 def level3(i):
     excs = []
     for f, arg in [(level2, i + 1), (raiseVE, i + 2)]:
         try:
             f(arg)
         except Exception as e:
             excs.append(e)
     raise ExceptionGroup("msg3", excs)
Example #12
0
def test_catch_nested_group():
    exceptions1 = []
    exceptions2 = []
    with catch({
        (ValueError, RuntimeError): exceptions1.append,
            ZeroDivisionError: exceptions2.append,
    }):
        nested_group = ExceptionGroup(
            "nested",
            [RuntimeError("bar"), ZeroDivisionError()])
        raise ExceptionGroup("booboo", [ValueError("foo"), nested_group])

    assert len(exceptions1) == 2
    assert isinstance(exceptions1[0], ValueError)
    assert isinstance(exceptions1[1], RuntimeError)

    assert len(exceptions2) == 1
    assert isinstance(exceptions2[0], ZeroDivisionError)
Example #13
0
def test_catch_no_match():
    try:
        with catch({(ValueError, RuntimeError): (lambda e: None)}):
            group = ExceptionGroup("booboo", [ZeroDivisionError()])
            raise group
    except ExceptionGroup as exc:
        assert exc is not group
    else:
        pytest.fail("Did not raise an ExceptionGroup")
    def test_bad_EG_construction__too_many_args(self):
        if sys.version_info >= (3, 11):
            MSG = (
                r"BaseExceptionGroup.__new__\(\) takes exactly 2 arguments \(3 given\)"
            )
        else:
            MSG = r"__new__\(\) takes 3 positional arguments but 4 were given"

        with self.assertRaisesRegex(TypeError, MSG):
            ExceptionGroup("eg", [ValueError("too")], [TypeError("many")])
def test_split_when_all_exception_unmatched():
    group = ExceptionGroup(
        "Many Errors",
        [RuntimeError("Runtime Error1"),
         RuntimeError("Runtime Error2")],
        ["Runtime Error1", "Runtime Error2"],
    )
    matched, unmatched = split(ValueError, group)
    assert matched is None
    assert unmatched is group
def test_split_with_predicate():
    def _match(err):
        return str(err) != "skip"

    error1 = RuntimeError("skip")
    error2 = RuntimeError("Runtime Error")
    group = ExceptionGroup("Many Errors", [error1, error2],
                           ["skip", "Runtime Error"])
    matched, unmatched = split(RuntimeError, group, match=_match)
    assert matched.exceptions == [error2]
    assert unmatched.exceptions == [error1]
def test_catch_no_match():
    try:
        try:
            group = ExceptionGroup("booboo", [ZeroDivisionError()])
            raise group
        except* (ValueError, RuntimeError):
            pass
    except ExceptionGroup as exc:
        assert isinstance(exc.exceptions[0], ZeroDivisionError)
        assert exc is not group
    else:
        pytest.fail("Did not raise an ExceptionGroup")
def test_exception_group_str():
    memberA = ValueError("memberA")
    memberB = ValueError("memberB")
    group = ExceptionGroup(
        "many error.", [memberA, memberB], [str(memberA), str(memberB)]
    )
    assert "memberA" in str(group)
    assert "memberB" in str(group)

    assert "ExceptionGroup: " in repr(group)
    assert "memberA" in repr(group)
    assert "memberB" in repr(group)
def test_catch_handler_raises():
    try:
        try:
            raise ExceptionGroup("booboo", [ValueError("bar")])
        except* ValueError:
            raise RuntimeError("new")
    except ExceptionGroup as exc:
        assert exc.message == ""
        assert len(exc.exceptions) == 1
        assert isinstance(exc.exceptions[0], RuntimeError)
    else:
        pytest.fail("Did not raise an ExceptionGroup")
def create_nested_eg():
    excs = []
    try:
        try:
            raise TypeError(bytes)
        except TypeError as e:
            raise ExceptionGroup("nested", [e])
    except ExceptionGroup as e:
        excs.append(e)

    try:
        try:
            raise MemoryError("out of memory")
        except MemoryError as e:
            raise ValueError(1) from e
    except ValueError as e:
        excs.append(e)

    try:
        raise ExceptionGroup("root", excs)
    except ExceptionGroup as eg:
        return eg
Example #21
0
def test_formatting(capsys):
    exceptions = []
    try:
        raise ValueError("foo")
    except ValueError as exc:
        exceptions.append(exc)

    try:
        raise RuntimeError("bar")
    except RuntimeError as exc:
        exc.__note__ = "Note from bar handler"
        exceptions.append(exc)

    try:
        raise ExceptionGroup("test message", exceptions)
    except ExceptionGroup as exc:
        exc.__note__ = "Displays notes attached to the group too"
        sys.excepthook(type(exc), exc, exc.__traceback__)

    lineno = test_formatting.__code__.co_firstlineno
    if sys.version_info >= (3, 11):
        module_prefix = ""
        underline1 = "\n  |     " + "^" * 48
        underline2 = "\n    |     " + "^" * 23
        underline3 = "\n    |     " + "^" * 25
    else:
        module_prefix = "exceptiongroup."
        underline1 = underline2 = underline3 = ""

    output = capsys.readouterr().err
    assert output == (
        f"""\
  + Exception Group Traceback (most recent call last):
  |   File "{__file__}", line {lineno + 14}, in test_formatting
  |     raise ExceptionGroup("test message", exceptions){underline1}
  | {module_prefix}ExceptionGroup: test message
  | Displays notes attached to the group too
  +-+---------------- 1 ----------------
    | Traceback (most recent call last):
    |   File "{__file__}", line {lineno + 3}, in test_formatting
    |     raise ValueError("foo"){underline2}
    | ValueError: foo
    +---------------- 2 ----------------
    | Traceback (most recent call last):
    |   File "{__file__}", line {lineno + 8}, in test_formatting
    |     raise RuntimeError("bar"){underline3}
    | RuntimeError: bar
    | Note from bar handler
    +------------------------------------
"""
    )
def test_exception_group_init():
    memberA = ValueError("A")
    memberB = RuntimeError("B")
    group = ExceptionGroup(
        "many error.", [memberA, memberB], [str(memberA), str(memberB)]
    )
    assert group.exceptions == [memberA, memberB]
    assert group.message == "many error."
    assert group.sources == [str(memberA), str(memberB)]
    assert group.args == (
        "many error.",
        [memberA, memberB],
        [str(memberA), str(memberB)],
    )
def test_split_when_contains_matched_and_unmatched():
    error1 = RuntimeError("Runtime Error1")
    error2 = ValueError("Value Error2")
    group = ExceptionGroup("Many Errors", [error1, error2],
                           ["Runtime Error1", "Value Error2"])
    matched, unmatched = split(RuntimeError, group)
    assert isinstance(matched, ExceptionGroup)
    assert isinstance(unmatched, ExceptionGroup)
    assert matched.exceptions == [error1]
    assert matched.message == "Many Errors"
    assert matched.sources == ["Runtime Error1"]
    assert unmatched.exceptions == [error2]
    assert unmatched.message == "Many Errors"
    assert unmatched.sources == ["Value Error2"]
def test_catch_group():
    value_runtime_errors = []
    zero_division_errors = []
    try:
        raise ExceptionGroup(
            "booboo",
            [
                ValueError("foo"),
                ValueError("bar"),
                RuntimeError("bar"),
                ZeroDivisionError(),
            ],
        )
    except* (ValueError, RuntimeError) as exc:
        value_runtime_errors.append(exc)
Example #25
0
def test_catch_full_match():
    with catch({(ValueError, RuntimeError): (lambda e: None)}):
        raise ExceptionGroup("booboo", [ValueError()])
 def make_deep_eg(self):
     e = TypeError(1)
     for _ in range(2000):
         e = ExceptionGroup("eg", [e])
     return e
 def test_EG_wraps_BaseException__raises_TypeError(self):
     MSG = "Cannot nest BaseExceptions in an ExceptionGroup"
     with self.assertRaisesRegex(TypeError, MSG):
         ExceptionGroup("eg", [ValueError(1), KeyboardInterrupt(2)])
 def test_EG_wraps_Exceptions__creates_EG(self):
     excs = [ValueError(1), TypeError(2)]
     self.assertIs(type(ExceptionGroup("eg", excs)), ExceptionGroup)
 def test_bad_EG_construction__nested_non_exceptions(self):
     MSG = r"Item [0-9]+ of second argument \(exceptions\) is not an exception"
     with self.assertRaisesRegex(ValueError, MSG):
         ExceptionGroup("expect instance, not type", [OSError])
     with self.assertRaisesRegex(ValueError, MSG):
         ExceptionGroup("bad error", ["not an exception"])
 def test_bad_EG_construction__bad_message(self):
     MSG = "argument 1 must be str, not "
     with self.assertRaisesRegex(TypeError, MSG):
         ExceptionGroup(ValueError(12), SyntaxError("bad syntax"))
     with self.assertRaisesRegex(TypeError, MSG):
         ExceptionGroup(None, [ValueError(12)])