Re: [Python-Dev] Pre-PEP: Unifying try-except and try-finally

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

> [Steven Bethard]
>> I have a feeling that it might actually be easier to continue to
>> document try/except and try/finally separately and then just give the
>> semantics of try/except/finally in terms of the other semantics.  Take
>> a look at the Java Language Specification[1] (pages 399-401) if you
>> want to see how nastly documenting try/except/finally can get.  And
>> they don't even have an else clause! ;-)
>
> Fine with me.
>
> Can I go ahead and approve this now 

While I see the cost of this PEP being pretty small, I see the benefit
the same way too.

> before someone proposes to add a new keyword?

Heh.

Cheers,
mwh

-- 
  If i don't understand lisp, it would be wise to not bray about
  how lisp is stupid or otherwise criticize, because my stupidity
  would be archived and open for all in the know to see.
-- Xah, comp.lang.lisp
___
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-12 Thread Paul Moore
On 5/11/05, Guido van Rossum <[EMAIL PROTECTED]> wrote:
> I realize that the pushback was against looping, but whereas in the
> PEP 340 proposal general exception handling comes out naturally, it
> feels as an ugly wart in the modified PEP 310 proposal.
> 
> Plus I think the use cases are much weaker (even PEP 340 doesn't have
> many use cases for exception handling -- the only one is the
> auto-retry example).

Accepted, but I still feel that the templates should explicitly
include the try...finally, rather than simply having the yield mark
the split. The examples seem more readable that way. Explicit is
better than implicit, and all that...

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] Merging PEP 310 and PEP 340-redux?

2005-05-12 Thread Ka-Ping Yee
On Wed, 11 May 2005, Guido van Rossum wrote:
> [Steven Bethard]
> > exc = ()
> > try:
> > try:
> > BLOCK1
> > except:
> > exc = sys.exc_info()
> > finally:
> > stmt_exit(*exc)
> >
> > would this make any of the examples impossible to write?  All you have
> > to do to suppress an exception is to not reraise it in __exit__.
>
> But this use case would contain a trap for the unwary user who is
> writing an __exit__ method -- they have to remember to re-raise an
> exception if it was passed in, but that's easy to forget (and slightly
> tricky since you have to check the arg count or whether the first
> argument is not None).

Then wouldn't it be simplest to separate normal exit from exceptional
exit?  That is, split __exit__ into __except__ and __finally__.  If
__except__ is defined, then it handles the exception, otherwise the
exception is raised normally.

> class locking:
> def __init__(self, lock): self.lock = lock
> def __enter__(self): self.lock.acquire()
> def __exit__(self, *args): self.lock.release()

Having __exit__ take varargs is a signal to me that it mashes together
what really are two different methods.


-- ?!ng
___
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-12 Thread Nick Coghlan
Steven Bethard wrote:
> On 5/11/05, Nick Coghlan <[EMAIL PROTECTED]> wrote:
> 
>>The gist is that the alternative is to require an __exit__() method to raise
>>TerminateBlock in order to suppress an exception.
> 
> So I didn't see any examples that really needed TerminateBlock to
> suppress an exception.

Yeah, I figured out a tidier way to handle it after reading Phillip's message 
earlier today. My idea is similar to your second solution, but with an early 
exit via break, continue or return still indicated to the __exit__() method via 
TerminateBlock so that examples like transaction() continue to do the right 
thing:

 the_stmt = EXPR1
 stmt_enter = getattr(the_stmt, "__enter__", None)
 stmt_exit = getattr(the_stmt, "__exit__", None)
 if stmt_enter is None or stmt_exit is None:
 raise TypeError("User defined statement template required")

 terminate = True
 VAR1 = stmt_enter() # Omit 'VAR1 =' if no 'as' clause
 try:
 try:
 BLOCK1
 except TerminateBlock:
 raise # Disallow suppression of TerminateBlock
 except:
 terminate = False
 if not stmt_exit(*sys.exc_info()):
 raise
 else:
 terminate = False
 stmt_exit()
 finally:
 if terminate:
 try:
 stmt_exit(TerminateBlock, None, None)
 except TerminateBlock:
 pass

Version 1.5 uses these updated semantics, and the suggested generator 
__exit__() 
method semantics are adjusted appropriately. I've also added a paragraph in 
Open 
Issues about removing the ability to suppress exceptions as Guido has 
suggested. 
However, I'm hoping his objections are based on the assorted horrible 
mechanisms 
I used in versions before this one - he is quite right that forcing every 
__exit__() method to reraise exceptions was a rather ugly wart.

The new version also fixes a typo in the auto_retry example that a couple of 
people pointed out, and adds a non-exception related example from Arnold deVos.

The URL is the same as before:
http://members.iinet.net.au/~ncoghlan/public/pep-3XX.html

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


[Python-Dev] a patch to inspect and a non-feature request

2005-05-12 Thread Michele Simionato
Well, I logged into Sourceforge with the idea of filing my feature request
about copying functions, and then my eye went on my previous submissions.
It seems it takes some time to fix non-critical bugs, isn't it? ;)

Two years ago, I discovered a bug with pydoc for classes containing "super" 
objects:

>>> class C(object):
...pass

>>> C.s = super(C)

>>> help(C) # aargh!!

I filed that bug 25 months ago and it is still there (actually Brett
Cannot fixed it but then somebody else broke his patch).
 
Clearly nobody uses this feature and the bug fixing is not at
all urgent still it disturbs me, so I have worked out
a patch. Actually, the problem is not in pydoc but in inspect,
that treats super objects as methods, whereas they should be treated
as data. Here is the patch:

$ diff -c /home/micheles/python/dist/src/Lib/inspect.py inspect.py
*** /home/micheles/python/dist/src/Lib/inspect.py   Thu May 12 13:05:10 2005
--- inspect.py  Thu May 12 13:06:55 2005
***
*** 77,83 
  and not hasattr(object, "__set__") # else it's a data descriptor
  and not ismethod(object)   # mutual exclusion
  and not isfunction(object)
! and not isclass(object))

  def isdatadescriptor(object):
  """Return true if the object is a data descriptor.
--- 77,84 
  and not hasattr(object, "__set__") # else it's a data descriptor
  and not ismethod(object)   # mutual exclusion
  and not isfunction(object)
! and not isclass(object)
! and not isinstance(object, super))

  def isdatadescriptor(object):
  """Return true if the object is a data descriptor.

