Workaround for quirks in contextlib.nested

I understand why contextlib.nested is deprecated .

But if I write a program for an old version of python without a plural form with (ie, <2.7), I (almost) have no other choice.

To avoid a failure of the following design:

with nested(open("f1"), open("f2")) as (f1, f2): 

( f1 will not be closed if opening f2 fails because the context manager is not entered)

I could imagine a context manager that translates initialization into my __enter__ :

 @contextmanager def late_init(f, *a, **k): r = f(*a, **k) with r as c: yield c 

Do I think that right

 with nested(late_init(open, "f1"), late_init(open, "f2")) as (f1, f2): 

will be enough to make it "clean"?


The given usage example is just an example. Imagine that you have a list of files whose length was not prematurely known. Then neither 2.7 linked with can be used, nor nested up to 2.7 words with several indentation with .


I probably should be more detailed.

This question solves the problem at a glance: the function call is executed in a safe place, so that a failure can be detected and handled accordingly.

My question is: does it cure a flaw or am I having other problems?

+4
source share
2 answers

Now I saw that my solution ( late_init() ) would probably cure the first attack:

First, since all context managers are built before the __new__() and __init__() functions are called for internal context managers, they are not really covered by the scope of external context managers. This means, for example, that when using nested() to open two files, this is a programming error, since the first file will not be closed if an exception occurs when opening the second file.

But the second one:

Secondly, if the __enter__() method of one of the internal contexts throw an exception that is caught and suppressed by the __exit__() method of one of the external context managers, this construct will raise a RuntimeError rather than skipping the body with the statement.

(which is probably caused by the missing yield vars from nested() ) is not covered by this.

So either

  • avoiding the use of โ€œexclusive eatersโ€ in combination with nested() ,
  • given nested() should be replaced with a better or
  • Avoid using variable-length exception manager lists and older versions of Python.
+1
source

The contextlib.nested tool is designed to compose context managers in one. This was deprecated because it was erroneous in design (that's exactly how you showed where f1 would not be closed if f2 didn't open).

You are using a case that does not require composition. Regular nesting will be sufficient:

 with open('f1') as f1: with open('f2') as f2: ... 
+3
source

Source: https://habr.com/ru/post/1403305/


All Articles