Re: [Python-Dev] PEP 377 - allow __enter__() methods to skip the statement body

2009-03-16 Thread Nick Coghlan
P.J. Eby wrote:
> At 06:28 AM 3/16/2009 +1000, Nick Coghlan wrote:
>> There are some practical hurdles to that idea (specifically, creating a
>> callable which uses its parent's namespace rather than having its own),
>> but the basic concept seems sound.
> 
> Actually, that bit's pretty simple -- they're just "nonlocal"
> variables.  But the cost of creating that function, and the cost of
> having cell variables in the surrounding function is potentially high. 
> (In CPython at least, function calls are optimized in certain ways when
> the function only has "fast" locals, and no "cell" locals.)

Some additional complexities occurred to me today - they go by the names
"return", "break" and "continue". With the current design those are
perfectly well defined inside a with statement, but they pose a pretty
serious hurdle for a practical implementation of glyph's idea.

So I'm going to stick with the more modest approach of a new control
flow exception for PEP 377.

I still find the callable block idea somewhat intriguing, but if it ever
happens it should be a new construct rather than overloading the meaning
of the with statement.

Cheers,
Nick.

-- 
Nick Coghlan   |   ncogh...@gmail.com   |   Brisbane, Australia
---
___
Python-Dev mailing list
Python-Dev@python.org
http://mail.python.org/mailman/listinfo/python-dev
Unsubscribe: 
http://mail.python.org/mailman/options/python-dev/archive%40mail-archive.com


Re: [Python-Dev] PEP 377 - allow __enter__() methods to skip the statement body

2009-03-16 Thread Nick Coghlan
Michael Foord wrote:
> Well, StopIteration is still an implementation detail that only
> occasionally bleeds through to actual programming. It says nothing about
> whether using exceptions for non-exceptional circumstances (control
> flow) is good practise. Personally I think it makes the intent of code
> less easy to understand - in effect the exceptions *are* being used as a
> goto.

Note that raising SkipStatement manually is likely to be even rarer than
raising StopIteration. Catching it should almost never happen other than
implicitly inside a with statement (that's the reason I made it a peer
of SystemExit and GeneratorExit rather than a peer of StopIteration).

It is primarily proposed as a way for contextlib.contextmanager to tell
the interpreter that the underlying generator didn't yield, so the body
of the with statement should be skipped completely. It just so happens
that manually implemented context managers will also be free to use it
if they need to for some reason.

An alternative approach worth considering may be to use NotImplemented
as a model instead of StopIteration. With that approach, instead of
having SkipStatement be an exception, have it be a singleton that can be
returned from __enter__ to indicate that the with statement body would
be skipped.

That has a big advantage over using an exception when it comes to
execution speed. The statement semantics in that case would become:

mgr = (EXPR)
exit = mgr.__exit__  # Not calling it yet
value = mgr.__enter__()
if value is not SkipStatement:
exc = True
try:
try:
VAR = value  # Only if "as VAR" is present
BLOCK
except:
# The exceptional case is handled here
exc = False
if not exit(*sys.exc_info()):
raise
# The exception is swallowed if exit() returns true
finally:
# The normal and non-local-goto cases are handled here
if exc:
exit(None, None, None)

(keeping in mind that I already plan to change PEP 377 to drop the idea
of assigning anything to VAR when the statement body is skipped)

The major drawback of that approach is that it becomes a little trickier
to write a context manager like nested() correctly - it would need to
check all of the __enter__() return values and start unwinding the
context manager stack if it encountered SkipStatement. The fix isn't
particularly complicated*, but it does contrast with the fact that
having SkipStatement as an exception means that the current
implementation of nested() will "just work" with the new semantics.

Cheers,
Nick.

* For reference, to support a "SkipStatement as return value" approach
the main loop in nested() would have to change from this:

for mgr in managers:
exit = mgr.__exit__
enter = mgr.__enter__
vars.append(enter())
exits.append(exit)
yield vars

To this:

for mgr in managers:
exit = mgr.__exit__
enter = mgr.__enter__
var = enter()
if var is SkipStatement:
break
vars.append(var)
exits.append(exit)
else:
yield vars

As mentioned above, if SkipStatement is an exception then nested() works
correctly without any changes.

-- 
Nick Coghlan   |   ncogh...@gmail.com   |   Brisbane, Australia
---
___
Python-Dev mailing list
Python-Dev@python.org
http://mail.python.org/mailman/listinfo/python-dev
Unsubscribe: 
http://mail.python.org/mailman/options/python-dev/archive%40mail-archive.com


Re: [Python-Dev] Ext4 data loss

2009-03-16 Thread Nick Coghlan
Greg Ewing wrote:
> What might make more sense is a context manager,
> e.g.
> 
>   with renaming_file("blarg.txt", "w") as f:
> ...

As you were describing the problems with "rename on close", I actually
immediately thought of the oft-repeated db transaction commit/rollback
example from PEP 343 :)

Cheers,
Nick.

-- 
Nick Coghlan   |   ncogh...@gmail.com   |   Brisbane, Australia
---
___
Python-Dev mailing list
Python-Dev@python.org
http://mail.python.org/mailman/listinfo/python-dev
Unsubscribe: 
http://mail.python.org/mailman/options/python-dev/archive%40mail-archive.com


Re: [Python-Dev] PEP 377 - allow __enter__() methods to skip the statement body

2009-03-16 Thread Guido van Rossum
I have no right to speak because I haven't read through all the
details of the proposal, but reading this I am very sad that we have
to introduce a whole new exception (and one with special status as
well) in order to fix such a niggly corner case of the context manager
protocol.

Since IIUC the original context manager design was intended to have
exactly one yield in the body of the context manager -- can't we just
declare fewer (or more) yields an error and rase an appropriate
TypeError or something?

--Guido

On Mon, Mar 16, 2009 at 4:43 AM, Nick Coghlan  wrote:
> Michael Foord wrote:
>> Well, StopIteration is still an implementation detail that only
>> occasionally bleeds through to actual programming. It says nothing about
>> whether using exceptions for non-exceptional circumstances (control
>> flow) is good practise. Personally I think it makes the intent of code
>> less easy to understand - in effect the exceptions *are* being used as a
>> goto.
>
> Note that raising SkipStatement manually is likely to be even rarer than
> raising StopIteration. Catching it should almost never happen other than
> implicitly inside a with statement (that's the reason I made it a peer
> of SystemExit and GeneratorExit rather than a peer of StopIteration).
>
> It is primarily proposed as a way for contextlib.contextmanager to tell
> the interpreter that the underlying generator didn't yield, so the body
> of the with statement should be skipped completely. It just so happens
> that manually implemented context managers will also be free to use it
> if they need to for some reason.
>
> An alternative approach worth considering may be to use NotImplemented
> as a model instead of StopIteration. With that approach, instead of
> having SkipStatement be an exception, have it be a singleton that can be
> returned from __enter__ to indicate that the with statement body would
> be skipped.
>
> That has a big advantage over using an exception when it comes to
> execution speed. The statement semantics in that case would become:
>
>    mgr = (EXPR)
>    exit = mgr.__exit__  # Not calling it yet
>    value = mgr.__enter__()
>    if value is not SkipStatement:
>        exc = True
>        try:
>            try:
>                VAR = value  # Only if "as VAR" is present
>                BLOCK
>            except:
>                # The exceptional case is handled here
>                exc = False
>                if not exit(*sys.exc_info()):
>                    raise
>                # The exception is swallowed if exit() returns true
>        finally:
>            # The normal and non-local-goto cases are handled here
>            if exc:
>                exit(None, None, None)
>
> (keeping in mind that I already plan to change PEP 377 to drop the idea
> of assigning anything to VAR when the statement body is skipped)
>
> The major drawback of that approach is that it becomes a little trickier
> to write a context manager like nested() correctly - it would need to
> check all of the __enter__() return values and start unwinding the
> context manager stack if it encountered SkipStatement. The fix isn't
> particularly complicated*, but it does contrast with the fact that
> having SkipStatement as an exception means that the current
> implementation of nested() will "just work" with the new semantics.
>
> Cheers,
> Nick.
>
> * For reference, to support a "SkipStatement as return value" approach
> the main loop in nested() would have to change from this:
>
>    for mgr in managers:
>        exit = mgr.__exit__
>        enter = mgr.__enter__
>        vars.append(enter())
>        exits.append(exit)
>    yield vars
>
> To this:
>
>    for mgr in managers:
>        exit = mgr.__exit__
>        enter = mgr.__enter__
>        var = enter()
>        if var is SkipStatement:
>            break
>        vars.append(var)
>        exits.append(exit)
>    else:
>        yield vars
>
> As mentioned above, if SkipStatement is an exception then nested() works
> correctly without any changes.
>
> --
> Nick Coghlan   |   ncogh...@gmail.com   |   Brisbane, Australia
> ---
> ___
> Python-Dev mailing list
> Python-Dev@python.org
> http://mail.python.org/mailman/listinfo/python-dev
> Unsubscribe: 
> http://mail.python.org/mailman/options/python-dev/guido%40python.org
>



