def test_template_class(): config = Config() config.register_class_specialization("A", "Ad", {"T": "double"}) with cython_extension_from("templateclass.hpp", config=config): from templateclass import Ad a = Ad(5.0) assert_equal(a.get(), 5.0)
def test_blacklisted_method(): config = Config() config.ignore_method(class_name="MyClassB", method_name="myMethod") with cython_extension_from("ignoremethod.hpp", config=config, assert_warn=UserWarning, warn_msg="blacklist"): pass
def test_abstract_class(): config = Config() config.abstract_class("AbstractClass") with cython_extension_from("abstractclass.hpp", config=config, assert_warn=UserWarning, warn_msg="abstract"): from abstractclass import AbstractClass, DerivedClass d = DerivedClass(5.0) a = d.clone() assert_equal(a.square(), 25.0)
def test_blacklisted_class(): config = Config() config.ignore_class(full_paths("ignoreclass.hpp")[0], class_name="MyClassA") with cython_extension_from("ignoreclass.hpp", config=config, assert_warn=UserWarning, warn_msg="blacklist"): pass
def test_template_function(): config = Config() config.register_function_specialization("addOne", "add_one_i", {"T": "int"}) config.register_function_specialization("addOne", "add_one_d", {"T": "double"}) with cython_extension_from("templatefunction.hpp", config=config): from templatefunction import add_one_i, add_one_d assert_equal(add_one_i(1), 2) assert_is_instance(add_one_i(1), int) assert_equal(add_one_d(2.0), 3.0) assert_is_instance(add_one_d(2.0), float)
def test_class_specializer(): config = Config() config.register_class_specialization("MyClass", "MyClassDouble", {"T": "double"}) specializer = ClassSpecializer(config) template = TemplateClass("test.hpp", "", "MyClass") template.template_types.append("T") classes = specializer.specialize(template) assert_equal(len(classes), 1) clazz = classes[0] assert_equal(clazz.name, "MyClassDouble") assert_equal(clazz.get_cppname(), "MyClass[double]") assert_equal(clazz.get_attached_typeinfo(), {"T": "double"})
def test_method_specialization(): config = Config() config.register_method_specialization("MyClass", "myMethod", "my_method_b", {"T": "bool"}) specializer = MethodSpecializer(config) template = TemplateMethod("myMethod", "T", "MyClass") template.nodes.append(Param("a", "T")) template.template_types.append("T") methods = specializer.specialize(template) assert_equal(len(methods), 1) method = methods[0] assert_equal(method.name, "my_method_b") assert_equal(method.result_type, "bool") assert_equal(len(method.nodes), 1) assert_equal(method.nodes[0].tipe, "bool")
def test_register_custom_type_converter(): class CustomTypeConverter(AbstractTypeConverter): def matches(self): raise NotImplementedError() def n_cpp_args(self): raise NotImplementedError() def add_includes(self, includes): raise NotImplementedError() def python_to_cpp(self): raise NotImplementedError() def cpp_call_args(self): raise NotImplementedError() def return_output(self, copy=True): raise NotImplementedError() def python_type_decl(self): raise NotImplementedError() def cpp_type_decl(self): raise NotImplementedError() config = Config() config.registered_converters.append(CustomTypeConverter) with cython_extension_from("boolinboolout.hpp", assert_warn=UserWarning, warn_msg="Ignoring method", config=config): pass
def test_missing_template_specialization(): config = Config() specializer = FunctionSpecializer(config) template = TemplateFunction("test.hpp", "", "myFun", "T") template.template_types.append("T") assert_warns_message(UserWarning, "No template specialization registered", specializer.specialize, template)
def test_simple_function_def(): method = MethodDefinition( "Testclass", "", "testfun", [], Includes(), "void", TypeInfo({}), Config()).make() assert_multi_line_equal( method, lines("cpdef testfun(Testclass self):", " self.thisptr.testfun()") )
def test_function_def(): fun = FunctionDefinition("myFun", "", [], Includes(), "void", TypeInfo(), Config()).make() assert_multi_line_equal( fun, lines( "cpdef my_fun():", " cpp.myFun()" ) )
def test_default_ctor_def(): ctor = ConstructorDefinition("MyClass", "", [], Includes(), TypeInfo(), Config(), "MyClass").make() assert_multi_line_equal( ctor, lines( "def __init__(MyClass self):", " self.thisptr = new cpp.MyClass()" ) )
def test_array_arg_function_def(): method = MethodDefinition( "Testclass", "", "testfun", [Param("a", "double *"), Param("aSize", "unsigned int")], Includes(), "void", TypeInfo({}), Config()).make() assert_multi_line_equal( method, lines("cpdef testfun(Testclass self, np.ndarray[double, ndim=1] a):", " self.thisptr.testfun(&a[0], a.shape[0])") )
def test_template_method(): config = Config() specs = { "A::addOne": [ ("add_one_i", {"T": "int"}), ("add_one_d", {"T": "double"}) ] } config.register_method_specialization("A", "addOne", "add_one_i", {"T": "int"}) config.register_method_specialization("A", "addOne", "add_one_d", {"T": "double"}) with cython_extension_from("templatemethod.hpp", config=config): from templatemethod import A a = A() assert_equal(a.add_one_i(1), 2) assert_is_instance(a.add_one_i(1), int) assert_equal(a.add_one_d(2.0), 3.0) assert_is_instance(a.add_one_d(2.0), float)
def test_function_def_with_another_cppname(): fun = FunctionDefinition("myFunInt", "", [], Includes(), "void", TypeInfo(), Config(), cppname="myFun").make() assert_multi_line_equal( fun, lines( "cpdef my_fun_int():", " cpp.myFun()" ) )
def test_function_specializer(): config = Config() config.register_function_specialization("MyNamespace::myFun", "myFunInt", {"T": "int"}) config.register_function_specialization("MyNamespace::myFun", "myFunDouble", {"T": "double"}) specializer = FunctionSpecializer(config) template = TemplateFunction("test.hpp", "MyNamespace", "myFun", "T") template.nodes.append(Param("a", "T")) template.template_types.append("T") functions = specializer.specialize(template) assert_equal(len(functions), 2) assert_equal(functions[0].name, "myFunInt") assert_equal(functions[0].result_type, "int") assert_equal(len(functions[0].nodes), 1) assert_equal(functions[0].nodes[0].tipe, "int") assert_equal(functions[1].name, "myFunDouble") assert_equal(functions[1].result_type, "double") assert_equal(len(functions[1].nodes), 1) assert_equal(functions[1].nodes[0].tipe, "double")
def test_setter_definition(): field = Field("myField", "double", "MyClass") setter = SetterDefinition( "MyClass", field, Includes(), TypeInfo(), Config()).make() assert_multi_line_equal( setter, lines( "cpdef __set_my_field(MyClass self, double myField):", " cdef double cpp_myField = myField", " self.thisptr.myField = cpp_myField" ) )
def main(): config = Config() config.registered_converters.append(DoubleArray2dTypeConverter) results = make_cython_wrapper("../src/promp.h", ["../src/promp.cpp"], "promp", ".", config, ["../src"], verbose=0) del results["setup.py"] write_files(results, ".") run_setup("setup.py")
def test_getter_definition(): field = Field("myField", "double", "MyClass") getter = GetterDefinition( "MyClass", field, Includes(), TypeInfo(), Config()).make() assert_multi_line_equal( getter, lines( "cpdef __get_my_field(MyClass self):", " cdef double result = self.thisptr.myField", " return result", "" ) )
def test_typedef_decl(): typedef = Typedef("test.hpp", "", "MyType", "double") exporter = CythonDeclarationExporter(Includes(), Config()) exporter.visit_typedef(typedef) exporter.visit_ast(None) decl = exporter.export() assert_multi_line_equal( decl.strip(), lines( "cdef extern from \"test.hpp\" namespace \"\":", " ctypedef double MyType" ) )
def test_class_decl(): clazz = Clazz("test.hpp", "", "MyClass") exporter = CythonDeclarationExporter(Includes(), Config()) exporter.visit_clazz(clazz) exporter.visit_ast(None) decl = exporter.export() assert_multi_line_equal( decl.strip(), lines( "cdef extern from \"test.hpp\" namespace \"\":", " cdef cppclass MyClass:", " pass" ) )
def test_function_decl(): fun = Function("test.hpp", "", "myFun", "void") ignored_fun = Function("test.hpp", "", "myFun", "void") ignored_fun.ignored = True exporter = CythonDeclarationExporter(Includes(), Config()) exporter.visit_function(fun) exporter.visit_function(ignored_fun) exporter.visit_ast(None) decl = exporter.export() assert_multi_line_equal( decl.strip(), lines( "cdef extern from \"test.hpp\" namespace \"\":", " void myFun() except +" ) )
def test_enum_decl(): enum = Enum("test.hpp", "", "MyEnum") enum.constants.append("one") enum.constants.append("two") exporter = CythonDeclarationExporter(Includes(), Config()) exporter.visit_enum(enum) exporter.visit_ast(None) decl = exporter.export() assert_multi_line_equal( decl.strip(), lines( "cdef extern from \"test.hpp\" namespace \"\":", " cdef enum MyEnum:", " one", " two" ) )
def test_field_decl(): clazz = Clazz("test.hpp", "", "MyClass") field = Field("myField", "double", "MyClass") ignored_field = Field("myField", "double", "MyClass") ignored_field.ignored = True exporter = CythonDeclarationExporter(Includes(), Config()) exporter.visit_field(field) exporter.visit_field(ignored_field) exporter.visit_clazz(clazz) exporter.visit_ast(None) decl = exporter.export() assert_multi_line_equal( decl.strip(), lines( "cdef extern from \"test.hpp\" namespace \"\":", " cdef cppclass MyClass:", " double myField" ) )
def test_ctor_decl(): clazz = Clazz("test.hpp", "", "MyClass") ctor = Constructor("MyClass") ignored_ctor = Constructor("MyClass") ignored_ctor.ignored = True exporter = CythonDeclarationExporter(Includes(), Config()) exporter.visit_constructor(ctor) exporter.visit_constructor(ignored_ctor) exporter.visit_clazz(clazz) exporter.visit_ast(None) decl = exporter.export() assert_multi_line_equal( decl.strip(), lines( "cdef extern from \"test.hpp\" namespace \"\":", " cdef cppclass MyClass:", " MyClass()" ) )
def test_method_decl(): clazz = Clazz("test.hpp", "", "MyClass") method = Method("myMethod", "void", "MyClass") ignored_method = Method("", "", "") ignored_method.ignored = True exporter = CythonDeclarationExporter(Includes(), Config()) exporter.visit_param(Param("myParam", "double")) exporter.visit_method(method) exporter.visit_method(ignored_method) exporter.visit_clazz(clazz) exporter.visit_ast(None) decl = exporter.export() assert_multi_line_equal( decl.strip(), lines( "cdef extern from \"test.hpp\" namespace \"\":", " cdef cppclass MyClass:", " void myMethod(double myParam) except +" ) )
def test_template_method(): config = Config() specs = { "A::addOne": [("add_one_i", { "T": "int" }), ("add_one_d", { "T": "double" })] } config.register_method_specialization("A", "addOne", "add_one_i", {"T": "int"}) config.register_method_specialization("A", "addOne", "add_one_d", {"T": "double"}) with cython_extension_from("templatemethod.hpp", config=config): from templatemethod import A a = A() assert_equal(a.add_one_i(1), 2) assert_is_instance(a.add_one_i(1), int) assert_equal(a.add_one_d(2.0), 3.0) assert_is_instance(a.add_one_d(2.0), float)
def test_external_library(): library_dir = full_paths("externallib")[0] cwd = os.getcwd() try: os.chdir(library_dir) with hidden_stdout(): os.system("make") finally: os.chdir(cwd) shutil.copyfile(os.path.join(library_dir, "libmylib.so"), "libmylib.so") config = Config() config.add_library_dir(library_dir) config.add_library("mylib") with cython_extension_from("withexternallib.hpp", config=config, incdirs=["externallib"]): try: from withexternallib import get_number assert_equal(get_number(), 5) finally: os.remove("libmylib.so")
def test_convert_vector(): eigen3_incdir = "/usr/include/eigen3" if not os.path.exists(eigen3_incdir): raise SkipTest("Eigen 3 include directory '%s' not found" % eigen3_incdir) eigen_vector_decl = """ cdef extern from "Eigen/Dense" namespace "Eigen": cdef cppclass VectorXd: VectorXd() VectorXd(int rows) VectorXd(VectorXd&) double* data() int rows() double& get "operator()"(int rows) """ class EigenConverter(AbstractTypeConverter): def __init__(self, tname, python_argname, type_info, context): super(EigenConverter, self).__init__(tname, python_argname, type_info, context) if self.python_argname is not None: self.cpp_argname = "cpp_" + python_argname else: self.cpp_argname = None def matches(self): return self.tname == "VectorXd" def n_cpp_args(self): return 1 def add_includes(self, includes): includes.numpy = True def python_to_cpp(self): return lines( "cdef int %(python_argname)s_length = %(python_argname)s.shape[0]", "cdef cpp.VectorXd %(cpp_argname)s = cpp.VectorXd(%(python_argname)s_length)", "cdef int %(python_argname)s_idx", "for %(python_argname)s_idx in range(%(python_argname)s_length):", " %(cpp_argname)s.data()[%(python_argname)s_idx] = %(python_argname)s[%(python_argname)s_idx]" ) % { "python_argname": self.python_argname, "cpp_argname": self.cpp_argname } def cpp_call_args(self): return [self.cpp_argname] def return_output(self, copy=True): return lines( "cdef int size = result.rows()", "cdef int res_idx", "cdef np.ndarray[double, ndim=1] res = np.ndarray(shape=(size,))", "for res_idx in range(size):", " res[res_idx] = result.get(res_idx)", "return res") def python_type_decl(self): return "np.ndarray[double, ndim=1] " + self.python_argname def cpp_type_decl(self): return "cdef cpp.VectorXd" config = Config() config.registered_converters.append(EigenConverter) config.add_decleration(eigen_vector_decl) with cython_extension_from("eigen.hpp", config=config, incdirs=eigen3_incdir): from eigen import make a = np.ones(5) assert_array_equal(make(a), a * 2.0)
def test_converter_not_available(): assert_raises(NotImplementedError, create_type_converter, "UnknownType", "unknownType", TypeInfo([]), Config())
def test_convert_vector(): eigen3_incdir = "/usr/include/eigen3" if not os.path.exists(eigen3_incdir): raise SkipTest("Eigen 3 include directory '%s' not found" % eigen3_incdir) eigen_vector_decl = """ cdef extern from "Eigen/Dense" namespace "Eigen": cdef cppclass VectorXd: VectorXd() VectorXd(int rows) VectorXd(VectorXd&) double* data() int rows() double& get "operator()"(int rows) """ class EigenConverter(AbstractTypeConverter): def __init__(self, tname, python_argname, type_info, context): super(EigenConverter, self).__init__( tname, python_argname, type_info, context) if self.python_argname is not None: self.cpp_argname = "cpp_" + python_argname else: self.cpp_argname = None def matches(self): return self.tname == "VectorXd" def n_cpp_args(self): return 1 def add_includes(self, includes): includes.numpy = True def python_to_cpp(self): return lines( "cdef int %(python_argname)s_length = %(python_argname)s.shape[0]", "cdef cpp.VectorXd %(cpp_argname)s = cpp.VectorXd(%(python_argname)s_length)", "cdef int %(python_argname)s_idx", "for %(python_argname)s_idx in range(%(python_argname)s_length):", " %(cpp_argname)s.data()[%(python_argname)s_idx] = %(python_argname)s[%(python_argname)s_idx]" ) % {"python_argname": self.python_argname, "cpp_argname": self.cpp_argname} def cpp_call_args(self): return [self.cpp_argname] def return_output(self, copy=True): return lines( "cdef int size = result.rows()", "cdef int res_idx", "cdef np.ndarray[double, ndim=1] res = np.ndarray(shape=(size,))", "for res_idx in range(size):", " res[res_idx] = result.get(res_idx)", "return res" ) def python_type_decl(self): return "np.ndarray[double, ndim=1] " + self.python_argname def cpp_type_decl(self): return "cdef cpp.VectorXd" config = Config() config.registered_converters.append(EigenConverter) config.add_decleration(eigen_vector_decl) with cython_extension_from("eigen.hpp", config=config, incdirs=eigen3_incdir): from eigen import make a = np.ones(5) assert_array_equal(make(a), a * 2.0)
def test_cpp_operator(): config = Config() assert_equal(config.cpp_to_py_operator("operator()"), "__call__") assert_raises(NotImplementedError, config.cpp_to_py_operator, "operator<<")