It changes the code of ismethoddescriptor to make sure that super objects
are not treated as methods.

BTW, I have downloaded the CVS version of Python and run test_inspect
against the patch and it is working. However, introspection tools have
the tendency to be very fragile (especially with the rate of changes
in Python) and it is possible that this fix would break something else.

Let The Powers That Be to decide.

The test suite should be augmented with a test such

>>> inspect.ismethoddescriptor(C.s)
False

In my experience super is a huge can of worms and actually I have a non-feature 
request about the descriptor aspect of super: I would like super's
__get__ method
and the possibily to call super with just one argument to be removed
in Python 3000.
They are pretty much useless (yes I know of "autosuper") and error prone.

   Michele Simionato
___
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] Pre-PEP: Unifying try-except and try-finally

2005-05-12 Thread Guido van Rossum
> > Can I go ahead and approve this now
> 
> While I see the cost of this PEP being pretty small, I see the benefit
> the same way too.

Sure. Let me approve it and we'll see if someone cares enough to implement it.

-- 
--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] Merging PEP 310 and PEP 340-redux?

2005-05-12 Thread Steven Bethard
On 5/12/05, Nick Coghlan <[EMAIL PROTECTED]> wrote:
> Yeah, I figured out a tidier way to handle it after reading Phillip's message
> earlier today. My idea is similar to your second solution, but with an early
> exit via break, continue or return still indicated to the __exit__() method 
> via
> TerminateBlock so that examples like transaction() continue to do the right 
> thing:

Do they?  I don't write enough transactional code, but I would have
thought that break, continue or return would have been a normal,
expected exit from the do-statement and therefore should do a
db.commit(), not a db.rollback().  Do you think you could add an
example of how the transaction do-statement would be used in such a
way that these would be the desired semantics?

Thanks,

STeVe
-- 
You can wordify anything if you just verb it.
--- Bucky Katt, Get Fuzzy
___
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] a patch to inspect and a non-feature request

2005-05-12 Thread Steven Bethard
On 5/12/05, Michele Simionato <[EMAIL PROTECTED]> wrote:
> In my experience super is a huge can of worms and actually I have a 
> non-feature
> request about the descriptor aspect of super: I would like super's
> __get__ method
> and the possibily to call super with just one argument to be removed
> in Python 3000.

+1 while super doesn't work with "meta-attributes" and classmethods:

py> class B(object):
... "The B type"
... @classmethod
... def m(cls):
... print "B.m"
... 
py> class C(B):
... @classmethod
... def m(cls):
... print "C.m"
... cls._sup.m()
... 
py> C._sup = super(C)
py> super(C, C).__doc__
'The B type'
py> super(C, C).__name__
Traceback (most recent call last):
  File "", line 1, in ?
AttributeError: 'super' object has no attribute '__name__'
py> C().m()
C.m
Traceback (most recent call last):
  File "", line 1, in ?
  File "", line 5, in m
AttributeError: 'super' object has no attribute 'm'

STeVe
-- 
You can wordify anything if you just verb it.
--- Bucky Katt, Get Fuzzy
___
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] Merging PEP 310 and PEP 340-redux?

2005-05-12 Thread Jim Jewett
In  http://mail.python.org/pipermail/python-dev/2005-May/053652.html Nick wrote:

 terminate = True
 VAR1 = stmt_enter() # Omit 'VAR1 =' if no 'as' clause
 try:
 try:
 BLOCK1
 except TerminateBlock:
 raise # Disallow suppression of TerminateBlock
 except:
 terminate = False
 if not stmt_exit(*sys.exc_info()):
 raise
 else:
 terminate = False
 stmt_exit()
 finally:
 if terminate:
 try:
 stmt_exit(TerminateBlock, None, None)
 except TerminateBlock:
 pass

This seems confusing to me, as if it were saying "OK, I don't want to 
finalize this, so I'll set terminate to false, but then finalize anyhow."

Would "terminated=False" (and getting set later to True) still meet
your requirements?  Or even "finalized=False"?  I realize that the
spelling of
finalise is a bugaboo, but presumably this is really a hidden variable,
instead of something that the user must type.  Or have I misunderstood
that as well?

-jJ
___
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-12 Thread Guido van Rossum
A quick response to various small issues...

- Benji York proposes that file and lock objects (for example) could
  have suitable __enter__ and __exit__ methods (__enter__ would have
  to return self).  Right!

- Greg Ewing (I believe) wants 'do' instead of 'with' for the
  keyword.  I think I like 'with' better, especially combining it with
  Benji's proposal.  IMO this reads better with 'with' than with 'do':

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

- Steve Bethard has this example:

stmt = EXPR1
VAR1 = stmt.__enter__()
exc = () # or (None, None, None) if you prefer
try:
try:
BLOCK1
except:
exc = sys.exc_info()
finally:
if stmt.__exit__(*exc) is not None:
raise exc[0], exc[1], exc[2]

  but he seems to forget that finally *always* re-raises the
  exception.  Anyway, I still don't care for the use case; rather than
  fixing the coding bug, your time would be better spent arguing why
  this functionality can't be missed.

- Eric Nieuwland asks if the VAR is still optional.  Yes, it is (this
  is implicit in the entire set of threads).

- Paul Moore wants the generator templates to explicitly contain
  try/finally (or try/except, depending on the use case).  That's much
  more work though (passing exceptions into a generator is a new
  feature) and is not necessary to get the "redux" version.

- Ka-ping Yee thinks we need separate entry points for the exceptional
  and the normal termination case.  I disagree; this would end up in
  unnecessary duplication of code (or boilerplate to equate the two
  methods) in most cases.  The whole *point* is that finally gets to
  do its clean-up act regardless of whether an exception is being
  processed or not.  The varargs signature to __exit__ was just me
  being lazy instead of typing

def __exit__(self, t=None, v=None, tb=None): ...

- Nick is still peddling his much more complicated variant.  I
  recommend that he focuses on arguing use cases rather than semantic
  subtleties, or else it won't get any traction (at least not with me
  :-).

--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] a patch to inspect and a non-feature request

2005-05-12 Thread Michele Simionato
On 5/12/05, Steven Bethard <[EMAIL PROTECTED]> wrote:
>super doesn't work with "meta-attributes" and classmethods:
> 
> py> super(C, C).__name__
> Traceback (most recent call last):
>   File "", line 1, in ?
> AttributeError: 'super' object has no attribute '__name__'

