On May 31, 2010, at 9:48 PM, Dan Stromberg wrote:

>
> I'm attempting to get a Cython module to raise exceptions that'll be  
> visible to the calling CPython.
>
> The Cython code in question looks like:
>    def add_from_fileno(self, fileno, length_to_add):
>       exception_string = self.add_from_fileno_c(fileno, length_to_add)
>       if exception_string.startswith("Buffer error"):
>          raise exceptions.BufferError, exception_string
>       elif exception_string == '':
>          pass
>       else:
>          raise exceptions.AssertionError, exception_string
>
>    cdef add_from_fileno_c(self, fileno, length_to_add):
>       if self.would_overflow(length_to_add):
>          return "Buffer error: Would overflow"
>       # FIXME: We need to do something about EINTR on these 3 read's!
>       if self.would_add_wrap(length_to_add):
>          # do the read in two pieces
>          first_length, second_length =  
> self.split_to_two_add(length_to_add)
>          length_added = read(fileno, &self.buffer[self.end],  
> first_length)
>          if length_added != first_length:
>             return "length_added != first_length"
>          length_added = read(fileno, self.buffer, second_length)
>          if length_added != second_length:
>             return "length_added != second_length"
>          self.end = second_length
>       else:
>          # do the read in one piece
>          length_added = read(fileno, &self.buffer[self.end],  
> length_to_add)
>          if length_added != length_to_add:
>             return "length_added != length_to_add"
>          self.end += length_to_add
>       return ''
> ...and in the caller (CPython code, inheriting from unittest):
>    def test_fileno_from_file_overflow(self):
>       file_ = open('input-file', 'w')
>       file_.write('abc' * 15)
>       file_.close()
>
>       rb = ring_buffer_mod.Ring_buffer(buffer_size = 10)
>       input_fileno = os.open('input-file', os.O_RDONLY)
>       for i in xrange(10):
>          rb.add_from_fileno(input_fileno, 1)
>       #self.assertRaises(exceptions.BufferError, rb.add_from_fileno,  
> input_fileno, 1)
>       try:
>          rb.add_from_fileno(input_fileno, 1)
>       except exceptions.BufferError:
>          pass
>
> All seems fine, except for the exceptions.  When I raise an  
> exception in Cython, I see a message on my terminal (I believe there  
> should be none), and the calling CPython code doesn't appear to  
> realize that an exception has been raised.  I added the  
> add_from_fileno_c/add_from_file distinction, because I was hoping  
> that a def would be able to raise an exception, after finding that  
> cdef's and cpdef's seemed to have problems with it - but it appears  
> that there's some sort of exception barrier between Cython and  
> CPython.
>
> I've googled quite a bit, but haven't found much on the topic that  
> didn't seem kind of hand wavey.
>
> What do I need to do, to raise an exception in Cython, that CPython  
> code will be able to see?

This should work just fine for def functions, as well as c(p)def  
functions not declaring a c return type (in which case you should see  
[1]). Have you tried calling this directly from the command line  
(eliminating the possibility that it's something with the unittest  
framework?) What if you do

cdef class A:
     def spam(self):
         raise TypeError
     cpdef eggs(self):
         raise ValueError

Does that work for you? (It does for me.)

- Robert

[1] 
http://docs.cython.org/src/userguide/language_basics.html#error-return-values

_______________________________________________
Cython-dev mailing list
[email protected]
http://codespeak.net/mailman/listinfo/cython-dev

Reply via email to