From 7645c6a9aa704acab0a6c913fd83bb5d96eb51f8 Mon Sep 17 00:00:00 2001 From: =?utf8?q?Vladim=C3=ADr=20Vondru=C5=A1?= Date: Sat, 24 Aug 2019 09:50:22 +0200 Subject: [PATCH] documentation/python: correctly link all type annotations as well. --- documentation/python.py | 16 ++++++++----- .../inspect_type_links.second.Foo.html | 4 ++-- .../inspect_type_links.second.FooSlots.html | 2 +- ...ect_type_links.second.FooSlotsInvalid.html | 2 +- .../inspect_type_links.second.html | 24 +++++++++++++------ .../inspect_type_links/second.py | 10 +++++++- .../pybind_type_links.Foo.html | 2 +- .../pybind_type_links/pybind_type_links.html | 4 ++-- documentation/test_python/test_pybind.py | 5 +++- 9 files changed, 47 insertions(+), 22 deletions(-) diff --git a/documentation/python.py b/documentation/python.py index c57d0eac..dabfc69a 100755 --- a/documentation/python.py +++ b/documentation/python.py @@ -615,9 +615,10 @@ def parse_pybind_type(state: State, referrer_path: List[str], signature: str) -> input_type = match.group(0) signature = signature[len(input_type):] # Prefix types with the typing module to be consistent with pure - # Python annotations + # Python annotations and allow them to be linked to if input_type in ['Callable', 'Dict', 'List', 'Optional', 'Set', 'Tuple', 'Union']: - type = type_link = 'typing.' + input_type + type = 'typing.' + input_type + type_link = make_name_link(state, referrer_path, type) else: type = map_name_prefix(state, input_type) type_link = make_name_link(state, referrer_path, type) @@ -889,19 +890,22 @@ def extract_annotation(state: State, referrer_path: List[str], annotation) -> st logging.warning("can't inspect annotation %s for %s, falling back to a string representation", annotation, '.'.join(referrer_path)) return str(annotation) + # Add type links to name + name_link = make_name_link(state, referrer_path, name) + # Arguments of generic types, recurse inside if args: # For Callable, put the arguments into a nested list to separate # them from the return type if name == 'typing.Callable': assert len(args) >= 1 - return '{}[[{}], {}]'.format(name, + return '{}[[{}], {}]'.format(name_link, ', '.join([extract_annotation(state, referrer_path, i) for i in args[:-1]]), extract_annotation(state, referrer_path, args[-1])) else: - return '{}[{}]'.format(name, ', '.join([extract_annotation(state, referrer_path, i) for i in args])) + return '{}[{}]'.format(name_link, ', '.join([extract_annotation(state, referrer_path, i) for i in args])) else: - return name + return name_link # Things like (float, int) instead of Tuple[float, int] or using np.array # instead of np.ndarray. Ignore with a warning. @@ -913,7 +917,7 @@ def extract_annotation(state: State, referrer_path: List[str], annotation) -> st # 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 'None' + return 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))) diff --git a/documentation/test_python/inspect_type_links/inspect_type_links.second.Foo.html b/documentation/test_python/inspect_type_links/inspect_type_links.second.Foo.html index 7629eb46..720d2f83 100644 --- a/documentation/test_python/inspect_type_links/inspect_type_links.second.Foo.html +++ b/documentation/test_python/inspect_type_links/inspect_type_links.second.Foo.html @@ -47,7 +47,7 @@
A property
- type_property_string_nested: typing.Tuple[Foo, typing.List[Enum], typing.Any] get + type_property_string_nested: typing.Tuple[Foo, typing.List[Enum], typing.Any] get
A property
@@ -59,7 +59,7 @@
A writeonly property with invalid string type
- type_property_writeonly_string_nested: typing.Tuple[Foo, typing.List[Enum], typing.Any] set + type_property_writeonly_string_nested: typing.Tuple[Foo, typing.List[Enum], typing.Any] set
A writeonly property with a string nested type
diff --git a/documentation/test_python/inspect_type_links/inspect_type_links.second.FooSlots.html b/documentation/test_python/inspect_type_links/inspect_type_links.second.FooSlots.html index 0899d4cd..21ed4833 100644 --- a/documentation/test_python/inspect_type_links/inspect_type_links.second.FooSlots.html +++ b/documentation/test_python/inspect_type_links/inspect_type_links.second.FooSlots.html @@ -42,7 +42,7 @@
- type_slot_string_nested: typing.Tuple[Foo, typing.List[Enum], typing.Any] get set del + type_slot_string_nested: typing.Tuple[Foo, typing.List[Enum], typing.Any] get set del
diff --git a/documentation/test_python/inspect_type_links/inspect_type_links.second.FooSlotsInvalid.html b/documentation/test_python/inspect_type_links/inspect_type_links.second.FooSlotsInvalid.html index 0ee0df12..60c9e2be 100644 --- a/documentation/test_python/inspect_type_links/inspect_type_links.second.FooSlotsInvalid.html +++ b/documentation/test_python/inspect_type_links/inspect_type_links.second.FooSlotsInvalid.html @@ -38,7 +38,7 @@

