From: Vladimír Vondruš Date: Tue, 27 Aug 2019 20:09:59 +0000 (+0200) Subject: documentation/python: provide both type and type with links everywhere. X-Git-Url: https://www.chiark.greenend.org.uk/ucgi/~cjwatson/git?a=commitdiff_plain;h=95d6aa0dfada0fb97800bbb3dd3cb792459fa534;p=blog.git documentation/python: provide both type and type with links everywhere. Makes it possible for templates to use those in different cases (such as link alt text) and also unblocks the possibility to have separate docs for function overloads (in the next commits). --- diff --git a/doc/documentation/python.rst b/doc/documentation/python.rst index 193f00d7..e5facc99 100644 --- a/doc/documentation/python.rst +++ b/doc/documentation/python.rst @@ -1068,6 +1068,8 @@ Property Description :py:`enum.base` Base class from which the enum is derived. Set to :py:`None` if no base class information is available. +:py:`enum.base_link` Like :py:`enum.base`, but with + cross-linked types :py:`enum.values` List of enum values :py:`enum.has_details` If there is enough content for the full description block. [3]_ @@ -1102,6 +1104,8 @@ Property Description :py:`function.summary` Doc summary :py:`function.content` Detailed documentation, if any :py:`function.type` Function return type annotation [2]_ +:py:`function.type_link` Like :py:`function.type`, but with + cross-linked types :py:`function.params` List of function parameters. See below for details. :py:`function.has_complex_params` Set to :py:`True` if the parameter list @@ -1133,6 +1137,7 @@ Property Description =========================== =================================================== :py:`param.name` Parameter name :py:`param.type` Parameter type annotation [2]_ +:py:`param.type_link` Like :py:`param.type`, but with cross-linked types :py:`param.default` Default parameter value, if any :py:`param.kind` Parameter kind, a string equivalent to one of the `inspect.Parameter.kind `_ @@ -1155,6 +1160,8 @@ Property Description :py:`property.name` Property name :py:`property.id` Property ID [5]_ :py:`property.type` Property getter return type annotation [2]_ +:py:`property.type_link` Like :py:`property.type`, but with + cross-linked types :py:`property.summary` Doc summary :py:`property.content` Detailed documentation, if any :py:`property.is_gettable` If the property is gettable @@ -1175,6 +1182,8 @@ Property Description :py:`data.name` Data name :py:`data.id` Data ID [5]_ :py:`data.type` Data type +:py:`data.type_link` Like :py:`data.type_link`, but with + cross-linked types :py:`data.summary` Doc summary :py:`data.content` Detailed documentation, if any :py:`data.value` Data value representation diff --git a/documentation/python.py b/documentation/python.py index 7ddaec8e..d494e642 100755 --- a/documentation/python.py +++ b/documentation/python.py @@ -707,9 +707,9 @@ def parse_pybind_signature(state: State, referrer_path: List[str], signature: st # Return type (optional) if signature.startswith(' -> '): signature = signature[4:] - signature, _, return_type_link = parse_pybind_type(state, referrer_path, signature) + signature, return_type, return_type_link = parse_pybind_type(state, referrer_path, signature) else: - return_type_link = None + return_type, return_type_link = None, None # Expecting end of the signature line now, if not there, we failed if signature and signature[0] != '\n': raise SyntaxError() @@ -722,14 +722,14 @@ def parse_pybind_signature(state: State, referrer_path: List[str], signature: st summary = inspect.cleandoc(original_signature[end + 1:]).partition('\n\n')[0] else: summary = '' - return (name, summary, [('…', None, None, None)], None) + return (name, summary, [('…', None, None, None)], None, None) if len(signature) > 1 and signature[1] == '\n': summary = inspect.cleandoc(signature[2:]).partition('\n\n')[0] else: summary = '' - return (name, summary, args, return_type_link) + return (name, summary, args, return_type, return_type_link) def parse_pybind_docstring(state: State, referrer_path: List[str], doc: str) -> List[Tuple[str, str, List[Tuple[str, str, str]], str]]: name = referrer_path[-1] @@ -840,24 +840,24 @@ def get_type_hints_or_nothing(state: State, path: List[str], object) -> Dict: logging.warning("failed to dereference type hints for %s (%s), falling back to non-dereferenced", '.'.join(path), e.__class__.__name__) return {} -def extract_annotation(state: State, referrer_path: List[str], annotation) -> str: +def extract_annotation(state: State, referrer_path: List[str], annotation) -> Tuple[str, str]: # Empty annotation, as opposed to a None annotation, handled below - if annotation is inspect.Signature.empty: return None + if annotation is inspect.Signature.empty: return None, None # If dereferencing with typing.get_type_hints() failed, we might end up # with forward-referenced types being plain strings. Keep them as is, since # those are most probably an error. - if type(annotation) == str: return annotation + if type(annotation) == str: return annotation, annotation # Or the plain strings might be inside (e.g. List['Foo']), which gets # converted by Python to ForwardRef. Hammer out the actual string and again # leave it as-is, since it's most probably an error. elif isinstance(annotation, typing.ForwardRef if sys.version_info >= (3, 7) else typing._ForwardRef): - return annotation.__forward_arg__ + return annotation.__forward_arg__, annotation.__forward_arg__ # Generic type names -- use their name directly elif isinstance(annotation, typing.TypeVar): - return annotation.__name__ + return annotation.__name__, annotation.__name__ # If the annotation is from the typing module, it ... gets complicated. It # could be a "bracketed" type, in which case we want to recurse to its @@ -888,7 +888,7 @@ def extract_annotation(state: State, referrer_path: List[str], annotation) -> st # representation at least. else: # pragma: no cover logging.warning("can't inspect annotation %s for %s, falling back to a string representation", annotation, '.'.join(referrer_path)) - return str(annotation) + return str(annotation), str(annotation) # Add type links to name name_link = make_name_link(state, referrer_path, name) @@ -899,28 +899,50 @@ def extract_annotation(state: State, referrer_path: List[str], annotation) -> st # them from the return type if name == 'typing.Callable': assert len(args) >= 1 - return '{}[[{}], {}]'.format(name_link, - ', '.join([extract_annotation(state, referrer_path, i) for i in args[:-1]]), - extract_annotation(state, referrer_path, args[-1])) + + nested_types = [] + nested_type_links = [] + for i in args[:-1]: + nested_type, nested_type_link = extract_annotation(state, referrer_path, i) + nested_types += [nested_type] + nested_type_links += [nested_type_link] + nested_return_type, nested_return_type_link = extract_annotation(state, referrer_path, args[-1]) + + return ( + '{}[[{}], {}]'.format(name, ', '.join(nested_types), nested_return_type), + '{}[[{}], {}]'.format(name_link, ', '.join(nested_type_links), nested_return_type_link) + ) + else: - return '{}[{}]'.format(name_link, ', '.join([extract_annotation(state, referrer_path, i) for i in args])) - else: - return name_link + nested_types = [] + nested_type_links = [] + for i in args: + nested_type, nested_type_link = extract_annotation(state, referrer_path, i) + nested_types += [nested_type] + nested_type_links += [nested_type_link] + + return ( + '{}[{}]'.format(name, ', '.join(nested_types)), + '{}[{}]'.format(name_link, ', '.join(nested_type_links)), + ) + + else: return name, name_link # Things like (float, int) instead of Tuple[float, int] or using np.array # instead of np.ndarray. Ignore with a warning. elif not isinstance(annotation, type): logging.warning("invalid annotation %s in %s, ignoring", annotation, '.'.join(referrer_path)) - return None + return None, None # According to https://www.python.org/dev/peps/pep-0484/#using-none, # None and type(None) are equivalent. Calling extract_type() on None would # give us NoneType, which is unnecessarily long. elif annotation is type(None): - return make_name_link(state, referrer_path, 'None') + return 'None', make_name_link(state, referrer_path, 'None') # Otherwise it's a plain type. Turn it into a link. - return make_name_link(state, referrer_path, map_name_prefix(state, extract_type(annotation))) + name = extract_type(annotation) + return name, make_name_link(state, referrer_path, map_name_prefix(state, name)) def extract_module_doc(state: State, entry: Empty): assert inspect.ismodule(entry.object) @@ -958,7 +980,8 @@ def extract_enum_doc(state: State, entry: Empty): out.has_details = bool(out.content) out.base = extract_type(entry.object.__base__) - if out.base: out.base = make_name_link(state, entry.path, out.base) + if out.base: out.base_link = make_name_link(state, entry.path, out.base) + else: out.base, out.base_link = None, None for i in entry.object: value = Empty() @@ -1039,14 +1062,14 @@ def extract_function_doc(state: State, parent, entry: Empty) -> List[Any]: if state.config['PYBIND11_COMPATIBILITY'] and entry.object.__doc__ and entry.object.__doc__.startswith(entry.path[-1]): funcs = parse_pybind_docstring(state, entry.path, entry.object.__doc__) overloads = [] - for name, summary, args, type in funcs: + for name, summary, args, type, type_link in funcs: out = Empty() out.name = entry.path[-1] out.params = [] out.has_complex_params = False out.summary, out.content = extract_docs(state, state.function_docs, entry.path, summary) out.has_details = bool(out.content) - out.type = type + out.type, out.type_link = type, type_link # There's no other way to check staticmethods than to check for # self being the name of first parameter :( No support for @@ -1096,10 +1119,10 @@ def extract_function_doc(state: State, parent, entry: Empty) -> List[Any]: param.name = name # Don't include redundant type for the self argument if i == 0 and name == 'self': - param.type = None + param.type, param.type_link = None, None arg_types += [None] else: - param.type = type_link + param.type, param.type_link = type, type_link arg_types += [type] if default: # If the type is a registered enum, try to make a link to @@ -1173,16 +1196,16 @@ def extract_function_doc(state: State, parent, entry: Empty) -> List[Any]: signature = inspect.signature(entry.object) if 'return' in type_hints: - out.type = extract_annotation(state, entry.path, type_hints['return']) + out.type, out.type_link = extract_annotation(state, entry.path, type_hints['return']) else: - out.type = extract_annotation(state, entry.path, signature.return_annotation) + out.type, out.type_link = extract_annotation(state, entry.path, signature.return_annotation) for i in signature.parameters.values(): param = Empty() param.name = i.name if i.name in type_hints: - param.type = extract_annotation(state, entry.path, type_hints[i.name]) + param.type, param.type_link = extract_annotation(state, entry.path, type_hints[i.name]) else: - param.type = extract_annotation(state, entry.path, i.annotation) + param.type, param.type_link = extract_annotation(state, entry.path, i.annotation) if param.type: out.has_complex_params = True if i.default is inspect.Signature.empty: @@ -1228,7 +1251,7 @@ def extract_function_doc(state: State, parent, entry: Empty) -> List[Any]: param.name = '...' param.name_type = param.name out.params = [param] - out.type = None + out.type, out.type_link = None, None if not state.config['SEARCH_DISABLED']: result = Empty() @@ -1268,11 +1291,11 @@ def extract_property_doc(state: State, parent, entry: Empty): type_hints = get_type_hints_or_nothing(state, entry.path, parent) if out.name in type_hints: - out.type = extract_annotation(state, entry.path, type_hints[out.name]) + out.type, out.type_link = extract_annotation(state, entry.path, type_hints[out.name]) elif hasattr(parent, '__annotations__') and out.name in parent.__annotations__: - out.type = extract_annotation(state, entry.path, parent.__annotations__[out.name]) + out.type, out.type_link = extract_annotation(state, entry.path, parent.__annotations__[out.name]) else: - out.type = None + out.type, out.type_link = None, None return out @@ -1322,9 +1345,9 @@ def extract_property_doc(state: State, parent, entry: Empty): type_hints = get_type_hints_or_nothing(state, entry.path, entry.object.fget) if 'return' in type_hints: - out.type = extract_annotation(state, entry.path, type_hints['return']) + out.type, out.type_link = extract_annotation(state, entry.path, type_hints['return']) else: - out.type = extract_annotation(state, entry.path, signature.return_annotation) + out.type, out.type_link = extract_annotation(state, entry.path, signature.return_annotation) else: assert entry.object.fset signature = inspect.signature(entry.object.fset) @@ -1337,23 +1360,23 @@ def extract_property_doc(state: State, parent, entry: Empty): # version value_parameter = list(signature.parameters.values())[1] if value_parameter.name in type_hints: - out.type = extract_annotation(state, entry.path, type_hints[value_parameter.name]) + out.type, out.type_link = extract_annotation(state, entry.path, type_hints[value_parameter.name]) else: - out.type = extract_annotation(state, entry.path, value_parameter.annotation) + out.type, out.type_link = extract_annotation(state, entry.path, value_parameter.annotation) except ValueError: # pybind11 properties have the type in the docstring if state.config['PYBIND11_COMPATIBILITY']: if entry.object.fget: - out.type = parse_pybind_signature(state, entry.path, entry.object.fget.__doc__)[3] + out.type, out.type_link = parse_pybind_signature(state, entry.path, entry.object.fget.__doc__)[3:] else: assert entry.object.fset parsed_args = parse_pybind_signature(state, entry.path, entry.object.fset.__doc__)[2] # If argument parsing failed, we're screwed - if len(parsed_args) == 1: out.type = None - else: out.type = parsed_args[1][2] + if len(parsed_args) == 1: out.type, out.type_link = None, None + else: out.type, out.type_link = parsed_args[1][1:3] else: - out.type = None + out.type, out.type_link = None, None if not state.config['SEARCH_DISABLED']: result = Empty() @@ -1381,11 +1404,11 @@ def extract_data_doc(state: State, parent, entry: Empty): type_hints = get_type_hints_or_nothing(state, entry.path, parent) if out.name in type_hints: - out.type = extract_annotation(state, entry.path, type_hints[out.name]) + out.type, out.type_link = extract_annotation(state, entry.path, type_hints[out.name]) elif hasattr(parent, '__annotations__') and out.name in parent.__annotations__: - out.type = extract_annotation(state, entry.path, parent.__annotations__[out.name]) + out.type, out.type_link = extract_annotation(state, entry.path, parent.__annotations__[out.name]) else: - out.type = None + out.type, out.type_link = None, None out.value = format_value(state, entry.path, entry.object) diff --git a/documentation/templates/python/details-data.html b/documentation/templates/python/details-data.html index b386cdad..e0a47b07 100644 --- a/documentation/templates/python/details-data.html +++ b/documentation/templates/python/details-data.html @@ -1,6 +1,6 @@

