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
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
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
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
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)