unpacking context managers in WITH statement

Hello, With the removal of "contextlib.nested" in python 3.2 nothing was introduced to replace it. However, I found it pretty useful, despite the fact that it had its own quirks. These quirks can (at least partially) be addressed by allowing unpacking syntax in the context manager. Consider the following snipped of code: ctxs = () if args.profile: ctxs += (ApplicationProfilerContext(),) if args.logging: ctxs += (ApplicationLoggingContext(),) with *ctxs: Application.run() As of now, without "nested" we have either option of reimplementing it, or to write lots of ugly code with nested 'try..except's. So the feature was taken out, but nothing replaced it. What do you think guys? Thanks, Yury

Of course there is something to replace nested:
The nested function was removed because it is broken. E.g. take this:
What if opening of spam.txt produces an exception? Then egg.txt will never be closed! The new with syntax takes care of this. It basically rewrites it as:
On 02/03/2012 04:09 PM, Yury Selivanov wrote:

This is not about explicitly writing comma-separated list of context managers in the statement, but rather about ability to compose this list dynamically. With unpacking you won't have the problem of uncaught exception in __new__/__init__, because such exception would propagate on the stage of constructing the list of managers. Exceptions occurred during the with statement execution, i.e. in __enter__ and __exit__ methods will work just fine, or am I missing something? On 2012-02-03, at 11:30 AM, Mathias Panzenböck wrote:

Oh, wait. You do something a bit different. Hm, yes, when you have a list of context managers its something different. Still, I'm not sure if it is a good thing to do it like you've proposed. After all, usually the constructor of a nested context manager shall only be called if the parent context could be entered. You would construct all context managers before you enter any. Maybe it's ok for for your case, but it might send the wrong signal to the developers and might be used like nested was (see my other mail). On 02/03/2012 04:09 PM, Yury Selivanov wrote:

Well, I bet most of the developers will continue using explicit syntax as it is just more convenient. Unpacking is just a specific feature to address some specific needs, where the case about "not executing constructor in case of parent context fault" may not be applicable. "With" statement is far more now than just about opening files after all ;) On 2012-02-03, at 11:35 AM, Mathias Panzenböck wrote:

On 3 February 2012 15:09, Yury Selivanov <yselivanov.ml@gmail.com> wrote:
Well, I quite like this syntax and it does allow you to do something not currently easily possible: with *ctxs as tuple_of_results: ... The use case is reasonably obscure however, and should this be possible: with *ctx, other as tuple_of_results, another: ... Michael
-- http://www.voidspace.org.uk/ May you do good and not evil May you find forgiveness for yourself and forgive others May you share freely, never taking more than you give. -- the sqlite blessing http://www.sqlite.org/different.html

On 2012-02-03, at 12:50 PM, Michael Foord wrote:
with *ctxs as tuple_of_results:
This is not necessary, as 'ctxs' already holds all instances of all context managers; so the 'ctxs' would be equal to 'tuple_of_results'
with *ctx, other as tuple_of_results, another: ...
Looks useful to me. - Yury

On 3 February 2012 18:06, Yury Selivanov <yselivanov.ml@gmail.com> wrote:
The results are whatever is returned by ctx.__enter__(), not the context manager itself. Michael
-- http://www.voidspace.org.uk/ May you do good and not evil May you find forgiveness for yourself and forgive others May you share freely, never taking more than you give. -- the sqlite blessing http://www.sqlite.org/different.html

On Sat, Feb 4, 2012 at 1:09 AM, Yury Selivanov <yselivanov.ml@gmail.com> wrote:
As of now, without "nested" we have either option of reimplementing it, or to write lots of ugly code with nested 'try..except's. So the feature was taken out, but nothing replaced it.
What do you think guys?
I think you should try contextlib2 :) Specifically, ContextStack: http://contextlib2.readthedocs.org/en/latest/index.html#contextlib2.ContextS... Cheers, Nick. -- Nick Coghlan | ncoghlan@gmail.com | Brisbane, Australia

On Tue, Feb 7, 2012 at 6:08 AM, Yury Selivanov <yselivanov.ml@gmail.com> wrote:
Well, native syntax would be much useful, but ContextStack seems like a decent workaround. Will it be included in the stdlib (py3.3)?
Most likely (I'm the primary maintainer of contextlib, so it's basically my call). Feedback on what it's like to use in practice would definitely help with that - I put it up on PyPI as contextlib2 so people could try it out and help me avoid repeating the mistakes we made with nested() (which was an error prone bug trap). Cheers, Nick. -- Nick Coghlan | ncoghlan@gmail.com | Brisbane, Australia

03.02.12 17:09, Yury Selivanov написав(ла):
class EmptyContext: def __enter__(self): return self def __exit__(self, exc_type, exc_value, traceback): pass with ApplicationProfilerContext() if args.profile else EmptyContext(): with ApplicationLoggingContext() if args.logging else EmptyContext(): Application.run() Of cause, it will be better to use some special singleton value (None, False or ellipsis) instead EmptyContext(). If any false value would mean an empty context, we will be able to use "with args.profile and ApplicationProfilerContext()" idiom.