- {{ prefix }}{{ data.name }}{% if data.type %}: {{ data.type }}{% endif %} + {{ prefix }}{{ data.name }}{% if data.type_link %}: {{ data.type_link }}{% endif %} {# the empty line needs to be here to prevent the lines from merging #}

diff --git a/documentation/templates/python/details-enum.html b/documentation/templates/python/details-enum.html index fe88385f..79f21cd4 100644 --- a/documentation/templates/python/details-enum.html +++ b/documentation/templates/python/details-enum.html @@ -1,6 +1,6 @@

- class {{ prefix }}{{ enum.name }}({{ enum.base }}) + class {{ prefix }}{{ enum.name }}({{ enum.base_link }})

{% if enum.summary %}

{{ enum.summary }}

diff --git a/documentation/templates/python/details-function.html b/documentation/templates/python/details-function.html index 15068646..f48e1818 100644 --- a/documentation/templates/python/details-function.html +++ b/documentation/templates/python/details-function.html @@ -1,7 +1,7 @@

{% set j = joiner('\n ' if function.has_complex_params else ' ') %} - def {{ prefix }}{{ function.name }}({% for param in function.params %}{% if loop.index0 %}{% if function.params[loop.index0 - 1].kind == 'POSITIONAL_OR_KEYWORD' and param.kind == 'KEYWORD_ONLY' %}, *,{% else %},{% endif %}{% endif %}{{ j() }}{% if param.kind == 'VAR_POSITIONAL' %}*{% elif param.kind == 'VAR_KEYWORD' %}**{% endif %}{{ param.name }}{% if param.type %}: {{ param.type }}{% endif %}{% if param.default %} = {{ param.default }}{% endif %}{% if param.kind == 'POSITIONAL_ONLY' and (loop.last or function.params[loop.index0 + 1].kind != 'POSITIONAL_ONLY') %}, /{% endif %}{% endfor %}){% if function.type %} -> {{ function.type }}{% endif %}{% if function.is_classmethod %} classmethod{% elif function.is_staticmethod %} staticmethod{% endif %} + def {{ prefix }}{{ function.name }}({% for param in function.params %}{% if loop.index0 %}{% if function.params[loop.index0 - 1].kind == 'POSITIONAL_OR_KEYWORD' and param.kind == 'KEYWORD_ONLY' %}, *,{% else %},{% endif %}{% endif %}{{ j() }}{% if param.kind == 'VAR_POSITIONAL' %}*{% elif param.kind == 'VAR_KEYWORD' %}**{% endif %}{{ param.name }}{% if param.type_link %}: {{ param.type_link }}{% endif %}{% if param.default %} = {{ param.default }}{% endif %}{% if param.kind == 'POSITIONAL_ONLY' and (loop.last or function.params[loop.index0 + 1].kind != 'POSITIONAL_ONLY') %}, /{% endif %}{% endfor %}){% if function.type_link %} -> {{ function.type_link }}{% endif %}{% if function.is_classmethod %} classmethod{% elif function.is_staticmethod %} staticmethod{% endif %}

{% if function.summary %}

{{ function.summary }}

diff --git a/documentation/templates/python/details-property.html b/documentation/templates/python/details-property.html index 5f2159ea..0b72f950 100644 --- a/documentation/templates/python/details-property.html +++ b/documentation/templates/python/details-property.html @@ -1,6 +1,6 @@

- {{ prefix }}{{ property.name }}{% if property.type %}: {{ property.type }}{% endif %} {% if property.is_gettable and property.is_settable %}get set{% elif property.is_gettable %}get{% else %}set{% endif %}{% if property.is_deletable %} del{% endif %} + {{ prefix }}{{ property.name }}{% if property.type_link %}: {{ property.type_link }}{% endif %} {% if property.is_gettable and property.is_settable %}get set{% elif property.is_gettable %}get{% else %}set{% endif %}{% if property.is_deletable %} del{% endif %}

{% if property.summary %}

{{ property.summary }}

diff --git a/documentation/templates/python/entry-data.html b/documentation/templates/python/entry-data.html index e54faa2f..49227c7a 100644 --- a/documentation/templates/python/entry-data.html +++ b/documentation/templates/python/entry-data.html @@ -1,5 +1,5 @@ - {{ data.name }}{% if data.type %}: {{ data.type }}{% endif %}{% if data.value %} = {{ data.value }}{% endif %} + {{ data.name }}{% if data.type_link %}: {{ data.type_link }}{% endif %}{% if data.value %} = {{ data.value }}{% endif %} {# This has to be here to avoid the newline being eaten #} diff --git a/documentation/templates/python/entry-enum.html b/documentation/templates/python/entry-enum.html index 22e54bc8..12f827fd 100644 --- a/documentation/templates/python/entry-enum.html +++ b/documentation/templates/python/entry-enum.html @@ -1,5 +1,5 @@ {% set j = joiner('\n ') %} - class {{ enum.name }}{% if enum.base %}({{ enum.base }}){% endif %}: {% for value in enum.values %}{{ j() }}{{ value.name }}{% if value.value is not none %} = {{ value.value }}{% endif %}{% endfor %} + class {{ enum.name }}{% if enum.base_link %}({{ enum.base_link }}){% endif %}: {% for value in enum.values %}{{ j() }}{{ value.name }}{% if value.value is not none %} = {{ value.value }}{% endif %}{% endfor %}
{{ enum.summary }}
diff --git a/documentation/templates/python/entry-function.html b/documentation/templates/python/entry-function.html index 2cd7c8b1..96493ecd 100644 --- a/documentation/templates/python/entry-function.html +++ b/documentation/templates/python/entry-function.html @@ -1,5 +1,5 @@ {% set j = joiner('\n ' if function.has_complex_params else ' ') %} - def {{ function.name }}({% for param in function.params %}{% if loop.index0 %}{% if function.params[loop.index0 - 1].kind == 'POSITIONAL_OR_KEYWORD' and param.kind == 'KEYWORD_ONLY' %}, *,{% else %},{% endif %}{% endif %}{{ j() }}{% if param.kind == 'VAR_POSITIONAL' %}*{% elif param.kind == 'VAR_KEYWORD' %}**{% endif %}{{ param.name }}{% if param.type %}: {{ param.type }}{% endif %}{% if param.default %} = {{ param.default }}{% endif %}{% if param.kind == 'POSITIONAL_ONLY' and (loop.last or function.params[loop.index0 + 1].kind != 'POSITIONAL_ONLY') %}, /{% endif %}{% endfor %}){% if function.type %} -> {{ function.type }}{% endif %} + def {{ function.name }}({% for param in function.params %}{% if loop.index0 %}{% if function.params[loop.index0 - 1].kind == 'POSITIONAL_OR_KEYWORD' and param.kind == 'KEYWORD_ONLY' %}, *,{% else %},{% endif %}{% endif %}{{ j() }}{% if param.kind == 'VAR_POSITIONAL' %}*{% elif param.kind == 'VAR_KEYWORD' %}**{% endif %}{{ param.name }}{% if param.type_link %}: {{ param.type_link }}{% endif %}{% if param.default %} = {{ param.default }}{% endif %}{% if param.kind == 'POSITIONAL_ONLY' and (loop.last or function.params[loop.index0 + 1].kind != 'POSITIONAL_ONLY') %}, /{% endif %}{% endfor %}){% if function.type_link %} -> {{ function.type_link }}{% endif %}
{{ function.summary }}
diff --git a/documentation/templates/python/entry-property.html b/documentation/templates/python/entry-property.html index 6da7ba3e..a65e2fb3 100644 --- a/documentation/templates/python/entry-property.html +++ b/documentation/templates/python/entry-property.html @@ -1,4 +1,4 @@ - {{ property.name }}{% if property.type %}: {{ property.type }}{% endif %} {% if property.is_gettable and property.is_settable %}get set{% elif property.is_gettable %}get{% else %}set{% endif %}{% if property.is_deletable %} del{% endif %} + {{ property.name }}{% if property.type_link %}: {{ property.type_link }}{% endif %} {% if property.is_gettable and property.is_settable %}get set{% elif property.is_gettable %}get{% else %}set{% endif %}{% if property.is_deletable %} del{% endif %}
{{ property.summary }}
diff --git a/documentation/test_python/test_pybind.py b/documentation/test_python/test_pybind.py index 22c52101..6ce25359 100644 --- a/documentation/test_python/test_pybind.py +++ b/documentation/test_python/test_pybind.py @@ -41,7 +41,7 @@ class Signature(unittest.TestCase): ('foo', '', [ ('a', 'int', 'int', None), ('a2', 'module.Thing', 'module.Thing', None), - ], 'module.Thing3')) + ], 'module.Thing3', 'module.Thing3')) def test_newline(self): self.assertEqual(parse_pybind_signature(self.state, [], @@ -49,7 +49,7 @@ class Signature(unittest.TestCase): ('foo', '', [ ('a', 'int', 'int', None), ('a2', 'module.Thing', 'module.Thing', None), - ], 'module.Thing3')) + ], 'module.Thing3', 'module.Thing3')) def test_docs(self): self.assertEqual(parse_pybind_signature(self.state, [], @@ -57,26 +57,26 @@ class Signature(unittest.TestCase): ('foo', 'Docs here!!', [ ('a', 'int', 'int', None), ('a2', 'module.Thing', 'module.Thing', None), - ], 'module.Thing3')) + ], 'module.Thing3', 'module.Thing3')) def test_no_args(self): self.assertEqual(parse_pybind_signature(self.state, [], 'thingy() -> str'), - ('thingy', '', [], 'str')) + ('thingy', '', [], 'str', 'str')) def test_no_return(self): self.assertEqual(parse_pybind_signature(self.state, [], '__init__(self: module.Thing)'), ('__init__', '', [ ('self', 'module.Thing', 'module.Thing', None), - ], None)) + ], None, None)) def test_none_return(self): self.assertEqual(parse_pybind_signature(self.state, [], '__init__(self: module.Thing) -> None'), ('__init__', '', [ ('self', 'module.Thing', 'module.Thing', None), - ], 'None')) + ], 'None', 'None')) def test_no_arg_types(self): self.assertEqual(parse_pybind_signature(self.state, [], @@ -84,7 +84,7 @@ class Signature(unittest.TestCase): ('thingy', '', [ ('self', None, None, None), ('the_other_thing', None, None, None), - ], None)) + ], None, None)) def test_none_arg_types(self): self.assertEqual(parse_pybind_signature(self.state, [], @@ -92,7 +92,7 @@ class Signature(unittest.TestCase): ('thingy', '', [ ('self', None, None, None), ('the_other_thing', 'typing.Callable[[], None]', 'typing.Callable[[], None]', None), - ], None)) + ], None, None)) def test_square_brackets(self): self.assertEqual(parse_pybind_signature(self.state, [], @@ -100,7 +100,7 @@ class Signature(unittest.TestCase): ('foo', '', [ ('a', 'typing.Tuple[int, str]', 'typing.Tuple[int, str]', None), ('no_really', 'str', 'str', None), - ], 'typing.List[str]')) + ], 'typing.List[str]', 'typing.List[str]')) def test_nested_square_brackets(self): self.assertEqual(parse_pybind_signature(self.state, [], @@ -108,7 +108,7 @@ class Signature(unittest.TestCase): ('foo', '', [ ('a', 'typing.Tuple[int, typing.List[typing.Tuple[int, int]]]', 'typing.Tuple[int, typing.List[typing.Tuple[int, int]]]', None), ('another', 'float', 'float', None), - ], 'typing.Union[str, None]')) + ], 'typing.Union[str, None]', 'typing.Union[str, None]')) def test_callable(self): self.assertEqual(parse_pybind_signature(self.state, [], @@ -116,7 +116,7 @@ class Signature(unittest.TestCase): ('foo', '', [ ('a', 'typing.Callable[[int, typing.Tuple[int, int]], float]', 'typing.Callable[[int, typing.Tuple[int, int]], float]', None), ('another', 'float', 'float', None), - ], None)) + ], None, None)) def test_kwargs(self): self.assertEqual(parse_pybind_signature(self.state, [], @@ -124,7 +124,7 @@ class Signature(unittest.TestCase): ('foo', '', [ ('*args', None, None, None), ('**kwargs', None, None, None), - ], None)) + ], None, None)) # https://github.com/pybind/pybind11/commit/0826b3c10607c8d96e1d89dc819c33af3799a7b8, # released in 2.3.0. We want to support both, so test both. @@ -134,7 +134,7 @@ class Signature(unittest.TestCase): ('foo', '', [ ('a', 'float', 'float', '1.0'), ('b', 'str', 'str', '\'hello\''), - ], None)) + ], None, None)) def test_default_values_pybind23(self): self.assertEqual(parse_pybind_signature(self.state, [], @@ -142,42 +142,42 @@ class Signature(unittest.TestCase): ('foo', '', [ ('a', 'float', 'float', '1.0'), ('b', 'str', 'str', '\'hello\''), - ], None)) + ], None, None)) def test_crazy_stuff(self): self.assertEqual(parse_pybind_signature(self.state, [], 'foo(a: int, b: Math::Vector<4, UnsignedInt>)'), - ('foo', '', [('…', None, None, None)], None)) + ('foo', '', [('…', None, None, None)], None, None)) def test_crazy_stuff_nested(self): self.assertEqual(parse_pybind_signature(self.state, [], 'foo(a: int, b: List[Math::Vector<4, UnsignedInt>])'), - ('foo', '', [('…', None, None, None)], None)) + ('foo', '', [('…', None, None, None)], None, None)) def test_crazy_stuff_docs(self): self.assertEqual(parse_pybind_signature(self.state, [], 'foo(a: int, b: Math::Vector<4, UnsignedInt>)\n\nThis is text!!'), - ('foo', 'This is text!!', [('…', None, None, None)], None)) + ('foo', 'This is text!!', [('…', None, None, None)], None, None)) def test_crazy_return(self): self.assertEqual(parse_pybind_signature(self.state, [], 'foo(a: int) -> Math::Vector<4, UnsignedInt>'), - ('foo', '', [('…', None, None, None)], None)) + ('foo', '', [('…', None, None, None)], None, None)) def test_crazy_return_nested(self): self.assertEqual(parse_pybind_signature(self.state, [], 'foo(a: int) -> List[Math::Vector<4, UnsignedInt>]'), - ('foo', '', [('…', None, None, None)], None)) + ('foo', '', [('…', None, None, None)], None, None)) def test_crazy_return_docs(self): self.assertEqual(parse_pybind_signature(self.state, [], 'foo(a: int) -> Math::Vector<4, UnsignedInt>\n\nThis returns!'), - ('foo', 'This returns!', [('…', None, None, None)], None)) + ('foo', 'This returns!', [('…', None, None, None)], None, None)) def test_no_name(self): self.assertEqual(parse_pybind_signature(self.state, [], '(arg0: MyClass) -> float'), - ('', '', [('arg0', 'MyClass', 'MyClass', None)], 'float')) + ('', '', [('arg0', 'MyClass', 'MyClass', None)], 'float', 'float')) def test_module_mapping(self): state = self.state @@ -186,7 +186,7 @@ class Signature(unittest.TestCase): self.assertEqual(parse_pybind_signature(state, [], 'foo(a: module._module.Foo, b: typing.Tuple[int, module._module.Bar]) -> module._module.Baz'), ('foo', '', [('a', 'module.Foo', 'module.Foo', None), - ('b', 'typing.Tuple[int, module.Bar]', 'typing.Tuple[int, module.Bar]', None)], 'module.Baz')) + ('b', 'typing.Tuple[int, module.Bar]', 'typing.Tuple[int, module.Bar]', None)], 'module.Baz', 'module.Baz')) class Signatures(BaseInspectTestCase): def test_positional_args(self):