Actually this is the Right Thing to do for super. It is something
to be aware of, not something to change. Since __name__ is
a descriptor defined in the type metaclass and not an attribute
defined in the base class, super correctly does not retrieve it.
It is enough to add some documentation about "super" caveats
and nonobvious points.
What I really dislike is super called with only one argument since
it has many unpleasant surprises and not real advantages :-(
   
Michele Simionato
___
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-12 Thread Benji York
I think this is my first post to python-dev, so a mini-intro: I've 
been lurking here for about 5 years, "professional" user a bit longer, 
now working at Zope Corp.

Guido van Rossum wrote:
> Going for all-out simplicity, I would like to be able to write these examples:
> 
> class locking:
> def __init__(self, lock): self.lock = lock
> def __enter__(self): self.lock.acquire()
> def __exit__(self, *args): self.lock.release()
> 
> class opening:
> def __init__(self, filename): self.filename = filename
> def __enter__(self): self.f = open(self.filename); return self.f
> def __exit__(self, *args): self.f.close()

I've read the entire discussion, but may have missed this point, so, 
correct me if I'm wrong. Wouldn't these semantics let "normal" objects 
be used in a do.  For example, if the file object had these methods:

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

you could write

do file('whatever) as f:
 lines = f.readlines()

Or a lock:

def __enter__(self): self.aquire(); return self
def __exit__(self, *args): self.release()

do my_lock:
 a()
 b()
 c()
-- 
Benji York
Sr. Software Engineer
Zope Corporation
___
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-12 Thread Steven Bethard
On 5/12/05, Guido van Rossum <[EMAIL PROTECTED]> wrote:
> - Steve Bethard has this example:
> 
> stmt = EXPR1
> VAR1 = stmt.__enter__()
> exc = () # or (None, None, None) if you prefer
> try:
> try:
> BLOCK1
> except:
> exc = sys.exc_info()
> finally:
> if stmt.__exit__(*exc) is not None:
> raise exc[0], exc[1], exc[2]
> 
>   but he seems to forget that finally *always* re-raises the
>   exception.

Not if except catches it:

py> try:
... try:
... raise Exception
... except:
... exc = sys.exc_info()
... finally:
... pass
...
py>

As I understand it, finally only re-raises the exception if it wasn't
already caught.  And I have to use an except block above to catch it
so that sys.exc_info() returns something other than (None, None,
None).

>   Anyway, I still don't care for the use case; rather than
>   fixing the coding bug, your time would be better spent arguing why
>   this functionality can't be missed.

Sorry, I'm unclear.  Do you not want sys.exc_info() passed to
__exit__, or do you not want the with/do-statement to be allowed to
suppress exceptions?  Or both?

My feeling is that the mechanism for suppressing exceptions is
confusing, and it would probably be better to always reraise the
exception. (I included it mainly to provide a middle ground between
Guido's and Nick's proposals.)  That is, I prefer something like:

   stmt = EXPR1
   VAR1 = stmt.__enter__()
   exc = () # or (None, None, None) if you prefer
   try:
   try:
   BLOCK1
   except:
   exc = sys.exc_info()
   finally:
   stmt.__exit__(*exc)
   raise exc[0], exc[1], exc[2]

which should really read the same as Guido's suggestion:

   stmt = EXPR1
   VAR1 = stmt.__enter__()
   try:
   BLOCK1
   finally:
   stmt.__exit__(*sys.exc_info())

except that since sys.exc_info() returns (None, None, None) when there
wasn't an except block, this won't actually work.

If we don't provide some flag that an exception occurred, the
transaction example doesn't work.  My feeling is that if we're going
to provide any flag, we might as well provide the entire
sys.exc_info().

STeVe
-- 
You can wordify anything if you just verb it.
--- Bucky Katt, Get Fuzzy
___
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-12 Thread Michele Simionato
On 5/12/05, Benji York <[EMAIL PROTECTED]> wrote:
> if the file object had these methods:
> 
> def __enter__(self): return self
> def __exit__(self, *args): self.close()
> 
> you could write
> 
> do file('whatever) as f:
>  lines = f.readlines()
> 
> Or a lock:
> 
> def __enter__(self): self.aquire(); return self
> def __exit__(self, *args): self.release()
> 
> do my_lock:
>  a()
>  b()
>  c()

Ah, finally a proposal that I can understand! 
But maybe the keyword should be "let":

let lock:
   do_something

let open("myfile") as f:
for line in f: do_something(line)

or even, without need of "as":

let f=file("myfile") :
for line in f: do_something(line)

which I actually like more

 Michele Simionato
___
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-12 Thread Phillip J. Eby
At 07:50 AM 5/12/2005 -0700, Guido van Rossum wrote:
>- Paul Moore wants the generator templates to explicitly contain
>   try/finally (or try/except, depending on the use case).  That's much
>   more work though (passing exceptions into a generator is a new
>   feature) and is not necessary to get the "redux" version.

Uh oh.  Speaking on behalf of the "coroutine-y people" :), does this mean 
that we're not going to get the ability to pass exceptions into generators?

___
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-12 Thread Guido van Rossum
[Guido van Rossum]
> >- Paul Moore wants the generator templates to explicitly contain
> >   try/finally (or try/except, depending on the use case).  That's much
> >   more work though (passing exceptions into a generator is a new
> >   feature) and is not necessary to get the "redux" version.

[Phillip J. Eby]
> Uh oh.  Speaking on behalf of the "coroutine-y people" :), does this mean
> that we're not going to get the ability to pass exceptions into generators?

That would be a separate proposal (PEP 288 or PEP 325).

The do/with statement with its __enter__ and __exit__ APIs is entirely
independent from generators. Having shown a few non-generator do/with
wrappers I'm not so sure there's a lot of need for generators here;
especially since generators will always have that
round-peg-square-hole feeling when they're used in a non-looping
context. But I still want to leave the door open for using generators
as do/with-templates, hence my modification of PEP 310 (otherwise we
could just accept PEP 310 as is and be done with it).

For coroutines, see PEP 342.

-- 
--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


[Python-Dev] "with" use case: exception chaining

2005-05-12 Thread Ka-Ping Yee
> - Ka-ping Yee thinks we need separate entry points for the exceptional
>   and the normal termination case.  I disagree; this would end up in
>   unnecessary duplication of code (or boilerplate to equate the two
>   methods) in most cases.  The whole *point* is that finally gets to
>   do its clean-up act regardless of whether an exception is being
>   processed or not.

Okay, let me back up for a second.  My suggestion responded to your
reply to Steve Bethard's example about exception handling.  The point
of the suggestion is that *if* we are going to let "with" do exception
handling, it should be done in a separate method.  I didn't mean to
imply that __finally__ should be skipped.

This brings us back to the question of whether "with" should be able
to handle exceptions.  On this, you wrote:

> For try/finally we have a large body of use cases that just scream for
> abstraction. I'm not convinced that we have the same for try/except.

So let's look at some use cases.  I've thought of two; the first one is
nice and simple, and the second one is messier so i'll discuss it in a
separate message.

Example 1: Exception Chaining.

As has been previously discussed, the information from an exception can
be lost when the handling of the exception runs into a problem.  It is
often helpful to preserve the original reason for the problem.

Suppose, by convention, that the "reason" attribute on exception objects
is designated for this purpose.  The assignment of this attribute can be
conveniently abstracted using a "with" clause as follows:

try:
# ... risky operation ...
except:
with reason(sys.exc_info()):
# ... cleanup ...

The "with reason" construct would be implemented like this:

class reason:
def __init__(self, etype, evalue, etb):
self.reason = etype, evalue, etb

def __except__(self, etype, evalue, etb):
evalue.reason = self.reason
raise etype, evalue, etb

(Other possible names for "reason" might be "cause" or "context".)


-- ?!ng
___
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] "with" use case: replacing a file

2005-05-12 Thread Ka-Ping Yee
Here's another use case to think about.

Example 2: Replacing a File.

Suppose we want to reliably replace a file.  We require that either:

(a) The file is completely replaced with the new contents;
 or (b) the filesystem is unchanged and a meaningful exception is thrown.

We'd like to be able to write this conveniently as:

with replace(filename) as file:
...
file.write(spam)
...
file.write(eggs)
...

To make sure the file is never only partially written, we rely on the
filesystem to rename files atomically, so the basic steps (without
error handling) look like this:

tempname = filename + '.tmp'
file = open(tempname, 'w')
...
file.write(spam)
...
file.close()
os.rename(tempname, filename)

We would like to make sure the temporary file is cleaned up and no
filehandles are left open.  Here's my analysis of all the execution
paths we need to cover:

1. +open +write +close +rename
2. +open +write +close -rename ?remove
3. +open +write -close ?remove
4. +open -write +close ?remove
5. +open -write -close ?remove
6. -open

(In this list, + means success, - means failure, ? means don't care.)

When i add error handling, i get this:

tempname = filename + '.tmp'
file = open(tempname, 'w') # okay to let exceptions escape
problem = None
try:
try:
...
file.write(spam)
...
except:
problem = sys.exc_info()
raise problem
finally:
try:
file.close()
except Exception, exc:
problem, problem.reason = exc, problem
if not problem:
try:
os.rename(tempname, filename)
except Exception, exc:
problem, problem.reason = exc, problem
if problem:
try:
os.remove(tempname)
except Exception, exc:
problem, problem.reason = exc, problem
raise problem

In this case, the implementation of replace() doesn't require a
separate __except__ method:

class replace:
def __init__(self, filename):
self.filename = filename
self.tempname = '%s.%d.%d' % (self.filename, os.getpid(), id(self))

def __enter__(self):
self.file = open(self.tempname, 'w')
return self

def write(self, data):
self.file.write(data)

def __exit__(self, *problem):
try:
self.file.close()
except Exception, exc:
problem, problem.reason = exc, problem
if not problem: # commit
try:
os.rename(tempname, filename)
except Exception, exc:
problem, problem.reason = exc, problem
if problem: # rollback
try:
os.remove(tempname)
except Exception, exc:
problem, problem.reason = exc, problem
raise problem

This is all so intricate i'm not sure if i got it right.  Somebody
let me know if this looks right or not.  (In any case, i look forward
to the day when i can rely on someone else to get it right, and they
only have to write it once!)


-- ?!ng
___
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] "with" use case: replacing a file

2005-05-12 Thread Phillip J. Eby
At 03:00 PM 5/12/2005 -0500, Ka-Ping Yee wrote:
>This is all so intricate i'm not sure if i got it right.  Somebody
>let me know if this looks right or not.  (In any case, i look forward
>to the day when i can rely on someone else to get it right, and they
>only have to write it once!)

It looks fine, but it's not a use case for suppressing exceptions, nor was 
the exception-chaining example.

Really, the only use case for suppressing exceptions is to, well, suppress 
exceptions that are being logged, shown to the user, sent via email, or 
just plain ignored.  Guido's point, I think, is that these use cases are 
rare enough (yet simple and similar enough) that they don't deserve support 
from the cleanup facility, and instead should use a try/except block.

After reviewing the cases in my own code where I might've used a 'with 
logged_exceptions()' or similar blocks, I think I now agree.  The 
difference between:

 try:
 BLOCK
 except:
 logger.exception(...)

and:

 with log_errors(logger):
 BLOCK

doesn't seem worth the effort, especially since this pattern just doesn't 
occur that often, compared to resource-using blocks.

What *your* use cases seem to illustrate, however, is that it's quite 
possible that an __exit__ might well need to contain complex error handling 
of its own, including the need to throw a different exception than the one 
that was passed in.

___
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] "with" use case: exception chaining

2005-05-12 Thread Guido van Rossum
[Ka-Ping Yee]
> Example 1: Exception Chaining.
> 
> As has been previously discussed, the information from an exception can
> be lost when the handling of the exception runs into a problem.  It is
> often helpful to preserve the original reason for the problem.
[example deleted]

This problem is universal -- every except clause (in theory) can have
this problem. I'd much rather deal with this in a systematic way in
the Python VM's exception handling machinery. Modifying every
potentially affected except clause to use some additional boilerplate
doesn't strike me as a good solution.

-- 
--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] "with" use case: exception chaining

2005-05-12 Thread Ka-Ping Yee
On Thu, 12 May 2005, Guido van Rossum wrote:
> [Ka-Ping Yee]
> > Example 1: Exception Chaining.
> >
> > As has been previously discussed, the information from an exception can
> > be lost when the handling of the exception runs into a problem.  It is
> > often helpful to preserve the original reason for the problem.
> [example deleted]
>
> This problem is universal -- every except clause (in theory) can have
> this problem. I'd much rather deal with this in a systematic way in
> the Python VM's exception handling machinery.

