From 570a6f4788e6520d022959a4f40e3299ee1e7c12 Mon Sep 17 00:00:00 2001 From: Julianus Pfeuffer Date: Tue, 7 Nov 2023 10:24:00 +0100 Subject: [PATCH] [FIX] comment parsing once and for all (#179) * [test] add more comment parsing tests * more tests * whitespace * test fixes * err * compare code contents * test fixes * first fixes towards tests * allow empty lines in the beginning * err * Update PXDParser.py * lint codebase to LL 100 * lint tests --- .github/workflows/black.yaml | 2 +- autowrap/CodeGenerator.py | 178 +++++++------------------ autowrap/ConversionProvider.py | 133 +++++------------- autowrap/DeclResolver.py | 49 ++----- autowrap/Main.py | 4 +- autowrap/PXDParser.py | 95 +++++++------ autowrap/Types.py | 10 +- autowrap/Utils.py | 8 +- autowrap/__init__.py | 10 +- memtests/sysinfo.py | 1 - memtests/test00.py | 10 +- tests/test_code_generator.py | 21 +-- tests/test_code_generator_minimal.py | 5 +- tests/test_code_generator_stllibcpp.py | 1 - tests/test_decl_resolver.py | 7 +- tests/test_full_library.py | 13 +- tests/test_main.py | 5 +- tests/test_pxd_parser.py | 55 +++++++- tests/test_types.py | 1 - tests/test_utils.py | 4 - 20 files changed, 210 insertions(+), 402 deletions(-) diff --git a/.github/workflows/black.yaml b/.github/workflows/black.yaml index b7bdfd5..6e31d66 100644 --- a/.github/workflows/black.yaml +++ b/.github/workflows/black.yaml @@ -9,4 +9,4 @@ jobs: - uses: actions/checkout@v3 - uses: psf/black@stable with: - options: "--check --diff" + options: "--line-length 100 --check --diff" diff --git a/autowrap/CodeGenerator.py b/autowrap/CodeGenerator.py index b0c6552..8711154 100644 --- a/autowrap/CodeGenerator.py +++ b/autowrap/CodeGenerator.py @@ -105,8 +105,7 @@ def augment_arg_names(method): """replaces missing arg_names with "in_%d" % i, where i is the position number of the arg""" return [ - (t, n if (n and n != "self") else "in_%d" % i) - for i, (n, t) in enumerate(method.arguments) + (t, n if (n and n != "self") else "in_%d" % i) for i, (n, t) in enumerate(method.arguments) ] @@ -115,9 +114,7 @@ def fixed_include_dirs(include_boost: bool) -> List[AnyStr]: boost = pkg_resources.resource_filename("autowrap", "data_files/boost") data = pkg_resources.resource_filename("autowrap", "data_files") - autowrap_internal = pkg_resources.resource_filename( - "autowrap", "data_files/autowrap" - ) + autowrap_internal = pkg_resources.resource_filename("autowrap", "data_files/autowrap") if not include_boost: return [autowrap_internal] @@ -184,7 +181,6 @@ def __init__( add_relative=False, shared_ptr="boost", ): - self.pxd_dir = None if all_decl is None: all_decl = dict() @@ -229,24 +225,17 @@ def __init__( self.all_decl = all_decl # If other external decls were passed: if len(all_decl) > 0: - self.all_typedefs = [] self.all_enums = [] self.all_functions = [] self.all_classes = [] for modname, v in all_decl.items(): - self.all_classes.extend( - [d for d in v["decls"] if isinstance(d, ResolvedClass)] - ) - self.all_enums.extend( - [d for d in v["decls"] if isinstance(d, ResolvedEnum)] - ) + self.all_classes.extend([d for d in v["decls"] if isinstance(d, ResolvedClass)]) + self.all_enums.extend([d for d in v["decls"] if isinstance(d, ResolvedEnum)]) self.all_functions.extend( [d for d in v["decls"] if isinstance(d, ResolvedFunction)] ) - self.all_typedefs.extend( - [d for d in v["decls"] if isinstance(d, ResolvedTypeDef)] - ) + self.all_typedefs.extend([d for d in v["decls"] if isinstance(d, ResolvedTypeDef)]) self.all_resolved = [] self.all_resolved.extend(sorted(self.all_typedefs, key=lambda d: d.name)) @@ -315,9 +304,7 @@ def create_pyx_file(self, debug: bool = False) -> None: def create_for( clazz: Type[ResolvedDecl], - method: Callable[ - [ResolvedDecl, Union[CodeDict, Tuple[CodeDict, CodeDict]]], None - ], + method: Callable[[ResolvedDecl, Union[CodeDict, Tuple[CodeDict, CodeDict]]], None], codez: Union[CodeDict, Tuple[CodeDict, CodeDict]], ): for resolved in self.resolved: @@ -334,9 +321,7 @@ def create_for( self.create_wrapper_for_enum, (self.enum_codes, self.typestub_codes), ) - create_for( - ResolvedFunction, self.create_wrapper_for_free_function, self.class_codes - ) + create_for(ResolvedFunction, self.create_wrapper_for_free_function, self.class_codes) # resolve extra for clz, codes in self.class_codes_extra.items(): @@ -533,7 +518,7 @@ def create_wrapper_for_enum( doc=doc, ) - for (optname, value) in decl.items: + for optname, value in decl.items: code.add(" $name = $value", name=optname, value=value) stub_code.add(" $name : int", name=optname, value=value) @@ -569,9 +554,7 @@ def create_wrapper_for_enum( self.typestub_codes[class_name].add(stub_code) self.class_codes[class_name].add(code) - def create_wrapper_for_class( - self, r_class: ResolvedClass, out_codes: CodeDict - ) -> None: + def create_wrapper_for_class(self, r_class: ResolvedClass, out_codes: CodeDict) -> None: """Create Cython code for a single class Note that the cdef class definition and the member variables go into @@ -604,9 +587,8 @@ def create_wrapper_for_class( docstring = "Cython implementation of %s\n" % cy_type docstring += special_class_doc % locals() if r_class.cpp_decl.annotations.get("wrap-inherits", "") != "": - docstring += ( - " -- Inherits from %s\n" - % r_class.cpp_decl.annotations.get("wrap-inherits", "") + docstring += " -- Inherits from %s\n" % r_class.cpp_decl.annotations.get( + "wrap-inherits", "" ) extra_doc = r_class.cpp_decl.annotations.get("wrap-doc", None) @@ -722,9 +704,7 @@ def create_wrapper_for_class( ) if "wrap-buffer-protocol" in r_class.cpp_decl.annotations: - buffer_parts = r_class.cpp_decl.annotations["wrap-buffer-protocol"][ - 0 - ].split(",") + buffer_parts = r_class.cpp_decl.annotations["wrap-buffer-protocol"][0].split(",") buffer_sourcer = buffer_parts[0] buffer_type = buffer_parts[1] buffer_sizer = buffer_parts[2] @@ -802,14 +782,12 @@ def create_wrapper_for_class( iterators, non_iter_methods = self.filterout_iterators(r_class.methods) - for (name, methods) in non_iter_methods.items(): + for name, methods in non_iter_methods.items(): if name == r_class.name: codes, stub_code = self.create_wrapper_for_constructor(r_class, methods) cons_created = True else: - codes, stub_code = self.create_wrapper_for_method( - r_class, name, methods - ) + codes, stub_code = self.create_wrapper_for_method(r_class, name, methods) typestub_code.add(stub_code) for ci in codes: class_code.add(ci) @@ -837,9 +815,7 @@ def create_wrapper_for_class( for class_name in r_class.cpp_decl.annotations.get("wrap-attach", []): code = Code() - display_name = r_class.cpp_decl.annotations.get("wrap-as", [r_class.name])[ - 0 - ] + display_name = r_class.cpp_decl.annotations.get("wrap-as", [r_class.name])[0] code.add("%s = %s" % (display_name, "__" + r_class.name)) tmp = self.class_codes_extra.get(class_name, []) tmp.append(code) @@ -899,7 +875,6 @@ def _create_iter_methods(self, iterators, instance_mapping, local_mapping): def _create_overloaded_method_decl( self, py_name, dispatched_m_names, methods, use_return, use_kwargs=False ): - L.info(" create wrapper decl for overloaded method %s" % py_name) method_code = Code() @@ -956,9 +931,7 @@ def _create_overloaded_method_decl( first_iteration = True - for (dispatched_m_name, method, sig) in zip( - dispatched_m_names, methods, signatures - ): + for dispatched_m_name, method, sig in zip(dispatched_m_names, methods, signatures): args = augment_arg_names(method) return_type = self.cr.get(method.result_type).matching_python_type_full( method.result_type @@ -1023,7 +996,6 @@ def _create_overloaded_method_decl( return method_code, typestub_code def create_wrapper_for_method(self, cdcl, py_name, methods): - if py_name.startswith("operator"): __, __, op = py_name.partition("operator") if op in ["!=", "==", "<", "<=", ">", ">="]: @@ -1041,87 +1013,59 @@ def create_wrapper_for_method(self, cdcl, py_name, methods): return [code_get, code_set], typestub_get elif op == "+": assert len(methods) == 1, "overloaded operator+ not supported" - code, stubs = self.create_special_op_method( - "add", "+", cdcl, methods[0] - ) + code, stubs = self.create_special_op_method("add", "+", cdcl, methods[0]) return [code], stubs elif op == "-": assert len(methods) == 1, "overloaded operator- not supported" - code, stubs = self.create_special_op_method( - "sub", "-", cdcl, methods[0] - ) + code, stubs = self.create_special_op_method("sub", "-", cdcl, methods[0]) return [code], stubs elif op == "*": assert len(methods) == 1, "overloaded operator* not supported" - code, stubs = self.create_special_op_method( - "mul", "*", cdcl, methods[0] - ) + code, stubs = self.create_special_op_method("mul", "*", cdcl, methods[0]) return [code], stubs elif op == "/": assert len(methods) == 1, "overloaded operator/ not supported" - code, stubs = self.create_special_op_method( - "truediv", "/", cdcl, methods[0] - ) + code, stubs = self.create_special_op_method("truediv", "/", cdcl, methods[0]) return [code], stubs elif op == "<<": assert len(methods) == 1, "overloaded operator<< not supported" - code, stubs = self.create_special_op_method( - "lshift", "<<", cdcl, methods[0] - ) + code, stubs = self.create_special_op_method("lshift", "<<", cdcl, methods[0]) return [code], stubs elif op == ">>": assert len(methods) == 1, "overloaded operator>> not supported" - code, stubs = self.create_special_op_method( - "rshift", ">>", cdcl, methods[0] - ) + code, stubs = self.create_special_op_method("rshift", ">>", cdcl, methods[0]) return [code], stubs elif op == "%": assert len(methods) == 1, "overloaded operator% no supported" - code, stubs = self.create_special_op_method( - "mod", "%", cdcl, methods[0] - ) + code, stubs = self.create_special_op_method("mod", "%", cdcl, methods[0]) return [code], stubs elif op == "+=": assert len(methods) == 1, "overloaded operator+= not supported" - code, stubs = self.create_special_iop_method( - "iadd", "+=", cdcl, methods[0] - ) + code, stubs = self.create_special_iop_method("iadd", "+=", cdcl, methods[0]) return [code], stubs elif op == "-=": assert len(methods) == 1, "overloaded operator-= not supported" - code, stubs = self.create_special_iop_method( - "isub", "-=", cdcl, methods[0] - ) + code, stubs = self.create_special_iop_method("isub", "-=", cdcl, methods[0]) return [code], stubs elif op == "*=": assert len(methods) == 1, "overloaded operator*= not supported" - code, stubs = self.create_special_iop_method( - "imul", "*=", cdcl, methods[0] - ) + code, stubs = self.create_special_iop_method("imul", "*=", cdcl, methods[0]) return [code], stubs elif op == "/=": assert len(methods) == 1, "overloaded operator/= not supported" - code, stubs = self.create_special_iop_method( - "itruediv", "/=", cdcl, methods[0] - ) + code, stubs = self.create_special_iop_method("itruediv", "/=", cdcl, methods[0]) return [code], stubs elif op == "%=": assert len(methods) == 1, "overloaded operator%= not supported" - code, stubs = self.create_special_iop_method( - "imod", "%=", cdcl, methods[0] - ) + code, stubs = self.create_special_iop_method("imod", "%=", cdcl, methods[0]) return [code], stubs elif op == "<<=": assert len(methods) == 1, "overloaded operator<<= not supported" - code, stubs = self.create_special_iop_method( - "ilshift", "<<=", cdcl, methods[0] - ) + code, stubs = self.create_special_iop_method("ilshift", "<<=", cdcl, methods[0]) return [code], stubs elif op == ">>=": assert len(methods) == 1, "overloaded operator>>= not supported" - code, stubs = self.create_special_iop_method( - "irshift", ">>=", cdcl, methods[0] - ) + code, stubs = self.create_special_iop_method("irshift", ">>=", cdcl, methods[0]) return [code], stubs if len(methods) == 1: @@ -1136,7 +1080,7 @@ def create_wrapper_for_method(self, cdcl, py_name, methods): # -> 2) force method renaming codes = [] dispatched_m_names = [] - for (i, method) in enumerate(methods): + for i, method in enumerate(methods): dispatched_m_name = "_%s_%d" % (py_name, i) dispatched_m_names.append(dispatched_m_name) # We should not need typestubs for the dispatched parent method @@ -1151,9 +1095,7 @@ def create_wrapper_for_method(self, cdcl, py_name, methods): codes.append(code) return codes, typestubs - def _create_fun_decl_and_input_conversion( - self, code, py_name, method, is_free_fun=False - ): + def _create_fun_decl_and_input_conversion(self, code, py_name, method, is_free_fun=False): """Creates the function declarations and the input conversion to C++ and the output conversion back to Python. @@ -1193,9 +1135,7 @@ def _create_fun_decl_and_input_conversion( py_signature = ", ".join(py_signature_parts) py_typing_signature = ", ".join(py_typing_signature_parts) - return_type = self.cr.get(method.result_type).matching_python_type_full( - method.result_type - ) + return_type = self.cr.get(method.result_type).matching_python_type_full(method.result_type) if return_type: return_type = "-> " + return_type else: @@ -1384,7 +1324,6 @@ def _create_wrapper_for_attribute(self, attribute): return code, stubs def create_wrapper_for_nonoverloaded_method(self, cdcl, py_name, method): - L.info(" create wrapper for %s ('%s')" % (py_name, method)) meth_code = Code() @@ -1441,7 +1380,6 @@ def create_wrapper_for_nonoverloaded_method(self, cdcl, py_name, method): to_py_code = out_converter.output_conversion(res_t, "_r", "py_result") if to_py_code is not None: # for non void return value - if isinstance(to_py_code, basestring): to_py_code = " %s" % to_py_code indented.add(to_py_code) @@ -1452,9 +1390,7 @@ def create_wrapper_for_nonoverloaded_method(self, cdcl, py_name, method): return meth_code, stubs - def create_wrapper_for_free_function( - self, decl: ResolvedFunction, out_codes: CodeDict - ) -> None: + def create_wrapper_for_free_function(self, decl: ResolvedFunction, out_codes: CodeDict) -> None: """ Creates wrapping code for a free function :param decl: The ResolvedFunction decl to be wrapped @@ -1509,9 +1445,7 @@ def _create_wrapper_for_free_function( cleanups, in_types, stubs, - ) = self._create_fun_decl_and_input_conversion( - fun_code, name, decl, is_free_fun=True - ) + ) = self._create_fun_decl_and_input_conversion(fun_code, name, decl, is_free_fun=True) call_args_str = ", ".join(call_args) mangled_name = "_" + orig_cpp_name + "_" + decl.pxd_import_path @@ -1542,7 +1476,6 @@ def _create_wrapper_for_free_function( out_vars = ["py_result"] if to_py_code is not None: # for non void return value - if isinstance(to_py_code, basestring): to_py_code = " %s" % to_py_code fun_code.add(to_py_code) @@ -1563,10 +1496,7 @@ def create_wrapper_for_constructor(self, class_decl, constructors): real_constructors.append(cons) if len(real_constructors) == 1: - - if real_constructors[0].cpp_decl.annotations.get( - "wrap-pass-constructor", False - ): + if real_constructors[0].cpp_decl.annotations.get("wrap-pass-constructor", False): # We have a single constructor that cannot be called (except # with the magic keyword), simply check the magic word cons_code = Code() @@ -1590,7 +1520,7 @@ def create_wrapper_for_constructor(self, class_decl, constructors): else: dispatched_cons_names = [] - for (i, constructor) in enumerate(real_constructors): + for i, constructor in enumerate(real_constructors): dispatched_cons_name = "_init_%d" % i dispatched_cons_names.append(dispatched_cons_name) # we don't need to generate the individual stubs here since @@ -1607,9 +1537,7 @@ def create_wrapper_for_constructor(self, class_decl, constructors): typestub_code.extend(typestub) return codes, typestub_code - def create_wrapper_for_nonoverloaded_constructor( - self, class_decl, py_name, cons_decl - ): + def create_wrapper_for_nonoverloaded_constructor(self, class_decl, py_name, cons_decl): """py_name is the name for constructor, as we dispatch overloaded constructors in __init__() the name of the method calling the C++ constructor is variable and given by `py_name`. @@ -1651,19 +1579,13 @@ def create_wrapper_for_nonoverloaded_constructor( return cons_code, stub_code - def create_special_op_method( - self, pyname, symbol, cdcl: ResolvedClass, mdcl: ResolvedMethod - ): + def create_special_op_method(self, pyname, symbol, cdcl: ResolvedClass, mdcl: ResolvedMethod): L.info(f" create wrapper for operator{symbol}") assert len(mdcl.arguments) == 1, f"operator{symbol} has wrong signature" ((__, t),) = mdcl.arguments name = cdcl.name - assert ( - t.base_type == name - ), f"can only apply operator{symbol} to object of same type" - assert ( - mdcl.result_type.base_type == name - ), f"can only return same type for operator{symbol}" + assert t.base_type == name, f"can only apply operator{symbol} to object of same type" + assert mdcl.result_type.base_type == name, f"can only return same type for operator{symbol}" cy_t = self.cr.cython_type(t) code = Code() # TODO use make_shared instead of new if C++11 available @@ -1695,12 +1617,8 @@ def create_special_iop_method(self, pyname, symbol, cdcl, mdcl): assert len(mdcl.arguments) == 1, f"operator{symbol} has wrong signature" ((__, t),) = mdcl.arguments name = cdcl.name - assert ( - t.base_type == name - ), f"can only apply operator{symbol} to object of same type" - assert ( - mdcl.result_type.base_type == name - ), f"can only return same type for operator{symbol}" + assert t.base_type == name, f"can only apply operator{symbol} to object of same type" + assert mdcl.result_type.base_type == name, f"can only return same type for operator{symbol}" cy_t = self.cr.cython_type(t) code = Code() code.add( @@ -1801,7 +1719,6 @@ def create_special_getitem_method(self, mdcl): out_var = "py_result" to_py_code = out_converter.output_conversion(res_t, "_r", out_var) if to_py_code is not None: # for non void return value - if isinstance(to_py_code, basestring): to_py_code = " %s" % to_py_code meth_code.add(to_py_code) @@ -1816,9 +1733,7 @@ def create_special_setitem_method(self, mdcl): # Object& operator[](size_t k) -> get and set is implemented res_t = mdcl.result_type if not res_t.is_ref: - L.info( - " skip set wrapper for operator[] since return value is not a reference" - ) + L.info(" skip set wrapper for operator[] since return value is not a reference") return Code(), Code() res_t_base = res_t.base_type @@ -1896,7 +1811,7 @@ def create_cast_methods(self, mdecls): raise Exception("wrap-cast annotation not unique for %s" % mdcl) py_names.append(name) codes = [] - for (py_name, mdecl) in zip(py_names, mdecls): + for py_name, mdecl in zip(py_names, mdecls): code = Code() res_t = mdecl.result_type cy_t = self.cr.cython_type(res_t) @@ -2033,9 +1948,7 @@ def create_foreign_cimports(self): mname = "." + module if os.path.basename(self.target_path).split(".pyx")[0] != module: - for resolved in self.all_decl[module]["decls"]: - # We need to import classes and enums that could be used in # the Cython code in the current module @@ -2051,7 +1964,6 @@ def create_foreign_cimports(self): else: code.add("from $mname cimport $name", locals()) if resolved.__class__ in (ResolvedClass,): - # Skip classes that explicitely should not have a pxd # import statement (abstract base classes and the like) if not resolved.no_pxd_import: diff --git a/autowrap/ConversionProvider.py b/autowrap/ConversionProvider.py index a5ed5a3..df60fef 100644 --- a/autowrap/ConversionProvider.py +++ b/autowrap/ConversionProvider.py @@ -86,9 +86,7 @@ def matches(self, cpp_type: CppType) -> bool: """ raise NotImplementedError() - def call_method( - self, res_type: CppType, cy_call_str: str, with_const: bool = True - ) -> str: + def call_method(self, res_type: CppType, cy_call_str: str, with_const: bool = True) -> str: """ Creates a temporary object which has the type of the current TypeConverter object. @@ -174,9 +172,9 @@ def _code_for_instantiate_object_from_iter(cpp_type: CppType, it: str) -> str: "shared_ptr[$cpp_type_base](new $cpp_type_base(deref(deref($it))))" ).substitute(locals()) else: - return string.Template( - "shared_ptr[$cpp_type](new $cpp_type(deref($it)))" - ).substitute(locals()) + return string.Template("shared_ptr[$cpp_type](new $cpp_type(deref($it)))").substitute( + locals() + ) class VoidConverter(TypeConverterBase): @@ -186,9 +184,7 @@ def get_base_types(self) -> List[str]: def matches(self, cpp_type: CppType) -> bool: return not cpp_type.is_ptr - def call_method( - self, res_type: CppType, cy_call_str: str, with_const: bool = True - ) -> str: + def call_method(self, res_type: CppType, cy_call_str: str, with_const: bool = True) -> str: return cy_call_str def matching_python_type(self, cpp_type: CppType) -> str: @@ -487,9 +483,7 @@ def input_conversion( cleanup = "" return code, call_as, cleanup - def call_method( - self, res_type: CppType, cy_call_str: str, with_const: bool = True - ) -> str: + def call_method(self, res_type: CppType, cy_call_str: str, with_const: bool = True) -> str: return "cdef char _r = %s" % cy_call_str def output_conversion( @@ -518,16 +512,13 @@ def input_conversion( self, cpp_type: CppType, argument_var: str, arg_num: int ) -> Tuple[Code, str, str]: code = Code().add( - "cdef const_char * input_%s = %s" - % (argument_var, argument_var) + "cdef const_char * input_%s = %s" % (argument_var, argument_var) ) call_as = "input_%s" % argument_var cleanup = "" return code, call_as, cleanup - def call_method( - self, res_type: CppType, cy_call_str: str, with_const: bool = True - ) -> str: + def call_method(self, res_type: CppType, cy_call_str: str, with_const: bool = True) -> str: return "cdef const_char * _r = _cast_const_away(%s)" % cy_call_str def output_conversion( @@ -560,9 +551,7 @@ def input_conversion( cleanup = "" return code, call_as, cleanup - def call_method( - self, res_type: CppType, cy_call_str: str, with_const: bool = True - ) -> str: + def call_method(self, res_type: CppType, cy_call_str: str, with_const: bool = True) -> str: return "cdef char * _r = _cast_const_away(%s)" % cy_call_str def output_conversion( @@ -612,7 +601,6 @@ def call_method( # If t is a ref, we would like to call on the base type t = t.base_type elif t.is_ptr: - # Special treatment for const raw ptr const = "" if t.is_const: @@ -636,7 +624,6 @@ def call_method( def output_conversion( self, cpp_type: CppType, input_cpp_var: str, output_py_var: str ) -> Optional[Union[Code, str]]: - cy_clz = self.converters.cython_type(cpp_type) # Need to ensure that type inside the raw ptr is an object and not a ref/ptr @@ -654,7 +641,6 @@ def output_conversion( class StdPairConverter(TypeConverterBase): - # remark: we use list instead of tuple internally, in order to # provide call by ref args. Python tuples are immutable. @@ -740,10 +726,7 @@ def input_conversion( cleanup_code = Code() if cpp_type.is_ref and not cpp_type.is_const: - if ( - not i1.is_enum - and t1.base_type in self.converters.names_of_wrapper_classes - ): + if not i1.is_enum and t1.base_type in self.converters.names_of_wrapper_classes: temp1 = "temp1" cleanup_code.add( """ @@ -754,10 +737,7 @@ def input_conversion( ) else: temp1 = "%s.first" % temp_var - if ( - not i2.is_enum - and t2.base_type in self.converters.names_of_wrapper_classes - ): + if not i2.is_enum and t2.base_type in self.converters.names_of_wrapper_classes: temp2 = "temp2" cleanup_code.add( """ @@ -777,15 +757,10 @@ def input_conversion( ) return code, "%s" % temp_var, cleanup_code - def call_method( - self, res_type: CppType, cy_call_str: str, with_const: bool = True - ) -> str: + def call_method(self, res_type: CppType, cy_call_str: str, with_const: bool = True) -> str: return "_r = %s" % (cy_call_str) - def output_conversion( - self, cpp_type: CppType, input_cpp_var: str, output_py_var: str - ) -> Code: - + def output_conversion(self, cpp_type: CppType, input_cpp_var: str, output_py_var: str) -> Code: assert not cpp_type.is_ptr ( t1, @@ -907,9 +882,7 @@ def input_conversion( value_conv = "<%s> value" % cy_tt_value elif tt_value.base_type in self.converters.names_of_wrapper_classes: value_conv = "deref((<%s>value).inst.get())" % tt_value.base_type - elif ( - tt_value.template_args is not None and tt_value.base_type == "libcpp_vector" - ): + elif tt_value.template_args is not None and tt_value.base_type == "libcpp_vector": # Special case: the value type is a std::vector< X >, maybe something we can convert? # code_top = """ @@ -1132,15 +1105,10 @@ def input_conversion( return code, "deref(%s)" % temp_var, cleanup_code - def call_method( - self, res_type: CppType, cy_call_str: str, with_const: bool = True - ) -> str: + def call_method(self, res_type: CppType, cy_call_str: str, with_const: bool = True) -> str: return "_r = %s" % cy_call_str - def output_conversion( - self, cpp_type: CppType, input_cpp_var: str, output_py_var: str - ) -> Code: - + def output_conversion(self, cpp_type: CppType, input_cpp_var: str, output_py_var: str) -> Code: assert not cpp_type.is_ptr tt_key, tt_value = cpp_type.template_args @@ -1154,17 +1122,11 @@ def output_conversion( not cy_tt_value.is_enum and tt_value.base_type in self.converters.names_of_wrapper_classes ) and ( - not cy_tt_key.is_enum - and tt_key.base_type in self.converters.names_of_wrapper_classes + not cy_tt_key.is_enum and tt_key.base_type in self.converters.names_of_wrapper_classes ): - raise Exception( - "Converter can not handle wrapped classes as keys and values in map" - ) + raise Exception("Converter can not handle wrapped classes as keys and values in map") - elif ( - not cy_tt_key.is_enum - and tt_key.base_type in self.converters.names_of_wrapper_classes - ): + elif not cy_tt_key.is_enum and tt_key.base_type in self.converters.names_of_wrapper_classes: key_conv = "deref(<%s *> (<%s> key).inst.get())" % (cy_tt_key, py_tt_key) else: key_conv = "<%s>(deref(%s).first)" % (cy_tt_key, it) @@ -1189,10 +1151,7 @@ def output_conversion( locals(), ) return code - elif ( - not cy_tt_key.is_enum - and tt_key.base_type in self.converters.names_of_wrapper_classes - ): + elif not cy_tt_key.is_enum and tt_key.base_type in self.converters.names_of_wrapper_classes: value_conv = "<%s>(deref(%s).second)" % (cy_tt_value, it) item_key = mangle("itemk_" + output_py_var) code = Code().add( @@ -1315,7 +1274,6 @@ def input_conversion( locals(), ) if cpp_type.is_ref and not cpp_type.is_const: - instantiation = self._code_for_instantiate_object_from_iter(inner, it) cleanup_code = Code().add( """ @@ -1357,15 +1315,10 @@ def input_conversion( ) return code, "%s" % temp_var, cleanup_code - def call_method( - self, res_type: CppType, cy_call_str: str, with_const: bool = True - ) -> str: + def call_method(self, res_type: CppType, cy_call_str: str, with_const: bool = True) -> str: return "_r = %s" % cy_call_str - def output_conversion( - self, cpp_type: CppType, input_cpp_var: str, output_py_var: str - ) -> Code: - + def output_conversion(self, cpp_type: CppType, input_cpp_var: str, output_py_var: str) -> Code: assert not cpp_type.is_ptr (tt,) = cpp_type.template_args @@ -1536,9 +1489,7 @@ def _prepare_recursive_cleanup( bottommost_code.add("del %s" % temp_var) return cleanup_code - def _prepare_nonrecursive_precall( - self, topmost_code, cpp_type, code_top, do_deref, *a, **kw - ): + def _prepare_nonrecursive_precall(self, topmost_code, cpp_type, code_top, do_deref, *a, **kw): # A) Prepare the pre-call if topmost_code is not None: if cpp_type.topmost_is_ref and not cpp_type.topmost_is_const: @@ -1573,7 +1524,6 @@ def _perform_recursion( *a, **kw ): - converter = self.cr.get(tt) py_type = converter.matching_python_type(tt) rec_arg_num = "%s_rec" % arg_num @@ -1749,9 +1699,7 @@ def input_conversion( # Case 1: We wrap a std::vector<> with an enum base type item = "item%s" % arg_num if topmost_code is not None: - raise Exception( - "Recursion in std::vector not yet implemented for enum" - ) + raise Exception("Recursion in std::vector not yet implemented for enum") code = Code().add( """ @@ -1933,20 +1881,14 @@ def input_conversion( return code, "%s" % temp_var, cleanup_code - def call_method( - self, res_type: CppType, cy_call_str: str, with_const: bool = True - ) -> str: - + def call_method(self, res_type: CppType, cy_call_str: str, with_const: bool = True) -> str: t = self.converters.cython_type(res_type) if t.is_ptr: return "_r = deref(%s)" % (cy_call_str) return "_r = %s" % (cy_call_str) - def output_conversion( - self, cpp_type: CppType, input_cpp_var: str, output_py_var: str - ) -> Code: - + def output_conversion(self, cpp_type: CppType, input_cpp_var: str, output_py_var: str) -> Code: (tt,) = cpp_type.template_args inner = self.converters.cython_type(tt) @@ -1991,7 +1933,6 @@ def output_conversion( tt.base_type == "shared_ptr" and len(set(tt.template_args[0].all_occuring_base_types())) == 1 ): - inner = self.converters.cython_type(tt) it = mangle("it_" + input_cpp_var) item = mangle("item_" + output_py_var) @@ -2184,9 +2125,7 @@ def type_check_expression(self, cpp_type: CppType, argument_var: str) -> str: (tt,) = cpp_type.template_args return "isinstance(%s, %s)" % (argument_var, tt) - def output_conversion( - self, cpp_type: CppType, input_cpp_var: str, output_py_var: str - ) -> Code: + def output_conversion(self, cpp_type: CppType, input_cpp_var: str, output_py_var: str) -> Code: # L.info("Output conversion for %s" % (cpp_type)) (tt,) = cpp_type.template_args code = Code() @@ -2222,18 +2161,13 @@ class ConverterRegistry(object): Therefore TypeConverterBase has methods .get_base_types and .matches """ - def __init__( - self, instance_mapping, names_of_classes_to_wrap, names_of_enums_to_wrap - ): - + def __init__(self, instance_mapping, names_of_classes_to_wrap, names_of_enums_to_wrap): self.lookup = defaultdict(list) self.names_of_wrapper_classes = list(instance_mapping.keys()) # add everything with a const prefix again # TODO super hack. We need to support const completely/better without hacks - self.names_of_wrapper_classes += [ - "const %s" % k for k in instance_mapping.keys() - ] + self.names_of_wrapper_classes += ["const %s" % k for k in instance_mapping.keys()] self.names_of_classes_to_wrap = names_of_classes_to_wrap self.names_of_enums_to_wrap = names_of_enums_to_wrap @@ -2252,7 +2186,6 @@ def process_and_set_type_mapping(self, instance_mapping): self.instance_mapping[alias] = type_.transformed(map_) def register(self, converter): - assert isinstance(converter, TypeConverterBase) L.info("register %s" % converter) converter._set_converter_registry(self) @@ -2273,9 +2206,7 @@ def get(self, cpp_type: CppType) -> TypeConverterBase: :return: TypeConverterBase :except: NameError """ - rv = [ - conv for conv in self.lookup[cpp_type.base_type] if conv.matches(cpp_type) - ] + rv = [conv for conv in self.lookup[cpp_type.base_type] if conv.matches(cpp_type)] if len(rv) < 1: raise NameError("no converter for %s in: %s" % (cpp_type, str(self.lookup))) @@ -2303,9 +2234,7 @@ def setup_converter_registry(classes_to_wrap, enums_to_wrap, instance_map): names_of_classes_to_wrap = list(set(c.cpp_decl.name for c in classes_to_wrap)) names_of_enums_to_wrap = list(set(c.cpp_decl.name for c in enums_to_wrap)) - converters = ConverterRegistry( - instance_map, names_of_classes_to_wrap, names_of_enums_to_wrap - ) + converters = ConverterRegistry(instance_map, names_of_classes_to_wrap, names_of_enums_to_wrap) converters.register(IntegerConverter()) converters.register(BooleanConverter()) diff --git a/autowrap/DeclResolver.py b/autowrap/DeclResolver.py index b63e3de..c3375be 100644 --- a/autowrap/DeclResolver.py +++ b/autowrap/DeclResolver.py @@ -226,9 +226,7 @@ class ResolvedMethod(object): "resolved" means that template parameters are resolved. """ - def __init__( - self, name, is_static, result_type, arguments, decl, instance_map, local_map - ): + def __init__(self, name, is_static, result_type, arguments, decl, instance_map, local_map): self.name: str = name self.is_static: bool = is_static self.result_type = result_type @@ -246,15 +244,12 @@ def __str__(self): class ResolvedFunction(ResolvedMethod): - pass def resolve_decls_from_files(paths, root, num_processes=1, cython_warn_level=1): if num_processes > 1: - return resolve_decls_from_files_multi_thread( - paths, root, num_processes, cython_warn_level - ) + return resolve_decls_from_files_multi_thread(paths, root, num_processes, cython_warn_level) else: return resolve_decls_from_files_single_thread(paths, root, cython_warn_level) @@ -269,9 +264,7 @@ def resolve_decls_from_files_single_thread(paths, root, cython_warn_level=1): return _resolve_decls(decls) -def resolve_decls_from_files_multi_thread( - paths, root, num_processes, cython_warn_level=1 -): +def resolve_decls_from_files_multi_thread(paths, root, num_processes, cython_warn_level=1): """Perform parsing with multiple threads This function distributes the work on `num_processes` processes and each @@ -294,9 +287,7 @@ def resolve_decls_from_files_multi_thread( "parsing progress %s out of %s with %s processes" % (len(paths) - remaining, len(paths), num_processes), ) - parse_pxd_file_warn = partial( - PXDParser.parse_pxd_file, warn_level=cython_warn_level - ) + parse_pxd_file_warn = partial(PXDParser.parse_pxd_file, warn_level=cython_warn_level) res = pool.map(parse_pxd_file_warn, args) for r in res: decls.extend(r) @@ -353,15 +344,11 @@ def filter_out(tt): # add enum mapping to class instances mapping intersecting_names = set(instance_mapping) & set(enum_mapping) - assert not intersecting_names, ( - "enum names and class decls overlap: %s" % intersecting_names - ) + assert not intersecting_names, "enum names and class decls overlap: %s" % intersecting_names instance_mapping.update(enum_mapping) - functions = [ - _resolve_function(f, instance_mapping, typedef_mapping) for f in function_decls - ] + functions = [_resolve_function(f, instance_mapping, typedef_mapping) for f in function_decls] enums = [ResolvedEnum(e) for e in enum_decls] typedefs = [ResolvedTypeDef(t) for t in typedef_decls] @@ -444,7 +431,6 @@ def _resolve_inheritance(cdcl, class_decls, inheritance_graph): def _add_inherited_methods(cdcl, super_cld, used_parameters): - logger.info("add_inherited_methods for %s" % cdcl.name) super_targs = super_cld.template_parameters @@ -454,9 +440,7 @@ def _add_inherited_methods(cdcl, super_cld, used_parameters): # check if parameterization signature matches: if len(used_parameters) != len(super_targs): - raise Exception( - "deriving %s from %s does not match" % (cdcl.name, super_cld.name) - ) + raise Exception("deriving %s from %s does not match" % (cdcl.name, super_cld.name)) # map template parameters in super class to the parameters used in current # class: @@ -508,7 +492,6 @@ def _parse_all_wrap_instances_comments(class_decls: List[PXDParser.CppClassDecl] def _parse_wrap_instances_comments( cdcl: PXDParser.CppClassDecl, ) -> Dict[AnyStr, Tuple[Types.CppType, Dict]]: - inst_annotations = cdcl.annotations.get("wrap-instances") r = dict() if cdcl.template_parameters is None and not inst_annotations: @@ -555,9 +538,7 @@ def _resolve_class_decls(class_decls, typedef_mapping, instance_mapping): """ """ all_resolved_classes = [] for class_decl in class_decls: - resolved_classes = _resolve_class_decl( - class_decl, typedef_mapping, instance_mapping - ) + resolved_classes = _resolve_class_decl(class_decl, typedef_mapping, instance_mapping) all_resolved_classes.extend(resolved_classes) return all_resolved_classes @@ -577,15 +558,13 @@ def _resolve_class_decl(class_decl, typedef_mapping, i_mapping): r_attributes.append(_resolve_attribute(adcl, i_mapping, local_mapping)) r_methods = [] - for (mname, mdcls) in class_decl.methods.items(): + for mname, mdcls in class_decl.methods.items(): for mdcl in mdcls: ignore = mdcl.annotations.get("wrap-ignore", False) if ignore: continue if mdcl.name == class_decl.name: - r_method = _resolve_constructor( - cinst_name, mdcl, i_mapping, local_mapping - ) + r_method = _resolve_constructor(cinst_name, mdcl, i_mapping, local_mapping) else: r_method = _resolve_method(mdcl, i_mapping, local_mapping) r_methods.append(r_method) @@ -598,9 +577,7 @@ def _resolve_class_decl(class_decl, typedef_mapping, i_mapping): def _build_local_typemap(t_param_mapping, typedef_mapping): # for resolving typedef'ed types in template instance args: - local_map = dict( - (n, t.transformed(typedef_mapping)) for (n, t) in t_param_mapping.items() - ) + local_map = dict((n, t.transformed(typedef_mapping)) for (n, t) in t_param_mapping.items()) # for resolving 'free' typedefs in method args and result types: if set(local_map) & set(typedef_mapping): @@ -646,9 +623,7 @@ def _resolve_method_or_function(method_decl, instance_mapping, local_type_map, c """ resolves aliases in return and argument types """ - result_type = _resolve_alias( - method_decl.result_type, instance_mapping, local_type_map - ) + result_type = _resolve_alias(method_decl.result_type, instance_mapping, local_type_map) args = [] for arg_name, arg_type in method_decl.arguments: arg_type = _resolve_alias(arg_type, instance_mapping, local_type_map) diff --git a/autowrap/Main.py b/autowrap/Main.py index 3893c20..dbf2871 100644 --- a/autowrap/Main.py +++ b/autowrap/Main.py @@ -190,9 +190,7 @@ def run_cython(inc_dirs, extra_opts, out, warn_level=1): directive_defaults["wraparound"] = False directive_defaults["language_level"] = sys.version_info.major - options = dict( - include_path=inc_dirs, compiler_directives=directive_defaults, cplus=True - ) + options = dict(include_path=inc_dirs, compiler_directives=directive_defaults, cplus=True) if extra_opts is not None: options.update(extra_opts) options = CompilationOptions(**options) diff --git a/autowrap/PXDParser.py b/autowrap/PXDParser.py index fb95cac..469373c 100644 --- a/autowrap/PXDParser.py +++ b/autowrap/PXDParser.py @@ -87,27 +87,46 @@ def _parse_multiline_annotations(lines: Collection[str]) -> AnnotDict: """ it = iter(lines) result = defaultdict(list) + in_annot_context = False + beginning = True while it: - try: - line = next(it).strip() - except StopIteration: - break - if not line: + if ( + not in_annot_context + ): # if we are coming from an annotation context, we already have the next line + try: + line = next(it).strip() + except StopIteration: + break + + # once a comment started, we do not allow empty lines anymore + if beginning and not line: # continue until the first comment after method/class continue - if line.startswith("#"): + + if line.startswith( + "#" + ): # TODO should we force a certain indentation for the annots themselves? + beginning = False line = line[1:].strip() if line.endswith(":"): + in_annot_context = True key = line.rstrip(":") - line = next(it).strip() + try: + # TODO this strip leads to requiring a non-empty line. We might want to allow empty lines in the beginning of a doc + line = next(it).strip() + except StopIteration: + raise ValueError("No more lines after start of multiline annotation " + line) + if not line.startswith("# "): + raise ValueError( + "No comment lines with an indentation of at least two whitespaces after start of multiline annotation " + + line + ) while line.startswith("# "): if key == "wrap-doc": - value = line[3:].rstrip() # rstrip to keep indentation in docs + value = line[3:].rstrip() # only rstrip to keep indentation in docs else: value = line[1:].strip() - if ( - key == "wrap-doc" or value - ): # don't add empty non wrap-doc values + if key == "wrap-doc" or value: # don't add empty non wrap-doc values result[key].append(value) try: @@ -115,6 +134,7 @@ def _parse_multiline_annotations(lines: Collection[str]) -> AnnotDict: except StopIteration: break else: + in_annot_context = False key = line result[key] = True else: @@ -132,9 +152,7 @@ def _parse_multiline_annotations(lines: Collection[str]) -> AnnotDict: return result -def parse_line_annotations( - node: Cython.Compiler.Nodes.Node, lines: Sequence[str] -) -> AnnotDict: +def parse_line_annotations(node: Cython.Compiler.Nodes.Node, lines: Sequence[str]) -> AnnotDict: """ parses comments at end of line, in most cases the lines of method declarations. @@ -165,9 +183,11 @@ def parse_line_annotations( continue if ":" in f: key, value = f.split(":", 1) - assert value.strip(), ( - "empty value (or excess space?) for key '%s' in line '%s'" - % (key, line.rstrip()) + assert ( + value.strip() + ), "empty value (or excess space?) for key '%s' in line '%s'" % ( + key, + line.rstrip(), ) result[key] = value elif f.find("wrap-") != -1: @@ -209,9 +229,7 @@ def _extract_template_args(node: Cython.Compiler.Nodes.Node) -> CppType: elif isinstance(node.index, NameNode): args = [CppType(node.index.name)] else: - raise Exception( - "Can not handle node %s in template argument declaration" % node.index - ) + raise Exception("Can not handle node %s in template argument declaration" % node.index) return CppType(name, args) @@ -238,13 +256,9 @@ def _extract_type( is_ptr = isinstance(arg_decl, CPtrDeclaratorNode) is_ref = isinstance(arg_decl, CReferenceDeclaratorNode) is_unsigned = ( - hasattr(arg_node.base_type, "signed") - and not arg_node.base_type.signed - ) - is_long = ( - hasattr(arg_node.base_type, "longness") - and arg_node.base_type.longness + hasattr(arg_node.base_type, "signed") and not arg_node.base_type.signed ) + is_long = hasattr(arg_node.base_type, "longness") and arg_node.base_type.longness # Handle const template arguments which do not have a name # themselves, only their base types have name attribute (see @@ -258,9 +272,7 @@ def _extract_type( args = None template_args = getattr(arg_node.base_type, "positional_args", None) if template_args: - args = [ - _extract_type(t.base_type, t.declarator) for t in template_args - ] + args = [_extract_type(t.base_type, t.declarator) for t in template_args] name = arg_node.base_type.base_type_node.name ttype = CppType( name, @@ -305,9 +317,7 @@ def _extract_type( class BaseDecl(object): - def __init__( - self, name: str, annotations: Dict[str, Union[bool, List[str]]], pxd_path: str - ): + def __init__(self, name: str, annotations: Dict[str, Union[bool, List[str]]], pxd_path: str): self.name: str = name self.annotations: AnnotDict = annotations self.pxd_path: str = pxd_path @@ -370,18 +380,14 @@ class CppClassDecl(BaseDecl): attributes: List[CppAttributeDecl] template_parameters: List[AnyStr] - def __init__( - self, name, template_parameters, methods, attributes, annotations, pxd_path - ): + def __init__(self, name, template_parameters, methods, attributes, annotations, pxd_path): super(CppClassDecl, self).__init__(name, annotations, pxd_path) self.methods = methods self.attributes = attributes self.template_parameters = template_parameters @classmethod - def parseTree( - cls, node: Cython.Compiler.Nodes.CppClassNode, lines: Collection[str], pxd_path - ): + def parseTree(cls, node: Cython.Compiler.Nodes.CppClassNode, lines: Collection[str], pxd_path): name = node.name template_parameters = node.templates if ( @@ -430,9 +436,7 @@ def parseTree( # attributes.append(decl) pass - return cls( - name, template_parameters, methods, attributes, class_annotations, pxd_path - ) + return cls(name, template_parameters, methods, attributes, class_annotations, pxd_path) def __str__(self): rv = ["cppclass %s: " % (self.name,)] @@ -525,9 +529,7 @@ def parseTree(cls, node: CVarDefNode, lines, pxd_path): # Handle regular declarations return CppAttributeDecl(decl.name, result_type, annotations, pxd_path) - if isinstance(decl, CPtrDeclaratorNode) and not isinstance( - decl.base, CFuncDeclaratorNode - ): + if isinstance(decl, CPtrDeclaratorNode) and not isinstance(decl.base, CFuncDeclaratorNode): # Handle raw pointer declarations (call with base name) return CppAttributeDecl(decl.base.name, result_type, annotations, pxd_path) @@ -561,9 +563,7 @@ def parseTree(cls, node: CVarDefNode, lines, pxd_path): tt = _extract_type(arg.base_type, argdecl) args.append((argname, tt)) - return CppMethodOrFunctionDecl( - result_type, name, args, is_static, annotations, pxd_path - ) + return CppMethodOrFunctionDecl(result_type, name, args, is_static, annotations, pxd_path) def parse_str(what): @@ -657,7 +657,6 @@ def cimport(b, _, __): if __name__ == "__main__": - import sys if len(sys.argv) == 3: diff --git a/autowrap/Types.py b/autowrap/Types.py index bf8eb43..79259bc 100644 --- a/autowrap/Types.py +++ b/autowrap/Types.py @@ -40,7 +40,6 @@ class CppType(object): - CTYPES = ["int", "long", "double", "float", "char", "void"] LIBCPPTYPES = ["vector", "string", "list", "pair"] @@ -95,7 +94,6 @@ def transformed(self, typemap): return copied def _transform(self, typemap, indent): - aliased_t = typemap.get(self.base_type) if aliased_t is not None: if self.template_args is not None: @@ -187,9 +185,7 @@ def toString(self, withConst): if ptr and ref: raise NotImplementedError("can not handle ref and ptr together") if self.template_args is not None: - inner = "[%s]" % ( - ",".join(t.toString(withConst) for t in self.template_args) - ) + inner = "[%s]" % (",".join(t.toString(withConst) for t in self.template_args)) else: inner = "" result = "%s%s%s %s%s %s" % ( @@ -237,9 +233,7 @@ def from_string(str_: AnyStr) -> CppType: @staticmethod def _from_string(str_: AnyStr) -> CppType: # TODO is there a reason why "_" is not in the regex? - matched = re.match( - r"([a-zA-Z0-9][ a-zA-Z0-9_]*)(\[.*\])? *[&\*]?", str_.strip() - ) + matched = re.match(r"([a-zA-Z0-9][ a-zA-Z0-9_]*)(\[.*\])? *[&\*]?", str_.strip()) if matched is None: raise ValueError("can not parse '%s'" % str_) base_type, t_str = matched.groups() diff --git a/autowrap/Utils.py b/autowrap/Utils.py index 75cbaab..55b1aca 100644 --- a/autowrap/Utils.py +++ b/autowrap/Utils.py @@ -63,7 +63,6 @@ def compile_and_import(name, source_files, include_dirs=None, **kws): - if include_dirs is None: include_dirs = [] @@ -81,9 +80,7 @@ def compile_and_import(name, source_files, include_dirs=None, **kws): print("\n") for source_file in source_files: if source_file[-4:] != ".pyx" and source_file[-4:] != ".cpp": - raise NameError( - "Expected pyx and/or cpp files as source files for compilation." - ) + raise NameError("Expected pyx and/or cpp files as source files for compilation.") shutil.copy(source_file, tempdir) stub = source_file[:-4] + ".pyi" if os.path.exists(stub): @@ -183,10 +180,9 @@ def find_cycle(graph_as_dict): def _check_for_cycles_in_mapping(mapping): - # detect cylces in typedefs graph = dict() - for (alias, type_) in mapping.items(): + for alias, type_ in mapping.items(): successors = type_.all_occuring_base_types() graph[alias] = successors diff --git a/autowrap/__init__.py b/autowrap/__init__.py index 4eaca7f..7d959ba 100644 --- a/autowrap/__init__.py +++ b/autowrap/__init__.py @@ -51,9 +51,7 @@ def parse(files, root, num_processes=1, cython_warn_level=1): import autowrap.DeclResolver - return DeclResolver.resolve_decls_from_files( - files, root, num_processes, cython_warn_level - ) + return DeclResolver.resolve_decls_from_files(files, root, num_processes, cython_warn_level) def generate_code( @@ -100,11 +98,7 @@ def parse_and_generate_code( extra_cimports=None, include_boost=True, ): - - print( - "Autowrap will start to parse and generate code. " - "Will parse %s files" % len(files) - ) + print("Autowrap will start to parse and generate code. " "Will parse %s files" % len(files)) decls, instance_map = parse(files, root) print("Done parsing the files, will generate the code...") return generate_code( diff --git a/memtests/sysinfo.py b/memtests/sysinfo.py index 5391ba4..593ebc5 100644 --- a/memtests/sysinfo.py +++ b/memtests/sysinfo.py @@ -7,7 +7,6 @@ libc = c.CDLL(ctypes.util.find_library("c")) class SysInfo(c.Structure): - # for libc5: needs padding padding = 20 - 2 * c.sizeof(c.c_long) - c.sizeof(c.c_int) diff --git a/memtests/test00.py b/memtests/test00.py index 82e3dcf..e9a931e 100644 --- a/memtests/test00.py +++ b/memtests/test00.py @@ -5,7 +5,6 @@ def show_mem(label): - p = free_mem() p /= 1024.0 * 1024 print(label + " ").ljust(50, "."), ": %8.2f MB" % p @@ -26,20 +25,15 @@ def MemTester(name, use_assert=False): def test00(): - import autowrap source_files = os.path.join(os.path.dirname(__file__), "source_files") target = os.path.join(source_files, "chunk_wrapper.pyx") - autowrap.parse_and_generate_code( - "chunk.pxd", root=source_files, target=target, debug=True - ) + autowrap.parse_and_generate_code("chunk.pxd", root=source_files, target=target, debug=True) - wrapped = autowrap.Utils.compile_and_import( - "chunk_wrapped", [target], [source_files] - ) + wrapped = autowrap.Utils.compile_and_import("chunk_wrapped", [target], [source_files]) os.remove(target) assert wrapped.__name__ == "chunk_wrapped", wrapped.__name__ diff --git a/tests/test_code_generator.py b/tests/test_code_generator.py index ea1254b..97efcea 100644 --- a/tests/test_code_generator.py +++ b/tests/test_code_generator.py @@ -77,7 +77,6 @@ def test_enums(): def test_number_conv(): - target = os.path.join(test_files, "number_conv.pyx") include_dirs = autowrap.parse_and_generate_code( @@ -97,26 +96,19 @@ def test_number_conv(): assert not math.isinf(mf2), "somehow overflow happened" repr_ = "%.13e" % mod.pass_full_precision(0.05) - assert repr_.startswith("5.0000000000000"), ( - "loss of precision during conversion: %s" % repr_ - ) + assert repr_.startswith("5.0000000000000"), "loss of precision during conversion: %s" % repr_ inl = [0.05] outl = mod.pass_full_precision_vec(inl) repr_ = "%.13e" % inl[0] - assert repr_.startswith("5.0000000000000"), ( - "loss of precision during conversion: %s" % repr_ - ) + assert repr_.startswith("5.0000000000000"), "loss of precision during conversion: %s" % repr_ repr_ = "%.13e" % outl[0] - assert repr_.startswith("5.0000000000000"), ( - "loss of precision during conversion: %s" % repr_ - ) + assert repr_.startswith("5.0000000000000"), "loss of precision during conversion: %s" % repr_ def test_shared_ptr(): - target = os.path.join(test_files, "shared_ptr_test.pyx") include_dirs = autowrap.CodeGenerator.fixed_include_dirs(True) + [test_files] m = autowrap.Utils.compile_and_import( @@ -159,7 +151,6 @@ def test_shared_ptr(): def test_inherited(): - target = os.path.join(test_files, "inherited.pyx") include_dirs = autowrap.parse_and_generate_code( ["inherited.pxd"], root=test_files, target=target, debug=True @@ -181,7 +172,6 @@ def test_inherited(): def test_templated(): - target = os.path.join(test_files, "templated_wrapper.pyx") decls, instance_map = autowrap.parse(["templated.pxd"], root=test_files) @@ -201,9 +191,7 @@ def test_templated(): cpp_source = os.path.join(test_files, "templated.cpp") cpp_sources = [] - twrapped = autowrap.Utils.compile_and_import( - "twrapped", [target] + cpp_sources, include_dirs - ) + twrapped = autowrap.Utils.compile_and_import("twrapped", [target] + cpp_sources, include_dirs) os.remove(target) assert twrapped.__name__ == "twrapped" @@ -276,7 +264,6 @@ def test_templated(): def test_gil_unlock(): - target = os.path.join(test_files, "gil_testing_wrapper.pyx") include_dirs = autowrap.parse_and_generate_code( ["gil_testing.pxd"], root=test_files, target=target, debug=True diff --git a/tests/test_code_generator_minimal.py b/tests/test_code_generator_minimal.py index af33100..01d7cfb 100644 --- a/tests/test_code_generator_minimal.py +++ b/tests/test_code_generator_minimal.py @@ -51,7 +51,6 @@ def test_minimal(): - from autowrap.ConversionProvider import TypeConverterBase, special_converters class SpecialIntConverter(TypeConverterBase): @@ -85,9 +84,7 @@ def output_conversion(self, cpp_type, input_cpp_var, output_py_var): ["minimal.pxd", "minimal_td.pxd"], root=test_files, target=target, debug=True ) cpp_source = os.path.join(test_files, "minimal.cpp") - wrapped = autowrap.Utils.compile_and_import( - "wrapped", [target, cpp_source], include_dirs - ) + wrapped = autowrap.Utils.compile_and_import("wrapped", [target, cpp_source], include_dirs) os.remove(target) assert wrapped.__name__ == "wrapped" diff --git a/tests/test_code_generator_stllibcpp.py b/tests/test_code_generator_stllibcpp.py index fbff67b..5170045 100644 --- a/tests/test_code_generator_stllibcpp.py +++ b/tests/test_code_generator_stllibcpp.py @@ -51,7 +51,6 @@ def test_stl_libcpp(): - target = os.path.join(test_files, "libcpp_stl_test.pyx") include_dirs = autowrap.parse_and_generate_code( diff --git a/tests/test_decl_resolver.py b/tests/test_decl_resolver.py index debe873..5f3e02e 100644 --- a/tests/test_decl_resolver.py +++ b/tests/test_decl_resolver.py @@ -174,7 +174,6 @@ def test_simple_mp(): def test_singular(): - resolved, map_ = _resolve("templates.pxd") assert len(resolved) == 2, len(resolved) @@ -478,8 +477,10 @@ def test_cycle_detection_in_class_hierarchy2(): def test_nested_templates(): - - (i1, i2,), map_ = DeclResolver.resolve_decls_from_string( + ( + i1, + i2, + ), map_ = DeclResolver.resolve_decls_from_string( """ from libcpp.string cimport string as libcpp_string from libcpp.vector cimport vector as libcpp_vector diff --git a/tests/test_full_library.py b/tests/test_full_library.py index 67cd0ab..a1509c2 100644 --- a/tests/test_full_library.py +++ b/tests/test_full_library.py @@ -80,7 +80,6 @@ def compile_and_import(names, source_files, include_dirs=None, extra_files=[], **kws): - if include_dirs is None: include_dirs = [] @@ -176,16 +175,13 @@ def test_full_lib(tmpdir): open("__init__.py", "a").close() try: - mnames = ["moduleA", "moduleB", "moduleCD"] # Step 1: parse all header files PY_NUM_THREADS = 1 pxd_files = ["A.pxd", "B.pxd", "C.pxd", "D.pxd"] full_pxd_files = [os.path.join(test_files, f) for f in pxd_files] - decls, instance_map = autowrap.parse( - full_pxd_files, ".", num_processes=int(PY_NUM_THREADS) - ) + decls, instance_map = autowrap.parse(full_pxd_files, ".", num_processes=int(PY_NUM_THREADS)) assert len(decls) == 13, len(decls) @@ -208,8 +204,7 @@ def test_full_lib(tmpdir): "files": [full_pxd_files[1]], } masterDict[mnames[2]] = { - "decls": pxd_decl_mapping[full_pxd_files[2]] - + pxd_decl_mapping[full_pxd_files[3]], + "decls": pxd_decl_mapping[full_pxd_files[2]] + pxd_decl_mapping[full_pxd_files[3]], "addons": [], "files": [full_pxd_files[2]] + [full_pxd_files[3]], } @@ -218,9 +213,7 @@ def test_full_lib(tmpdir): converters = [] for modname in mnames: m_filename = "%s.pyx" % modname - cimports, manual_code = autowrap.Main.collect_manual_code( - masterDict[modname]["addons"] - ) + cimports, manual_code = autowrap.Main.collect_manual_code(masterDict[modname]["addons"]) autowrap.Main.register_converters(converters) autowrap_include_dirs = autowrap.generate_code( masterDict[modname]["decls"], diff --git a/tests/test_main.py b/tests/test_main.py index 9d542e4..46b810c 100644 --- a/tests/test_main.py +++ b/tests/test_main.py @@ -51,7 +51,6 @@ def test_from_command_line(): def test_run(): - from autowrap.Main import run from autowrap.Utils import compile_and_import @@ -69,9 +68,7 @@ def test_run(): converters = [script_dir + "/test_files/converters"] extra_includes = [script_dir + "/test_files/includes"] - includes = run( - pxds, addons, converters, script_dir + "/test_files/out.pyx", extra_includes - ) + includes = run(pxds, addons, converters, script_dir + "/test_files/out.pyx", extra_includes) mod = compile_and_import("out", [script_dir + "/test_files/out.cpp"], includes) diff --git a/tests/test_pxd_parser.py b/tests/test_pxd_parser.py index 79d61c0..f29c34a 100644 --- a/tests/test_pxd_parser.py +++ b/tests/test_pxd_parser.py @@ -37,6 +37,7 @@ import os from autowrap.Types import CppType as CppType +from autowrap.Code import Code as Code from .utils import expect_exception @@ -77,6 +78,57 @@ def test_multiline_annotations(): assert mdcl.annotations == dict(a="3", b="4") +def test_multiline_annotations_plus_afterdecl(): + (cdcl,) = autowrap.PXDParser.parse_str( + """ +cdef extern from "*": + + cdef cppclass T: + # wrap-doc: + # Foobar wrap-wdsadas dsada + # continue + # Not enough spaces + # Enough spaces again but after a line without colon + # wrap-newwrapshiftedcomment: + # str w/ many spaces under an annot that is not wrap-doc + # wrap-secondnewwraprightafterthelast: + # bla + # wrap-notext + + fun(int x, # a:3 wrap-doc:Will be overwritten + float y, # b:4 + ) + # wrap-doc: + # multiline + # for function + + + """ + ) + (mdcl,) = cdcl.methods.get("fun") + + expected = dict(a="3", b="4") + c = Code() + c.addRawList(["multiline", "for function"]) + expected["wrap-doc"] = c.render() + mdcl.annotations["wrap-doc"] = mdcl.annotations["wrap-doc"].render() + assert mdcl.annotations == expected + + expected = dict() + c = Code() + c.addRawList(["Foobar wrap-wdsadas dsada", "continue"]) + expected["wrap-doc"] = c.render() + expected["wrap-newwrapshiftedcomment"] = [ + "str w/ many spaces under an annot that is not wrap-doc" + ] + expected["wrap-secondnewwraprightafterthelast"] = ["bla"] + expected["Not enough spaces"] = True + expected["Enough spaces again but after a line without colon"] = True + expected["wrap-notext"] = True + cdcl.annotations["wrap-doc"] = cdcl.annotations["wrap-doc"].render() + assert cdcl.annotations == expected + + def test_minimal(): (cld,) = autowrap.PXDParser.parse_str( """ @@ -315,7 +367,6 @@ def test_typedef(): def test_typedef2(): - (decl1,) = autowrap.PXDParser.parse_str( """ cdef extern from "A.h": @@ -328,7 +379,6 @@ def test_typedef2(): @expect_exception def test_doubleptr(): - autowrap.PXDParser.parse_str( """ cdef extern from "A.h": @@ -539,7 +589,6 @@ def test_annotations(): def test_parsing_of_nested_template_args(): - td1, td2, td3 = autowrap.PXDParser.parse_str( """ diff --git a/tests/test_types.py b/tests/test_types.py index a5487ae..d0e6e2f 100644 --- a/tests/test_types.py +++ b/tests/test_types.py @@ -154,7 +154,6 @@ def check(t, tobe): def test_transform(): - A = CppType("A") B = CppType("B") X = CppType("X") diff --git a/tests/test_utils.py b/tests/test_utils.py index bcbc322..bd0af23 100644 --- a/tests/test_utils.py +++ b/tests/test_utils.py @@ -33,7 +33,6 @@ def test_hierarchy_detector0(): - dd = dict() dd[1] = [2] dd[2] = [1] @@ -45,7 +44,6 @@ def test_hierarchy_detector0(): def test_hierarchy_detector1(): - dd = dict() dd[1] = [2, 3] dd[2] = [3] @@ -53,7 +51,6 @@ def test_hierarchy_detector1(): def test_hierarchy_detector2(): - dd = dict() dd[1] = [2, 3] dd[2] = [3] @@ -63,7 +60,6 @@ def test_hierarchy_detector2(): def test_hierarchy_detector3(): - dd = dict() dd[1] = [2] dd[2] = [3, 4]