chiark / gitweb /
documentation/python: provide both type and type with links everywhere.
authorVladimír Vondruš <mosra@centrum.cz>
Tue, 27 Aug 2019 20:09:59 +0000 (22:09 +0200)
committerVladimír Vondruš <mosra@centrum.cz>
Wed, 28 Aug 2019 20:34:06 +0000 (22:34 +0200)
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).

doc/documentation/python.rst
documentation/python.py
documentation/templates/python/details-data.html
documentation/templates/python/details-enum.html
documentation/templates/python/details-function.html
documentation/templates/python/details-property.html
documentation/templates/python/entry-data.html
documentation/templates/python/entry-enum.html
documentation/templates/python/entry-function.html
documentation/templates/python/entry-property.html
documentation/test_python/test_pybind.py

index 193f00d7dce64e41d8066751e955ad7af319d1de..e5facc99e10ae1e7936689d5b3d5c82b1f3bbee6 100644 (file)
@@ -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 <https://docs.python.org/3/library/inspect.html#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
index 7ddaec8e10dad188c7e14d4c390a29a5d9071eb2..d494e642b7917b590b27e224cb783f767322e9e7 100755 (executable)
@@ -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)
 
index b386cdad2ab1fe1f110c8c4178289ece96d1d535..e0a47b0709f600538ca204043b605e6012489611 100644 (file)
@@ -1,6 +1,6 @@
           <section class="m-doc-details" id="{{ data.id }}"><div>
             <h3>