That's reasonable.  Unless another use case comes up, i withdraw my
suggestion for a separate __except__ method.

I hope the examples were interesting, anyhow.


-- ?!ng
___
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] "with" use case: replacing a file

2005-05-12 Thread Nick Coghlan
Phillip J. Eby wrote:
> Really, the only use case for suppressing exceptions is to, well, suppress 
> exceptions that are being logged, shown to the user, sent via email, or 
> just plain ignored.  Guido's point, I think, is that these use cases are 
> rare enough (yet simple and similar enough) that they don't deserve support 
> from the cleanup facility, and instead should use a try/except block.

Particularly since the *action* can be factored out into a do statement - it's 
only the *suppression* that has to be reproduced inline. That is:

   try:
   do standard_reaction():
   pass
   except MyException:
   pass

> After reviewing the cases in my own code where I might've used a 'with 
> logged_exceptions()' or similar blocks, I think I now agree.

I think I'm convinced, too. The only actual use case in the PEP is auto_retry, 
and that can be more obviously written with a try/except block inside the loop:

   for retry in reversed(xrange(num_attempts)):
   try:
  make_attempt()
  break
   except IOError:
  if not retry:
  raise

Not as pretty perhaps, but the control flow is far easier to see.

Steven has also convinced me that break, continue and return should look like 
normal exits rather than exceptions. This should bring my next PEP draft back 
to 
something resembling Guido's option 3 - the __exit__() method still gets passed 
the contents of sys.exc_info(), it just can't do anything about it other than 
raise a different exception.

Cheers,
Nick.

P.S. The points regarding non-local flow control in Joel Spolsky's latest Joel 
on Software article (especially the links at the end) may have had something to 
do with my change of heart. . .


-- 
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


[Python-Dev] Tidier Exceptions

2005-05-12 Thread Ka-Ping Yee
It occurred to me as i was messing around with handling and re-raising
exceptions that tossing around these (type, value, traceback) triples
is irritating and error-prone.

How about just passing around a single value?  All we'd have to do is
put the traceback in value.traceback.

Implementation:

- "raise Class" and "raise Class, string" automatically set
  the .traceback attribute on the new instance of Class.

- "raise instance" automatically sets the .traceback attribute
  on the instance unless it already has one.

The behaviour of "except" and "sys.exc_*" could remain unchanged.
"raise t, v, tb" would eventually be deprecated in favour of "raise v".


-- ?!ng
___
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] Chained Exceptions

2005-05-12 Thread Ka-Ping Yee
Suppose exceptions have an optional "context" attribute, which is
set when the exception is raised in the context of handling another
exception.  Thus:

def a():
try:
raise AError
except:
raise BError

yields an exception which is an instance of BError.  This instance
would have as its "context" attribute an instance of AError.

Or, in a more complex case:

def compute():
try:
1/0
except Exception, exc:
log(exc)

def log(exc):
try:
file = open('error.log')   # oops, forgot 'w'
print >>file, exc
file.close()
except:
display(exc)

def display(exc):
print 'Aaaack!', ex# oops, misspelled 'exc'

Today, this just gives you a NameError about 'ex'.

With the suggested change, you would still get a NameError about 'ex';
its 'context' attribute would show that it occurred while handling an
IOError on error.log; and this IOError would have a 'context' attribute
containing the original ZeroDivisionError that started it all.

What do you think?


-- ?!ng
___
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-12 Thread Guido van Rossum
[Ka-Ping Yee]
> It occurred to me as i was messing around with handling and re-raising
> exceptions that tossing around these (type, value, traceback) triples
> is irritating and error-prone.
> 
> How about just passing around a single value?  All we'd have to do is
> put the traceback in value.traceback.

I proposed the same thing a while back (during the early hours of
writing PEP 340).

It won't fly as long as we have string exceptions (since there's
nowhere to put the traceback) but once those are dead I like it a lot.

-- 
--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] Chained Exceptions

2005-05-12 Thread Guido van Rossum
[Ka-Ping Yee]
> Suppose exceptions have an optional "context" attribute, which is
> set when the exception is raised in the context of handling another
> exception.  Thus:
> 
> def a():
> try:
> raise AError
> except:
> raise BError
> 
> yields an exception which is an instance of BError.  This instance
> would have as its "context" attribute an instance of AError.
[...]

I like the idea, but I'm not sure about the consequences, and I'm not
sure how it can be defined rigorously. Would it only happen when
something *in* an except clause raises an exception? Which piece of
code would be responsible for doing this?

Try to come up with a precise specification and we'll talk.

-- 
--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-12 Thread Brett C.
Guido van Rossum wrote:
> [Ka-Ping Yee]
> 
>>It occurred to me as i was messing around with handling and re-raising
>>exceptions that tossing around these (type, value, traceback) triples
>>is irritating and error-prone.
>>
>>How about just passing around a single value?  All we'd have to do is
>>put the traceback in value.traceback.
> 
> 
> I proposed the same thing a while back (during the early hours of
> writing PEP 340).
> 
> It won't fly as long as we have string exceptions (since there's
> nowhere to put the traceback) but once those are dead I like it a lot.
> 

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).

I don't think there is other data normally associated with exceptions is there?

I really need to get off my ass one of these days and just write a PEP targeted
for Python 3000 with base inheritance, standard attributes (including exception
chains), reworking the built-in exception inheritance hierarchy, and whether
bare 'except' statements should go or only catch certain exceptions.  Could
probably stand to break it up until multiple PEPs, though.  =)

-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] Chained Exceptions

2005-05-12 Thread Brett C.
Guido van Rossum wrote:
> [Ka-Ping Yee]
> 
>>Suppose exceptions have an optional "context" attribute, which is
>>set when the exception is raised in the context of handling another
>>exception.  Thus:
>>
>>def a():
>>try:
>>raise AError
>>except:
>>raise BError
>>
>>yields an exception which is an instance of BError.  This instance
>>would have as its "context" attribute an instance of AError.
> 
> [...]
> 
> I like the idea, but I'm not sure about the consequences, and I'm not
> sure how it can be defined rigorously. Would it only happen when
> something *in* an except clause raises an exception? Which piece of
> code would be responsible for doing this?
> 
> Try to come up with a precise specification and we'll talk.
> 

