From 1bd76b5ffd7ecfb658d3fe7bdc5bc52695862685 Mon Sep 17 00:00:00 2001 From: Julianus Pfeuffer Date: Wed, 21 Dec 2022 15:03:44 +0100 Subject: [PATCH 1/6] A few type fixes --- autowrap/CodeGenerator.py | 8 ++---- autowrap/ConversionProvider.py | 52 ++++++++++++++++++++++++++++------ 2 files changed, 46 insertions(+), 14 deletions(-) diff --git a/autowrap/CodeGenerator.py b/autowrap/CodeGenerator.py index 921d6e7..a3e6636 100644 --- a/autowrap/CodeGenerator.py +++ b/autowrap/CodeGenerator.py @@ -383,7 +383,8 @@ def create_for( pxd_code += c.render() pxd_code += " \n" - pyi_code = "from typing import overload, Any, List, Dict, Tuple, Set, Sequence, Union \n\n" + pyi_code = "from __future__ import annotations\n" + pyi_code += "from typing import overload, Any, List, Dict, Tuple, Set, Sequence, Union\n\n" pyi_code += "from enum import Enum as _PyEnum\n\n" pyi_code += "\n".join(ci.render() for ci in self.top_level_typestub_code) pyi_code += "\n\n" @@ -910,8 +911,6 @@ def _create_overloaded_method_decl( docstrings = Code() signatures = [] for method in methods: - ## TODO refactor this part as something like getTypingSignature or getTypingSignatureParts - ## or maybe save them for the after-the-next for-loop that generates them again args = augment_arg_names(method) py_typing_signature_parts = [] for arg_num, (t, n) in enumerate(args): @@ -931,9 +930,6 @@ def _create_overloaded_method_decl( # Add autodoc docstring signatures first: https://github.com/sphinx-doc/sphinx/pull/7748 sig = f"{py_name}(self, {args_typestub_str}) {return_type}" signatures.append(sig) - #docstrings.add(sig) - - #docstrings.add("") for method, sig in zip(methods, signatures): docstrings.add(".. rubric:: Overload:") diff --git a/autowrap/ConversionProvider.py b/autowrap/ConversionProvider.py index f853a1c..ef3407b 100644 --- a/autowrap/ConversionProvider.py +++ b/autowrap/ConversionProvider.py @@ -215,6 +215,7 @@ class IntegerConverter(TypeConverterBase): """ wraps long and int. "long" base_type is converted to "int" by the cython parser! + TODO Long does not exist in Python2 anymore. Can we remove stuff? """ def get_base_types(self) -> List[str]: @@ -235,7 +236,7 @@ def matches(self, cpp_type: CppType) -> bool: return not cpp_type.is_ptr def matching_python_type(self, cpp_type: CppType) -> str: - return "" + return "" #TODO can't we use int? Especially in py3 only. def matching_python_type_full(self, cpp_type: CppType) -> str: return "int" @@ -382,10 +383,11 @@ def matching_python_type(self, cpp_type: CppType) -> str: return "" def matching_python_type_full(self, cpp_type: CppType) -> str: - if self.enum.cpp_decl.annotations.get("wrap-attach"): - if not self.enum.scoped: - return "__" + self.enum.name - else: + if not self.enum.scoped: + # TODO add some other hint that this must be an + # int from the class "__" + self.enum.name + return "int" + elif self.enum.cpp_decl.annotations.get("wrap-attach"): return "_Py" + self.enum.name else: return self.enum.name @@ -1989,6 +1991,14 @@ def output_conversion( class StdStringConverter(TypeConverterBase): + """ + This converter deals with functions that expect/return a C++ std::string. + It expects and returns bytes on the python side. + Note that this provider will NOT be picked up if it is located inside + a container (e.g. std::vector aka libcpp_vector). However, it can and + should be used to indicate the correct typing for the automatic + conversion by Cython, which is set to bytes in autowrap. + """ def get_base_types(self) -> List[str]: return ["libcpp_string"] @@ -2018,20 +2028,34 @@ def output_conversion( return "%s = %s" % (output_py_var, input_cpp_var) +# TODO I think we have to be more clear about the use case of this ConvProv +# Currently it can be used if you don't know if the incoming +# py type is bytes or unicode. We currently have no provider that allows +# for specifically unicode only. class StdStringUnicodeConverter(StdStringConverter): + """ + This converter deals with functions that expect a C++ std::string. + Note that this provider will NOT be picked up if it is located inside + a container (e.g. std::vector aka libcpp_vector). Please use the usual + StdStringConverter to at least get the typing right. + It can only be used in function parameters (i.e. input). + It can handle both bytes and unicode strings and converts to bytes internally. + """ def get_base_types(self) -> List[str]: return ["libcpp_utf8_string"] def matching_python_type(self, cpp_type: CppType) -> str: - return "" + return "" # TODO can we use "basestring"? def matching_python_type_full(self, cpp_type: CppType) -> str: - return "Union[bytes, unicode]" + return "Union[bytes, str]" def input_conversion( self, cpp_type: CppType, argument_var: str, arg_num: int ) -> Tuple[Code, str, str]: code = Code() + # although python3 does not have "unicode" as a built-in type anymore, + # Cython understands it and uses the Py_IsUnicodeCheck code.add( """ |if isinstance($argument_var, unicode): @@ -2044,13 +2068,25 @@ def input_conversion( return code, call_as, cleanup def type_check_expression(self, cpp_type: CppType, argument_var: str) -> str: - return "isinstance(%s, (bytes, unicode))" % argument_var + return "isinstance(%s, (bytes, str))" % argument_var class StdStringUnicodeOutputConverter(StdStringUnicodeConverter): + """ + This converter deals with functions that return a C++ std::string. + Note that this provider will NOT be picked up if it is located inside + a container (e.g. std::vector aka libcpp_vector). Please use the usual + StdStringConverter to at least get the typing right. + It should only be used in function returns (i.e. output). + It returns unicode strings to python and therefore expects the C++ + function to return something that is decodable from utf8 (including ascii) + """ def get_base_types(self) -> List[str]: return ["libcpp_utf8_output_string"] + def matching_python_type_full(self, cpp_type: CppType) -> str: + return "str" # python3 + def output_conversion( self, cpp_type: CppType, input_cpp_var: str, output_py_var: str ) -> Optional[str]: From b17c5799e531c0b0b0e0c478ab3b49d1c7bd3e67 Mon Sep 17 00:00:00 2001 From: Julianus Pfeuffer Date: Wed, 21 Dec 2022 16:13:20 +0100 Subject: [PATCH 2/6] lint --- autowrap/ConversionProvider.py | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/autowrap/ConversionProvider.py b/autowrap/ConversionProvider.py index ef3407b..e9efe25 100644 --- a/autowrap/ConversionProvider.py +++ b/autowrap/ConversionProvider.py @@ -236,7 +236,7 @@ def matches(self, cpp_type: CppType) -> bool: return not cpp_type.is_ptr def matching_python_type(self, cpp_type: CppType) -> str: - return "" #TODO can't we use int? Especially in py3 only. + return "" #TODO can't we use int? Especially in py3 only. def matching_python_type_full(self, cpp_type: CppType) -> str: return "int" @@ -1999,6 +1999,7 @@ class StdStringConverter(TypeConverterBase): should be used to indicate the correct typing for the automatic conversion by Cython, which is set to bytes in autowrap. """ + def get_base_types(self) -> List[str]: return ["libcpp_string"] @@ -2041,6 +2042,7 @@ class StdStringUnicodeConverter(StdStringConverter): It can only be used in function parameters (i.e. input). It can handle both bytes and unicode strings and converts to bytes internally. """ + def get_base_types(self) -> List[str]: return ["libcpp_utf8_string"] @@ -2081,6 +2083,7 @@ class StdStringUnicodeOutputConverter(StdStringUnicodeConverter): It returns unicode strings to python and therefore expects the C++ function to return something that is decodable from utf8 (including ascii) """ + def get_base_types(self) -> List[str]: return ["libcpp_utf8_output_string"] From cacd6ca3cd7271ac4db68e819a29d4aaaeae22cc Mon Sep 17 00:00:00 2001 From: Julianus Pfeuffer Date: Wed, 21 Dec 2022 16:21:39 +0100 Subject: [PATCH 3/6] lint --- autowrap/ConversionProvider.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/autowrap/ConversionProvider.py b/autowrap/ConversionProvider.py index e9efe25..a02a166 100644 --- a/autowrap/ConversionProvider.py +++ b/autowrap/ConversionProvider.py @@ -236,7 +236,7 @@ def matches(self, cpp_type: CppType) -> bool: return not cpp_type.is_ptr def matching_python_type(self, cpp_type: CppType) -> str: - return "" #TODO can't we use int? Especially in py3 only. + return "" # TODO can't we use int? Especially in py3 only. def matching_python_type_full(self, cpp_type: CppType) -> str: return "int" @@ -388,7 +388,7 @@ def matching_python_type_full(self, cpp_type: CppType) -> str: # int from the class "__" + self.enum.name return "int" elif self.enum.cpp_decl.annotations.get("wrap-attach"): - return "_Py" + self.enum.name + return "_Py" + self.enum.name else: return self.enum.name @@ -1999,7 +1999,7 @@ class StdStringConverter(TypeConverterBase): should be used to indicate the correct typing for the automatic conversion by Cython, which is set to bytes in autowrap. """ - + def get_base_types(self) -> List[str]: return ["libcpp_string"] @@ -2088,7 +2088,7 @@ def get_base_types(self) -> List[str]: return ["libcpp_utf8_output_string"] def matching_python_type_full(self, cpp_type: CppType) -> str: - return "str" # python3 + return "str" # python3 def output_conversion( self, cpp_type: CppType, input_cpp_var: str, output_py_var: str From 5fc44bc518b4aea3537cde33ac4d70d898ff2ede Mon Sep 17 00:00:00 2001 From: Julianus Pfeuffer Date: Wed, 21 Dec 2022 16:24:23 +0100 Subject: [PATCH 4/6] lint --- autowrap/ConversionProvider.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/autowrap/ConversionProvider.py b/autowrap/ConversionProvider.py index a02a166..135ea4a 100644 --- a/autowrap/ConversionProvider.py +++ b/autowrap/ConversionProvider.py @@ -236,7 +236,7 @@ def matches(self, cpp_type: CppType) -> bool: return not cpp_type.is_ptr def matching_python_type(self, cpp_type: CppType) -> str: - return "" # TODO can't we use int? Especially in py3 only. + return "" # TODO can't we use int? Especially in py3 only. def matching_python_type_full(self, cpp_type: CppType) -> str: return "int" @@ -386,7 +386,7 @@ def matching_python_type_full(self, cpp_type: CppType) -> str: if not self.enum.scoped: # TODO add some other hint that this must be an # int from the class "__" + self.enum.name - return "int" + return "int" elif self.enum.cpp_decl.annotations.get("wrap-attach"): return "_Py" + self.enum.name else: @@ -2047,7 +2047,7 @@ def get_base_types(self) -> List[str]: return ["libcpp_utf8_string"] def matching_python_type(self, cpp_type: CppType) -> str: - return "" # TODO can we use "basestring"? + return "" # TODO can we use "basestring"? def matching_python_type_full(self, cpp_type: CppType) -> str: return "Union[bytes, str]" @@ -2088,7 +2088,7 @@ def get_base_types(self) -> List[str]: return ["libcpp_utf8_output_string"] def matching_python_type_full(self, cpp_type: CppType) -> str: - return "str" # python3 + return "str" # python3 def output_conversion( self, cpp_type: CppType, input_cpp_var: str, output_py_var: str From b8cd99dc252b1a57a74ca8e584fd642a89436f4d Mon Sep 17 00:00:00 2001 From: Julianus Pfeuffer Date: Wed, 21 Dec 2022 16:26:59 +0100 Subject: [PATCH 5/6] lint??? --- autowrap/ConversionProvider.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/autowrap/ConversionProvider.py b/autowrap/ConversionProvider.py index 135ea4a..570fb19 100644 --- a/autowrap/ConversionProvider.py +++ b/autowrap/ConversionProvider.py @@ -236,7 +236,7 @@ def matches(self, cpp_type: CppType) -> bool: return not cpp_type.is_ptr def matching_python_type(self, cpp_type: CppType) -> str: - return "" # TODO can't we use int? Especially in py3 only. + return "" # TODO can't we use int? Especially in py3 only. def matching_python_type_full(self, cpp_type: CppType) -> str: return "int" @@ -2047,7 +2047,7 @@ def get_base_types(self) -> List[str]: return ["libcpp_utf8_string"] def matching_python_type(self, cpp_type: CppType) -> str: - return "" # TODO can we use "basestring"? + return "" # TODO can we use "basestring"? def matching_python_type_full(self, cpp_type: CppType) -> str: return "Union[bytes, str]" @@ -2088,7 +2088,7 @@ def get_base_types(self) -> List[str]: return ["libcpp_utf8_output_string"] def matching_python_type_full(self, cpp_type: CppType) -> str: - return "str" # python3 + return "str" # python3 def output_conversion( self, cpp_type: CppType, input_cpp_var: str, output_py_var: str From 1b8ec998630ef462a0a8d069f64ca1bbaff0d1dd Mon Sep 17 00:00:00 2001 From: Julianus Pfeuffer Date: Wed, 21 Dec 2022 16:35:10 +0100 Subject: [PATCH 6/6] update changelog --- CHANGELOG.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index bf53e25..6c0f27c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1 +1,5 @@ autowrap 0.22.11 + +- Fixes some issues with typing support on python side +- Added a real C++ bool converter. C++ bools in a pxd will now be real booleans + on python side. Not "just" ints and will also be typed like that. \ No newline at end of file