-              {{ prefix }}<a href="#{{ data.id }}" class="m-doc-self">{{ data.name }}</a>{% if data.type %}: {{ data.type }}{% endif %}
+              {{ prefix }}<a href="#{{ data.id }}" class="m-doc-self">{{ data.name }}</a>{% if data.type_link %}: {{ data.type_link }}{% endif %}
               {# the empty line needs to be here to prevent the lines from merging #}
 
             </h3>
index fe88385f15663a22d2d1bf071e63d7b4775ac34d..79f21cd41410d7bd8c32d8c7841d36b5fdd7c627 100644 (file)
@@ -1,6 +1,6 @@
           <section class="m-doc-details" id="{{ enum.id }}"><div>
             <h3>
-              class {{ prefix }}<a href="#{{ enum.id }}" class="m-doc-self">{{ enum.name }}</a>({{ enum.base }})
+              class {{ prefix }}<a href="#{{ enum.id }}" class="m-doc-self">{{ enum.name }}</a>({{ enum.base_link }})
             </h3>
             {% if enum.summary %}
             <p>{{ enum.summary }}</p>
index 150686462262d46bec9f4a5b620984d8c024d224..f48e1818d5b9b58dfca56536c7da90e9051a1f83 100644 (file)
@@ -1,7 +1,7 @@
           <section class="m-doc-details" id="{{ function.id }}"><div>
             <h3>
               {% set j = joiner('\n              ' if function.has_complex_params else ' ') %}
-              <span class="m-doc-wrap-bumper">def {{ prefix }}</span><span class="m-doc-wrap"><span class="m-doc-wrap-bumper"><a href="#{{ function.id }}" class="m-doc-self">{{ function.name }}</a>(</span><span class="m-doc-wrap">{% for param in function.params %}{% if loop.index0 %}{% if function.params[loop.index0 - 1].kind == 'POSITIONAL_OR_KEYWORD' and param.kind == 'KEYWORD_ONLY' %},<span class="m-text m-dim"> *,</span>{% 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') %}<span class="m-text m-dim">, /</span>{% endif %}{% endfor %}){% if function.type %} -&gt; {{ function.type }}{% endif %}{% if function.is_classmethod %} <span class="m-label m-success">classmethod</span>{% elif function.is_staticmethod %} <span class="m-label m-info">staticmethod</span>{% endif %}</span></span>
+              <span class="m-doc-wrap-bumper">def {{ prefix }}</span><span class="m-doc-wrap"><span class="m-doc-wrap-bumper"><a href="#{{ function.id }}" class="m-doc-self">{{ function.name }}</a>(</span><span class="m-doc-wrap">{% for param in function.params %}{% if loop.index0 %}{% if function.params[loop.index0 - 1].kind == 'POSITIONAL_OR_KEYWORD' and param.kind == 'KEYWORD_ONLY' %},<span class="m-text m-dim"> *,</span>{% 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') %}<span class="m-text m-dim">, /</span>{% endif %}{% endfor %}){% if function.type_link %} -&gt; {{ function.type_link }}{% endif %}{% if function.is_classmethod %} <span class="m-label m-success">classmethod</span>{% elif function.is_staticmethod %} <span class="m-label m-info">staticmethod</span>{% endif %}</span></span>
             </h3>
             {% if function.summary %}
             <p>{{ function.summary }}</p>
index 5f2159ea17444af00e39ee66a94673124ffac219..0b72f950ce927acfd4bc445d02f652a5c60e4462 100644 (file)
@@ -1,6 +1,6 @@
           <section class="m-doc-details" id="{{ property.id }}"><div>
             <h3>
-              {{ prefix }}<a href="#{{ property.id }}" class="m-doc-self">{{ property.name }}</a>{% if property.type %}: {{ property.type }}{% endif %} <span class="m-label m-flat {% if property.is_gettable and property.is_settable %}m-success{% elif property.is_gettable %}m-warning{% else %}m-danger{% 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 %}</span>
+              {{ prefix }}<a href="#{{ property.id }}" class="m-doc-self">{{ property.name }}</a>{% if property.type_link %}: {{ property.type_link }}{% endif %} <span class="m-label m-flat {% if property.is_gettable and property.is_settable %}m-success{% elif property.is_gettable %}m-warning{% else %}m-danger{% 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 %}</span>
             </h3>
             {% if property.summary %}
             <p>{{ property.summary }}</p>
index e54faa2f6bb3f1170dee6217fefbb6a6d199d73b..49227c7ac4cd94d7169a02866881686dee0dda70 100644 (file)
@@ -1,5 +1,5 @@
             <dt{% if not data.has_details %} id="{{ data.id }}"{% endif %}>
-              <a href="#{{ data.id }}" class="m-doc{% if not data.has_details %}-self{% endif %}">{{ data.name }}</a>{% if data.type %}: {{ data.type }}{% endif %}{% if data.value %} = {{ data.value }}{% endif %}
+              <a href="#{{ data.id }}" class="m-doc{% if not data.has_details %}-self{% endif %}">{{ data.name }}</a>{% 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 #}
 
             </dt>
index 22e54bc8c9d2b4816ad6d1cea6f33f52066a0b29..12f827fdc6459ebee7da87edec33e60565725778 100644 (file)
@@ -1,5 +1,5 @@
             <dt{% if not enum.has_details %} id="{{ enum.id }}"{% endif %}>
               {% set j = joiner('\n              ') %}
-              <span class="m-doc-wrap-bumper">class <a href="#{{ enum.id }}" class="m-doc{% if not enum.has_details %}-self{% endif %}">{{ enum.name }}</a>{% if enum.base %}({{ enum.base }}){% endif %}: </span><span class="m-doc-wrap">{% for value in enum.values %}{{ j() }}<a href="#{{ value.id }}" {% if enum.has_details %}class="m-doc"{% else %}class="m-doc-self" id="{{ value.id }}"{% endif %}>{{ value.name }}</a>{% if value.value is not none %} = {{ value.value }}{% endif %}{% endfor %}</span>
+              <span class="m-doc-wrap-bumper">class <a href="#{{ enum.id }}" class="m-doc{% if not enum.has_details %}-self{% endif %}">{{ enum.name }}</a>{% if enum.base_link %}({{ enum.base_link }}){% endif %}: </span><span class="m-doc-wrap">{% for value in enum.values %}{{ j() }}<a href="#{{ value.id }}" {% if enum.has_details %}class="m-doc"{% else %}class="m-doc-self" id="{{ value.id }}"{% endif %}>{{ value.name }}</a>{% if value.value is not none %} = {{ value.value }}{% endif %}{% endfor %}</span>
             </dt>
             <dd>{{ enum.summary }}</dd>
index 2cd7c8b124f6471282e31240b79606b3f25c9eaf..96493ecd80cb6cfe28f0733f8017258f10c55b44 100644 (file)
@@ -1,5 +1,5 @@
             <dt{% if not function.has_details %} id="{{ function.id }}"{% endif %}>
               {% set j = joiner('\n              ' if function.has_complex_params else ' ') %}
-              <span class="m-doc-wrap-bumper">def <a href="#{{ function.id }}" class="m-doc{% if not function.has_details %}-self{% endif %}">{{ function.name }}</a>(</span><span class="m-doc-wrap">{% for param in function.params %}{% if loop.index0 %}{% if function.params[loop.index0 - 1].kind == 'POSITIONAL_OR_KEYWORD' and param.kind == 'KEYWORD_ONLY' %},<span class="m-text m-dim"> *,</span>{% 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') %}<span class="m-text m-dim">, /</span>{% endif %}{% endfor %}){% if function.type %} -&gt; {{ function.type }}{% endif %}</span>
+              <span class="m-doc-wrap-bumper">def <a href="#{{ function.id }}" class="m-doc{% if not function.has_details %}-self{% endif %}">{{ function.name }}</a>(</span><span class="m-doc-wrap">{% for param in function.params %}{% if loop.index0 %}{% if function.params[loop.index0 - 1].kind == 'POSITIONAL_OR_KEYWORD' and param.kind == 'KEYWORD_ONLY' %},<span class="m-text m-dim"> *,</span>{% 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') %}<span class="m-text m-dim">, /</span>{% endif %}{% endfor %}){% if function.type_link %} -&gt; {{ function.type_link }}{% endif %}</span>
             </dt>
             <dd>{{ function.summary }}</dd>
index 6da7ba3e57a7e822d257287c39e6aae118ca08ed..a65e2fb3cd367c864a6188c9c81ae6e0bfc23058 100644 (file)
@@ -1,4 +1,4 @@
             <dt{% if not property.has_details %} id="{{ property.id }}"{% endif %}>
-              <a href="#{{ property.id }}" class="m-doc{% if not property.has_details %}-self{% endif %}">{{ property.name }}</a>{% if property.type %}: {{ property.type }}{% endif %} <span class="m-label m-flat {% if property.is_gettable and property.is_settable %}m-success{% elif property.is_gettable %}m-warning{% else %}m-danger{% 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 %}</span>
+              <a href="#{{ property.id }}" class="m-doc{% if not property.has_details %}-self{% endif %}">{{ property.name }}</a>{% if property.type_link %}: {{ property.type_link }}{% endif %} <span class="m-label m-flat {% if property.is_gettable and property.is_settable %}m-success{% elif property.is_gettable %}m-warning{% else %}m-danger{% 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 %}</span>
             </dt>
             <dd>{{ property.summary }}</dd>
index 22c52101bfdb7cac46269dbc7a64010e4290279b..6ce2535973b2a397a900185d9fd5425641b9b181 100644 (file)
@@ -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):