Re: ANN: withrestart 0.2.1

2009-12-18 Thread Neal Becker
I haven't tried it, but it sounds really cool.  I suppose I should expect a 
lot more overhead compared to try/except, since it's not built-in to python?

-- 
http://mail.python.org/mailman/listinfo/python-list


Re: ANN: withrestart 0.2.1

2009-12-18 Thread Ryan Kelly
On Fri, 2009-12-18 at 07:12 -0500, Neal Becker wrote:
 I haven't tried it, but it sounds really cool.  I suppose I should expect a 
 lot more overhead compared to try/except, since it's not built-in to python?

It's a pretty thin layer on top of try/except so I'll be surprised if
there is *too* much overhead.  The only overhead is at establishment
and/or invocation time - calling some extra functions, walking a few
stack frames, etc.

I've attached a highly scientific benchmark I threw together this
morning.  Results:

  Establishing a restart/tryexcept but not using it:

test_tryexcept0:  1.23 usec
test_restarts0:  34.90 usec

  Establishing a restart/tryexcept, returning a new value:

test_tryexcept1:  3.56 usec
test_restarts1:  67.30 usec

  Establishing a restart/tryexcept, raising a new error: 

test_tryexcept2:  5.86 usec
test_restarts2:  90.20 usec

  Not having to pass status flags or callback functions through every
layer of your API to properly recover from errors:

tryexcept:impossible :-(
withrestart:  priceless  :-)


  Cheers,

  Ryan


-- 
Ryan Kelly
http://www.rfk.id.au  |  This message is digitally signed. Please visit
r...@rfk.id.au|  http://www.rfk.id.au/ramblings/gpg/ for details


from withrestart import *


def test_tryexcept0():
def raiser():
return 7
def invoker():
return raiser()
def catcher():
try:
return invoker()
except ValueError:
return 7
assert catcher() == 7

def test_tryexcept1():
def raiser():
raise ValueError
def invoker():
return raiser()
def catcher():
try:
return invoker()
except ValueError:
return 7
assert catcher() == 7

def test_tryexcept2():
def raiser():
raise ValueError
def invoker():
raiser()
def catcher():
try:
invoker()
except ValueError:
raise TypeError
try:
catcher()
except TypeError:
pass
else:
raise AssertionError



def test_restarts0():
def raiser():
return 7
def invoker():
with restarts(use_value) as invoke:
return invoke(raiser)
def catcher():
with Handler(ValueError,use_value,7):
return invoker()
assert catcher() == 7

def test_restarts1():
def raiser():
raise ValueError
def invoker():
with restarts(use_value) as invoke:
return invoke(raiser)
def catcher():
with Handler(ValueError,use_value,7):
return invoker()
assert catcher() == 7

def test_restarts2():
def raiser():
raise ValueError
def invoker():
with restarts(raise_error) as invoke:
invoke(raiser)
def catcher():
with Handler(ValueError,raise_error,TypeError):
invoker()
try:
catcher()
except TypeError:
pass
else:
raise AssertionError




signature.asc
Description: This is a digitally signed message part
-- 
http://mail.python.org/mailman/listinfo/python-list


ANN: withrestart 0.2.1

2009-12-17 Thread Ryan Kelly

Hi All,


  Apologies if you receive multiple copies of this, my python-announce
posts don't seem to be making it through.

  I've just released a new python module called withrestart.  It's an
attempted Pythonisation of the restart-based condition system of Common
Lisp.  Details are on PyPI:

http://pypi.python.org/pypi/withrestart/0.2.1


  For an introduction to conditions and restarts, see Beyond Exception
Handling by Peter Seibel:

   
http://www.gigamonkeys.com/book/beyond-exception-handling-conditions-and-restarts.html


  For a quick demo of the module in action, keep reading...

  Cheers,

  Ryan



About withrestart:
--

Version:  0.2.1
Licence:  MIT
Source:   http://github.com/rfk/withrestart


withrestart is a Pythonisation (Lispers might rightly say bastardisation) of
the restart-based condition system of Common Lisp.  It's designed to make error
recovery simpler and easier by removing the assumption that unhandled errors
must be fatal.

A restart represents a named strategy for resuming execution of a function
after the occurrence of an error.  At any point during its execution a
function can push a Restart object onto its call stack.  If an exception
occurs within the scope of that Restart, code higher-up in the call chain can
invoke it to recover from the error and let the function continue execution.
By providing several restarts, functions can offer several different strategies
for recovering from errors.

A handler represents a higher-level strategy for dealing with the occurrence
of an error.  It is conceptually similar to an except clause, in that one
establishes a suite of Handler objects to be invoked if an error occurs during
the execution of some code.  There is, however, a crucial difference: handlers
are executed without unwinding the call stack.  They thus have the opportunity
to take corrective action and then resume execution of whatever function
raised the error.

As an example, here's a function that doesn't like the number seven:

def anything_but_seven(v):
if v == 7:
raise ValueError(Argh!  A Seven!)
return v
 
And here's a function that can recover from the occurrence of a seven
using the pre-defined restarts skip and use_value:

def sum_items(items):
total = 0
for i in items:
with restarts(skip,use_value) as invoke:
total += invoke(anything_but_seven,i)
return total

Naively calling this will raise a ValueError:

 sum_items(range(8))
Traceback (most recent call last):
...
ValueError: Argh! A Seven!


But if we handle ValueErrors by invoking the skip restart, we can
still get the sum of the remaining items:

 with Handler(ValueError,skip):
... sum_items(range(8))
... 
21
 

Alternately, we can invoke the use_value restart to replace the sevens
with another value:

 with Handler(ValueError,use_value,12):
... sum_items(range(8))
... 
33
 

By splitting the responsibility for error recovery between Handlers and
Restarts, we can cleanly separate the low-level mechanics of recovering
from an error from the high-level decisions about what sort of recovery
to perform.



-- 
Ryan Kelly
http://www.rfk.id.au  |  This message is digitally signed. Please visit
r...@rfk.id.au|  http://www.rfk.id.au/ramblings/gpg/ for details





signature.asc
Description: This is a digitally signed message part
-- 
http://mail.python.org/mailman/listinfo/python-list