If a new exception is raised (e.g., not a bare 'raise') while a current
exception is active (e.g., sys.exc_info() would return something other than a
tuple of None), then the new exception is made the active exception and the now
old exception is assigned to the new exception's context attribute to be the
old exception.

-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] Chained Exceptions

2005-05-12 Thread Ka-Ping Yee
On Thu, 12 May 2005, Brett C. wrote:
> Guido van Rossum wrote:
> > Try to come up with a precise specification and we'll talk.
>
> If a new exception is raised (e.g., not a bare 'raise') while a current
> exception is active (e.g., sys.exc_info() would return something other
> than a tuple of None), then the new exception is made the active exception
> and the now old exception is assigned to the new exception's context
> attribute to be the old exception.

Yeah, i think that's basically all there is to it.  I'll go have a peek
at the interpreter to see if i'm forgetting something.


-- ?!ng
___
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-12 Thread Guido van Rossum
[Brett C.]
> If a new exception is raised (e.g., not a bare 'raise') while a current
> exception is active (e.g., sys.exc_info() would return something other than a
> tuple of None), then the new exception is made the active exception and the 
> now
> old exception is assigned to the new exception's context attribute to be the
> old exception.

Define "raise". Does that involve a raise statement? What about 1/0?
What if you call a method that executes 1/0? What if that method
catches that exception? What about the StopIteration conceptually
raised by next() called by the for-loop implementation? (Often it
doesn't get instantiated at all when the next() method belongs to a
built-in iterator.)

I believe there are (at least) two use cases:

(1) I catch some low-level exception (e.g. socket.error) and turn it
into a high-level exception (e.g. an HTTPRequestFailed exception).

(2) I write some exception handling code and somehow a bug in the
handler (or an uncooperative environment, e.g. a full disk) causes the
exception handling code to trip over an exception.

I'm fairly certain (but not 100%) that Ping meant to include both use cases.

-- 
--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-12 Thread Guido van Rossum
[Brett C.]
> 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).
> 
> I don't think there is other data normally associated with exceptions is 
> there?

I despise the "arg" argument -- I like Java's "message" concept better.

> I really need to get off my ass one of these days and just write a PEP 
> targeted
> for Python 3000 with base inheritance, standard attributes (including 
> exception
> chains), reworking the built-in exception inheritance hierarchy, and whether
> bare 'except' statements should go or only catch certain exceptions.  Could
> probably stand to break it up until multiple PEPs, though.  =)

+1.

I think these things are sufficiently closely related to keep them all
in one PEP.

-- 
--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] Chained Exceptions

2005-05-12 Thread Ka-Ping Yee
On Thu, 12 May 2005, Guido van Rossum wrote:
> Define "raise". Does that involve a raise statement?

Not necessarily; it could be a raise statement or an inadvertently
triggered exception, such as in the example code i posted.

> What about 1/0?

That counts.

> What if you call a method that executes 1/0?

That counts too.

> What if that method catches that exception?

Did you mean something like this?

def handle():
try:
open('spamspamspam')
except:
catchit()
# point A
...

def catchit():
try:
1/0
except:
pass

Then there's no exception to propagate, so it doesn't matter.
Once we're get to point A, the division by zero is long forgotten.

> What about the StopIteration conceptually
> raised by next() called by the for-loop implementation?

It's "caught" by the for-loop, so to speak, so it never gets out.
Conceptually, the for-loop expands to:

while 1:
try:
item = it.next()
except StopIteration:
break
# body of loop goes here

The 'break' can't possibly cause an exception, so the StopIteration
exception isn't retained.

> I believe there are (at least) two use cases:
>
> (1) I catch some low-level exception (e.g. socket.error) and turn it
> into a high-level exception (e.g. an HTTPRequestFailed exception).
>
> (2) I write some exception handling code and somehow a bug in the
> handler (or an uncooperative environment, e.g. a full disk) causes the
> exception handling code to trip over an exception.
>
> I'm fairly certain (but not 100%) that Ping meant to include both use cases.

Yes, though i did not expect to provide any mechanism for distinguishing
the two cases.  Do you think such a mechanism would be necessary?


-- ?!ng
___
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-12 Thread Ka-Ping Yee
On Thu, 12 May 2005, Brett C. wrote:
> whether bare 'except' statements should go or only catch certain exceptions.

Maybe bare 'except' should be spelled 'except *'.

I don't think it can be removed altogether because sometimes you just
need to be able to do magic, but it can be made a little more explicit.

With the asterisk, it's greppable, and editors can find it or highlight
it.  I like the parallel to 'import *' (frowned upon, but sometimes
useful if you really know what you are doing).


-- ?!ng
___
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-12 Thread Phillip J. Eby
At 07:36 PM 5/12/2005 -0500, Ka-Ping Yee wrote:
>On Thu, 12 May 2005, Brett C. wrote:
> > Guido van Rossum wrote:
> > > Try to come up with a precise specification and we'll talk.
> >
> > If a new exception is raised (e.g., not a bare 'raise') while a current
> > exception is active (e.g., sys.exc_info() would return something other
> > than a tuple of None), then the new exception is made the active exception
> > and the now old exception is assigned to the new exception's context
> > attribute to be the old exception.
>
>Yeah, i think that's basically all there is to it.  I'll go have a peek
>at the interpreter to see if i'm forgetting something.

I think the main problem is going to be that (IIUC), Python doesn't "know" 
when you've  exited an 'except:' clause and are therefore no longer 
handling the exception.  sys.exc_info() still gives you the exception you 
just caught.  I think that a lot of the questions Guido brought up are 
directly related to this.

Also, what about code like this:

 try:
 doSomething()
 except SomeError:
 pass

 doSomethingElse()

Should exceptions raised by doSomethingElse()' be treated as having the 
SomeError as their context, if it was raised?

If I understand correctly, the interpreter cannot currently distinguish 
between this, and the case where an error is raised inside the 'except' clause.

___
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-12 Thread Guido van Rossum
[Ka-Ping Yee]
> Maybe bare 'except' should be spelled 'except *'.

-1.

> I don't think it can be removed altogether because sometimes you just
> need to be able to do magic, but it can be made a little more explicit.

