Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Traceback broken for AttributeError with name only #43

Closed
sanderr opened this issue Nov 15, 2022 · 7 comments
Closed

Traceback broken for AttributeError with name only #43

sanderr opened this issue Nov 15, 2022 · 7 comments

Comments

@sanderr
Copy link

sanderr commented Nov 15, 2022

Observed behavior

Running pytest on the snippet below results in an error while attempting to construct the traceback.

from collections import abc


class NamedAttributeError(AttributeError):
    def __init__(self, name: str) -> None:
        self.name: str = name


def test_exceptiongroup_error() -> None:
    raise NamedAttributeError(name="mykey")
tests/test_exceptiongroup.py 
INTERNALERROR> Traceback (most recent call last):
INTERNALERROR>   File "/home/sander/.virtualenvs/sandbox-39/lib/python3.9/site-packages/_pytest/main.py", line 270, in wrap_session
INTERNALERROR>     session.exitstatus = doit(config, session) or 0
INTERNALERROR>   File "/home/sander/.virtualenvs/sandbox-39/lib/python3.9/site-packages/_pytest/main.py", line 324, in _main
INTERNALERROR>     config.hook.pytest_runtestloop(session=session)
INTERNALERROR>   File "/home/sander/.virtualenvs/sandbox-39/lib/python3.9/site-packages/pluggy/_hooks.py", line 265, in __call__
INTERNALERROR>     return self._hookexec(self.name, self.get_hookimpls(), kwargs, firstresult)
INTERNALERROR>   File "/home/sander/.virtualenvs/sandbox-39/lib/python3.9/site-packages/pluggy/_manager.py", line 80, in _hookexec
INTERNALERROR>     return self._inner_hookexec(hook_name, methods, kwargs, firstresult)
INTERNALERROR>   File "/home/sander/.virtualenvs/sandbox-39/lib/python3.9/site-packages/pluggy/_callers.py", line 60, in _multicall
INTERNALERROR>     return outcome.get_result()
INTERNALERROR>   File "/home/sander/.virtualenvs/sandbox-39/lib/python3.9/site-packages/pluggy/_result.py", line 60, in get_result
INTERNALERROR>     raise ex[1].with_traceback(ex[2])
INTERNALERROR>   File "/home/sander/.virtualenvs/sandbox-39/lib/python3.9/site-packages/pluggy/_callers.py", line 39, in _multicall
INTERNALERROR>     res = hook_impl.function(*args)
INTERNALERROR>   File "/home/sander/.virtualenvs/sandbox-39/lib/python3.9/site-packages/_pytest/main.py", line 349, in pytest_runtestloop
INTERNALERROR>     item.config.hook.pytest_runtest_protocol(item=item, nextitem=nextitem)
INTERNALERROR>   File "/home/sander/.virtualenvs/sandbox-39/lib/python3.9/site-packages/pluggy/_hooks.py", line 265, in __call__
INTERNALERROR>     return self._hookexec(self.name, self.get_hookimpls(), kwargs, firstresult)
INTERNALERROR>   File "/home/sander/.virtualenvs/sandbox-39/lib/python3.9/site-packages/pluggy/_manager.py", line 80, in _hookexec
INTERNALERROR>     return self._inner_hookexec(hook_name, methods, kwargs, firstresult)
INTERNALERROR>   File "/home/sander/.virtualenvs/sandbox-39/lib/python3.9/site-packages/pluggy/_callers.py", line 60, in _multicall
INTERNALERROR>     return outcome.get_result()
INTERNALERROR>   File "/home/sander/.virtualenvs/sandbox-39/lib/python3.9/site-packages/pluggy/_result.py", line 60, in get_result
INTERNALERROR>     raise ex[1].with_traceback(ex[2])
INTERNALERROR>   File "/home/sander/.virtualenvs/sandbox-39/lib/python3.9/site-packages/pluggy/_callers.py", line 39, in _multicall
INTERNALERROR>     res = hook_impl.function(*args)
INTERNALERROR>   File "/home/sander/.virtualenvs/sandbox-39/lib/python3.9/site-packages/_pytest/runner.py", line 112, in pytest_runtest_protocol
INTERNALERROR>     runtestprotocol(item, nextitem=nextitem)
INTERNALERROR>   File "/home/sander/.virtualenvs/sandbox-39/lib/python3.9/site-packages/_pytest/runner.py", line 131, in runtestprotocol
INTERNALERROR>     reports.append(call_and_report(item, "call", log))
INTERNALERROR>   File "/home/sander/.virtualenvs/sandbox-39/lib/python3.9/site-packages/_pytest/runner.py", line 222, in call_and_report
INTERNALERROR>     report: TestReport = hook.pytest_runtest_makereport(item=item, call=call)
INTERNALERROR>   File "/home/sander/.virtualenvs/sandbox-39/lib/python3.9/site-packages/pluggy/_hooks.py", line 265, in __call__
INTERNALERROR>     return self._hookexec(self.name, self.get_hookimpls(), kwargs, firstresult)
INTERNALERROR>   File "/home/sander/.virtualenvs/sandbox-39/lib/python3.9/site-packages/pluggy/_manager.py", line 80, in _hookexec
INTERNALERROR>     return self._inner_hookexec(hook_name, methods, kwargs, firstresult)
INTERNALERROR>   File "/home/sander/.virtualenvs/sandbox-39/lib/python3.9/site-packages/pluggy/_callers.py", line 55, in _multicall
INTERNALERROR>     gen.send(outcome)
INTERNALERROR>   File "/home/sander/.virtualenvs/sandbox-39/lib/python3.9/site-packages/_pytest/skipping.py", line 265, in pytest_runtest_makereport
INTERNALERROR>     rep = outcome.get_result()
INTERNALERROR>   File "/home/sander/.virtualenvs/sandbox-39/lib/python3.9/site-packages/pluggy/_result.py", line 60, in get_result
INTERNALERROR>     raise ex[1].with_traceback(ex[2])
INTERNALERROR>   File "/home/sander/.virtualenvs/sandbox-39/lib/python3.9/site-packages/pluggy/_callers.py", line 39, in _multicall
INTERNALERROR>     res = hook_impl.function(*args)
INTERNALERROR>   File "/home/sander/.virtualenvs/sandbox-39/lib/python3.9/site-packages/_pytest/runner.py", line 366, in pytest_runtest_makereport
INTERNALERROR>     return TestReport.from_item_and_call(item, call)
INTERNALERROR>   File "/home/sander/.virtualenvs/sandbox-39/lib/python3.9/site-packages/_pytest/reports.py", line 349, in from_item_and_call
INTERNALERROR>     longrepr = item.repr_failure(excinfo)
INTERNALERROR>   File "/home/sander/.virtualenvs/sandbox-39/lib/python3.9/site-packages/_pytest/python.py", line 1823, in repr_failure
INTERNALERROR>     return self._repr_failure_py(excinfo, style=style)
INTERNALERROR>   File "/home/sander/.virtualenvs/sandbox-39/lib/python3.9/site-packages/_pytest/nodes.py", line 484, in _repr_failure_py
INTERNALERROR>     return excinfo.getrepr(
INTERNALERROR>   File "/home/sander/.virtualenvs/sandbox-39/lib/python3.9/site-packages/_pytest/_code/code.py", line 669, in getrepr
INTERNALERROR>     return fmt.repr_excinfo(self)
INTERNALERROR>   File "/home/sander/.virtualenvs/sandbox-39/lib/python3.9/site-packages/_pytest/_code/code.py", line 944, in repr_excinfo
INTERNALERROR>     reprtraceback = self.repr_traceback(excinfo_)
INTERNALERROR>   File "/home/sander/.virtualenvs/sandbox-39/lib/python3.9/site-packages/_pytest/_code/code.py", line 871, in repr_traceback
INTERNALERROR>     reprentry = self.repr_traceback_entry(entry, einfo)
INTERNALERROR>   File "/home/sander/.virtualenvs/sandbox-39/lib/python3.9/site-packages/_pytest/_code/code.py", line 822, in repr_traceback_entry
INTERNALERROR>     s = self.get_source(source, line_index, excinfo, short=short)
INTERNALERROR>   File "/home/sander/.virtualenvs/sandbox-39/lib/python3.9/site-packages/_pytest/_code/code.py", line 760, in get_source
INTERNALERROR>     lines.extend(self.get_exconly(excinfo, indent=indent, markall=True))
INTERNALERROR>   File "/home/sander/.virtualenvs/sandbox-39/lib/python3.9/site-packages/_pytest/_code/code.py", line 772, in get_exconly
INTERNALERROR>     exlines = excinfo.exconly(tryshort=True).split("\n")
INTERNALERROR>   File "/home/sander/.virtualenvs/sandbox-39/lib/python3.9/site-packages/_pytest/_code/code.py", line 588, in exconly
INTERNALERROR>     lines = format_exception_only(self.type, self.value)
INTERNALERROR>   File "/usr/lib/python3.9/traceback.py", line 140, in format_exception_only
INTERNALERROR>     return list(TracebackException(etype, value, None).format_exception_only())
INTERNALERROR>   File "/home/sander/.virtualenvs/sandbox-39/lib/python3.9/site-packages/exceptiongroup/_formatting.py", line 125, in __init__
INTERNALERROR>     suggestion = _compute_suggestion_error(exc_value, exc_traceback)
INTERNALERROR>   File "/home/sander/.virtualenvs/sandbox-39/lib/python3.9/site-packages/exceptiongroup/_formatting.py", line 451, in _compute_suggestion_error
INTERNALERROR>     obj = exc_value.obj
INTERNALERROR> AttributeError: 'NamedAttributeError' object has no attribute 'obj'

==================================== no tests ran in 0.01s ====================================

Details

This behavior was introduced in 1.0.3. It seems to assume that if the name attribute is set, the obj attribute will be set as well. As far as I understand there are two issues with that assumption:

  1. The Python documentation doesn't mention any invariant that either both or neither should be set. It seems valid to me to set only the name and not the object.
  2. The name and obj attributes are only introduced in Python 3.10. In Python 3.9 and below it is perfectly valid to introduce a custom subclass that happens to have one or both of these names, which might have different meanings entirely than the ones defined in 3.10+.

The second issue could be argued to be of lesser importance (and more difficult to address). The first I would call a breaking bug.

Environment

I'm using the latest versions of pytest-7.2.0 and exceptiongroup-1.0.3 at the time of writing, but I believe older pytest versions are also susceptible to this issue.

@agronholm
Copy link
Owner

@cfbolz comments?

@cfbolz
Copy link
Contributor

cfbolz commented Nov 15, 2022

right, I see. yes, it should definitely not crash, sorry for not thinking about this case. I'm fixing it.

cfbolz added a commit to cfbolz/exceptiongroup that referenced this issue Nov 15, 2022
deal with this situation without crashing, AttributeError.obj is only
always there after 3.10
@sanderr
Copy link
Author

sanderr commented Nov 15, 2022

No problem, thanks for the quick resolution!

@agronholm
Copy link
Owner

@sanderr are you able to test against main? I will make a release then.

@sanderr
Copy link
Author

sanderr commented Nov 15, 2022

It works as expected:

tests/test_exceptiongroup.py F                                                          [100%]

========================================== FAILURES ===========================================
__________________________________ test_exceptiongroup_error __________________________________

    def test_exceptiongroup_error() -> None:
>       raise NamedAttributeError(name="mykey")
E       test_exceptiongroup.NamedAttributeError

tests/test_exceptiongroup.py:10: NamedAttributeError

@agronholm
Copy link
Owner

Released v1.0.4.

@sanderr
Copy link
Author

sanderr commented Nov 15, 2022

Thanks a lot! I really hadn't expected this to be resolved today.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants