Re: [Python-Dev] PEP 343 - Abstract Block Redux

2005-05-14 Thread Nick Coghlan
Robert Brewer wrote:
> There's a typo in the code snippets at the moment.
> 
> The translation of the above statement is:
> 
> abc = EXPR
> exc = ()  # Or (None, None, None) ?
> try:
> try:
> VAR = abc.__enter__()
> BLOCK
> except:
> exc = sys.exc_info()
> raise
> finally:
> abc.__exit__(exc)
> 
> I think you meant "abc.__exit__(*exc)". Assuming that, then "exc =
> (None, None, None)" makes the most sense. If exc_info() is going to be
> passed as a single arg, then I'd rather have the default "exc = ()", so
> I can simply check "if exc:" in the __exit__ method.

Also, the call to __enter__() needs to be before the try/finally block (as it 
is 
in PEP 310). Otherwise we get the "releasing a lock you failed to acquire" 
problem.

Cheers,
Nick.

-- 
Nick Coghlan   |   [EMAIL PROTECTED]   |   Brisbane, Australia
---
 http://boredomandlaziness.blogspot.com
___
Python-Dev mailing list
[email protected]
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 343 - Abstract Block Redux

2005-05-14 Thread Nick Coghlan
Guido van Rossum wrote:
> I've written up the specs for my "PEP 340 redux" proposal as a
> separate PEP, PEP 343.
> 
> http://python.org/peps/pep-0343.html
> 
> Those who have been following the thread "Merging PEP 310 and PEP
> 340-redux?" will recognize my proposal in that thread, which received
> mostly positive responses there.
> 
> Please review and ask for clarifications of anything that's unclear.

On the keyword front, the two keyword choices affect the naming conventions of 
templates differently, and I think need to be considered in that light.

The naming convention for 'do' is shown in the current PEP 343. The issue I've 
noticed with it is that *functions* read well, but methods don't because things 
get out of sequence. That is, "do locking(the_lock)" reads well, but "do 
the_lock.locking()" does not.

Whereas, using 'with', it can be written either way, and still read reasonably 
well ("with locked(the_lock)", "with the_lock.locked()").

The 'with' keyword also reads better if objects natively support use in 'with' 
blocks ("with the_lock", "with the_file").

Guido's concern regarding file objects being reused inappropriately can be 
dealt 
with in the file __enter__ method:

   def __enter__(self):
   if self.closed:
   raise RuntimeError, "Cannot reopen closed file handle"

Template generators have the exact same problem with reusability - the solution 
used there is raising a RuntimeError when __enter__() is called 
inappropriately. 
This would make sense as a standard idiom - if a statement template can't be 
reused, attempting to do so should trigger a RuntimeError the second time 
__enter__() is invoked.

For files, it may then become the common practice to keep pathnames around, 
rather than open file handles. When you actually needed access to the file, the 
existing "open" builtin would suffice:

   with open(filename, "rb") as f:
   for line in f:
   print line

I've written out the PEP 343 examples below, assuming types acquire native with 
statement support (including Decimal contexts - I also give PEP 343 style code 
for Decimal contexts).

PEP343 examples: 'with' keyword, native support in objects

1. A template for ensuring that a lock, acquired at the start of a
block, is released when the block is left:

 # New methods on lock objects
 def __enter__(self):
 self.acquire()

 def __exit__(self, *args):
 self.release()

Used as follows:

 with myLock:
 # Code here executes with myLock held.  The lock is
 # guaranteed to be released when the block is left (even
 # if via return or by an uncaught exception).

 2. A template for opening a file that ensures the file is closed
when the block is left:

 # New methods on file objects
 def __enter__(self):
 if self.closed:
 raise RuntimeError, "Cannot reopen closed file handle"

 def __exit__(self, *args):
 self.close()

Used as follows:

 with open("/etc/passwd") as f:
 for line in f:
 print line.rstrip()

 3. A template for committing or rolling back a database
transaction; this is written as a class rather than as a
decorator since it requires access to the exception information:

 class transaction:
 def __init__(self, db):
 self.db = db
 def __enter__(self):
 self.db.begin()
 def __exit__(self, *args):
 if args and args[0] is not None:
 self.db.rollback()
 else:
 self.db.commit()

   Used as follows:

 with transaction(db):
 # Exceptions in this code cause a rollback

 5. Redirect stdout temporarily:

 @with_template
 def redirected_stdout(new_stdout):
 save_stdout = sys.stdout
 sys.stdout = new_stdout
 yield None
 sys.stdout = save_stdout

Used as follows:

 with open(filename, "w") as f:
 with redirected_stdout(f):
 print "Hello world"

This isn't thread-safe, of course, but neither is doing this
same dance manually.  In a single-threaded program (e.g., a
script) it is a totally fine way of doing things.

 6. A variant on opening() that also returns an error condition:

 @with_template
 def open_w_error(filename, mode="r"):
 try:
 f = open(filename, mode)
 except IOError, err:
 yield None, err
 else:
 yield f, None
 f.close()

Used as follows:

 with open_w_error("/etc/passwd", "a") as f, err:
 if err:
 print "IOError:", err
 else:

Re: [Python-Dev] PEP 343 - Abstract Block Redux

2005-05-14 Thread Fredrik Lundh
Guido van Rossum wrote:

> I've written up the specs for my "PEP 340 redux" proposal as a
> separate PEP, PEP 343.
>
> http://python.org/peps/pep-0343.html
>
> Those who have been following the thread "Merging PEP 310 and PEP
> 340-redux?" will recognize my proposal in that thread, which received
> mostly positive responses there.
>
> Please review and ask for clarifications of anything that's unclear.

intuitively, I'm -1 on this proposal.

unlike the original design, all you get from this is
the ability to add try/finally blocks to your code
without ever writing a try/finally-clause (neither
in your code or in the block controller).  that
doesn't strike me as especially pythonic.

(neither does the argument that just because you
can use a mechanism to write inscrutable code,
such a mechanism must not be made available
feel right; Python's design has always been about
careful tradeoffs between policy and mechanism,
but this is too much policy for my taste.  the
original PEP 340 might have been too clever, but
this reduced version feels pretty pointless).





___
Python-Dev mailing list
[email protected]
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 343 - Abstract Block Redux

2005-05-14 Thread Nick Coghlan
Fredrik Lundh wrote:
> unlike the original design, all you get from this is
> the ability to add try/finally blocks to your code
> without ever writing a try/finally-clause (neither
> in your code or in the block controller).  that
> doesn't strike me as especially pythonic.

I think the key benefit relates to the fact that correctly written resource 
management code currently has to be split it into two pieces - the first piece 
before the try block (e.g. 'lock.acquire()', 'f = open()'), and the latter in 
the finally clause (e.g. 'lock.release()', 'f.close()').

PEP 343 (like PEP 310 before it) makes it possible to define the correct 
resource management *once*, and then invoke it via a 'with' (or 'do') statement.

Instead of having to check for "is this file closed properly?", as soon as you 
write or see "with open(filename) as f:", you *know* that that file is going to 
be closed correctly.

Cheers,
Nick.

-- 
Nick Coghlan   |   [EMAIL PROTECTED]   |   Brisbane, Australia
---
 http://boredomandlaziness.blogspot.com
___
Python-Dev mailing list
[email protected]
http://mail.python.org/mailman/listinfo/python-dev
Unsubscribe: 
http://mail.python.org/mailman/options/python-dev/archive%40mail-archive.com


Re: [Python-Dev] Merging PEP 310 and PEP 340-redux?

2005-05-14 Thread Michael Hudson
Guido van Rossum <[EMAIL PROTECTED]> writes:

> [Michael Hudson, after much thinking aloud]

Yeah, sorry about that :)

>> Oh, I guess the point is that with a decorated generator you can yield
>> a value to be used as VAR, rather than just discarding the value as
>> here.  Hmm.
>
> Right. (I thought it was worth quoting this for the benefit of other
> who went down the same trail but didn't quite make it to this
> destination.)
>
>> If things were fiddled such that sys.exc_info() return non-Nones when
>> a finally clause is being executed because of an exception, we don't
>> really need this wart, do we?
>
> The problem is that sys.exc_info() almost always returns *something*
> -- it's usually the last exception that was *ever* caught, except in
> certain circumstances.

Yeah, OK.  I'll stop claiming to understand sys.exc_info() apart from
the simple cases.

> [Michael again]
>> Compare and contrast:
>> 
>> @template
>> def redirected_stdout(out):
>> save_stdout = sys.stdout
>> sys.stdout = out
>> 
>> yield None
>> 
>> sys.stdout = save_stdout
>> 
>> class redirected_stdout(object):
>> 
>> def __init__(self, output):
>> self.output = output
>> 
>> def __enter__(self):
>> self.save_stdout = sys.stdout
>> sys.stdout = self.output
>> 
>> def __exit__(self):
>> sys.stdout = self.save_stdout
>> 
>> The former is shorter and contains less (well, no) 'self.'s, but I
>> think I find the latter somewhat clearer.
>
> Tastes differ. I think the generator wins; more so when there's more
> state to remember.

Certainly when there's more state to manage, yes.  But both will be
possible, so, *shrug*.  It's not a big deal.

> [Michael quoting Guido]
>> > The added complexity is caused by the need to separate VAR from EXPR
>> > so that a generator can be used. I personally like this separation; I
>> > actually like that the "anonymous block controller" is logically
>> > separate from the variable bound by the construct.
>> 
>> Nevertheless, I think I actually like this argument!
>
> (Repeated for the benefit of others.)

I guess this means PEP 310 can be retracted.

Finally, from PEP 343 rev 1.7:

exc = ()  # Or (None, None, None) ?

The latter, please.

Cheers,
mwh

-- 
. <- the pointyour article -> .
|- a long way |
   -- Christophe Rhodes, ucam.chat
___
Python-Dev mailing list
[email protected]
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 343 - Abstract Block Redux

2005-05-14 Thread Fredrik Lundh
Nick Coghlan wrote:

> I think the key benefit relates to the fact that correctly written resource
> management code currently has to be split it into two pieces - the first piece
> before the try block (e.g. 'lock.acquire()', 'f = open()'), and the latter in
> the finally clause (e.g. 'lock.release()', 'f.close()').
>
> PEP 343 (like PEP 310 before it) makes it possible to define the correct
> resource management *once*, and then invoke it via a 'with' (or 'do')
> statement.

sure, but even if you look at both the application code *and*
the resource management, there are no clues that the "with"
statement is really just a masked "try/finally" statement.  just
look at the generator example:

acquire
yield
release

what in this snippet tells you that the "release" part will run even if
the external block raises an exception?  you could at least change
that to

acquire
try:
yield
finally:
release

which would make it a lot more obvious what's going on here.

also, come to think of it, adding a new statement just to hide
try/finally statements is a waste of statement space.  why not
just enhance the existing try statement?  let

try with opening(file) as f:
body
except IOError:
deal with the error (you have to do this anyway)

behave like

try:
f = opening(file)
try:
try:
body
except:
exc = sys.exc_info()
else:
exc = None
finally:
f.__cleanup__(exc)
except IOError:
deal with the error

and you're done.  (or you could use __enter__ and __exit__ instead,
which would give you a variation of PEP-343-as-I-understand-it)

compared to a separate statement, the worst that can happen here,
usage-wise, is that you'll end up adding an "except: raise" line here
and there to propagate real exceptions rather than dealing with them
in place.  on the other hand, for the cases where you actually want
to deal with the exceptions, you'll save a line of code.  I think that's
a net win.

but I still think that something closer to the original PEP 340 is a lot
more useful.





___
Python-Dev mailing list
[email protected]
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 343 - Abstract Block Redux

2005-05-14 Thread Paul Moore
On 5/14/05, Fredrik Lundh <[EMAIL PROTECTED]> wrote:
> Nick Coghlan wrote:
> 
> > PEP 343 (like PEP 310 before it) makes it possible to define the correct
> > resource management *once*, and then invoke it via a 'with' (or 'do')
> > statement.

This is probably the main point for me - encapsulate the try...finally
dance in such a way that the two parts are not separated by an
(arbitrarily long) chunk of code. I hated the equivalent dances in C
(usually malloc/free stuff in that case) and it feels awkward that
this is the one real ugliness of C that Python hasn't fixed for me :-)

> sure, but even if you look at both the application code *and*
> the resource management, there are no clues that the "with"
> statement is really just a masked "try/finally" statement.  just
> look at the generator example:
> 
> acquire
> yield
> release
> 
> what in this snippet tells you that the "release" part will run even if
> the external block raises an exception?

I agree with this point, though. What I liked about the original PEP
340 was the fact that the generator was a template, with "yield"
acting as a "put the block here" placeholder.

> but I still think that something closer to the original PEP 340 is a lot
> more useful.

Overall, I'd agree. I'm still fond of the original PEP 340 in all its
glory - the looping issue was a wart, but PEP 343 seems so stripped
down as to be something entirely different, not just a fix to the
looping issue.

My view - PEP 343 get a +1 in preference to PEP 310.
I'd like to see PEP 342 - that gets a +1 from me.

Covering both these areas at once, PEP 340 would still probably be my
preference, though. (I'm not convinced there's much chance of
resurrecting it, though).

Even it its limited form, I prefer PEP 343 to the status quo, though.

Oh, and I'm leaning towards "with" as a keyword again, as a result of
the "works better with member functions" argument.

Paul.
___
Python-Dev mailing list
[email protected]
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 343 - Abstract Block Redux

2005-05-14 Thread Nick Coghlan
Paul Moore wrote:
> On 5/14/05, Fredrik Lundh <[EMAIL PROTECTED]> wrote:
> 
>>Nick Coghlan wrote:
>>
>>
>>>PEP 343 (like PEP 310 before it) makes it possible to define the correct
>>>resource management *once*, and then invoke it via a 'with' (or 'do')
>>>statement.
> 
> 
> This is probably the main point for me - encapsulate the try...finally
> dance in such a way that the two parts are not separated by an
> (arbitrarily long) chunk of code. I hated the equivalent dances in C
> (usually malloc/free stuff in that case) and it feels awkward that
> this is the one real ugliness of C that Python hasn't fixed for me :-)
> 
> 
>>sure, but even if you look at both the application code *and*
>>the resource management, there are no clues that the "with"
>>statement is really just a masked "try/finally" statement.  just
>>look at the generator example:
>>
>>acquire
>>yield
>>release
>>
>>what in this snippet tells you that the "release" part will run even if
>>the external block raises an exception?
> 
> 
> I agree with this point, though. What I liked about the original PEP
> 340 was the fact that the generator was a template, with "yield"
> acting as a "put the block here" placeholder.