Of course there is something to replace nested:
The nested function was removed because it is broken. E.g. take this:
What if opening of spam.txt produces an exception? Then egg.txt will never be closed! The new with syntax takes care of this. It basically rewrites it as:
On 02/03/2012 04:09 PM, Yury Selivanov wrote:

This is not about explicitly writing comma-separated list of context managers in the statement, but rather about ability to compose this list dynamically. With unpacking you won't have the problem of uncaught exception in __new__/__init__, because such exception would propagate on the stage of constructing the list of managers. Exceptions occurred during the with statement execution, i.e. in __enter__ and __exit__ methods will work just fine, or am I missing something? On 2012-02-03, at 11:30 AM, Mathias Panzenböck wrote:

Oh, wait. You do something a bit different. Hm, yes, when you have a list of context managers its something different. Still, I'm not sure if it is a good thing to do it like you've proposed. After all, usually the constructor of a nested context manager shall only be called if the parent context could be entered. You would construct all context managers before you enter any. Maybe it's ok for for your case, but it might send the wrong signal to the developers and might be used like nested was (see my other mail). On 02/03/2012 04:09 PM, Yury Selivanov wrote:

Well, I bet most of the developers will continue using explicit syntax as it is just more convenient. Unpacking is just a specific feature to address some specific needs, where the case about "not executing constructor in case of parent context fault" may not be applicable. "With" statement is far more now than just about opening files after all ;) On 2012-02-03, at 11:35 AM, Mathias Panzenböck wrote:

On 3 February 2012 15:09, Yury Selivanov <yselivanov.ml@gmail.com> wrote:
Well, I quite like this syntax and it does allow you to do something not currently easily possible: with *ctxs as tuple_of_results: ... The use case is reasonably obscure however, and should this be possible: with *ctx, other as tuple_of_results, another: ... Michael
-- http://www.voidspace.org.uk/ May you do good and not evil May you find forgiveness for yourself and forgive others May you share freely, never taking more than you give. -- the sqlite blessing http://www.sqlite.org/different.html

On 2012-02-03, at 12:50 PM, Michael Foord wrote:
with *ctxs as tuple_of_results:
This is not necessary, as 'ctxs' already holds all instances of all context managers; so the 'ctxs' would be equal to 'tuple_of_results'
with *ctx, other as tuple_of_results, another: ...
Looks useful to me. - Yury

On 3 February 2012 18:06, Yury Selivanov <yselivanov.ml@gmail.com> wrote:
The results are whatever is returned by ctx.__enter__(), not the context manager itself. Michael
-- http://www.voidspace.org.uk/ May you do good and not evil May you find forgiveness for yourself and forgive others May you share freely, never taking more than you give. -- the sqlite blessing http://www.sqlite.org/different.html

On Sat, Feb 4, 2012 at 1:09 AM, Yury Selivanov <yselivanov.ml@gmail.com> wrote:
As of now, without "nested" we have either option of reimplementing it, or to write lots of ugly code with nested 'try..except's. So the feature was taken out, but nothing replaced it.
What do you think guys?
I think you should try contextlib2 :) Specifically, ContextStack: http://contextlib2.readthedocs.org/en/latest/index.html#contextlib2.ContextS... Cheers, Nick. -- Nick Coghlan | ncoghlan@gmail.com | Brisbane, Australia

On Tue, Feb 7, 2012 at 6:08 AM, Yury Selivanov <yselivanov.ml@gmail.com> wrote:
Well, native syntax would be much useful, but ContextStack seems like a decent workaround. Will it be included in the stdlib (py3.3)?
Most likely (I'm the primary maintainer of contextlib, so it's basically my call). Feedback on what it's like to use in practice would definitely help with that - I put it up on PyPI as contextlib2 so people could try it out and help me avoid repeating the mistakes we made with nested() (which was an error prone bug trap). Cheers, Nick. -- Nick Coghlan | ncoghlan@gmail.com | Brisbane, Australia

03.02.12 17:09, Yury Selivanov написав(ла):
class EmptyContext: def __enter__(self): return self def __exit__(self, exc_type, exc_value, traceback): pass with ApplicationProfilerContext() if args.profile else EmptyContext(): with ApplicationLoggingContext() if args.logging else EmptyContext(): Application.run() Of cause, it will be better to use some special singleton value (None, False or ellipsis) instead EmptyContext(). If any false value would mean an empty context, we will be able to use "with args.profile and ApplicationProfilerContext()" idiom.
participants (6)
-
Alexander Heger
-
Mathias Panzenböck
-
Michael Foord
-
Nick Coghlan
-
Serhiy Storchaka
-
Yury Selivanov