Page 1 of 2

Adding more Exceptions

Posted: Tue Jun 24, 2014 8:58 am
by nelfata
What would be the best method to add more exceptions?
- extend the built-in exceptions?
- is there another user extension to add more exceptions

Some examples:
timeout, no data, read error,...

Thanks.

Re: Adding more Exceptions

Posted: Tue Jun 24, 2014 2:15 pm
by pfalcon
https://docs.python.org/3.4/tutorial/er ... exceptions

If you have issues with subclassing exceptions (or other builtin types) in MicroPython, please submit bug describing your use case and providing test case to reproduce your issue.

Re: Adding more Exceptions

Posted: Tue Jun 24, 2014 2:46 pm
by dhylands
I'm assuming that you're talking about adding Exceptions from python, and not from C?

As pfalcon suggests, it should be the standard way that python supports extensions.

I threw together a small example to confirm that they work. I created a file called extest.py:

Code: Select all

class MyError(Exception):
    pass

def func1():
    print("About to throw MyError")
    raise MyError
    print("After raising MyError")

def func2():
    try:
        func1()
    except MyError:
        print("Whoops")
and this is what I got on the pyboard:

Code: Select all

Micro Python v1.1.1-32-gcd590cb on 2014-06-24; PYBv1.0 with STM32F405RG
Type "help()" for more information.
>>> import extest
>>> extest.func2()
About to throw MyError
Whoops

Re: Adding more Exceptions

Posted: Tue Jun 24, 2014 5:17 pm
by dhylands
I added some arguments to MyError.

I also discovered that currently the only way to get a traceback printed is to pass the exception out to the REPL. There doesn't seem to be any way for the python code to print a traceback and retain control.

Updated example:

Code: Select all

class MyError(Exception):
    pass

def func1():
    print("About to throw MyError")
    raise MyError("some args", 57)
    print("After raising MyError")

def func2():
    try:
        func1()
    except MyError as ex:
        print("Whoops")
        raise ex

func2()
Results of running unix version:

Code: Select all

 >./micropython ../../extest.py 
About to throw MyError
Whoops
Traceback (most recent call last):
  File "../../extest.py", line 16, in <module>
  File "../../extest.py", line 14, in func2
  File "../../extest.py", line 14, in func2
  File "../../extest.py", line 11, in func2
  File "../../extest.py", line 6, in func1
MyError: ('some args', 57)
The results running on pyboard are similar, except the fiename is slightly different.

Re: Adding more Exceptions

Posted: Tue Jun 24, 2014 6:05 pm
by nelfata
Thank you for the prompt reply.
In fact I was talking about a C exception to be raised from C and caught in MP. I made the modifications in the C firmware, but I was wondering if there is some simpler way to extend the exception (in C) set without modifying the core MP code.

By the way since you mentioned about the trace, I noticed that if exceptions occur from other lower level C code layers, and in the Python code a Try/Exception is added, then the lower level exception messages are hidden and it becomes very hard to know what occurred.

Re: Adding more Exceptions

Posted: Tue Jun 24, 2014 7:20 pm
by nelfata
To add to this note, if there is a print in the C code and a Try/Except is added on the Python side, the print in C seems to be masked.

Re: Adding more Exceptions

Posted: Tue Jun 24, 2014 7:31 pm
by dhylands
Exceptions at the C level are really setjmp/longjmp (or conceptually similar).

In C you raise an exception using nlr_raise: like so:
https://github.com/micropython/micropyt ... int.c#L143

To add a custom exception in C, you can just create an your exception as an object derived from Exception.

Right now it looks like MP_DEFINE_EXCEPTION is in objexcept.c and it sounds like it should be moved into a header so that C modules could create their own exceptions. It also looks like some of the required support functions are declared static, and they should probably be exposed.

For an example of catching an exception in C, you can look at:
https://github.com/micropython/micropyt ... int.c#L367

Can you give an example of the hidden try/catch block thing in python? I'm guessing that it can be recoded, but without knowing what your python code looks like it's hard to know if it's a real problem (i.e. bug) or not (i.e. can be recoded).

Re: Adding more Exceptions

Posted: Tue Jun 24, 2014 7:38 pm
by dhylands
nelfata wrote:To add to this note, if there is a print in the C code and a Try/Except is added on the Python side, the print in C seems to be masked.
I think we'd need to see an example. The print should be happening right when the print statement is called. I'm not aware of any way to mask the print. The only thing I can think of is that it's sitting in the buffer to be sent out over USB serial, and that never happens because something resets USB. In this case if you set things up so that prints go out a UART, you should definitely see the print exactly when it occurs (there is no buffering of any kind which gets in the way of UART prints)

Re: Adding more Exceptions

Posted: Tue Jun 24, 2014 8:30 pm
by nelfata
Here is an example where the print in C is being masked when using a try/except block in MP:
(the Wiki is changing the tabs)

MP CODE
-----------
while receiveComplete == False:
try:
d = self.client_s.read(size, flags, timeout_ms*10)
except NoDataError:
print('no data error in read')
continue
except:
# some error occurred, we may need to restart the connection
self.errorFlag = 1
print('error in read')
break

C CODE
---------
... some code
status = _sock_isavailable(self->fd, 1, timeout);
RAISE_EXCEP(status>=0, mp_type_ReadError, "read failed");
RAISE_EXCEP(status==0, mp_type_NoDataError, "no data"); <<<<------MP is detecting this exception (exception message is masked)
....

STATIC int _sock_isavailable(int fd, int r_or_w, int timeout_ms)
{
...some code...
rc = cc3k_sock_select(fd+1, fd_read, fd_write, NULL, ptimeout);
if(rc == 0)
{ // select timed out, no data available
printf("select timedout\n"); <<<<<-------MP is masking this printf
}


NOTE: I created new exceptions here ReadError and NoDataError.

#define RAISE_EXCEP(assertion, type, msg) { if ((assertion) == 0) nlr_raise(mp_obj_new_exception_msg(&(type), (msg))); }

Re: Adding more Exceptions

Posted: Tue Jun 24, 2014 8:34 pm
by nelfata
dhylands wrote:
nelfata wrote:To add to this note, if there is a print in the C code and a Try/Except is added on the Python side, the print in C seems to be masked.
I think we'd need to see an example. The print should be happening right when the print statement is called. I'm not aware of any way to mask the print. The only thing I can think of is that it's sitting in the buffer to be sent out over USB serial, and that never happens because something resets USB. In this case if you set things up so that prints go out a UART, you should definitely see the print exactly when it occurs (there is no buffering of any kind which gets in the way of UART prints)
Could it be that we need to flush the printf (fflush(stdout)) when using the USB serial?