Reputation: 4833
I have been using a lot of context managers as a clean way of composing various setup/teardown situations. Since my deployments target Python 2.6, this means using contextlib.nested
.
Lately I've been interested in supporting both Python 2.x and Python 3 with the same code base. This has been possible with some projects, but I'm running into trouble in the case of context managers because:
contextlib.nested
isn't supported in Python 3with aa() as a, bb() as b: ...
) aren't supported in 2.6. There is a basic syntactic incompatibility here. For various reasons beyond my control, 2.7 may be difficult to get into production for now, but I'd like to future-proof the code as much as possible, hence the Python 3 interest.
Can anyone suggest a workaround for supporting nested context managers in the same code base for 2.6 and 3.x? Or is this a lost cause?
Upvotes: 2
Views: 476
Reputation: 91500
If the quirks of nested
that Veedrac mentioned aren't an issue for you, you can just copy the code from the Python standard library.
If they do bother you, then your only choices are to manually nest them, or to drop Python 2.6 support. It really doesn't matter if you use two code-bases or one for this. If this is the case, then the only way it will work in Python 2.6 would be to nest them. I guess you could play with writing some kind of custom 2to3 fixer that translates your unnested 2.7 code into nested 2.6 code. But honestly, it will be less painful to just use a single code-base with nested managers until you can drop 2.6 support.
Upvotes: 2
Reputation: 57281
You can always reimplement nested
on your own and keep it in a compatibility.py
file within the project. This is often what is done to cross versions.
Edit: I see that @JBernardo already mentioned this solution in a comment.
Upvotes: 1
Reputation: 60147
From the docs:
This function has two major quirks that have led to it being deprecated. Firstly, as the context managers are all constructed before the function is invoked, the
__new__()
and__init__()
methods of the inner context managers are not actually covered by the scope of the outer context managers. That means, for example, that usingnested()
to open two files is a programming error as the first file will not be closed promptly if an exception is thrown when opening the second file.Secondly, if the
__enter__()
method of one of the inner context managers raises an exception that is caught and suppressed by the__exit__()
method of one of the outer context managers, this construct will raiseRuntimeError
rather than skipping the body of the with statement.
Thus in almost all cases the correct answer is JBernardo's. It's a bit more indenting but it's a bit less buggy, too.
Upvotes: 3