[GRASS-dev] Howto use a Python function as error handler in libgis

Dear developers,
i am trying to register a Python function as error handler callback
using ctypes in libgis.
I use this code in the temporal framework:

{{{
def error_handler(data):
    pass

CALLBACK = CFUNCTYPE(None, c_void_p)
CALLBACK.restype = None
CALLBACK.argtypes = c_void_p

cerror_handler = CALLBACK(error_handler)

libgis.G_add_error_handler(cerror_handler, POINTER(None))
}}}

Unfortunately i get this error:

{{{
Traceback (most recent call last):
  File "/usr/lib/python2.7/multiprocessing/process.py", line 258, in _bootstrap
    self.run()
  File "/usr/lib/python2.7/multiprocessing/process.py", line 114, in run
    self._target(*self._args, **self._kwargs)
  File "/home/soeren/src/grass7.1/grass_trunk/dist.x86_64-unknown-linux-gnu/etc/python/grass/temporal/c_libraries_interface.py",
line 759, in c_library_server
    libgis.G_add_error_handler(cerror_handler, POINTER(None))
ArgumentError: argument 1: <type 'exceptions.TypeError'>: expected
CFunctionType instance instead of CFunctionType
}}}

Does anyone know what the correct way is to register a Python function
as error handler in libgis?

Any help is highly welcome.

Best regards
Soeren

Dear Developers,
any clue about how to register a Python function
as error handler in libgis using libgis.G_add_error_handler()?

Or is there any other way to recognize a fatal error call from libgis in Python?
I tried to catch the signals, unfortunately is Python not able to
catch signals emitted from a C-library.
Is it possible to write an error handler in C that can transfer a
signal that Python is able to catch using the Python API?

My current approach is a Python-thread that checks if the Python
process that accesses the C-library functions every 0.2 seconds is
still alive. The reason why i need this is, that the Python Pipe
communication object between the processes must be closed correctly to
avoid endless waiting in the receiver process/thread.

Any suggestions are welcome.

Best regards
Soeren

2015-02-06 23:41 GMT+01:00 Sören Gebbert <soerengebbert@googlemail.com>:

Dear developers,
i am trying to register a Python function as error handler callback
using ctypes in libgis.
I use this code in the temporal framework:

{{{
def error_handler(data):
    pass

CALLBACK = CFUNCTYPE(None, c_void_p)
CALLBACK.restype = None
CALLBACK.argtypes = c_void_p

cerror_handler = CALLBACK(error_handler)

libgis.G_add_error_handler(cerror_handler, POINTER(None))
}}}

Unfortunately i get this error:

{{{
Traceback (most recent call last):
  File "/usr/lib/python2.7/multiprocessing/process.py", line 258, in _bootstrap
    self.run()
  File "/usr/lib/python2.7/multiprocessing/process.py", line 114, in run
    self._target(*self._args, **self._kwargs)
  File "/home/soeren/src/grass7.1/grass_trunk/dist.x86_64-unknown-linux-gnu/etc/python/grass/temporal/c_libraries_interface.py",
line 759, in c_library_server
    libgis.G_add_error_handler(cerror_handler, POINTER(None))
ArgumentError: argument 1: <type 'exceptions.TypeError'>: expected
CFunctionType instance instead of CFunctionType
}}}

Does anyone know what the correct way is to register a Python function
as error handler in libgis?

Any help is highly welcome.

Best regards
Soeren

Sören Gebbert wrote:

Dear developers,
i am trying to register a Python function as error handler callback
using ctypes in libgis.
I use this code in the temporal framework:

{{{
def error_handler(data):
    pass

CALLBACK = CFUNCTYPE(None, c_void_p)

AFAICT, this needs to be:

  CALLBACK = CFUNCTYPE(c_void_p, c_void_p)

For callbacks, ctypesgen converts any return type which isn't a
primitive C type to c_void_p. And None isn't a primitive C type.

--
Glynn Clements <glynn@gclements.plus.com>

Hi Glynn,
thanks a lot, that solved the issue.

Best regards
Soeren

2015-02-14 4:10 GMT+01:00 Glynn Clements <glynn@gclements.plus.com>:

Sören Gebbert wrote:

Dear developers,
i am trying to register a Python function as error handler callback
using ctypes in libgis.
I use this code in the temporal framework:

{{{
def error_handler(data):
    pass

CALLBACK = CFUNCTYPE(None, c_void_p)

AFAICT, this needs to be:

        CALLBACK = CFUNCTYPE(c_void_p, c_void_p)

For callbacks, ctypesgen converts any return type which isn't a
primitive C type to c_void_p. And None isn't a primitive C type.

--
Glynn Clements <glynn@gclements.plus.com>

Sören Gebbert wrote:

> AFAICT, this needs to be:
>
> CALLBACK = CFUNCTYPE(c_void_p, c_void_p)
>
> For callbacks, ctypesgen converts any return type which isn't a
> primitive C type to c_void_p. And None isn't a primitive C type.

thanks a lot, that solved the issue.

Actually, for forward compatibility, use:

  CALLBACK = CFUNCTYPE(libgis.UNCHECKED(None), c_void_p)

I'm thinking that we might want to change the definition of UNCHECKED
so that UNCHECKED(None) == None.

I didn't want to mess with ctypesgen too much to make it easier to
sync with upstream. But if ctypesgen is abandoned (the last commit was
August 2013), that's not really an issue.

--
Glynn Clements <glynn@gclements.plus.com>