I also think the "generator as statement template" works much better if the 
__exit__ method is able to inject the exception into the generator frame, 
rather 
than always calling next().

Maybe PEP 343 should drop any suggestion of using generators to define these 
things, and focus on the PEP 310 style templates.

Cheers,
Nick.

-- 
Nick Coghlan   |   [EMAIL PROTECTED]   |   Brisbane, Australia
---
 http://boredomandlaziness.blogspot.com
___
Python-Dev mailing list
[email protected]
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 343 - Abstract Block Redux

2005-05-14 Thread Guido van Rossum
[Nick Coghlan]
> Also, the call to __enter__() needs to be before the try/finally block (as it 
> is
> in PEP 310). Otherwise we get the "releasing a lock you failed to acquire" 
> problem.

I did that on purpose. There's a separate object ('abc' in the
pseudo-code of the translation) whose __enter__ and __exit__ methods
are called, and in __enter__ it can keep track of the reversible
actions it has taken.

Consider an application where you have to acquire *two* locks regularly:

def lockBoth():
got1 = got2 = False
lock1.acquire(); got1 = True
lock2.acquire(); got2 = True
yield None
if got2: lock2.release()
if got1: lock1.release()

If this gets interrupted after locking lock1 but before locking lock2,
it still has some cleanup to do.

I know that this complicates simpler use cases, and I'm not 100% sure
this is the right solution; but I don't know how else to handle this
use case.

-- 
--Guido van Rossum (home page: http://www.python.org/~guido/)
___
Python-Dev mailing list
[email protected]
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 343 - Abstract Block Redux

2005-05-14 Thread Guido van Rossum
[Nick Coghlan]
> Maybe PEP 343 should drop any suggestion of using generators to define these
> things, and focus on the PEP 310 style templates.

But then the reason for separating VAR from EXPR becomes unclear.
Several people have mentioned that they thought this was "a good idea
on its own", but without giving additional use cases. Without the
ability to write the acquire/release template as a generator, the big
question is, "why not just PEP 310" ?

-- 
--Guido van Rossum (home page: http://www.python.org/~guido/)
___
Python-Dev mailing list
[email protected]
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 343 - Abstract Block Redux

2005-05-14 Thread Phillip J. Eby
At 01:55 PM 5/14/2005 +0200, Fredrik Lundh wrote:
>also, come to think of it, adding a new statement just to hide
>try/finally statements is a waste of statement space.  why not
>just enhance the existing try statement?  let
>
> try with opening(file) as f:
> body
> except IOError:
> deal with the error (you have to do this anyway)
>
>behave like
>
> try:
> f = opening(file)
> try:
> try:
> body
> except:
> exc = sys.exc_info()
> else:
> exc = None
> finally:
> f.__cleanup__(exc)
> except IOError:
> deal with the error
>
>and you're done.  (or you could use __enter__ and __exit__ instead,
>which would give you a variation of PEP-343-as-I-understand-it)

I like this, if you take out the "with" part, change the method names to 
__try__ and __finally__, and allow "try" to work as a block on its own if 
you've specified an expression.  i.e.:

 try opening(filename) as f:
 # do stuff

 try locking(self.__lock):
 # do stuff

 try redirecting_stdout(f):
 # something

 try decimal.Context(precision=23):
 # okay, this one's a little weird

 try self.__lock:
 # and so's this; nouns read better with a gerund wrapper

and I'd make the translation be:

 try:
 __exc = ()
 VAR = EXPR.__try__()
 try:
 try:
 BODY
 except:
 __exc = sys.exc_info()
 raise
 finally:
 EXPR.__finally__()

 # except/else/finally clauses here, if there were any in the original try


>but I still think that something closer to the original PEP 340 is a lot
>more useful.

I agree, but mainly because I'd like to be able to allow try/finally around 
"yield" in generators, be able to pass exceptions into generators, and tell 
generators to release their resources.  :)

I do think that the PEP 340 template concept is much more elegant than the 
various PEP 310-derived approaches, though.

___
Python-Dev mailing list
[email protected]
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 343 - Abstract Block Redux

2005-05-14 Thread Guido van Rossum
[Fredrik Lundh]
> intuitively, I'm -1 on this proposal.

So we need to do better. Do you just prefer all of PEP 340? What about
the objections against it? The mostly unnecessary loopiness in
particular?

> unlike the original design, all you get from this is
> the ability to add try/finally blocks to your code
> without ever writing a try/finally-clause (neither
> in your code or in the block controller).  that
> doesn't strike me as especially pythonic.

Would it be better if we pulled back in the generator exit handling
from PEP 340? That's a pretty self-contained thing, and would let you
write try/finally around the yield.

> (neither does the argument that just because you
> can use a mechanism to write inscrutable code,
> such a mechanism must not be made available
> feel right; Python's design has always been about
> careful tradeoffs between policy and mechanism,
> but this is too much policy for my taste.  the
> original PEP 340 might have been too clever, but
> this reduced version feels pretty pointless).

Maybe. It still solves the majority of use cases for PEP 340, most of
which are try/finally abstractions.

Maybe I'm overreacting to Raymond Chen's rant about flow-control
macros -- but having had to maintain code once that was riddled with
these, it rang very true.

PEP 340 is still my favorite, but it seems there's too much opposition
to it, so I'm trying to explore alternatives; at the same time I
*really* dislike the complexities of some of the non-looping
counterproposals (e.g. Nick Coghlan's PEP 3XX or the proposals that
make every keyword associated with 'try' a method).

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


Re: [Python-Dev] Tidier Exceptions

2005-05-14 Thread Aahz
On Fri, May 13, 2005, Greg Ewing wrote:
> Brett C. wrote:
>> 
>> Seems like, especially if we require inheritance from a base
>> exception class in Python 3000, exceptions should have standard 'arg'
>> and 'traceback' attributes with a possible 'context' attribute (or
>> always a 'context' attribute set to None if not a chained exception).
>
> Instead of an 'args' attribute, I'd suggest that the constructor take
> keyword arguments and store them in corresponding attributes. Then
> interested parties could retrieve them by name instead of having to
> remember their positions in the args tuple of the exception class
> concerned.

Sounds reasonable, but it should be equally easy to handle::

raise MyError, "message"
-- 
Aahz ([EMAIL PROTECTED])   <*> http://www.pythoncraft.com/

"And if that makes me an elitist...I couldn't be happier."  --JMS
___
Python-Dev mailing list
[email protected]
http://mail.python.org/mailman/listinfo/python-dev
Unsubscribe: 
http://mail.python.org/mailman/options/python-dev/archive%40mail-archive.com


Re: [Python-Dev] Chained Exceptions

2005-05-14 Thread Brett C.
Guido van Rossum wrote:
> [Brett C.]
> 
>>Maybe, but as long as caught exceptions get cleared that should be an issue.
>>Would this be solved if, when an 'except' branch is exited, exceptions are
>>cleared?  So, in the above example, once the 'pass' is hit in catchit() no
>>exception is considered active any longer.  This could be done with a 
>>CLEAR_EXC
>>opcode very easily inserted at the end of an 'except' branch by the compiler.
> 
> 
> Sure, but that would be backwards incompatible.

Right.  None of what I am discussing here I would expect to be implemented any
sooner than Python 3000.

> There's plenty of code
> that expects sys.exc_info() to continue to return the caught exception
> *outside* the except block. This is all incredibly tricky, to some
> extent for backwards compatibility reasons (please read the source
> code for maintaining the exc_info data!).
> 
> In Python 3000, I think we can get rid of sys.exc_info() altogether
> once we place the traceback in the exception object as the 'traceback'
> attribute: if you want this info, all you need is write
> 
> except SomeException, err:
> # now type is err.__class__, value is err, and traceback is
> err.traceback.
> 

Right, that is kind of the end goal in my mind.

> If you want to have this with an "except:" clause, you can just catch
> 'Exception' or perhaps 'BaseException'. This isn't possible in Python
> 2.x since there's no single base class.
> 

Right.  Once again I am only thinking about Python 3000.

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


Re: [Python-Dev] Python's Unicode width default (New Py_UNICODE doc)

2005-05-14 Thread Shane Hathaway
M.-A. Lemburg wrote:
> It is important to be able to rely on a default that
> is used when no special options are given. The decision
> to use UCS2 or UCS4 is much too important to be
> left to a configure script.

Should the choice be a runtime decision?  I think it should be.  That
could mean two unicode types, a call similar to
sys.setdefaultencoding(), a new unicode extension module, or something else.

BTW, thanks for discussing these issues.  I tried to write a patch to
the unicode API documentation, but it's hard to know just what to write.
 I think I can say this: "sometimes your strings are UTF-16, so you're
working with code units that are not necessarily complete code points;
sometimes your strings are UCS4, so you're working with code units that
are also complete code points.  The choice between UTF-16 and UCS4 is
made at the time the Python interpreter is compiled and the default
choice varies by operating system and configuration."

Shane
___
Python-Dev mailing list
[email protected]
http://mail.python.org/mailman/listinfo/python-dev
Unsubscribe: 
http://mail.python.org/mailman/options/python-dev/archive%40mail-archive.com


Re: [Python-Dev] Tidier Exceptions

2005-05-14 Thread James Y Knight
On May 14, 2005, at 2:34 PM, Aahz wrote:
> On Fri, May 13, 2005, Greg Ewing wrote:
>
> Sounds reasonable, but it should be equally easy to handle::
>
> raise MyError, "message"

Make that:
raise MyError("message")

There's really no reason for a multi-argument raise when exceptions  
are objects anyhow.

James
___
Python-Dev mailing list
[email protected]
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 343 - Abstract Block Redux

2005-05-14 Thread Brett C.
Guido van Rossum wrote:
> [Fredrik Lundh]
> 
>>intuitively, I'm -1 on this proposal.
> 

Just to toss in my opinion, I prefer PEP 340 over 343 as well, but not so much
to give 343 a -1 from me.

[SNIP - question of how to handle argument against 340 being a loop which I
never totally got since you know it ahead of time so you just deal with it]

[SNIP]
> Maybe I'm overreacting to Raymond Chen's rant about flow-control
> macros -- but having had to maintain code once that was riddled with
> these, it rang very true.
> 

You might be overreacting.  I read the essay and I understand his arguments
having been taught how to program in Scheme.  But I don't think this is as
serious.  People will have the semantics of the block statement explained to
them so how that works will be clear.  And at that point they just have to
track down the generator or iterator that the block statement is using.

If you think about it, how is it different than the implicit iter() call on a
'for' loop along with the implicit next() call each time through the loop?
Just because there is an implicit closing call back into the block generator at
the end of a block statement?  Doesn't seem so bad to me or that much of a
stretch from the magic of a 'for' loop to be that huge of a thing.

I think Raymond was reeling against arbitrary macro creation that hides flow
control.  We don't have that here.  What we have is a clearly defined statement
that does some very handy syntactic sugar for us.  It doesn't feel as arbitrary
as what Lisp and Scheme allow you to do.

> PEP 340 is still my favorite, but it seems there's too much opposition
> to it, so I'm trying to explore alternatives; at the same time I
> *really* dislike the complexities of some of the non-looping
> counterproposals (e.g. Nick Coghlan's PEP 3XX or the proposals that
> make every keyword associated with 'try' a method).
> 

Nick's was obviously directly against looping, but, with no offense to Nick,
how many other people were against it looping?  It never felt like it was a
screaming mass with pitchforks but more of a "I don't love it, but I can deal"
crowd.

And as for the overly complex examples, that I believed stemmed from people
realizing what might be possible if the statement was extended and tweaked this
way or that so as to be able to do just one more thing.  But that happens with
every proposal; seemed like standard feature creep.  The reason we have a BDFL
is to tell us that yes, we could get the jumbo sized candy bar for $2 more but
there is no way you will be able to finish that much chocolate before it melts
all over your hands and get it all over your nice PyCon t-shirt.

But then again I don't know if you got private emails asking to see if PEP 340
weighed as much as wood so it could be burned at the stake for being a witch.

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


Re: [Python-Dev] Python's Unicode width default (New Py_UNICODE doc)

2005-05-14 Thread Bob Ippolito

On May 14, 2005, at 3:05 PM, Shane Hathaway wrote:

> M.-A. Lemburg wrote:
>
>> It is important to be able to rely on a default that
>> is used when no special options are given. The decision
>> to use UCS2 or UCS4 is much too important to be
>> left to a configure script.
>>
>
> Should the choice be a runtime decision?  I think it should be.  That
> could mean two unicode types, a call similar to
> sys.setdefaultencoding(), a new unicode extension module, or  
> something else.
>
> BTW, thanks for discussing these issues.  I tried to write a patch to
> the unicode API documentation, but it's hard to know just what to  
> write.
>  I think I can say this: "sometimes your strings are UTF-16, so you're
> working with code units that are not necessarily complete code points;
> sometimes your strings are UCS4, so you're working with code units  
> that
> are also complete code points.  The choice between UTF-16 and UCS4 is
> made at the time the Python interpreter is compiled and the default
> choice varies by operating system and configuration."

Well, if you're going to make it runtime, you might as well do it  
right.  Take away the restriction that the unicode type backing store  
is forced to be a particular encoding (i.e. get rid of  
PyUnicode_AS_UNICODE) and give it more flexibility.

The implementation of NSString in OpenDarwin's libFoundation  (BSD license), or the CFString  
implementation in Apple's CoreFoundation  (APSL) would be an excellent place to look for  
how this can be done.

Of course, for backwards compatibility reasons, this would have to be  
a new type that descends from basestring.  text would probably be a  
good name for it.  This would be an abstract implementation, where  
you can make concrete subclasses that actually implement the various  
operations as necessary.  For example, you could have text_ucs2,  
text_ucs4, text_ascii, text_codec, etc.

The bonus here is you can get people to shut up about space efficient  
representations, because you can use whatever makes sense.

-bob

___
Python-Dev mailing list
[email protected]
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 343 - Abstract Block Redux

2005-05-14 Thread Shane Hathaway
Guido van Rossum wrote:
> [Nick Coghlan]
> 
>>Also, the call to __enter__() needs to be before the try/finally block (as it 
>>is
>>in PEP 310). Otherwise we get the "releasing a lock you failed to acquire" 
>>problem.
> 
> 
> I did that on purpose. There's a separate object ('abc' in the
> pseudo-code of the translation) whose __enter__ and __exit__ methods
> are called, and in __enter__ it can keep track of the reversible
> actions it has taken.
> 
> Consider an application where you have to acquire *two* locks regularly:
> 
> def lockBoth():
> got1 = got2 = False
> lock1.acquire(); got1 = True
> lock2.acquire(); got2 = True
> yield None
> if got2: lock2.release()
> if got1: lock1.release()
> 
> If this gets interrupted after locking lock1 but before locking lock2,
> it still has some cleanup to do.

That code is incorrect, though.  Say lockBoth() acquires lock1 but then
lock2.acquire() throws an exception.  (Maybe the lock requires some I/O
operation, and the operation fails.)  The interpreter will never reach
the yield statement and lock1 will never be released.

You really have to write it like this:

def lockBoth():
lock1.acquire()
try:
lock2.acquire()
except:
lock1.release()
raise
yield None
try:
lock2.release()
finally:
lock1.release()

> I know that this complicates simpler use cases, and I'm not 100% sure
> this is the right solution; but I don't know how else to handle this
> use case.

If __enter__ raises an exception, it has to clean up after itself before
propagating the exception.  __exit__ shouldn't be called if __enter__ fails.

Shane
___
Python-Dev mailing list
[email protected]
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 343 - Abstract Block Redux

2005-05-14 Thread Shane Hathaway
Brett C. wrote:
> Guido van Rossum wrote:
>>PEP 340 is still my favorite, but it seems there's too much opposition
>>to it, so I'm trying to explore alternatives; at the same time I
>>*really* dislike the complexities of some of the non-looping
>>counterproposals (e.g. Nick Coghlan's PEP 3XX or the proposals that
>>make every keyword associated with 'try' a method).
>>
> 
> 
> Nick's was obviously directly against looping, but, with no offense to Nick,
> how many other people were against it looping?  It never felt like it was a
> screaming mass with pitchforks but more of a "I don't love it, but I can deal"
> crowd.

PEP 340 is very nice, but it became less appealing to me when I saw what
it would do to "break" and "continue" statements.

text = 'diamond'
for fn in filenames:
opening(fn) as f:
if text in f.read():
print 'I found the text in %s' % fn
break

I think it would be pretty surprising if the break didn't stop the loop.

Here's a new suggestion for PEP 340: use one keyword to start a block
you don't want to loop, and a different keyword to start a block that
can loop.  If you specify the non-looping keyword but the block template
produces more than one result, a RuntimeError results.  Here is example
A, a non-looping block statement using "try":

text = 'diamond'
for fn in filenames:
try opening(fn) as f:
if text in f.read():
print 'I found the text in %s' % fn
break

In example A, the break statement breaks the "for" loop.  If the
opening() iterator returns more than one result, a RuntimeError will be
generated by the Python interpreter.

Here is example B, a looping block statement using "in", adapted from
PEP 340:

in auto_retry(3, IOError) as attempt:
f = urllib.urlopen("http://python.org/peps/pep-0340.html";)
print f.read()

Note that I introduced no new keywords except "as", and the syntax in
both cases is currently illegal.

Shane
___
Python-Dev mailing list
[email protected]
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 343 - Abstract Block Redux

2005-05-14 Thread Nick Coghlan
Guido van Rossum wrote:
> [Nick Coghlan]
> 
>>Also, the call to __enter__() needs to be before the try/finally block (as it 
>>is
>>in PEP 310). Otherwise we get the "releasing a lock you failed to acquire" 
>>problem.
> 
> 
> I did that on purpose. There's a separate object ('abc' in the
> pseudo-code of the translation) whose __enter__ and __exit__ methods
> are called, and in __enter__ it can keep track of the reversible
> actions it has taken.
> 
> Consider an application where you have to acquire *two* locks regularly:
> 
> def lockBoth():
> got1 = got2 = False
> lock1.acquire(); got1 = True
> lock2.acquire(); got2 = True
> yield None
> if got2: lock2.release()
> if got1: lock1.release()
> 
> If this gets interrupted after locking lock1 but before locking lock2,
> it still has some cleanup to do.
> 
> I know that this complicates simpler use cases, and I'm not 100% sure
> this is the right solution; but I don't know how else to handle this
> use case.
> 

If we retained the ability to inject exceptions into generators, this would be 
written with the extremely natural:

   @with template:
   def lockboth():
 lock1.acquire()
 try:
 lock2.acquire()
 try:
 yield
 finally:
 lock2.release()
 finally:
 lock1.release()

Or, even more simply:

@with_template:
def lockboth():
with lock1:
with lock2:
yield

I think Fredrik's intuition is on to something - PEP 343 has scaled the idea 
back *too* far by throwing away the injection of exceptions into generator 
templates, when the only major objection was to the looping nature of the 
proposal.

Cheers,
Nick.

-- 
Nick Coghlan   |   [EMAIL PROTECTED]   |   Brisbane, Australia
---
 http://boredomandlaziness.blogspot.com
___
Python-Dev mailing list
[email protected]
http://mail.python.org/mailman/listinfo/python-dev
Unsubscribe: 
http://mail.python.org/mailman/options/python-dev/archive%40mail-archive.com


Re: [Python-Dev] [Python-checkins] python/nondist/peps pep-0343.txt, 1.8, 1.9

2005-05-14 Thread Raymond Hettinger
> -was, under the covers, a (optential) looping construct.  This
> +was, under the covers, a (potential) looping construct.  This

I'm glad I didn't fix this one.
I thought he meant to use "optional".


Raymond Hettinger
___
Python-Dev mailing list
[email protected]
http://mail.python.org/mailman/listinfo/python-dev
Unsubscribe: 
http://mail.python.org/mailman/options/python-dev/archive%40mail-archive.com


[Python-Dev] PEP 343: Resource Composition and Idempotent __exit__

2005-05-14 Thread Ka-Ping Yee
Yikes, this turned out to be rather long.  Here's a summary:

  - The expansion suggested by Shane (moving __enter__ outside the
try-finally) fits the expectation that __exit__ will always be
paired with a successful __enter__.  This "paired-exit" expansion
is fairly intuitive and makes simple resources easy to write,
but they are not very composable.

  - The expansion that Guido currently has in PEP 343 encourages an
implementation style where __exit__ is idempotent.  If we use it,
we should document this fact, since it may seem a little unusual
at first; we should also rename "enter"/"exit" so they do not
mislead programmers into believing that they are paired.  Simple
resources are a little more work to write than with a paired-exit
expansion, but they are easier to compose and reuse.

  - The generator style in PEP 340 is the easiest to compose and
reuse, but its implementation is the most complex to understand.

I lean (but only slightly) toward the second option, because it seems
to be a reasonable compromise.  The increased complexity of writing
resources for PEP 343 over PEP 340 becomes less of an issue if we have
a good do_template function in the standard library; on the other hand,
the use of do_template may complicate debugging.

For idempotent-exit, possible renamings of enter/exit might be
enter/finish, enter/cleanup, enter/finally, start/finally, begin/finally.

*   *   *

Okay.  Here's how i arrived at the above conclusions.  (In the following,
i'll just use "with" for "do/with".)

PEP 343 (rev 1.8) currently expands

with EXPR as VAR:
BLOCK

to this, which i'll call the "idempotent-exit" expansion:

resource = EXPR
exc = (None, None, None)
try:
try:
VAR = resource.__enter__()
BLOCK
except:
exc = sys.exc_info()
raise
finally:
resource.__exit__(*exc)

If there are problems during __enter__, then __enter__ is expected to
record this fact so that __exit__ can clean up.  Since __exit__ is
called regardless of whether __enter__ succeeded, this encourages a
style of writing resources where __exit__ is idempotent.

An alternative, advocated by Shane (and by my first instincts), is this
expansion, which i'll call the "paired-exit" expansion:

resource = EXPR
exc = (None, None, None)
VAR = resource.__enter__()
try:
try:
BLOCK
except:
exc = sys.exc_info()
raise
finally:
resource.__exit__(*exc)

If there are problems during __enter__, __enter__ must clean them up
before propagating an exception, because __exit__ will not be called.

To evaluate these options, we could look at a few scenarios where we're
trying to write a resource wrapper for some lock objects.  Each lock
object has two methods, .acquire() and .release().

Scenario 1. You have two resource objects and you want to acquire both.

Scenario 2. You want a single resource object that acquires two locks.

Scenario 3. Your resource object acquires one of two locks depending
on some runtime condition.


Scenario 1 (Composition by client)
==

The client writes this:

with resource1:
with resource2:
BLOCK

The idempotent-exit expansion would yield this:

exc1 = (None, None, None)
try:
try:
resource1.__enter__()
exc2 = (None, None, None)
try:
try:
resource2.__enter__()
BLOCK
except:
exc2 = sys.exc_info()
raise
finally:
resource2.__exit__(*exc2)
except:
exc1 = sys.exc_info()
raise
finally:
resource1.__exit__(*exc1)

Because __exit__ is always called even if __enter__ fails, the resource
wrapper must record whether __enter__ succeeded:

class ResourceI:
def __init__(self, lock):
self.lock = lock
self.acquired = False

def __enter__(self):
self.lock.acquire()
self.acquired = True

def __exit__(self, *exc):
if self.acquired:
self.lock.release()
self.acquired = False

The paired-exit expansion would yield this:

exc1 = (None, None, None)
resource1.__enter__()
try:
try:
exc2 = (None, None, None)
resource2.__enter__()
try:
try:
BLOCK
except:
exc2 = sys.exc_info()
raise
finally:
resource2.__exit__(*exc2)
except:
exc1 = sys.exc_info()
raise
finally:
resource1.__exit__(*exc1)

In this case the lock can simply be implemented as:

class ResourceP:
def