Assuming a single root of the exception tree, you can spell it
explicitly as "except Exception" or perhaps (if that's not the root)
"except Raisable" (cf. Java's Throwable).

> With the asterisk, it's greppable, and editors can find it or highlight
> it.  I like the parallel to 'import *' (frowned upon, but sometimes
> useful if you really know what you are doing).

How is "except:" less greppable?

And is *args also frowned upon?

-- 
--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-12 Thread Ka-Ping Yee
On Thu, 12 May 2005, Guido van Rossum wrote:
> How is "except:" less greppable?

Duh.  I'm slow today.


-- ?!ng
___
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-12 Thread Guido van Rossum
[Phillip J. Eby]
> I think the main problem is going to be that (IIUC), Python doesn't "know"
> when you've  exited an 'except:' clause and are therefore no longer
> handling the exception.

But the compiler knows and could insert code to maintain this state.

> sys.exc_info() still gives you the exception you
> just caught.  I think that a lot of the questions Guido brought up are
> directly related to this.

Right.

> Also, what about code like this:
> 
>  try:
>  doSomething()
>  except SomeError:
>  pass
> 
>  doSomethingElse()
> 
> Should exceptions raised by doSomethingElse()' be treated as having the
> SomeError as their context, if it was raised?
> 
> If I understand correctly, the interpreter cannot currently distinguish
> between this, and the case where an error is raised inside the 'except' 
> clause.

Indeed the interpreter currently doesn't distinguish between these,
but I think it ought to for the  purposes of this proposal.

-- 
--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] Chained Exceptions

2005-05-12 Thread Guido van Rossum
[Guido]
> > What if that method catches that exception?

[Ka-Ping Yee]
> Did you mean something like this?
> 
> def handle():
> try:
> open('spamspamspam')
> except:
> catchit()
> # point A
> ...
> 
> def catchit():
> try:
> 1/0
> except:
> pass
> 
> Then there's no exception to propagate, so it doesn't matter.
> Once we're get to point A, the division by zero is long forgotten.

But at what point does the attaching happen? If I catch the
ZeroDivisionException inside catchit() and inspects its context
attribute, does it reference the IOError instance raised by
open('spamspamspam')? This could potentially cause a lot of extra
work: when an inner loop that raises and catches lots of exceptions is
invoked in the context of having caught an exception at some outer
level, the inner loop keeps attaching the outer exception to each
exception raised.

> Yes, though i did not expect to provide any mechanism for distinguishing
> the two cases.  Do you think such a mechanism would be necessary?

No, I was just trying to figure out what you meant when you said
"raise". It's clear now.

-- 
--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] Merging PEP 310 and PEP 340-redux?

2005-05-12 Thread Shane Hathaway
Guido van Rossum wrote:
> Going for all-out simplicity, I would like to be able to write these examples:
> 
> class locking:
> def __init__(self, lock): self.lock = lock
> def __enter__(self): self.lock.acquire()
> def __exit__(self, *args): self.lock.release()
> 
> class opening:
> def __init__(self, filename): self.filename = filename
> def __enter__(self): self.f = open(self.filename); return self.f
> def __exit__(self, *args): self.f.close()\
> 
> And do EXPR as VAR: BLOCK would mentally be translated into
> 
> itr = EXPR
> VAR = itr.__enter__()
> try: BLOCK
> finally: itr.__exit__(*sys.exc_info()) # Except sys.exc_info() isn't
> defined by finally

If it's this simple, it should be possible to write something that
combines the acquisition of multiple resources in a single statement.
For example:

with combining(opening(src_fn), opening(dst_fn, 'w')) as src, dst:
copy(src, dst)

I think the following class would do it.

class combining:
def __init__(self, *resources):
self.resources = resources
self.entered = 0

def __enter__(self):
results = []
try:
for r in self.resources:
results.append(r.__enter__())
self.entered += 1
return results
except:
# exit resources before re-raising the exception
self.__exit__()
raise

def __exit__(self, *args):
last_exc = None
# exit only the resources successfully entered
to_exit = self.resources[:self.entered]
while to_exit:
r = to_exit.pop()
try:
r.__exit__(*args)
except:
# re-raise the exception after exiting the others
last_exc = sys.exc_info()
if last_exc is not None:
raise last_exc[0], last_exc[1], last_exc[2]

Would that work?

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] Chained Exceptions

2005-05-12 Thread James Y Knight

On May 12, 2005, at 6:32 PM, Ka-Ping Yee wrote:
> Suppose exceptions have an optional "context" attribute, which is
> set when the exception is raised in the context of handling another
> exception.  Thus:
>
> def a():
> try:
> raise AError
> except:
> raise BError
>
> yields an exception which is an instance of BError.  This instance
> would have as its "context" attribute an instance of AError.
>

I think it's a bad idea to have this happen automatically. Many times  
if an exception is raised in the except clause, that doesn't  
necessarily imply it's related to the original exception. It just  
means there's a bug in the exception handler.

Take the divide by 0 example:
try:
   doABunchOfStuff()
except:
   1/0

If you're going to do anything useful with the chained exception  
information (such as have it printed by the default exception  
printer), it'd be best to not print a bunch of irrelevant backtraces  
for all exceptions up the stack. The reason that doABunchOfStuff  
failed is not important. What is important is only that you had a  
divide by 0.

In my mind it's much better to be explicit about your intentions, via  
something like:

try:
   raise AError
except Raiseable, e:
   raise BError(cause=e)

Of course you can already do similar with current python, it just  
can't be spelled as nicely, and the default traceback printer won't  
use the info:

try:
   raise AError
except:
   newException = BError()
   newException.cause=sys.exc_info()
   raise newException

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] Merging PEP 310 and PEP 340-redux?

2005-05-12 Thread Guido van Rossum
[Shane Hathaway]
> If it's this simple, it should be possible to write something that
> combines the acquisition of multiple resources in a single statement.
> For example:
> 
> with combining(opening(src_fn), opening(dst_fn, 'w')) as src, dst:
> copy(src, dst)

Yeah (and I don't see anything wrong with your implementation of
combining either), but even if that existed I think I'd prefer to just
write

  with opening(src_fn) as src:
  with opening(dst_fn) as dst:
  copy(src, dst)

See Ma, no magic! :-)

-- 
--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] Chained Exceptions

2005-05-12 Thread Delaney, Timothy C (Timothy)
James Y Knight wrote:

> Of course you can already do similar with current python, it just
> can't be spelled as nicely, and the default traceback printer won't
> use the info:
> 
> try:
>raise AError
> except:
>newException = BError()
>newException.cause=sys.exc_info()
>raise newException