Properties

- type_slot_string_invalid: typing.List[FooBar] get set del + type_slot_string_invalid: typing.List[FooBar] get set del
diff --git a/documentation/test_python/inspect_type_links/inspect_type_links.second.html b/documentation/test_python/inspect_type_links/inspect_type_links.second.html index 350f9bde..e9933e37 100644 --- a/documentation/test_python/inspect_type_links/inspect_type_links.second.html +++ b/documentation/test_python/inspect_type_links/inspect_type_links.second.html @@ -61,13 +61,23 @@

Functions

+
+ def returns_none(a: typing.Callable[[], None]) -> None +
+
In order to disambiguate between a missing return annotation and an +annotated none, the None return annotation is kept, converted from NoneType +to None
+
+ def returns_none_type(a: typing.Callable[[], None]) -> None +
+
And it should behave the same when using None or type(None)
Annotation linking to a type that's a part of INPUT_MODULES but not known
def type_default_values(a: Enum = Enum.SECOND, - b: typing.Tuple[Foo] = (<class 'inspect_type_links.second.Foo'>,), + b: typing.Tuple[Foo] = (<class 'inspect_type_links.second.Foo'>,), c: Foo = …)
A function with default values, one enum, one tuple and the third nonrepresentable (yes, the tuple looks ugly)
@@ -76,15 +86,15 @@
Function referencing an enum
- def type_nested(a: typing.Tuple[Foo, typing.List[Enum], typing.Any]) + def type_nested(a: typing.Tuple[Foo, typing.List[Enum], typing.Any])
A function with nested type annotation
- def type_nested_string(a: typing.Tuple[Foo, typing.List[Enum], typing.Any]) + def type_nested_string(a: typing.Tuple[Foo, typing.List[Enum], typing.Any])
A function with nested string type annotation
- def type_nested_string_invalid(a: typing.Tuple[FooBar, List[Enum], Any]) + def type_nested_string_invalid(a: typing.Tuple[FooBar, List[Enum], Any])
A function with invalid nested string type annotation
@@ -96,7 +106,7 @@
A function with invalid return string type annotation
- def type_return_string_nested() -> typing.Tuple[Foo, typing.List[Enum], typing.Any] + def type_return_string_nested() -> typing.Tuple[Foo, typing.List[Enum], typing.Any]
A function with a string nested return type
@@ -108,7 +118,7 @@
A function with invalid string type annotation
- def type_string_nested(a: typing.Tuple[Foo, typing.List[Enum], typing.Any]) + def type_string_nested(a: typing.Tuple[Foo, typing.List[Enum], typing.Any])
A function with string nested type annotation
@@ -125,7 +135,7 @@
- TYPE_DATA_STRING_NESTED: typing.Tuple[Foo, typing.List[Enum], typing.Any] = {} + TYPE_DATA_STRING_NESTED: typing.Tuple[Foo, typing.List[Enum], typing.Any] = {}
diff --git a/documentation/test_python/inspect_type_links/inspect_type_links/second.py b/documentation/test_python/inspect_type_links/inspect_type_links/second.py index e4f00baf..363d2b39 100644 --- a/documentation/test_python/inspect_type_links/inspect_type_links/second.py +++ b/documentation/test_python/inspect_type_links/inspect_type_links/second.py @@ -1,6 +1,6 @@ """Second module""" -from typing import Tuple, List, Any +from typing import Tuple, List, Any, Callable import enum @@ -95,6 +95,14 @@ def type_cant_link(a: _Hidden): def type_default_values(a: Enum = Enum.SECOND, b: Tuple[Foo] = (Foo, ), c: Foo = Foo()): """A function with default values, one enum, one tuple and the third nonrepresentable (yes, the tuple looks ugly)""" +def returns_none(a: Callable[[], None]) -> None: + """In order to disambiguate between a missing return annotation and an + annotated none, the None return annotation is kept, converted from NoneType + to None""" + +def returns_none_type(a: Callable[[], type(None)]) -> type(None): + """And it should behave the same when using None or type(None)""" + TYPE_DATA: Foo = Foo() TYPE_DATA_STRING_NESTED: 'Tuple[Foo, List[Enum], Any]' = {} diff --git a/documentation/test_python/pybind_type_links/pybind_type_links.Foo.html b/documentation/test_python/pybind_type_links/pybind_type_links.Foo.html index a8064058..e08ebe78 100644 --- a/documentation/test_python/pybind_type_links/pybind_type_links.Foo.html +++ b/documentation/test_python/pybind_type_links/pybind_type_links.Foo.html @@ -41,7 +41,7 @@
def __init__(self, - arg0: Enum, /) -> None + arg0: Enum, /) -> None
Constructor
diff --git a/documentation/test_python/pybind_type_links/pybind_type_links.html b/documentation/test_python/pybind_type_links/pybind_type_links.html index 03428c30..c65bdb31 100644 --- a/documentation/test_python/pybind_type_links/pybind_type_links.html +++ b/documentation/test_python/pybind_type_links/pybind_type_links.html @@ -58,11 +58,11 @@

