Skip to content

Commit

Permalink
Merge pull request #175 from OpenMS/typefixes
Browse files Browse the repository at this point in the history
A few typing fixes
  • Loading branch information
jpfeuffer authored Dec 21, 2022
2 parents d4fd150 + 1b8ec99 commit ca62dc2
Show file tree
Hide file tree
Showing 3 changed files with 54 additions and 15 deletions.
4 changes: 4 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -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.
8 changes: 2 additions & 6 deletions autowrap/CodeGenerator.py
Original file line number Diff line number Diff line change
Expand Up @@ -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"
Expand Down Expand Up @@ -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):
Expand All @@ -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:")
Expand Down
57 changes: 48 additions & 9 deletions autowrap/ConversionProvider.py
Original file line number Diff line number Diff line change
Expand Up @@ -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]:
Expand All @@ -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"
Expand Down Expand Up @@ -417,11 +418,12 @@ 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:
return "_Py" + self.enum.name
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

Expand Down Expand Up @@ -2024,6 +2026,15 @@ 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"]

Expand Down Expand Up @@ -2053,20 +2064,35 @@ def output_conversion(
return "%s = <libcpp_string>%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):
Expand All @@ -2079,13 +2105,26 @@ 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]:
Expand Down

0 comments on commit ca62dc2

Please sign in to comment.