Well, one thing you can do is (somewhat evil ;)

::

import sys

try:
raise AError, 'message'
except:
exc_type, exc_value, exc_traceback - sys.exc_info()
raise BError, exc_value, exc_traceback

with the result:

Traceback (most recent call last):
File ...
raise AError, 'message'
BError: message

So you store the original exception as the argument to the new exception
(so it's accessible). This has the nice side effect that message is
displayed in the traceback - but the type has changed.

Whilst in the above example, it's particularly evil, in the case where
the original exception came from a function call and you want to
translate the type it works very nicely.

Tim Delaney
___
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-12 Thread Guido van Rossum
[James Y Knight ]
> I think it's a bad idea to have this happen automatically. Many times
> if an exception is raised in the except clause, that doesn't
> necessarily imply it's related to the original exception. It just
> means there's a bug in the exception handler.

Yeah, but especially in that case I think it would be nice if the
traceback printed by the system (if all this doesn't get caught at an
outer level) could show both the traceback from the handler and the
traceback that it was trying to handle -- I've had many occasions
where a trivial bug in the handler blew away the original traceback
which was shy enough to make repeating it a pain.

-- 
--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


[Python-Dev] the current behavior of try: ... finally:

2005-05-12 Thread Michele Simionato
All this talk about try: ... finally: and exceptions reminded me of a curious
behavior I discovered a while back, i.e. that finally can swallow
your exceptions. This is a contrived example, but shows the point:

def divide1(n1, n2): 
try:
result = n1/n2
finally:
print "cleanup"
result = "Infinity\n"
return result # the exception is swallowed away

def divide2(n1, n2):
try:
result = n1/n2
finally:
print "cleanup"
result = "Infinity\n"
return result # the exception is NOT swallowed away

print divide1(10, 0) # no-exception
print divide2(10, 0) # error

If there is an indentation error in "divide2" and the return line is too
indented the exceptions get swallowed by the finally clause.

I am not sure if this is good or bad, but sure it surprised me that a
finally clause could hide my exception.

 Michele Simionato
___
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] the current behavior of try: ... finally:

2005-05-12 Thread Greg Ewing
Michele Simionato wrote:

> def divide1(n1, n2): 
> try:
> result = n1/n2
> finally:
> print "cleanup"
> result = "Infinity\n"
> return result # the exception is swallowed away

What would you prefer to have happen in this case?

Or do you think return (and break and continue) should
be disallowed in a finally?

-- 
Greg Ewing, Computer Science Dept, +--+
University of Canterbury,  | A citizen of NewZealandCorp, a   |
Christchurch, New Zealand  | wholly-owned subsidiary of USA Inc.  |
[EMAIL PROTECTED]  +--+
___
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-12 Thread Greg Ewing
Guido van Rossum wrote:
> It won't fly as long as we have string exceptions (since there's
> nowhere to put the traceback) but once those are dead I like it a lot.

Are there plans as to when string exceptions will be
exterminated? Surely the only places they're used now
are in some very old library modules.

-- 
Greg Ewing, Computer Science Dept, +--+
University of Canterbury,  | A citizen of NewZealandCorp, a   |
Christchurch, New Zealand  | wholly-owned subsidiary of USA Inc.  |
[EMAIL PROTECTED]  +--+
___
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-12 Thread Greg Ewing
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.

-- 
Greg Ewing, Computer Science Dept, +--+
University of Canterbury,  | A citizen of NewZealandCorp, a   |
Christchurch, New Zealand  | wholly-owned subsidiary of USA Inc.  |
[EMAIL PROTECTED]  +--+
___
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-12 Thread Greg Ewing
Guido van Rossum wrote:

> - Greg Ewing (I believe) wants 'do' instead of 'with' for the
>   keyword.  I think I like 'with' better, especially combining it with
>   Benji's proposal.  IMO this reads better with 'with' than with 'do':
> 
> with open("/etc/passwd") as f:
> for line in f:
> ...

I don't think I like the idea of giving the file object
itself __enter__ and __exit__ methods, because it doesn't
ensure that the opening and closing are done as a pair.
It would permit the following kind of mistake:

   f = open("somefile")
   with f:
 do_something()
   with f:
 do_something_else()

which our proposed construct, if it is any good, should
be able to prevent.

Also I don't at all agree that "with open(...)" reads
better; on the contrary, it seems ungrammatical.
Especially when compared with the very beautiful
"do opening(...)", which I would be disappointed
to give up.

I still also have reservations about "with" on the
grounds that we're making it mean something very
different to what it means in most other languages
that have a "with".

-- 
Greg Ewing, Computer Science Dept, +--+
University of Canterbury,  | A citizen of NewZealandCorp, a   |
Christchurch, New Zealand  | wholly-owned subsidiary of USA Inc.  |
[EMAIL PROTECTED]  +--+
___
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-12 Thread Greg Ewing
Michele Simionato wrote:

> let lock:
>do_something
> 
> let open("myfile") as f:
> for line in f: do_something(line)

This is getting even further into the realm
of gibberish to my ear.

> let f=file("myfile") :
> for line in f: do_something(line)

To anyone with a Lisp or funcional background, that
looks like nothing more than a local variable
binding.

-- 
Greg Ewing, Computer Science Dept, +--+
University of Canterbury,  | A citizen of NewZealandCorp, a   |
Christchurch, New Zealand  | wholly-owned subsidiary of USA Inc.  |
[EMAIL PROTECTED]  +--+
___
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] the current behavior of try: ... finally:

2005-05-12 Thread Michele Simionato
On 5/13/05, Greg Ewing <[EMAIL PROTECTED]> wrote:
> Michele Simionato wrote:
> 
> > def divide1(n1, n2):
> > try:
> > result = n1/n2
> > finally:
> > print "cleanup"
> > result = "Infinity\n"
> > return result # the exception is swallowed away
> 
> What would you prefer to have happen in this case?
> 
> Or do you think return (and break and continue) should
> be disallowed in a finally?
> 

Honestly, I don't know. This is why I ask here ;)

  Michele Simionato
___
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] the current behavior of try: ... finally:

2005-05-12 Thread Sakesun Roykiattisak

It did surprise me also.  Because I've come to Python from Delphi.  
There are no return statement in Delphi.
I also write some c++, the language has no finally-statement. This 
problem probably python exclusive.

I think it's not too difficult to get used to it. This behavior is fine 
for me.
___
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