(I composed this earlier but there was an SMTP error. Resending in case it
is still relevant.)
(On that note I'm only semi-available the next 12 days or so.)
David Simmons-Duffin wrote:
> I'm still working on wrapping the computer algebra package LiE in
cython. For those unfamiliar, LiE is basically it's own language,
written in C. And I'm interested in calling some of the math-heavy
functions, but bypassing the interpreter.
> Error checking is sprinkled throughout the LiE source, for instance:
matrix *mat_mul_mat_mat(matrix *a, matrix *b) {
> if (a->ncols != b->nrows)
> error("Number columns arg1 unequal number of rows arg2 .\n");
> return Matmult(a, b);
> }
> When an error is found, LiE calls the error() function, which prints out
a traceback, cleans up a little bit, and finally does a longjump to
"envbuf," which is at the beginning of the interpreter loop:
> void error(char *format, ...)
> {
> symblst list;
> extern jmp_buf envbuf;
> va_list ap;
> va_start(ap, format);
> vfprintf(stderr, format, ap);
> if (am_monitor) vfprintf(monfile, format, ap);
> if (label->name)
> {
> boolean printin = (label->name != seq_name);
> if (printin)
> Printf("(in %s",name_tab[label->name]);
> if (no_terminal(cur_in) || strcmp(label->fname, "stdin")!=0) {
> if (!printin) Printf("(");
> Printf(" at line %d of file %s)\n",label->line, label-
> >fname);
> }
> else
> if (printin) Printf(")\n");
> }
> if (fun_name)
> Printf("[in function %s ]\n", name_tab[fun_name]);
> for (list = top_definitions; list!=NULL; list = list->next)
> /* Recover symbol table */
> { if (list->class == FUNCTION_COPIED) list->class = FUNCTION;
> if (list->next && list->next->class == DUMMY)
> list->next = list->next->next; /* Remove sym */
> }
> if (repair_obj) {
> setshared(repair_obj);
> repair_obj = (object) NULL;
> }
> if (cur_in==stdin)
> clear_input();
> else
> do exit_input_file(parsing); while (cur_in!=stdin); /* pop
> input files */
> longjmp(envbuf, -1);
> }
> Instead of doing all this stuff, and longjumping to the LiE
> interpreter, I'd like to raise a python exception that could be caught
by whatever cython function called "mat_mul_mat_mat." Does anyone have
any advice on how to do this? I took a look at the python
I think you should avoid using jumps since you will not call the functions
from the interpreter loop but instead call them directly; so there's no
canonical place to jump back to.
There are two ways of achieving this:
I) The usual CPython way of doing this is to have a seperate return path.
So you need to do
matrix *mat_mul_mat_mat(matrix *a, matrix *b) {
if (a->ncols != b->nrows) {
error("Number columns arg1 unequal number of rows arg2 .\n");
return NULL;
}
return Matmult(a, b);
}
The problem is when a function calls another function which may call error
-- then you must start to insert checks like this:
if ((ret = mat_mul_mat_mat(...)) == NULL) return NULL;
... use ret ...
>From the error function using a jump it looks like memory is never
dynamically allocated using malloc or similar? Anyway, if it is, then such
memory must be freed also during error-returns.
You must then declare the functions in Cython with an "except NULL"
clause. See docs.cython.org on exceptions.
II) Potentially easier: Try to compile the library using C++. Then error
can raise a C++ exception which frees you of having to check return values
(but memory allocated using malloc must still be dealt with, through using
try/catch clauses or std::auto_ptr). Using "except +" Cython-side, Cython
can trap C++ exceptions and convert them to Python exceptions.
> exception portion of the C/API. It seems like I might want to make a C
file with my own error function:
> error(char* format, ...) {
> turn format into a string
> PyErr_SetString(errorstring)
Correct, PyErr_Format(...) might be easier in some contexts but I suppose
here the error string is already assembled.
Dag Sverre
_______________________________________________
Cython-dev mailing list
[email protected]
http://codespeak.net/mailman/listinfo/cython-dev