Page 1 of 1

[Solved]Catch exception raised in C in python

Posted: Tue Oct 02, 2018 2:40 pm
by BramPeeters
Hi.

I just read an (old) thread about this topic (viewtopic.php?f=2&t=178) which seems to indicate that it is possible to 'catch' an 'exception' in a python try-except block that is raised in C.
However i am not able to reproduce that nor do I understand how to get it working.

The original thread use an MP_RAISE macro around nlr_raise, which as the original thread points out just is a setjmp/longjmp (to where nlr_push was done).
In my case this is in execute_from_string (based on the demo code), so it is outside of the mp_call_function_0 which i used to start the python code.

Code: Select all

     if (nlr_push(&nlr) == 0)
    {
        qstr src_name = MP_QSTR_;
        mp_lexer_t *lex = mp_lexer_new_from_str_len( src_name, str, strlen(str), false);
        mp_parse_tree_t pt = mp_parse(lex, MP_PARSE_FILE_INPUT);
        mp_obj_t module_fun = mp_compile(&pt, src_name, MP_EMIT_OPT_NONE, false);
        mp_call_function_0(module_fun);
        nlr_pop();
        return 0;
    } else {
      //exception handling code, C level
    ...
    }
I don't see how with I can change this mechanism to end up in try block at python level similar to the dhtest.py example from the original thread. Was this possible in older versions but not anymore ? Should i use something else than the nlr_raise based functions (mp_raise_msg & co) ? Did I misunderstand the original thread ?

Thanks
Bram

Re: Catch exception raised in C in python

Posted: Tue Oct 02, 2018 2:56 pm
by stijn
Does nlr_raise not work for you somehow? It's all that's needed.. As in, under normal circumstances if you are in a Python script in a try/except block and call a function which is implemented in C and the latter one in turn uses nlr_raise, that exception will make it to the except block. It's how all of the source code works. But it's not really clear to me what you are trying exactly, can you show some code?

Re: Catch exception raised in C in python

Posted: Tue Oct 02, 2018 3:34 pm
by BramPeeters
You describe exactly what I was trying to do and after rechecking it in fact it works perfect, thank you!
How does it work under the hood, does try 'try' instruction (temporary) replace the target jump address ?

The reason it did not seem to work before is because I was still using an old .py script without a try except block so it jumped to the initial C level nlr_push(&nlr) point. And it was still the old script because i copy the scripts over to my target using USB drivers from stm which get an award for being horrible (amongst many others, busy waiting at interrupt level, why not) and every once and a while just do not copy a file even though you think it was successful. Only after your comment that it should work I read back the file and i noticed it....my bad.

Re: Catch exception raised in C in python

Posted: Tue Oct 02, 2018 4:49 pm
by jickster
BramPeeters wrote:
Tue Oct 02, 2018 3:34 pm
How does it work under the hood, does try 'try' instruction (temporary) replace the target jump address ?
Clarify this question.

Re: Catch exception raised in C in python

Posted: Wed Oct 03, 2018 8:51 am
by stijn
BramPeeters wrote:
Tue Oct 02, 2018 3:34 pm
How does it work under the hood, does try 'try' instruction (temporary) replace the target jump address ?
Would be possible theoretically I think (might get messy for nested try blocks though) but it's done in a different way, see use of PUSH_EXC_BLOCK and the exception_handler label in mp_execute_bytecode in vm.c: the main vm loop just sets some flags to indicate whether currently in a try block and if so stores the exception on the stack then continues execution (e.g. doing something with the exception in the except block), whereas when there was no try block execution stops there and mp_execute_bytecode returns MP_VM_RETURN_EXCEPTION to indicate that, which is handled further.

Re: [Solved]Catch exception raised in C in python

Posted: Sun Oct 07, 2018 4:38 pm
by BramPeeters
Ok, thanks for the pointers/explanation !