Beispiel #1
0
 def _arg_to_str(self, arg):
     if arg == str:
         import _cppyy
         arg = _cppyy._std_string_name()
     elif type(arg) != str:
         arg = arg.__name__
     return arg
Beispiel #2
0
 def _arg_to_str(self, arg):
     try:
         arg = arg.__cppname__
     except AttributeError:
         if arg == str:
             import _cppyy
             arg = _cppyy._std_string_name()
         elif type(arg) != str:
             arg = arg.__name__
     return arg
Beispiel #3
0
 def _arg_to_str(self, arg):
   # arguments are strings representing types, types, or builtins
     if type(arg) == str:
         return arg                       # string describing type
     elif hasattr(arg, '__cppname__'):
         return arg.__cppname__           # C++ bound type
     elif arg == str:
         import _cppyy
         return _cppyy._std_string_name() # special case pystr -> C++ string
     elif isinstance(arg, type):          # builtin types
         return arg.__name__
     return str(arg)                      # builtin values
Beispiel #4
0
def _pythonize(pyclass):

    try:
        _pythonizations[pyclass.__name__](pyclass)
    except KeyError:
        pass

    # general note: use 'in pyclass.__dict__' rather than 'hasattr' to prevent
    # adding pythonizations multiple times in derived classes

    import _cppyy

    # map __eq__/__ne__ through a comparison to None
    if '__eq__' in pyclass.__dict__:

        def __eq__(self, other):
            if other is None: return not self
            if not self and not other: return True
            try:
                return self._cxx_eq(other)
            except TypeError:
                return NotImplemented

        pyclass._cxx_eq = pyclass.__dict__['__eq__']
        pyclass.__eq__ = __eq__

    if '__ne__' in pyclass.__dict__:

        def __ne__(self, other):
            if other is None: return not not self
            if type(self) is not type(other): return True
            return self._cxx_ne(other)

        pyclass._cxx_ne = pyclass.__dict__['__ne__']
        pyclass.__ne__ = __ne__

    # map size -> __len__ (generally true for STL)
    if 'size' in pyclass.__dict__ and not '__len__' in pyclass.__dict__ \
           and callable(pyclass.size):
        pyclass.__len__ = pyclass.size

    # map push_back -> __iadd__ (generally true for STL)
    if 'push_back' in pyclass.__dict__ and not '__iadd__' in pyclass.__dict__:

        def __iadd__(self, ll):
            [self.push_back(x) for x in ll]
            return self

        pyclass.__iadd__ = __iadd__

    # map begin()/end() protocol to iter protocol on STL(-like) classes, but
    # not on vector, which is pythonized in the capi (interp-level; there is
    # also the fallback on the indexed __getitem__, but that is slower)
    if not 'vector' in pyclass.__name__[:11] and \
            ('begin' in pyclass.__dict__ and 'end' in pyclass.__dict__):
        if _cppyy._scope_byname(pyclass.__cppname__+'::iterator') or \
                _cppyy._scope_byname(pyclass.__cppname__+'::const_iterator'):

            def __iter__(self):
                i = self.begin()
                while i != self.end():
                    yield i.__deref__()
                    i.__preinc__()
                i.__destruct__()
                raise StopIteration

            pyclass.__iter__ = __iter__
        # else: rely on numbered iteration

    # combine __getitem__ and __len__ to make a pythonized __getitem__
    if '__getitem__' in pyclass.__dict__ and '__len__' in pyclass.__dict__:
        pyclass._getitem__unchecked = pyclass.__getitem__
        if '__setitem__' in pyclass.__dict__ and '__iadd__' in pyclass.__dict__:
            pyclass.__getitem__ = python_style_sliceable_getitem
        else:
            pyclass.__getitem__ = python_style_getitem

    # string comparisons
    if pyclass.__name__ == _cppyy._std_string_name():

        def eq(self, other):
            if type(other) == pyclass:
                return self.c_str() == other.c_str()
            else:
                return self.c_str() == other

        pyclass.__eq__ = eq
        pyclass.__str__ = pyclass.c_str

    # std::pair unpacking through iteration
    if 'std::pair' == pyclass.__name__[:9] or 'pair' == pyclass.__name__[:4]:

        def getitem(self, idx):
            if idx == 0: return self.first
            if idx == 1: return self.second
            raise IndexError("out of bounds")

        def return2(self):
            return 2

        pyclass.__getitem__ = getitem
        pyclass.__len__ = return2
