def convert_string_vector_in(datum_ptr): """ Convert a datum pointer into a python tuple of strings. :param datum_ptr: Sprokit datum pointer. :return: List of strings :rtype: list[str] """ _VL = find_vital_library.find_vital_library() _VCL = find_vital_library.find_vital_type_converter_library() func = _VCL['vital_string_vector_from_datum'] func.argtypes = [ ctypes.py_object, ctypes.POINTER(ctypes.POINTER(ctypes.c_char_p)), ctypes.POINTER(ctypes.c_size_t) ] sl_free = _VL['vital_common_free_string_list'] sl_free.argtypes = [ctypes.c_size_t, ctypes.POINTER(ctypes.c_char_p)] c_arr_strings = ctypes.POINTER(ctypes.c_char_p)() c_arr_size = ctypes.c_size_t() func(datum_ptr, ctypes.byref(c_arr_strings), ctypes.byref(c_arr_size)) # Convert output array into tuple of strings s_list = [] for i in range(c_arr_size.value): s_list.append(c_arr_strings[i]) # Free strings allocated in C function. sl_free(c_arr_size, c_arr_strings) return s_list
def test_find_lib_caching(self): nose.tools.assert_is_none(fvl.__LIBRARY_PATH_CACHE__) l = fvl.find_vital_library() nose.tools.assert_is_instance(l, ctypes.CDLL) nose.tools.assert_is_not_none(fvl.__LIBRARY_CACHE__)
class VitalObject(object): """ Basic VITAL python interface class. Guarantees that should be maintained: - c_type() and c_ptr_type() should be used when trying to get C types from class types. - C_TYPE and C_TYPE_PTR should be used when trying to get C types from class instances, and thus should only refer to a single type in an instance. Value undefined defined on the class level. """ __metaclass__ = VitalClassMeta VITAL_LIB = find_vital_library() # C API opaque structure + pointer C_TYPE = None C_TYPE_PTR = None @classmethod def c_type(cls, *args): """ Get the C opaque type """ return cls.C_TYPE @classmethod def c_ptr_type(cls, *args): """ Get the C opaque pointer type """ return cls.C_TYPE_PTR @classmethod def _call_cfunc(cls, func_name, argtypes=(), args=(), restype=None, exception_map=None): """ Extract function from vital library and call it with a VitalErrorHandle. This assumes that the C function takes an additional parameter than what is given to this function that is the error handle. This function may raise an exception when the C function call's error handle picked something up. :param func_name: C function name to pull from library :type func_name: str :param argtypes: Ctypes argument type array :type argtypes: list | tuple :param args: sequence of positional arguments to the C function :type args: list | tuple :param restype: optional Ctypes return type :param exception_map: Return code to exception mapping to give to the error handler. :type exception_map: dict[int, BaseException | types.FunctionType] :return: Result of the c function call """ # local to prevent circular import from vital.util import VitalErrorHandle f = cls.VITAL_LIB[func_name] if argtypes: f.argtypes = list(argtypes) + [VitalErrorHandle.c_ptr_type()] f.restype = restype with VitalErrorHandle() as eh: if exception_map: eh.set_exception_map(exception_map) return f(*(list(args) + [eh])) def __init__(self, from_cptr=None, *args, **kwds): """ Create a new instance of the Python vital type wrapper. This initializer should only be called after C_TYPE/C_TYPE_PTR are concrete types. :param from_cptr: Existing C opaque instance pointer to use, preventing new instance construction. This should of course be a valid pointer to an instance. Only a new instance pointer or a new shared pointer reference should be passed here, otherwise memory issue will ensue. Thus this should only be used if you know what you're doing. Optional keyword arguments: :param allow_null_pointer: Allow a null pointer to be returned from the _new method instead of raising an exception. """ self._inst_ptr = None if None in (self.C_TYPE, self.C_TYPE_PTR): raise RuntimeError("Derived class did not define opaque handle " "structure types.") allow_null_pointer = kwds.get('allow_null_pointer', None) if allow_null_pointer is not None: del kwds['allow_null_pointer'] if from_cptr is not None: # if null pointer and we're not allowing them if not (allow_null_pointer or bool(from_cptr)): raise RuntimeError("Cannot initialize to a null pointer") # if not a valid opaque pointer type elif not isinstance(from_cptr, self.C_TYPE_PTR): raise RuntimeError( "Given C Opaque Pointer is not of the " "correct type. Given '%s' but expected '%s'." % (type(from_cptr), self.C_TYPE_PTR)) self._inst_ptr = from_cptr else: self._inst_ptr = self._new(*args, **kwds) # raise if we have a null pointer and we don't allow nulls if not (allow_null_pointer or bool(self._inst_ptr)): raise RuntimeError("Failed to construct new %s instance: Null " "pointer returned from construction." % self.__class__.__name__) def __del__(self): if hasattr(self, '_inst_ptr') and self._inst_ptr is not None: self._destroy() def __nonzero__(self): """ bool() operator for 2.x """ return bool(self.c_pointer) def __bool__(self): """ bool() operator for 3.x """ return bool(self.c_pointer) @property def _as_parameter_(self): """ Ctypes interface attribute for allowing a user to pass the python object instance as argument to a C function instead of the opaque pointer. This means that when an instance of this class is passed as an argument, the underlying opaque pointer is automatically passed in its place. """ return self.c_pointer @classmethod def logger(cls): return logging.getLogger('.'.join([cls.__module__, cls.__name__])) @property def _log(self): return self.logger() @property def c_pointer(self): """ :return: The ctypes opaque structure pointer :rtype: _ctypes._Pointer """ return self._inst_ptr @abc.abstractmethod def _new(self, *args, **kwds): """ Construct a new instance, returning new instance opaque C pointer and initializing any other necessary object properties :returns: New C opaque structure pointer. :rtype: _ctypes._Pointer """ raise NotImplementedError("Calling VitalObject class abstract _new " "method.") @abc.abstractmethod def _destroy(self): """ Call C API destructor for derived class """ raise NotImplementedError( "Calling VitalObject class abstract _destroy " "method.")
def test_find_lib_no_caching(self): nose.tools.assert_is_none(fvl.__LIBRARY_PATH_CACHE__) l = fvl.find_vital_library(use_cache=False) nose.tools.assert_is_instance(l, ctypes.CDLL) nose.tools.assert_is_none(fvl.__LIBRARY_CACHE__)