-- 
--Guido van Rossum (home page: http://www.python.org/~guido/)
___
Python-Dev mailing list
Python-Dev@python.org
http://mail.python.org/mailman/listinfo/python-dev
Unsubscribe: 
http://mail.python.org/mailman/options/python-dev/archive%40mail-archive.com


Re: [Python-Dev] PEP 377 - allow __enter__() methods to skip the statement body

2009-03-16 Thread Guido van Rossum
Moreover, since the main use case seems to be fixing a corner case of
the nested() context manager, perhaps the effort towards changing the
language would be better directed towards supporting "with a, b:" as a
shorthand for "with a: with b:" .

On Mon, Mar 16, 2009 at 10:01 AM, Guido van Rossum  wrote:
> I have no right to speak because I haven't read through all the
> details of the proposal, but reading this I am very sad that we have
> to introduce a whole new exception (and one with special status as
> well) in order to fix such a niggly corner case of the context manager
> protocol.
>
> Since IIUC the original context manager design was intended to have
> exactly one yield in the body of the context manager -- can't we just
> declare fewer (or more) yields an error and rase an appropriate
> TypeError or something?
>
> --Guido
>
> On Mon, Mar 16, 2009 at 4:43 AM, Nick Coghlan  wrote:
>> Michael Foord wrote:
>>> Well, StopIteration is still an implementation detail that only
>>> occasionally bleeds through to actual programming. It says nothing about
>>> whether using exceptions for non-exceptional circumstances (control
>>> flow) is good practise. Personally I think it makes the intent of code
>>> less easy to understand - in effect the exceptions *are* being used as a
>>> goto.
>>
>> Note that raising SkipStatement manually is likely to be even rarer than
>> raising StopIteration. Catching it should almost never happen other than
>> implicitly inside a with statement (that's the reason I made it a peer
>> of SystemExit and GeneratorExit rather than a peer of StopIteration).
>>
>> It is primarily proposed as a way for contextlib.contextmanager to tell
>> the interpreter that the underlying generator didn't yield, so the body
>> of the with statement should be skipped completely. It just so happens
>> that manually implemented context managers will also be free to use it
>> if they need to for some reason.
>>
>> An alternative approach worth considering may be to use NotImplemented
>> as a model instead of StopIteration. With that approach, instead of
>> having SkipStatement be an exception, have it be a singleton that can be
>> returned from __enter__ to indicate that the with statement body would
>> be skipped.
>>
>> That has a big advantage over using an exception when it comes to
>> execution speed. The statement semantics in that case would become:
>>
>>    mgr = (EXPR)
>>    exit = mgr.__exit__  # Not calling it yet
>>    value = mgr.__enter__()
>>    if value is not SkipStatement:
>>        exc = True
>>        try:
>>            try:
>>                VAR = value  # Only if "as VAR" is present
>>                BLOCK
>>            except:
>>                # The exceptional case is handled here
>>                exc = False
>>                if not exit(*sys.exc_info()):
>>                    raise
>>                # The exception is swallowed if exit() returns true
>>        finally:
>>            # The normal and non-local-goto cases are handled here
>>            if exc:
>>                exit(None, None, None)
>>
>> (keeping in mind that I already plan to change PEP 377 to drop the idea
>> of assigning anything to VAR when the statement body is skipped)
>>
>> The major drawback of that approach is that it becomes a little trickier
>> to write a context manager like nested() correctly - it would need to
>> check all of the __enter__() return values and start unwinding the
>> context manager stack if it encountered SkipStatement. The fix isn't
>> particularly complicated*, but it does contrast with the fact that
>> having SkipStatement as an exception means that the current
>> implementation of nested() will "just work" with the new semantics.
>>
>> Cheers,
>> Nick.
>>
>> * For reference, to support a "SkipStatement as return value" approach
>> the main loop in nested() would have to change from this:
>>
>>    for mgr in managers:
>>        exit = mgr.__exit__
>>        enter = mgr.__enter__
>>        vars.append(enter())
>>        exits.append(exit)
>>    yield vars
>>
>> To this:
>>
>>    for mgr in managers:
>>        exit = mgr.__exit__
>>        enter = mgr.__enter__
>>        var = enter()
>>        if var is SkipStatement:
>>            break
>>        vars.append(var)
>>        exits.append(exit)
>>    else:
>>        yield vars
>>
>> As mentioned above, if SkipStatement is an exception then nested() works
>> correctly without any changes.
>>
>> --
>> Nick Coghlan   |   ncogh...@gmail.com   |   Brisbane, Australia
>> ---
>> ___
>> Python-Dev mailing list
>> Python-Dev@python.org
>> http://mail.python.org/mailman/listinfo/python-dev
>> Unsubscribe: 
>> http://mail.python.org/mailman/options/python-dev/guido%40python.org
>>
>
>
>
> --
> --Guido van Rossum (home page: http://www.python.org/~guido/)
>



-- 
--Guido van Rossum (home page: http://www.python.org/~guido/)

Re: [Python-Dev] PEP 377 - allow __enter__() methods to skip the statement body

2009-03-16 Thread Steven Bethard
On Mon, Mar 16, 2009 at 11:06 AM, Guido van Rossum  wrote:
> Moreover, since the main use case seems to be fixing a corner case of
> the nested() context manager, perhaps the effort towards changing the
> language would be better directed towards supporting "with a, b:" as a
> shorthand for "with a: with b:" .
>
> On Mon, Mar 16, 2009 at 10:01 AM, Guido van Rossum  wrote:
>> I have no right to speak because I haven't read through all the
>> details of the proposal, but reading this I am very sad that we have
>> to introduce a whole new exception (and one with special status as
>> well) in order to fix such a niggly corner case of the context manager
>> protocol.
>>
>> Since IIUC the original context manager design was intended to have
>> exactly one yield in the body of the context manager -- can't we just
>> declare fewer (or more) yields an error and rase an appropriate
>> TypeError or something?

It's not really a generator specific thing. You can generate similar
problems by just defining a class with an __enter__() method that
raises an exception.

But I agree that it seems like a big change for a small corner case.
Is there anything other than contextlib.nested() which needs this? If
there is no other use case, then I'm a strong +1 for Guido's
suggestion of providing syntactic support for ``with a, b:`` instead.

BTW, I think the explanation of the problem isn't as clear as it could
be. The core problem, if I understand it right, is that
contextlib.nested() is not equivalent to a real nested with statement
because it calls the nested __enter__() methods too early. A real
nested with statement translates into something like::

mgr1.__enter__()
try:
mgr2.__enter__()
try:
BLOCK
except:
...
except:
if not mgr1.__exit__(*sys.exc_info()):
raise

But contextlib.nested() calls all the __enter__() methods in its own
__enter__() so it translates into something like::

mgr1.__enter__()
mgr2.__enter__()
try:
BLOCK
except:
...

The key problem here is that ``mgr2.__enter__()`` is outside of the
try block, and the context manager has no way to put it inside. So the
thing that contextlib.nested() really needs is a way to be able to
insert statements into the BLOCK part of the code. (I'm not actually
suggesting we go this route, but that seems to be what
contextlib.nested() is really after.)

Steve
-- 
I'm not *in*-sane. Indeed, I am so far *out* of sane that you appear a
tiny blip on the distant coast of sanity.
--- Bucky Katt, Get Fuzzy
___
Python-Dev mailing list
Python-Dev@python.org
http://mail.python.org/mailman/listinfo/python-dev
Unsubscribe: 
http://mail.python.org/mailman/options/python-dev/archive%40mail-archive.com


Re: [Python-Dev] PEP 377 - allow __enter__() methods to skip the statement body

2009-03-16 Thread Guido van Rossum
On Mon, Mar 16, 2009 at 11:26 AM, Steven Bethard
 wrote:
> On Mon, Mar 16, 2009 at 11:06 AM, Guido van Rossum  wrote:
>> Moreover, since the main use case seems to be fixing a corner case of
>> the nested() context manager, perhaps the effort towards changing the
>> language would be better directed towards supporting "with a, b:" as a
>> shorthand for "with a: with b:" .
>>
>> On Mon, Mar 16, 2009 at 10:01 AM, Guido van Rossum  wrote:
>>> I have no right to speak because I haven't read through all the
>>> details of the proposal, but reading this I am very sad that we have
>>> to introduce a whole new exception (and one with special status as
>>> well) in order to fix such a niggly corner case of the context manager
>>> protocol.
>>>
>>> Since IIUC the original context manager design was intended to have
>>> exactly one yield in the body of the context manager -- can't we just
>>> declare fewer (or more) yields an error and rase an appropriate
>>> TypeError or something?
>
> It's not really a generator specific thing. You can generate similar
> problems by just defining a class with an __enter__() method that
> raises an exception.

Huh? According to PEP 343, if __enter__ raises an exception, that's
the end of the story. __exit__ shouldn't be called, the exception is
not modified, the flow is interrupted right there.

> But I agree that it seems like a big change for a small corner case.
> Is there anything other than contextlib.nested() which needs this? If
> there is no other use case, then I'm a strong +1 for Guido's
> suggestion of providing syntactic support for ``with a, b:`` instead.
>
> BTW, I think the explanation of the problem isn't as clear as it could
> be. The core problem, if I understand it right, is that
> contextlib.nested() is not equivalent to a real nested with statement
> because it calls the nested __enter__() methods too early. A real
> nested with statement translates into something like::
>
>    mgr1.__enter__()
>    try:
>        mgr2.__enter__()
>        try:
>            BLOCK
>        except:
>            ...
>    except:
>        if not mgr1.__exit__(*sys.exc_info()):
>            raise
>
> But contextlib.nested() calls all the __enter__() methods in its own
> __enter__() so it translates into something like::
>
>    mgr1.__enter__()
>    mgr2.__enter__()
>    try:
>        BLOCK
>    except:
>        ...
>
> The key problem here is that ``mgr2.__enter__()`` is outside of the
> try block, and the context manager has no way to put it inside. So the
> thing that contextlib.nested() really needs is a way to be able to
> insert statements into the BLOCK part of the code. (I'm not actually
> suggesting we go this route, but that seems to be what
> contextlib.nested() is really after.)

Yeah, it really seems pretty much limited to contextlib.nested(). I'd
be happy to sacrifice the possibility to *exactly* emulate two nested
with-statements. The cost of a new exception is huge -- everyone will
have to explain its existence, and historically "you don't need to
know about this little detail" isn't acceptable for Python docs.
Little details you don't need to know about add up.

-- 
--Guido van Rossum (home page: http://www.python.org/~guido/)
___
Python-Dev mailing list
Python-Dev@python.org
http://mail.python.org/mailman/listinfo/python-dev
Unsubscribe: 
http://mail.python.org/mailman/options/python-dev/archive%40mail-archive.com


Re: [Python-Dev] Ext4 data loss

2009-03-16 Thread Valentino Volonghi


On Mar 15, 2009, at 3:25 PM, Greg Ewing wrote:


 with renaming_file("blarg.txt", "w") as f:
   ...



By chance during the weekend I actually wrote something like that:

from __future__ import with_statement

import os
import codecs
import shutil
import tempfile

from contextlib import contextmanager

TDIR = tempfile.mktemp(dir='/tmp/')

@contextmanager
def topen(filepath, mode='wb', bufsize=-1, encoding=None,
  inplace=False, tmpd=TDIR, sync=False):
"""
C{topen} is a transactional version of the Python builtin C{open}
function for file IO. It manages transactionality by using a
temporary file and then moving it to the final position once its
content has been written to disk.
If the mode used to open the file doesn't modify the file, this
function is equivalent to the built-in C{open} with automatic
file closing behavior.

@param filepath: The path of the file that you want to open
@type filepath: C{str}

@param mode: POSIX mode in which you want to open the file.
@type mode: C{str} see documentation for the format.

@param bufsize: Buffer size for file IO
@type bufsize: C{int} see documentation for the meaning

@param encoding: Encoding that should be used to read the file
@type encoding: C{str}

@param inplace: Indicates if the temporary file should reside
in the same directory of the final file.
@type inplace: C{bool}

@param tmpd: The temporary directory in which file IO is
 performed. Then files are moved from here to
 their original destination.
@type tmpd: C{str}

@param sync: Force topen to fsync the file before closing it
@type sync: C{bool}
"""
if 'r' in mode or 'a' in mode:
fp = filepath
else:
if inplace:
source_dir, _ = os.path.split(filepath)
tmpd = source_dir

if not os.path.exists(tmpd):
os.makedirs(tmpd)
_f, fp = tempfile.mkstemp(dir=tmpd)

if encoding is not None:
f = codecs.open(fp, mode, encoding=encoding)
else:
f = open(fp, mode, bufsize)

try:
yield f
finally:
if 'r' in mode:
if "+" in mode:
f.flush()
if sync:
os.fsync(f.fileno())
f.close()
return

f.flush()
if sync:
os.fsync(f.fileno())
f.close()
if 'w' in mode:
shutil.move(fp, filepath)

if __name__ == "__main__":
with topen("a_test") as f:
f.write("hello")
assert file("a_test", "rb").read() == 'hello'
assert os.path.exists(TDIR)
os.rmdir(TDIR)

with topen("a_test", mode="rb") as f:
assert f.read() == "hello"
assert not os.path.exists(TDIR)
os.remove("a_test")


--
Valentino Volonghi aka Dialtone
Now running MacOS X 10.5
Home Page: http://www.twisted.it
http://www.adroll.com



PGP.sig
Description: This is a digitally signed message part
___
Python-Dev mailing list
Python-Dev@python.org
http://mail.python.org/mailman/listinfo/python-dev
Unsubscribe: 
http://mail.python.org/mailman/options/python-dev/archive%40mail-archive.com


Re: [Python-Dev] PEP 377 - allow __enter__() methods to skip the statement body

2009-03-16 Thread Baptiste Carvello

Nick Coghlan a écrit :


Implementing __with__ instead would give the CM complete control over
whether or not to execute the block.

please note, however, that this is an important change in the semantics of the 
with statement. As things are today, barring exceptional circunstances, the body 
of the with statement *will* be executed immediately. This allows to forget 
about the with statement when first reading code, as it doesn't change the 
intent of the programmer. What Glyph is proposing is more akin to Ruby code blocks.


cheers,
Baptiste

___
Python-Dev mailing list
Python-Dev@python.org
http://mail.python.org/mailman/listinfo/python-dev
Unsubscribe: 
http://mail.python.org/mailman/options/python-dev/archive%40mail-archive.com


Re: [Python-Dev] PEP 377 - allow __enter__() methods to skip the statement body

2009-03-16 Thread Nick Coghlan
Guido van Rossum wrote:
> Yeah, it really seems pretty much limited to contextlib.nested(). I'd
> be happy to sacrifice the possibility to *exactly* emulate two nested
> with-statements.

Then I really haven't explained the problem well at all. One of the
premises of PEP 343 was "Got a frequently recurring block of code that
only has one variant sequence of statements somewhere in the middle?
Well, now you can factor that out by putting it in a generator,
replacing the part that varies with a yield statement and decorating the
generator with contextlib.contextmanager."

It turns out that there's a caveat that needs to go on the end of that
though: "Be very, very sure that the yield statement can *never* be
skipped or your context manager based version will raise a RuntimeError
in cases where the original code would have just skipped over the
variant section of code and resumed execution afterwards."

Nested context managers (whether through contextlib.nested or through
syntactic support) just turns out to be a common case where you *don't
necessarily know* just by looking at the code whether it can skip over
the body of the code or not.

Suppose you have 3 context managers that are regularly used together
(call them cmA(), cmB(), cmC() for now).

Writing that as:

  with cmA():
with cmB():
  with cmC():
do_something()

Or the tentatively proposed:

  with cmA(), cmB(), cmC():
do_something()

is definitely OK, regardless of the details of the context managers.

However, whether or not you can bundle that up into a *new* context
manager (regardless of nesting syntax) depends on whether or not an
outer context manager can suppress an exception raised by an inner one.

  @contextmanager
  def cmABC():
with cmA():
  with cmB():
with cmC():
  yield

  with cmABC():
do_something()

The above is broken if cmB().__enter__() or cmC.__enter__() can raise an
exception that cmA().__exit__() suppresses, or cmB.__enter__() raises an
exception that cmB().__exit__() suppresses. So whereas the inline
versions were clearly correct, the correctness of the second version
currently depends on details of the context managers themselves.
Changing the syntax to allow the three context managers to be written on
one line does nothing to fix that semantic discrepancy between the
original inline code and the factored out version.

PEP 377 is about changing the with statement semantics and the
@contextmanager implementation so that the semantics of the factored out
version actually matches that of the original inline code.

You can get yourself into similar trouble without nesting context
managers - all it takes is some way of skipping the variant code in a
context manager that wouldn't have raised an exception if the code was
written out inline instead of being factored out into the context manager.

Suppose for instance you wanted to use a context manager as a different
way of running tests:

  @contextmanager
  def inline_test(self, *setup_args):
try:
  self.setup(*setup_args)
except:
  # Setup exception occurred, trap it and log it
  return
try:
  yield
except:
  # Test exception occurred, trap it and log it
finally:
  try:
self.teardown()
  except:
# Teardown exception occurred, trap it and log it

  with inline_test(setup1):
test_one()
  with inline_test(setup2):
test_two()
  with inline_test(setup3):
test_three()

That approach isn't actually valid - a context manager is not permitted
to decide in it's __enter__() method that executing the body of the with
statement would be a bad idea.

The early return in the above makes it obvious that that CM is broken
under the current semantics, but what about the following one:

  @contextmanager
  def broken_cm(self):
try:
  call_user_setup()
  try:
yield
  finally:
call_user_teardown()
except UserCancel:
  show_message("Operation aborted by user")

That CM will raise RuntimeError if the user attempts to cancel an
operation during the execution of the "call_user_setup()" method.
Without SkipStatement or something like it, that can't be fixed.

Hell, I largely wrote PEP 377 to try to get out of having to document
these semantic problems with the with statement - if I'm having trouble
getting *python-dev* to grasp the problem, what hope do other users of
Python have?

Cheers,
Nick.

-- 
Nick Coghlan   |   ncogh...@gmail.com   |   Brisbane, Australia
---
___
Python-Dev mailing list
Python-Dev@python.org
http://mail.python.org/mailman/listinfo/python-dev
Unsubscribe: 
http://mail.python.org/mailman/options/python-dev/archive%40mail-archive.com


Re: [Python-Dev] PEP 377 - allow __enter__() methods to skip the statement body

2009-03-16 Thread Guido van Rossum
On Mon, Mar 16, 2009 at 2:37 PM, Nick Coghlan  wrote:
> Guido van Rossum wrote:
>> Yeah, it really seems pretty much limited to contextlib.nested(). I'd
>> be happy to sacrifice the possibility to *exactly* emulate two nested
>> with-statements.
>
> Then I really haven't explained the problem well at all. One of the
> premises of PEP 343 was "Got a frequently recurring block of code that
> only has one variant sequence of statements somewhere in the middle?
> Well, now you can factor that out by putting it in a generator,
> replacing the part that varies with a yield statement and decorating the
> generator with contextlib.contextmanager."
>
> It turns out that there's a caveat that needs to go on the end of that
> though: "Be very, very sure that the yield statement can *never* be
> skipped or your context manager based version will raise a RuntimeError
> in cases where the original code would have just skipped over the
> variant section of code and resumed execution afterwards."

Well, I don't think you can take that premise (promise? :-) literally
anyways, since you cannot turn a loop into a with-statement either. So
I would be fine with just adding the condition that the variant
sequence should be executed exactly once.

> Nested context managers (whether through contextlib.nested or through
> syntactic support) just turns out to be a common case where you *don't
> necessarily know* just by looking at the code whether it can skip over
> the body of the code or not.
>
> Suppose you have 3 context managers that are regularly used together
> (call them cmA(), cmB(), cmC() for now).
>
> Writing that as:
>
>  with cmA():
>    with cmB():
>      with cmC():
>        do_something()
>
> Or the tentatively proposed:
>
>  with cmA(), cmB(), cmC():
>        do_something()
>
> is definitely OK, regardless of the details of the context managers.
>
> However, whether or not you can bundle that up into a *new* context
> manager (regardless of nesting syntax) depends on whether or not an
> outer context manager can suppress an exception raised by an inner one.
>
> �...@contextmanager
>  def cmABC():
>    with cmA():
>      with cmB():
>        with cmC():
>          yield
>
>  with cmABC():
>    do_something()

While all this may make sense to the original inventor of context
managers (== you ;-), I personally find this example quite perverse.
Do you have an example taken from real life?

> The above is broken if cmB().__enter__() or cmC.__enter__() can raise an
> exception that cmA().__exit__() suppresses, or cmB.__enter__() raises an
> exception that cmB().__exit__() suppresses. So whereas the inline
> versions were clearly correct, the correctness of the second version
> currently depends on details of the context managers themselves.
> Changing the syntax to allow the three context managers to be written on
> one line does nothing to fix that semantic discrepancy between the
> original inline code and the factored out version.

I think I understand that, I just don't see a use case so important as
to warrant introducing a brand new exception deriving from
BaseException.

> PEP 377 is about changing the with statement semantics and the
> @contextmanager implementation so that the semantics of the factored out
> version actually matches that of the original inline code.
>
> You can get yourself into similar trouble without nesting context
> managers - all it takes is some way of skipping the variant code in a
> context manager that wouldn't have raised an exception if the code was
> written out inline instead of being factored out into the context manager.

Yeah, see above -- you can't write a context manager that implements a
loop either.

> Suppose for instance you wanted to use a context manager as a different
> way of running tests:
>
> �...@contextmanager
>  def inline_test(self, *setup_args):
>    try:
>      self.setup(*setup_args)
>    except:
>      # Setup exception occurred, trap it and log it
>      return
>    try:
>      yield
>    except:
>      # Test exception occurred, trap it and log it
>    finally:
>      try:
>        self.teardown()
>      except:
>        # Teardown exception occurred, trap it and log it
>
>  with inline_test(setup1):
>    test_one()
>  with inline_test(setup2):
>    test_two()
>  with inline_test(setup3):
>    test_three()
>
> That approach isn't actually valid

(but your proposal would make it valid right?)

> - a context manager is not permitted
> to decide in it's __enter__() method that executing the body of the with
> statement would be a bad idea.

A setup failure sounds like a catastrophic error to me.

> The early return in the above makes it obvious that that CM is broken
> under the current semantics, but what about the following one:
>
> �...@contextmanager
>  def broken_cm(self):
>    try:
>      call_user_setup()
>      try:
>        yield
>      finally:
>        call_user_teardown()
>    except UserCancel:
>      show_message("Operation aborted by user")
>
> T

Re: [Python-Dev] PEP 377 - allow __enter__() methods to skip the statement body

2009-03-16 Thread Nick Coghlan
Baptiste Carvello wrote:
> Nick Coghlan a écrit :
>>
>> Implementing __with__ instead would give the CM complete control over
>> whether or not to execute the block.
>>
> please note, however, that this is an important change in the semantics
> of the with statement. As things are today, barring exceptional
> circunstances, the body of the with statement *will* be executed
> immediately. This allows to forget about the with statement when first
> reading code, as it doesn't change the intent of the programmer. What
> Glyph is proposing is more akin to Ruby code blocks.

Yep - the idea is intriguing, powerful, and far beyond the scope of what
I'm trying to achieve with PEP 377. I suspect such blocks would have to
be more along the lines of what PJE suggested in order to be practical
anyway (i.e. nested functions where all "local" variables were
implicitly declared as nonlocal), which then leads to the question of
how much of a gain they would actually provide now that you *can*
explicitly declare nonlocal variables.

Cheers,
Nick.

-- 
Nick Coghlan   |   ncogh...@gmail.com   |   Brisbane, Australia
---
___
Python-Dev mailing list
Python-Dev@python.org
http://mail.python.org/mailman/listinfo/python-dev
Unsubscribe: 
http://mail.python.org/mailman/options/python-dev/archive%40mail-archive.com


Re: [Python-Dev] PEP 377 - allow __enter__() methods to skip the statement body

2009-03-16 Thread Nick Coghlan
Guido van Rossum wrote:
>> Hell, I largely wrote PEP 377 to try to get out of having to document
>> these semantic problems with the with statement - if I'm having trouble
>> getting *python-dev* to grasp the problem, what hope do other users of
>> Python have?
> 
> Hell, if you can't come up with a real use case, why bother? :-)

I figured I'd try for a solution that didn't offend my sense of
aesthetics before caving in and working out how to better document the
limitations of the status quo :)

> Perhaps you could address my worry about introducing an obscure
> BaseException subclass that will forever add to the weight of the list
> of built-in exceptions in all documentation?

Since this is really just a matter of the aesthetics of the underlying
design from my point of view rather than solving a real world problem, I
don't have a good answer for you.

In the absence of reports of actual problems caused by this limitation,
should I consider the PEP rejected?

Cheers,
Nick.

-- 
Nick Coghlan   |   ncogh...@gmail.com   |   Brisbane, Australia
---
___
Python-Dev mailing list
Python-Dev@python.org
http://mail.python.org/mailman/listinfo/python-dev
Unsubscribe: 
http://mail.python.org/mailman/options/python-dev/archive%40mail-archive.com


Re: [Python-Dev] PEP 377 - allow __enter__() methods to skip the statement body

2009-03-16 Thread Guido van Rossum
On Mon, Mar 16, 2009 at 3:19 PM, Nick Coghlan  wrote:
> Guido van Rossum wrote:
>>> Hell, I largely wrote PEP 377 to try to get out of having to document
>>> these semantic problems with the with statement - if I'm having trouble
>>> getting *python-dev* to grasp the problem, what hope do other users of
>>> Python have?
>>
>> Hell, if you can't come up with a real use case, why bother? :-)
>
> I figured I'd try for a solution that didn't offend my sense of
> aesthetics before caving in and working out how to better document the
> limitations of the status quo :)
>
>> Perhaps you could address my worry about introducing an obscure
>> BaseException subclass that will forever add to the weight of the list
>> of built-in exceptions in all documentation?
>
> Since this is really just a matter of the aesthetics of the underlying
> design from my point of view rather than solving a real world problem, I
> don't have a good answer for you.
>
> In the absence of reports of actual problems caused by this limitation,
> should I consider the PEP rejected?

Yes -- sorry for your wasted efforts.

-- 
--Guido van Rossum (home page: http://www.python.org/~guido/)
___
Python-Dev mailing list
Python-Dev@python.org
http://mail.python.org/mailman/listinfo/python-dev
Unsubscribe: 
http://mail.python.org/mailman/options/python-dev/archive%40mail-archive.com


[Python-Dev] What level of detail wanted for import and the language reference?

2009-03-16 Thread Brett Cannon
At this point importlib is done for its public API for Python 3.1. That
means it's time to turn my attention to making sure the semantics of import
are well documented. But where to put all of the details? The language
reference for import (
http://docs.python.org/dev/py3k/reference/simple_stmts.html#the-import-statement)
explains the basics, but is lacking all of the details of PEP 302 and other
stuff like __path__ that have existed for ages.

My question is if I should flesh out the details in the language reference
or do it in importlib's intro docs. The main reason I could see not doing it
in the langauge reference (or at least duplicating it) is it would be
somewhat easier to reference specific objects in importlib but I am not sure
if the language reference should try to stay away from stdlib references.

-Brett
___
Python-Dev mailing list
Python-Dev@python.org
http://mail.python.org/mailman/listinfo/python-dev
Unsubscribe: 
http://mail.python.org/mailman/options/python-dev/archive%40mail-archive.com


Re: [Python-Dev] PEP 377 - allow __enter__() methods to skip the statement body

2009-03-16 Thread Nick Coghlan
Guido van Rossum wrote:
> On Mon, Mar 16, 2009 at 3:19 PM, Nick Coghlan  wrote:
>> Guido van Rossum wrote:
 Hell, I largely wrote PEP 377 to try to get out of having to document
 these semantic problems with the with statement - if I'm having trouble
 getting *python-dev* to grasp the problem, what hope do other users of
 Python have?
>>> Hell, if you can't come up with a real use case, why bother? :-)
>> I figured I'd try for a solution that didn't offend my sense of
>> aesthetics before caving in and working out how to better document the
>> limitations of the status quo :)
>>
>>> Perhaps you could address my worry about introducing an obscure
>>> BaseException subclass that will forever add to the weight of the list
>>> of built-in exceptions in all documentation?
>> Since this is really just a matter of the aesthetics of the underlying
>> design from my point of view rather than solving a real world problem, I
>> don't have a good answer for you.
>>
>> In the absence of reports of actual problems caused by this limitation,
>> should I consider the PEP rejected?
> 
> Yes -- sorry for your wasted efforts.

Not wasted - I prefer having this as a recognised limitation of the
semantics rather than as an accident of the implementation.

Who knows, maybe somebody will come up with a real world use case some
day and we can drag the PEP out and dust it off a bit :)

Cheers,
Nick.

-- 
Nick Coghlan   |   ncogh...@gmail.com   |   Brisbane, Australia
---
___
Python-Dev mailing list
Python-Dev@python.org
http://mail.python.org/mailman/listinfo/python-dev
Unsubscribe: 
http://mail.python.org/mailman/options/python-dev/archive%40mail-archive.com


Re: [Python-Dev] What level of detail wanted for import and the language reference?

2009-03-16 Thread Michael Foord

Brett Cannon wrote:
At this point importlib is done for its public API for Python 3.1. 
That means it's time to turn my attention to making sure the semantics 
of import are well documented. But where to put all of the details? 
The language reference for import 
(http://docs.python.org/dev/py3k/reference/simple_stmts.html#the-import-statement) 
explains the basics, but is lacking all of the details of PEP 302 and 
other stuff like __path__ that have existed for ages.


My question is if I should flesh out the details in the language 
reference or do it in importlib's intro docs. The main reason I could 
see not doing it in the langauge reference (or at least duplicating 
it) is it would be somewhat easier to reference specific objects in 
importlib but I am not sure if the language reference should try to 
stay away from stdlib references.


Having the Python import semantics well documented will be an 
*excellent* side effect of importlib. Thank you for your astonishing 
efforts on this project.


Personally I would rather see the import semantics themselves in the 
language reference.


Michael


-Brett


___
Python-Dev mailing list
Python-Dev@python.org
http://mail.python.org/mailman/listinfo/python-dev
Unsubscribe: 
http://mail.python.org/mailman/options/python-dev/fuzzyman%40voidspace.org.uk
  



--
http://www.ironpythoninaction.com/
http://www.voidspace.org.uk/blog


___
Python-Dev mailing list
Python-Dev@python.org
http://mail.python.org/mailman/listinfo/python-dev
Unsubscribe: 
http://mail.python.org/mailman/options/python-dev/archive%40mail-archive.com


Re: [Python-Dev] What level of detail wanted for import and the language reference?

2009-03-16 Thread Benjamin Peterson
2009/3/16 Brett Cannon :
> At this point importlib is done for its public API for Python 3.1. That
> means it's time to turn my attention to making sure the semantics of import
> are well documented. But where to put all of the details? The language
> reference for import
> (http://docs.python.org/dev/py3k/reference/simple_stmts.html#the-import-statement)
> explains the basics, but is lacking all of the details of PEP 302 and other
> stuff like __path__ that have existed for ages.
>
> My question is if I should flesh out the details in the language reference
> or do it in importlib's intro docs. The main reason I could see not doing it
> in the langauge reference (or at least duplicating it) is it would be
> somewhat easier to reference specific objects in importlib but I am not sure
> if the language reference should try to stay away from stdlib references.

Thanks so much for doing this! Personally, I think you should put it
in the language reference. (I think it deserves it's own file if it's
as big as I suspect it will be.) If I wanted to use importlib, I
wouldn't really want to slog through a in-depth description of how
exactly import works.



-- 
Regards,
Benjamin
___
Python-Dev mailing list
Python-Dev@python.org
http://mail.python.org/mailman/listinfo/python-dev
Unsubscribe: 
http://mail.python.org/mailman/options/python-dev/archive%40mail-archive.com


Re: [Python-Dev] What level of detail wanted for import and the language reference?

2009-03-16 Thread Aahz
On Mon, Mar 16, 2009, Michael Foord wrote:
>
> Personally I would rather see the import semantics themselves in the  
> language reference.

Either way is fine with me, but it needs to be cross-referenced.
-- 
Aahz (a...@pythoncraft.com)   <*> http://www.pythoncraft.com/

Adopt A Process -- stop killing all your children!
___
Python-Dev mailing list
Python-Dev@python.org
http://mail.python.org/mailman/listinfo/python-dev
Unsubscribe: 
http://mail.python.org/mailman/options/python-dev/archive%40mail-archive.com


Re: [Python-Dev] PEP 377 - allow __enter__() methods to skip the statement body

2009-03-16 Thread Greg Ewing

Nick Coghlan wrote:

One of the
premises of PEP 343 was "Got a frequently recurring block of code that
only has one variant sequence of statements somewhere in the middle?
Well, now you can factor that out


Um, no -- it says explicitly right at the very top of
PEP 343 that it's only about factoring out try/finally
statements.

There's no way that

  try:
code_block
  finally:
...

can fail to enter the code block if you get as far as
the "try". So it's not reasonable to expect the with
statement to provide this ability.

--
Greg
___
Python-Dev mailing list
Python-Dev@python.org
http://mail.python.org/mailman/listinfo/python-dev
Unsubscribe: 
http://mail.python.org/mailman/options/python-dev/archive%40mail-archive.com


Re: [Python-Dev] What level of detail wanted for import and the language reference?

2009-03-16 Thread Steve Holden
Brett Cannon wrote:
> At this point importlib is done for its public API for Python 3.1. That
> means it's time to turn my attention to making sure the semantics of
> import are well documented. But where to put all of the details? The
> language reference for import
> (http://docs.python.org/dev/py3k/reference/simple_stmts.html#the-import-statement)
> explains the basics, but is lacking all of the details of PEP 302 and
> other stuff like __path__ that have existed for ages.
> 
> My question is if I should flesh out the details in the language
> reference or do it in importlib's intro docs. The main reason I could
> see not doing it in the langauge reference (or at least duplicating it)
> is it would be somewhat easier to reference specific objects in
> importlib but I am not sure if the language reference should try to stay
> away from stdlib references.

Why not just put a section in both places that says "can't be bothered
to spell this out right now" and put a URL in referring to this thread
on Google ... that appears to have been the traditional approach to
import semantics :)

regards
 Steve
-- 
Steve Holden   +1 571 484 6266   +1 800 494 3119
Holden Web LLC http://www.holdenweb.com/
Want to know? Come to PyCon - soon! http://us.pycon.org/

___
Python-Dev mailing list
Python-Dev@python.org
http://mail.python.org/mailman/listinfo/python-dev
Unsubscribe: 
http://mail.python.org/mailman/options/python-dev/archive%40mail-archive.com


Re: [Python-Dev] PEP 377 - allow __enter__() methods to skip the statement body

2009-03-16 Thread James Pye

On Mar 16, 2009, at 3:40 PM, Nick Coghlan wrote:

Not wasted - I prefer having this as a recognised limitation of the
semantics rather than as an accident of the implementation.


Well, I'm glad some good came from the issue report. =)


Who knows, maybe somebody will come up with a real world use case some
day and we can drag the PEP out and dust it off a bit :)



I don't expect this to be at all compelling, but FWIW:

The identification of this issue came from an *experiment* attempting  
to create a *single* "daemonized()" CM that would execute the with- 
statement's block in a new child process and, of course, not execute  
it in the parent. At first, I ran into the RuntimeError in the parent  
process, and then after rewriting the CMs as classes, I realized the  
futility.


with daemonized():
 run_some_subprocess()

Of course it was all possible if I used the component CMs directly:

with parent_trap():
 with fork_but_raise_in_parent():
  run_some_subprocess()

And thus:

def daemonized():
 return contextlib.nested(parent_trap(), fork_but_raise_in_parent())
___
Python-Dev mailing list
Python-Dev@python.org
http://mail.python.org/mailman/listinfo/python-dev
Unsubscribe: 
http://mail.python.org/mailman/options/python-dev/archive%40mail-archive.com


[Python-Dev] Daemon process context as a ‘with ’ context manager (was: PEP 377 - allow __enter __() methods to skip the statement body)

2009-03-16 Thread Ben Finney
James Pye  writes:

> The identification of this issue came from an *experiment* attempting
> to create a *single* "daemonized()" CM that would execute the with- 
> statement's block in a new child process and, of course, not execute
> it in the parent. At first, I ran into the RuntimeError in the parent
> process, and then after rewriting the CMs as classes, I realized the
> futility.
> 
> with daemonized():
>  run_some_subprocess()

This use case is addressed by my up-coming PEP, currently in draft
form but submitted to the PEP editor. A reference implementation is at
http://pypi.python.org/pypi/python-daemon/>.

I'd like to know whether this meets your needs; follow-ups privately
to me or in ‘python-ideas’ as you think appropriate.

-- 
 \ “Holy tintinnabulation, Batman!” —Robin |
  `\   |
_o__)  |
Ben Finney

___
Python-Dev mailing list
Python-Dev@python.org
http://mail.python.org/mailman/listinfo/python-dev
Unsubscribe: 
http://mail.python.org/mailman/options/python-dev/archive%40mail-archive.com


Re: [Python-Dev] Daemon process context as a ‘with ’ context manager

2009-03-16 Thread Ben Finney
Ben Finney  writes:

> James Pye  writes:
> 
> > with daemonized():
> >  run_some_subprocess()
> 
> This use case is addressed by my up-coming PEP, currently in draft
> form but submitted to the PEP editor. A reference implementation is
> at http://pypi.python.org/pypi/python-daemon/>.

On second blush, it addresses a smaller use case, with the same syntax
as your example. It should still be applicable at some level.

> I'd like to know whether this meets your needs; follow-ups privately
> to me or in ‘python-ideas’ as you think appropriate.

Ditto.

-- 
 \  “Life does not cease to be funny when people die any more than |
  `\  it ceases to be serious when people laugh.” —George Bernard Shaw |
_o__)  |
Ben Finney

___
Python-Dev mailing list
Python-Dev@python.org
http://mail.python.org/mailman/listinfo/python-dev
Unsubscribe: 
http://mail.python.org/mailman/options/python-dev/archive%40mail-archive.com