Beispiel #5
0
def _pythonize(pyclass, name):
    # general note: use 'in pyclass.__dict__' rather than 'hasattr' to prevent
    # adding pythonizations multiple times in derived classes

    import _cppyy

    # map __eq__/__ne__ through a comparison to None
    if '__eq__' in pyclass.__dict__:
        def __eq__(self, other):
            if other is None: return not self
            if not self and not other: return True
            try:
                return self._cxx_eq(other)
            except TypeError:
                return NotImplemented
        pyclass._cxx_eq = pyclass.__dict__['__eq__']
        pyclass.__eq__ = __eq__

    if '__ne__' in pyclass.__dict__:
        def __ne__(self, other):
            if other is None: return not not self
            if type(self) is not type(other): return True
            return self._cxx_ne(other)
        pyclass._cxx_ne = pyclass.__dict__['__ne__']
        pyclass.__ne__ = __ne__

    # map size -> __len__ (generally true for STL)
    if 'size' in pyclass.__dict__ and not '__len__' in pyclass.__dict__ \
           and callable(pyclass.size):
        pyclass.__len__ = pyclass.size

    # map push_back -> __iadd__ (generally true for STL)
    if 'push_back' in pyclass.__dict__ and not '__iadd__' in pyclass.__dict__:
        if 'reserve' in pyclass.__dict__:
            def iadd(self, ll):
                self.reserve(len(ll))
                for x in ll: self.push_back(x)
                return self
        else:
            def iadd(self, ll):
                for x in ll: self.push_back(x)
                return self
        pyclass.__iadd__ = iadd

    # map begin()/end() protocol to iter protocol on STL(-like) classes, but
    # not on vector, which is pythonized in the capi (interp-level; there is
    # also the fallback on the indexed __getitem__, but that is slower)
    add_checked_item = False
    if name.find('std::vector', 0, 11) != 0:
        if ('begin' in pyclass.__dict__ and 'end' in pyclass.__dict__):
            if _cppyy._scope_byname(name+'::iterator') or \
                    _cppyy._scope_byname(name+'::const_iterator'):
                def __iter__(self):
                    i = self.begin()
                    while i != self.end():
                        yield i.__deref__()
                        i.__preinc__()
                    i.__destruct__()
                    raise StopIteration
                pyclass.__iter__ = __iter__
            else:
                # rely on numbered iteration
                add_checked_item = True

    # add python collection based initializer
    if name.find('std::vector', 0, 11) == 0:
        pyclass.__real_init__ = pyclass.__init__
        def vector_init(self, *args):
            if len(args) == 1 and isinstance(args[0], (tuple, list)):
                ll = args[0]
                self.__real_init__()
                self.reserve(len(ll))
                for item in ll:
                    self.push_back(item)
                return
            return self.__real_init__(*args)
        pyclass.__init__ = vector_init

        # size-up the return of data()
        if hasattr(pyclass, 'data'):   # not the case for e.g. vector<bool>
            pyclass.__real_data = pyclass.data
            def data_with_len(self):
                arr = self.__real_data()
                arr.reshape((len(self),))
                return arr
            pyclass.data = data_with_len

    # TODO: must be a simpler way to check (or at least hook these to a namespace
    # std specific pythonizor)
    if add_checked_item or name.find('std::vector', 0, 11) == 0 or \
            name.find('std::array', 0, 11) == 0 or name.find('std::deque', 0, 10) == 0:
        # combine __getitem__ and __len__ to make a pythonized __getitem__
        if '__getitem__' in pyclass.__dict__ and '__len__' in pyclass.__dict__:
            pyclass._getitem__unchecked = pyclass.__getitem__
            if '__setitem__' in pyclass.__dict__ and '__iadd__' in pyclass.__dict__:
                pyclass.__getitem__ = python_style_sliceable_getitem
            else:
                pyclass.__getitem__ = python_style_getitem

    # string comparisons
    if name == _cppyy._std_string_name():
        def eq(self, other):
            if type(other) == pyclass:
                return self.c_str() == other.c_str()
            else:
                return self.c_str() == other
        pyclass.__eq__  = eq
        pyclass.__str__ = pyclass.c_str

    # std::pair unpacking through iteration
    if 'std::pair' == name[:9]:
        def getitem(self, idx):
            if idx == 0: return self.first
            if idx == 1: return self.second
            raise IndexError("out of bounds")
        def return2(self):
            return 2
        pyclass.__getitem__ = getitem
        pyclass.__len__     = return2

    # user provided, custom pythonizations
    try:
        ns_name, cl_name = extract_namespace(name)
        pythonizors = _pythonizations[ns_name]
        name = cl_name
    except KeyError:
        pythonizors = _pythonizations['']   # global scope

    for p in pythonizors:
        p(pyclass, name)