[New-bugs-announce] [issue46330] Simplify the signature of __exit__

Jelle Zijlstra report at bugs.python.org
Mon Jan 10 08:08:08 EST 2022

New submission from Jelle Zijlstra <jelle.zijlstra at gmail.com>:

With Irit's recent changes (bpo-45711), the (typ, exc, tb) tuple is now always redundant with just exc. As a result, `__exit__` methods now should only need to accept a single argument. If we were designing the context manager protocol from scratch, we could do:

class CM:
    def __enter__(self):
        return self
    def __exit__(self, exc: BaseException | None, /):
        if exc is not None:
           print("an exception occurred")

Instead of the current cumbersome three-parameter `__exit__`.

But we're not designing it from scratch, and we need to deal with lots of existing code with three-parameter `__exit__` methods.

One possible decision is that we keep the existing signature, because the cost of changing it is too high. However, this would needlessly complicate learning Python for all future new users.

Here's a possible migration approach:
- When the interpreter encounters a `with` statement, it does `getattr(cm, "__enable_single_parameter_exit__", False)` on the context manager. If this attribute exists and is truthy, `__exit__` is called with a single parameter; otherwise we keep the current behavior.
- After a few releases, we flip the default, so you have to explicitly set `__enable_single_parameter_exit__ = False` to keep three-parameter `__exit__`. Libraries that still wish to support Python 3.10 and older can use this.
- Eventually, after Python 3.10 reaches EOL, we always use one-parameter `__exit__`.

To help the migration, we can do a few things:
- Linters and type checkers can check for discrepancies in the __exit__ signature.
- In the interpreter, we can provide a custom error message if the number of parameters to `__exit__` is not as expected, nudging the user towards setting `__enable_single_parameter_exit__`.
- In the compiler, we can likely warn if a class body contains three-parameter `__exit__` but doesn't set `__enable_single_parameter_exit__ = False`, or similar discrepancies.

Everything here should apply equally to `__aexit__`.

This will require a PEP if implemented, but I want to first see whether other people think this is worth pursuing at all.

messages: 410210
nosy: Jelle Zijlstra, iritkatriel
priority: normal
severity: normal
status: open
title: Simplify the signature of __exit__

Python tracker <report at bugs.python.org>

More information about the New-bugs-announce mailing list