Functions

- def type_enum(value: Enum = Enum.SECOND) -> None + def type_enum(value: Enum = Enum.SECOND) -> None
A function taking an enum
- def type_nested(arg0: typing.Tuple[Foo, typing.List[Enum]], /) -> None + def type_nested(arg0: typing.Tuple[Foo, typing.List[Enum]], /) -> None
A function with nested type annotation
diff --git a/documentation/test_python/test_pybind.py b/documentation/test_python/test_pybind.py index 0d40947f..22c52101 100644 --- a/documentation/test_python/test_pybind.py +++ b/documentation/test_python/test_pybind.py @@ -268,8 +268,11 @@ class TypeLinks(BaseInspectTestCase): pybind_type_links.Foo.__annotations__ = {} pybind_type_links.Foo.__annotations__['TYPE_DATA'] = pybind_type_links.Enum self.run_python({ + 'PLUGINS': ['m.sphinx'], 'INPUT_MODULES': [pybind_type_links], - 'PYBIND11_COMPATIBILITY': True + 'PYBIND11_COMPATIBILITY': True, + 'M_SPHINX_INVENTORIES': [ + ('../../../doc/documentation/python.inv', 'https://docs.python.org/3/', [], ['m-doc-external'])] }) self.assertEqual(*self.actual_expected_contents('pybind_type_links.html')) self.assertEqual(*self.actual_expected_contents('pybind_type_links.Foo.html')) -- 2.30.2