[Python-Dev] Handle errors in cleanup code

Nick Coghlan ncoghlan at gmail.com
Mon Jun 12 03:46:22 EDT 2017


On 12 June 2017 at 17:10, Serhiy Storchaka <storchaka at gmail.com> wrote:
> Does it mean that we should rewrite every chunk of code similar to the
> above? And if such cumbersome code is necessary and become common, maybe it
> needs syntax support in the language? Or changing the semantic of exceptions
> raised in error handlers and finally blocks?

No, as in general there's no way for us to reliably tell the
difference between intentionally changing the exception type (e.g.
KeyError->AttributeError and vice-versa), unintentionally changing the
exception type due to a bug in the cleanup code (e.g.
SystemExit->KeyError), and the exception type changing due to external
events (e.g. KeyError -> KeyboardInterrupt).

So in the example given if an expected-and-allowed kind of exception
can escape from "undo_something()", it's not really cleanup code, it's
normal code, and needs to be refactored more like the way most close()
methods work: particular known-to-be-possible exceptions get caught
and reported (or silently ignored), but not propagated.

That last example also shows that the suggested replacement idiom is
incorrect, as it can suppress SystemExit, KeyboardInterrupt, etc.

That said, as far as better builtin support for dynamic resource
management goes: that would currently be contextlib.ExitStack.

I'm also completely open to adding more hooks to let users tweak how
that reports exceptions, including adding a contextlib.ResourceSet
variant, which *doesn't* semantically nest the callback handling the
way ExitStack does, and instead collects any exceptions raised into a
new __cleanup_errors__ attribute on the original exception (thus
leaving the original exception chain untouched).

That would still need some fiddling to work out what to do in the
"exception that doesn't inherit from Exception" case (probably clean
up all the registered resources anyway then raise the first such
exception caught, while still attaching all the others to
__cleanup_errors__ on the original exception), but it's likely to be
significantly more feasible than doing anything at the syntax level.

Cheers,
Nick.

-- 
Nick Coghlan   |   ncoghlan at gmail.com   |   Brisbane, Australia


More information about the Python-Dev mailing list