예제 #1
0
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__)
예제 #3
0
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.")
예제 #4
0
 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__)