Hi,
expy is an expressway to extend python.
in release 0.5.2, expy now supports custom exceptions, besides all built-in ones, and exception handling is made easy.
for more info, see
cheers,
Yingjie
Hi,
Yingjie Lan, 03.02.2010 07:43:
in release 0.5.2, expy now supports custom exceptions, besides all built-in ones, and exception handling is made easy.
How does that work? I.e., how do you handle exceptions that occur inside of the plain string that expy uses to integrate C code?
Stefan
Hi,
Yingjie Lan, 03.02.2010 07:43:
in release 0.5.2, expy now supports custom exceptions, besides all built-in ones, and exception handling is made easy.
How does that work? I.e., how do you handle exceptions that occur inside of the plain string that expy uses to integrate C code?
There are several ways to throw exceptions with expy. First of all, you can use @throws(...) to throw exceptions based on input and output of a function. Another possibility is to throw exceptions inside your function implementation, and upon return of your code, the wrapper function would return NULL after all necessary reference count management, if any exception is thrown by your function implementation code. Please also refer to the documentation of expy on exception handling here (it also includes how to create a custom exception, and how to manage exception inheritance):
http://expy.sourceforge.net/tutorial.html#exception-for-arguments-returns
Yingjie
Yingjie Lan, 03.02.2010 10:46:
in release 0.5.2, expy now supports custom exceptions, besides all built-in ones, and exception handling is made easy.
How does that work? I.e., how do you handle exceptions that occur inside of the plain string that expy uses to integrate C code?
There are several ways to throw exceptions with expy. First of all, you can use @throws(...) to throw exceptions based on input and output of a function. Another possibility is to throw exceptions inside your function implementation, and upon return of your code, the wrapper function would return NULL after all necessary reference count management, if any exception is thrown by your function implementation code. Please also refer to the documentation of expy on exception handling here (it also includes how to create a custom exception, and how to manage exception inheritance):
http://expy.sourceforge.net/tutorial.html#exception-for-arguments-returns
Hmm, there's a lot of code in that example. Let's contrast that to Cython.
MyError = gfield(exception('module1f.MyError', ValueError)) NegError = gfield(exception('module1f.NegEror', MyError))
Cython:
class MyError(ValueError): pass
class NegError(MyError): pass
#'$return': returned value @function(int) @throws('$return<0', NegError, 'No negatives!') @throws('$return>100', ValueError, 'Out of range: %i', '$return') def range_check(n = int): return "n*n"
Cython:
def range_check(int n):
cdef int retval = n*n
if retval < 0:
raise NegError('No negatives!')
if retval > 100:
raise ValueError('Out of range: %d' % retval)
return retval
Note that the C compiler will likely discard the "retval < 0" block here. I assume you meant to check the input value instead?
@function(str) @throws('n<0', ValueError, 'No nagatives: %s=%i!','desc, n') @throws('$return==NULL', code=""" //you can also do sth else here PyErr_NoMemory(); """) def stringify(n=int, desc = str): return """{ char* s = malloc(sizeof(char)*20); if (s) sprintf(s, "%i", n); return s; }"""
This example will actually leak memory. Also, it won't work correctly on a 64-bit system.
Anyway, here's some Cython code for this:
from stdio cimport sprintf
from stdlib cimport malloc, free
from python_exc cimport PyErr_NoMemory
def stringify(int n, desc):
cdef char* s
if n < 0:
raise ValueError('No negatives: %s = %d' % (desc,i))
s = malloc(sizeof(char)*20)
if s is NULL:
PyErr_NoMemory()
sprintf(s, "%i", n)
try:
return s
finally:
free(s)
Personally, I'd rather write this:
def stringify(int n, str desc):
if n < 0:
raise ValueError('No negatives: %s = %d' % (desc,i))
return str(n)
or even this:
def stringify(unsigned int n):
return str(n)
which will also do the right thing.
#throws(True/False, ...): #special case when you provide all code #for exception checking and handling #True for arguement, False for returned values @function(int) #argument checking @throws('den > 500', MyError, "Can't handle it!") @throws(True, code=""" int i = 2; while(i < den && (den % i)) i++; if (i != den){ //not a prime! PyErr_SetString(PyExc_Exception, "argument 'den' must be a prime!"); //usually don't return here //unless no argument is of object type, //as you need to DEC_REF it, which //is automatically handled later. } """) @throws(False, code=""" int i = 2; while(i < $return && ($return % i)) i++; if (i != $return){ //not a prime! PyErr_SetString(PyExc_Exception, "must return a prime!"); return NULL; } """) def prime_friend(den = int): return "den+2"
Cython:
cdef check_prime(int p, error_message):
cdef int i
for i in range(2, p): # I'd add at least a sqrt() here
if not (p % i):
raise Exception(error_message)
def prime_friend(int den):
cdef int i, retval
if den > 500:
raise MyError("Can't handle it!")
check_prime(den)
check_prime(den+2)
return den+2
Looking at the two implementations, I actually wonder what the term "express way" means to you exactly.
Stefan
Hi, Thank you very much for making this fantastic contrast with Cython. Admittedly, Cython has a lot of good things, and it is improved a lot. The task expy is targeting at is different from that of Cython, and I hope expy provides more flexibility when it comes to extend Python.
in release 0.5.2, expy now supports custom exceptions, besides all built-in ones, and exception handling is made easy.
How does that work? I.e., how do you handle exceptions that occur inside of the plain string that expy uses to integrate C code?
There are several ways to throw exceptions with expy. First of all, you can use @throws(...) to throw exceptions based on input and output of a function. Another possibility is to throw exceptions inside your function implementation, and upon return of your code, the wrapper function would return NULL after all necessary reference count management, if any exception is thrown by your function implementation code. Please also refer to the documentation of expy on exception handling here (it also includes how to create a custom exception, and how to manage exception inheritance):
http://expy.sourceforge.net/tutorial.html#exception-for-arguments-returns
Hmm, there's a lot of code in that example. Let's contrast that to Cython.
MyError = gfield(exception('module1f.MyError', ValueError)) NegError = gfield(exception('module1f.NegEror', MyError))
Cython:
class MyError(ValueError): pass class NegError(MyError): pass
Yes, this looks much easier, I need to modify the way exceptions are defined in expy, after which the same thing would be possible with expy. Thanks! There are many good things to learn from Cython.
#'$return': returned value @function(int) @throws('$return<0', NegError, 'No negatives!') @throws('$return>100', ValueError, 'Out of range: %i', '$return') def range_check(n = int): return "n*n"
Cython:
def range_check(int n): cdef int retval = n*n if retval < 0: raise NegError('No negatives!') if retval > 100: raise ValueError('Out of range: %d' % retval) return retval
Note that the C compiler will likely discard the "retval < 0" block here. I assume you meant to check the input value instead?
You are right, n*n < 0 would never happen.
@function(str) @throws('n<0', ValueError, 'No nagatives: %s=%i!','desc, n') @throws('$return==NULL', code=""" //you can also do sth else here PyErr_NoMemory(); """) def stringify(n=int, desc = str): return """{ char* s = malloc(sizeof(char)*20); if (s) sprintf(s, "%i", n); return s; }"""
This example will actually leak memory. Also, it won't work correctly on a 64-bit system.
First of all, thank you very much for pointing this out to me. I'm not sure if this is something unavoidable by the design of expy or if I can avoid this by improve my implementation code of this particular example. I will check this and see what I can do about it. Meanwhile, I wonder if you can give me some suggestions, especially on the memory leak issue.
Anyway, here's some Cython code for this:
from stdio cimport sprintf from stdlib cimport malloc, free from python_exc cimport PyErr_NoMemory
def stringify(int n, desc): cdef char* s if n < 0: raise ValueError('No negatives: %s = %d' % (desc,i)) s = malloc(sizeof(char)*20) if s is NULL: PyErr_NoMemory() sprintf(s, "%i", n) try: return s finally: free(s)
Personally, I'd rather write this:
def stringify(int n, str desc): if n < 0: raise ValueError('No negatives: %s = %d' % (desc,i)) return str(n)
or even this:
def stringify(unsigned int n): return str(n)
which will also do the right thing.
EXPY requires you to do things in pure C when it comes to logic/functionality, the bright side of this is that you have full control over the implementation. As I said, EXPY and Cython are different in their objectives.
#throws(True/False, ...): #special case when you provide all code #for exception checking and handling #True for arguement, False for returned values @function(int) #argument checking @throws('den > 500', MyError, "Can't handle it!") @throws(True, code=""" int i = 2; while(i < den && (den % i)) i++; if (i != den){ //not a prime! PyErr_SetString(PyExc_Exception, "argument 'den' must be a prime!"); //usually don't return here //unless no argument is of object type, //as you need to DEC_REF it, which //is automatically handled later. } """) @throws(False, code=""" int i = 2; while(i < $return && ($return % i)) i++; if (i != $return){ //not a prime! PyErr_SetString(PyExc_Exception, "must return a prime!"); return NULL; } """) def prime_friend(den = int): return "den+2"
Cython:
cdef check_prime(int p, error_message): cdef int i for i in range(2, p): # I'd add at least a sqrt() here if not (p % i): raise Exception(error_message)
def prime_friend(int den): cdef int i, retval if den > 500: raise MyError("Can't handle it!") check_prime(den) check_prime(den+2) return den+2
Looking at the two implementations, I actually wonder what the term "express way" means to you exactly.
Well, in EXPY, you can also define this check_prime(.) function and then use it, I will improve this the way you did. Thanks again!
Yingjie
Yingjie Lan, 03.02.2010 13:21:
The task expy is targeting at is different from that of Cython
Well, expy generates plain glue code, whereas Cython is a full fledged programming language with an optimising compiler. Both aim to simplify writing extension modules for CPython, and both interface with C code. It's not the task that's different, it's the feature set.
and I hope expy provides more flexibility when it comes to extend Python.
I guess I'm too biased to comment on that one.
Stefan
participants (2)
-
Stefan Behnel
-
Yingjie Lan