Nick Coghlan <ncogh...@gmail.com> added the comment:

TestCase.setUp() and TestCase.tearDown() were amongst the precursors 
to__enter__() and __exit__(). addCleanUp() fills exactly the same role here - 
and I've seen *plenty* of positive feedback directed towards Michael for that 
addition to the unittest API.

For individual one-off cases, a flag variable and an if statement inside a 
finally block is an adequate, but not ideal, solution, because it suffers from 
all the readability and auditability problems of *any* try/finally based 
solution. It's particularly annoying when an object *does* support the context 
management protocol, but I can't use a with statement simply because I don't 
*always* need (and/or own) that resource (this kind of thing happens in a few 
places in runpy, since the behaviour changes depending on whether or not runpy 
created temporary objects for itself or was given objects as arguments)

Custom context managers are typically a bad idea in these circumstances, 
because they make readability *worse* (relying on people to understand what the 
context manager does). A standard library based solution, on the other hand, 
offers the best of both worlds:
- code becomes easier to write correctly and to audit for correctness (for all 
the reasons with statements were added in the first place)
- the idiom will eventually become familiar to all Python users

If other "cleanup function" registration APIs didn't already exist, I'd agree 
with you that this needed further exposure. However, I simply don't agree 
that's the case - atexit and addCleanup provide your field testing, the rest of 
the design is just a matter of integrating those concepts with the context 
management protocol.

Indeed, one of the objections I received after we deprecated 
contextlib.nested() was that you couldn't easily pass a programmatically 
generated list of resources to nested with statements. Given 
contextlib.CleanupManager it becomes trivial:

    with contextlib.CleanupManager as cm:
        files = [cm.enter_context(open(fname)) for fname in names]
        # All files will be closed when we leave the context

I can take this up on python-dev if you want, but I hope to persuade you that 
the desire *is* there, it's just that the workarounds for the lack of this 
functionality involve avoiding the context management protocol entirely:

    try:
        files = [open(fname) for fname in names]
        # Are all files closed when we're done?
        # I dunno, scroll down past the algorithm code to check!


        # Avoiding this would be good for all the reasons the
        # with statement was added in the first place

    finally:
        for f in files:
            f.close()

----------

_______________________________________
Python tracker <rep...@bugs.python.org>
<http://bugs.python.org/issue13585>
_______________________________________
_______________________________________________
Python-bugs-list mailing list
Unsubscribe: 
http://mail.python.org/mailman/options/python-bugs-list/archive%40mail-archive.com

Reply via email to