On Mon, Sep 6, 2021 at 9:37 AM Finn Mason
Hello all,
In Python 3.10 and 3.11, exception tracebacks are being greatly improved. I noticed that there's nothing related to a fairly common (in my personal experience) cryptic traceback relating to the `with` statement:
with ContextManager as ctx: ... # do something with `ctx` ... Traceback (most recent call last): File "<stdin>", line 1, in <module> AttributeError: __enter__
I'm seeing a different message, so it looks like something HAS been improved: Python 3.11.0a0 (heads/main:ed524b4569, Aug 14 2021, 11:29:01) [GCC 8.3.0] on linux Type "help", "copyright", "credits" or "license" for more information.
import contextlib with contextlib.ExitStack: ... ... Traceback (most recent call last): File "<stdin>", line 1, in <module> TypeError: 'ABCMeta' object does not support the context manager protocol
This occurs when one forgets to use a instance of a context manager class and uses the class itself. It's obviously not a very helpful traceback. ("Is it not a context manager?" "Is it the wrong class?") Something like the following would be better.
with ContextManager as ctx: ... # do something with `ctx` ... Traceback (most recent call last): File "<stdin>", line 1, in <module> AttributeError: <type Context manager> is not a context manager. Did you mean "with ContextManager()..."?
The actual traceback message should probably be more specific than "<type Context manager> is not a context manager". Thoughts?
The "did you mean" part depends on or assumes that it can figure out that calling it would have given a viable context manager. This could be done by probing whether thing.__enter__ exists, but I'm not sure that'd be entirely safe. Also, it won't catch those made from generators:
@contextlib.contextmanager ... def foo(): yield ... with foo: ... ... Traceback (most recent call last): File "<stdin>", line 1, in <module> TypeError: 'function' object does not support the context manager protocol with foo(): ... ... Ellipsis foo
In any case, the biggest advantage (IMO) comes from naming the type, which will make it easy to distinguish the object from its type. ChrisA