Method without return value in python c extension module
Asked Answered
F

2

14

I'm trying to create a script in python that sends data through a parallel port. I'm creating my own module in C language.

The problem is: when I try to execute my module, python crashes. No errors, no data, nothing. It simply closes.

This is my module:

#include <Python.h>
#include <sys/io.h>
#define BaseAddr 0x378

/*----------------------------------------------------------------------------------
Este es un módulo destinado a controlar el puerto paralelo.
Probablemente tenga que ser ejecutado como administrador.

Created by markmb
------------------------------------------------------------------------------------*/

static PyObject *
paralelo(PyObject *self, PyObject *args){
    int pin;
    ioperm(BaseAddr,3,1);
    if (!PyArg_ParseTuple(args, "i", &pin))
        return NULL;
    outb(pin,BaseAddr);
    ioperm(BaseAddr,3,0);
    return 1
}
PyMethodDef methods[] = {
    {"paralelo", paralelo, METH_VARARGS, "Sends data through a parallel port"},
    {NULL, NULL, 0, NULL}
};
PyMODINIT_FUNC
initparalelo(void){
    (void) Py_InitModule("paralelo", methods);
}

(It works without all python mess) I compile it through distutils and then, in terminal (using xubuntu), I put:

import paralelo
while True:
    paralelo.paralelo(255)

And here, it goes out of python, it puts "markmb@..."

Thanks in advance!

Freyah answered 9/12, 2011 at 19:11 Comment(6)
I haven't made my own Python module in C, but in your function paralelo where it's supposed to return PyObject *, why are you returning 1 at the end?Catha
It really shouldn't return nothing, but I left that return for remember if I ever do another module againFreyah
So how about if you return NULL instead? Rather than 1 which is an invalid pointer.Catha
It looks better... But it still crashes. Now, it throws an error when I use the module in a program I'm creating: SystemError: error return without exception setFreyah
BTW, there is already a module for this, pypi.python.org/pypi/portioCheriecherilyn
Yes, an other user said that, but it seems it deleted its answer. I couldn't find it, and because I started, I'd like to finish. And your solution of "Py_None" works (you forgot the underscore)Freyah
A
13

Returning NULL to the python/c API indicates that an error has occurred. But since you didn't actually set an exception you get the error:

SystemError: error return without exception set

If you are trying to return None, use:

return Py_BuildValue("");
Abisha answered 9/12, 2011 at 19:47 Comment(2)
I used what the other comment says: return Py_None, and it worksFreyah
@markmb, careful! If you use return Py_None, you need to increment the reference count or else you will run into trouble. You should either use what I have, or the Py_RETURN_NONE that the other answer has or call Py_IncRef(Py_None)Abisha
C
23

All python functions should return a PyObject, unless when they want to raise an exception, as explained: here http://docs.python.org/extending/extending.html#intermezzo-errors-and-exceptions

The error message you get SystemError: error return without exception set, is trying to tell you that your function returned NULL (=error, raise an exception) but did not inform the python interpreter what exception you wanted to raise.

When you don't want to return a value from a python function you make it return None (which is same thing that happens if you in python code have a function that runs to the end or does a simple return without any value).

In the cpython api you do this by returning the Py_None object, and don't forget to increment its refcount. To help you not forgetting the refcount there is a macro to do it for you: http://docs.python.org/c-api/none.html#Py_RETURN_NONE.

So a function skeleton for a function returning nothing (=returning None) you look something like this:

static PyObject *
myfunction(PyObject *self, PyObject *args){
    if (!PyArg_ParseTuple(args, "i", ...))
        return NULL;
    /* .... */
    Py_RETURN_NONE;
}

Finally, for the record: there is a python module for doing the ioperm/outb calls already: http://pypi.python.org/pypi/portio

Cheriecherilyn answered 9/12, 2011 at 20:2 Comment(0)
A
13

Returning NULL to the python/c API indicates that an error has occurred. But since you didn't actually set an exception you get the error:

SystemError: error return without exception set

If you are trying to return None, use:

return Py_BuildValue("");
Abisha answered 9/12, 2011 at 19:47 Comment(2)
I used what the other comment says: return Py_None, and it worksFreyah
@markmb, careful! If you use return Py_None, you need to increment the reference count or else you will run into trouble. You should either use what I have, or the Py_RETURN_NONE that the other answer has or call Py_IncRef(Py_None)Abisha

© 2022 - 2024 — McMap. All rights reserved.