From: Vladimír Vondruš Date: Wed, 10 Jul 2019 14:08:32 +0000 (+0200) Subject: documentation/python: format also anchors for class/module members. X-Git-Url: https://www.chiark.greenend.org.uk/ucgi/~cjwatson/git?a=commitdiff_plain;h=0257a1f8c4b444c8907b30411b9938919c2b6889;p=blog.git documentation/python: format also anchors for class/module members. First step towards symbol crosslinking. --- diff --git a/doc/documentation/python.rst b/doc/documentation/python.rst index 1bb3a401..0d21fb6c 100644 --- a/doc/documentation/python.rst +++ b/doc/documentation/python.rst @@ -254,6 +254,10 @@ Variable Description for modules, classes, pages and index pages. See `Custom URL formatters`_ for more information. +:py:`ID_FORMATTER: Callable` Function for creating link anchors for + module and class members. See + `Custom URL formatters`_ for more + information. =================================== =========================================== `Theme selection`_ @@ -402,6 +406,21 @@ The ``type`` is an enum, if you don't want to fiddle with imports, compare that case the ``path`` has always just one item, one of :py:`'pages'`, :py:`'modules'` or :py:`'classes'`. +The :py:`ID_FORMATTER` handles formatting of anchors on a page. Again it takes +an entry type (which in this case is always one of :py:`'ENUM'`, +:py:`'ENUM_VALUE'`, :py:`'FUNCTION'`, :py:`'PROPERTY'`, :py:`'DATA'` or, in +case of pybind11 code, :py:`'OVERLOADED_FUNCTION'`. The second parameter is +again a path, being always just one item except for :py:`'ENUM_VALUE'` (in +which case it's enum name and value name together) and for +:py:`'OVERLOADED_FUNCTION'`, in which case it contains also a llist of argument +types. The default implementation simply returns the the path concatenated with +dashes: + +.. code:: py + + def default_id_formatter(type: EntryType, path: List[str]) -> str: + return '-'.join(path) + `Module inspection`_ ==================== @@ -981,6 +1000,7 @@ Property Description Property Description ======================================= ======================================= :py:`enum.name` Enum name +:py:`enum.id` Enum ID [4]_ :py:`enum.summary` Doc summary :py:`enum.base` Base class from which the enum is derived. Set to :py:`None` if no base @@ -1000,6 +1020,7 @@ Every item of :py:`enum.values` has the following properties: Property Description =========================== =================================================== :py:`value.name` Value name +:py:`value.id` Value ID [4]_ :py:`value.value` Value value. Set to :py:`None` if no value is available. :py:`value.summary` Value doc summary @@ -1014,6 +1035,7 @@ Property Description Property Description =================================== =========================================== :py:`function.name` Function name +:py:`function.id` Function ID [4]_ :py:`function.summary` Doc summary :py:`function.type` Function return type annotation [1]_ :py:`function.params` List of function parameters. See below for @@ -1065,6 +1087,7 @@ set to :py:`"..."` and the rest being empty. Property Description =================================== =========================================== :py:`property.name` Property name +:py:`property.id` Property ID [4]_ :py:`property.type` Property getter return type annotation [1]_ :py:`property.summary` Doc summary :py:`property.is_writable` If the property is writable @@ -1083,6 +1106,7 @@ Property Description Property Description =================================== =========================================== :py:`data.name` Data name +:py:`data.id` Data ID [4]_ :py:`data.type` Data type :py:`data.summary` Doc summary. Currently always empty. :py:`data.value` Data value representation @@ -1150,3 +1174,5 @@ Module/class list is ordered in a way that all modules are before all classes. the summary listing on top of the page to avoid unnecessary repetition. .. [3] :py:`page.filename` and :py:`page.url` is generated by an URL formatter, see `Custom URL formatters`_ for more information +.. [4] :py:`i.id` is an ID used for linking to given entry on a page. Generated + by an anchor formatter, see `Custom URL formatters`_ for more information. diff --git a/documentation/python.py b/documentation/python.py index 8d8d45ac..6831b27f 100755 --- a/documentation/python.py +++ b/documentation/python.py @@ -29,6 +29,7 @@ import copy import docutils import enum import urllib.parse +import hashlib import html import importlib import inspect @@ -64,8 +65,12 @@ class EntryType(Enum): ENUM = 4 ENUM_VALUE = 5 FUNCTION = 6 - PROPERTY = 7 - DATA = 8 + # Denotes a potentially overloaded pybind11 function. Has to be here to + # be able to distinguish between zero-argument normal and pybind11 + # functions. + OVERLOADED_FUNCTION = 7 + PROPERTY = 8 + DATA = 9 def default_url_formatter(type: EntryType, path: List[str]) -> Tuple[str, str]: # TODO: what about nested pages, how to format? @@ -73,6 +78,19 @@ def default_url_formatter(type: EntryType, path: List[str]) -> Tuple[str, str]: assert '/' not in url # TODO return url, url +def default_id_formatter(type: EntryType, path: List[str]) -> str: + # Encode pybind11 function overloads into the anchor (hash them, like Rust + # does) + if type == EntryType.OVERLOADED_FUNCTION: + return path[0] + '-' + hashlib.sha1(', '.join([str(i) for i in path[1:]]).encode('utf-8')).hexdigest()[:5] + + if type == EntryType.ENUM_VALUE: + assert len(path) == 2 + return '-'.join(path) + + assert len(path) == 1 + return path[0] + default_config = { 'PROJECT_TITLE': 'My Python Project', 'PROJECT_SUBTITLE': None, @@ -125,7 +143,8 @@ default_config = { 'SEARCH_BASE_URL': None, 'SEARCH_EXTERNAL_URL': None, - 'URL_FORMATTER': default_url_formatter + 'URL_FORMATTER': default_url_formatter, + 'ID_FORMATTER': default_id_formatter } class State: @@ -555,6 +574,7 @@ def extract_class_doc(state: State, path: List[str], class_): def extract_enum_doc(state: State, path: List[str], enum_): out = Empty() out.name = path[-1] + out.id = state.config['ID_FORMATTER'](EntryType.ENUM, path[-1:]) out.values = [] out.has_details = False out.has_value_details = False @@ -573,6 +593,7 @@ def extract_enum_doc(state: State, path: List[str], enum_): for i in enum_: value = Empty() value.name = i.name + value.id = state.config['ID_FORMATTER'](EntryType.ENUM_VALUE, path[-1:] + [i.name]) value.value = html.escape(repr(i.value)) # Value doc gets by default inherited from the enum, that's useless @@ -598,6 +619,7 @@ def extract_enum_doc(state: State, path: List[str], enum_): for name, v in enum_.__members__.items(): value = Empty() value. name = name + value.id = state.config['ID_FORMATTER'](EntryType.ENUM_VALUE, path[-1:] + [name]) value.value = int(v) # TODO: once https://github.com/pybind/pybind11/pull/1160 is # released, extract from class docs (until then the class @@ -691,6 +713,10 @@ def extract_function_doc(state: State, parent, path: List[str], function) -> Lis out.params += [param] + # Format the anchor. Pybind11 functions are sometimes overloaded, + # thus name alone is not enough. + out.id = state.config['ID_FORMATTER'](EntryType.OVERLOADED_FUNCTION, path[-1:] + [param.type for param in out.params]) + overloads += [out] return overloads @@ -699,6 +725,7 @@ def extract_function_doc(state: State, parent, path: List[str], function) -> Lis else: out = Empty() out.name = path[-1] + out.id = state.config['ID_FORMATTER'](EntryType.FUNCTION, path[-1:]) out.params = [] out.has_complex_params = False out.has_details = False @@ -744,6 +771,7 @@ def extract_property_doc(state: State, path: List[str], property): out = Empty() out.name = path[-1] + out.id = state.config['ID_FORMATTER'](EntryType.PROPERTY, path[-1:]) # TODO: external summary for properties out.summary = extract_summary(state, {}, [], property.__doc__) out.is_settable = property.fset is not None @@ -767,6 +795,7 @@ def extract_data_doc(state: State, parent, path: List[str], data): out = Empty() out.name = path[-1] + out.id = state.config['ID_FORMATTER'](EntryType.DATA, path[-1:]) # Welp. https://stackoverflow.com/questions/8820276/docstring-for-variable out.summary = '' out.has_details = False diff --git a/documentation/templates/python/details-enum.html b/documentation/templates/python/details-enum.html index aac8f6c9..ea3bdff7 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 }})

{% if enum.summary %}

{{ enum.summary }}

@@ -11,7 +11,7 @@ {% for value in enum.values %} - {{ value.name }} + {{ value.name }} {% if value.summary %}

{{ value.summary }}

diff --git a/documentation/templates/python/entry-data.html b/documentation/templates/python/entry-data.html index 3e351daa..25930b1a 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 %}: {{ data.type }}{% 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 773a0aa6..e9620d64 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 %}({{ enum.base }}){% 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 245f3c19..fc689ca3 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 %}: {{ 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 %}
{{ function.summary }}
diff --git a/documentation/templates/python/entry-property.html b/documentation/templates/python/entry-property.html index 78852ee8..b608938a 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 %} get{% if property.is_settable %} set{% endif %}{% if property.is_deletable %} del{% endif %} + {{ property.name }}{% if property.type %}: {{ property.type }}{% endif %} get{% if property.is_settable %} set{% endif %}{% if property.is_deletable %} del{% endif %}
{{ property.summary }}
diff --git a/documentation/test_python/CMakeLists.txt b/documentation/test_python/CMakeLists.txt index e38d63f7..9f41e496 100644 --- a/documentation/test_python/CMakeLists.txt +++ b/documentation/test_python/CMakeLists.txt @@ -32,6 +32,12 @@ foreach(target signatures enums submodules) set_target_properties(pybind_${target} PROPERTIES LIBRARY_OUTPUT_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/pybind_${target}) endforeach() +# Need a special location for this one +pybind11_add_module(pybind_link_formatting link_formatting/link_formatting/pybind.cpp) +set_target_properties(pybind_link_formatting PROPERTIES + OUTPUT_NAME pybind + LIBRARY_OUTPUT_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/link_formatting/link_formatting) + # Need a special name for this one pybind11_add_module(pybind_name_mapping pybind_name_mapping/sub.cpp) set_target_properties(pybind_name_mapping PROPERTIES diff --git a/documentation/test_python/content/content.html b/documentation/test_python/content/content.html index 01edd0af..604bbad7 100644 --- a/documentation/test_python/content/content.html +++ b/documentation/test_python/content/content.html @@ -50,7 +50,7 @@ tho.

Data

- CONSTANT: float = 3.14 + CONSTANT: float = 3.14
This is finally a docstring for content.CONSTANT
diff --git a/documentation/test_python/inspect_all_property/inspect_all_property.html b/documentation/test_python/inspect_all_property/inspect_all_property.html index 8150aadd..0e6a75de 100644 --- a/documentation/test_python/inspect_all_property/inspect_all_property.html +++ b/documentation/test_python/inspect_all_property/inspect_all_property.html @@ -55,14 +55,14 @@

Enums

- class _MyPrivateEnum(enum.Enum): VALUE = 1 - ANOTHER = 2 - YAY = 3 + class _MyPrivateEnum(enum.Enum): VALUE = 1 + ANOTHER = 2 + YAY = 3
- class UndocumentedEnum(enum.IntFlag): FLAG_ONE = 1 - FLAG_SEVENTEEN = 17 + class UndocumentedEnum(enum.IntFlag): FLAG_ONE = 1 + FLAG_SEVENTEEN = 17
@@ -71,7 +71,7 @@

Functions

- def _private_but_exposed_func() + def _private_but_exposed_func()
@@ -80,34 +80,34 @@

Data

- _private_data = 'Hey!' + _private_data = 'Hey!'

Enum documentation

-
+

- class inspect_all_property._MyPrivateEnum(enum.Enum) + class inspect_all_property._MyPrivateEnum(enum.Enum)

- + - + - + diff --git a/documentation/test_python/inspect_annotations/inspect_annotations.Foo.html b/documentation/test_python/inspect_annotations/inspect_annotations.Foo.html index 7a1735dc..a83a1714 100644 --- a/documentation/test_python/inspect_annotations/inspect_annotations.Foo.html +++ b/documentation/test_python/inspect_annotations/inspect_annotations.Foo.html @@ -39,7 +39,7 @@

Methods

- def string_annotation(self: inspect_annotations.Foo) + def string_annotation(self: inspect_annotations.Foo)
String annotations
@@ -48,7 +48,7 @@

Properties

- a_property: typing.List[bool] get + a_property: typing.List[bool] get
A property with a type annotation
diff --git a/documentation/test_python/inspect_annotations/inspect_annotations.html b/documentation/test_python/inspect_annotations/inspect_annotations.html index 1d11437a..31af659e 100644 --- a/documentation/test_python/inspect_annotations/inspect_annotations.html +++ b/documentation/test_python/inspect_annotations/inspect_annotations.html @@ -46,40 +46,40 @@

Functions

- def annotated_positional_keyword(bar = False, *, + def annotated_positional_keyword(bar = False, *, foo: str, **kwargs)
Function with explicitly delimited keyword args and type annotations
- def annotation(param: typing.List[int], + def annotation(param: typing.List[int], another: bool, third: str = 'hello') -> inspect_annotations.Foo
An annotated function
- def args_kwargs(a, b, *args, **kwargs) + def args_kwargs(a, b, *args, **kwargs)
Function with args and kwargs
- def no_annotation(a, b, z) + def no_annotation(a, b, z)
Non-annotated function
- def no_annotation_default_param(param, + def no_annotation_default_param(param, another, third = 'hello')
Non-annotated function
- def partial_annotation(foo, + def partial_annotation(foo, param: typing.Tuple[int, int], unannotated, cls: inspect_annotations.Foo)
Partially annotated function
- def positional_keyword(positional_kw, *, kw_only) + def positional_keyword(positional_kw, *, kw_only)
Function with explicitly delimited keyword args
@@ -88,11 +88,11 @@

Data

- ANNOTATED_VAR: typing.Tuple[bool, str] = (False, 'No.') + ANNOTATED_VAR: typing.Tuple[bool, str] = (False, 'No.')
- UNANNOTATED_VAR = 3.45 + UNANNOTATED_VAR = 3.45
diff --git a/documentation/test_python/inspect_annotations/math.html b/documentation/test_python/inspect_annotations/math.html index 90c1e2f1..57768b03 100644 --- a/documentation/test_python/inspect_annotations/math.html +++ b/documentation/test_python/inspect_annotations/math.html @@ -39,11 +39,11 @@ mathematical functions defined by the C standard.

Functions

- def pow(x, y, /) + def pow(x, y, /)
Return x**y (x to the power of y).
- def log(...) + def log(...)
log(x, [base=math.e]) Return the logarithm of x to the given base.
diff --git a/documentation/test_python/inspect_annotations/math36.html b/documentation/test_python/inspect_annotations/math36.html index f8cf25d2..0964811c 100644 --- a/documentation/test_python/inspect_annotations/math36.html +++ b/documentation/test_python/inspect_annotations/math36.html @@ -39,7 +39,7 @@ mathematical functions defined by the C standard.

Functions

- def log(...) + def log(...)
log(x[, base])
diff --git a/documentation/test_python/inspect_name_mapping/inspect_name_mapping.Class.html b/documentation/test_python/inspect_name_mapping/inspect_name_mapping.Class.html index 10f6a250..1772ea86 100644 --- a/documentation/test_python/inspect_name_mapping/inspect_name_mapping.Class.html +++ b/documentation/test_python/inspect_name_mapping/inspect_name_mapping.Class.html @@ -38,7 +38,7 @@

Methods

- def a_thing(self) -> inspect_name_mapping.Class + def a_thing(self) -> inspect_name_mapping.Class
A method
diff --git a/documentation/test_python/inspect_name_mapping/inspect_name_mapping.html b/documentation/test_python/inspect_name_mapping/inspect_name_mapping.html index 1cc90c6e..53ff83d6 100644 --- a/documentation/test_python/inspect_name_mapping/inspect_name_mapping.html +++ b/documentation/test_python/inspect_name_mapping/inspect_name_mapping.html @@ -53,7 +53,7 @@

Functions

- def foo() -> inspect_name_mapping.Class + def foo() -> inspect_name_mapping.Class
This function returns Class, *not* _sub.Foo
diff --git a/documentation/test_python/inspect_name_mapping/inspect_name_mapping.submodule.html b/documentation/test_python/inspect_name_mapping/inspect_name_mapping.submodule.html index 658657d8..016ba03e 100644 --- a/documentation/test_python/inspect_name_mapping/inspect_name_mapping.submodule.html +++ b/documentation/test_python/inspect_name_mapping/inspect_name_mapping.submodule.html @@ -38,7 +38,7 @@

Functions

- def foo(a: inspect_name_mapping.Class, + def foo(a: inspect_name_mapping.Class, b: int) -> int
A function
diff --git a/documentation/test_python/inspect_string/inspect_string.Foo.html b/documentation/test_python/inspect_string/inspect_string.Foo.html index 206fba51..ead3e321 100644 --- a/documentation/test_python/inspect_string/inspect_string.Foo.html +++ b/documentation/test_python/inspect_string/inspect_string.Foo.html @@ -63,14 +63,14 @@

Enums

- class InnerEnum(enum.Enum): VALUE = 0 - ANOTHER = 1 - YAY = 2 + class InnerEnum(enum.Enum): VALUE = 0 + ANOTHER = 1 + YAY = 2
Inner enum
- class UndocumentedInnerEnum(enum.IntFlag): FLAG_ONE = 1 - FLAG_SEVENTEEN = 17 + class UndocumentedInnerEnum(enum.IntFlag): FLAG_ONE = 1 + FLAG_SEVENTEEN = 17
@@ -79,7 +79,7 @@

Class methods

- def func_on_class(a) + def func_on_class(a)
A class method
@@ -88,7 +88,7 @@

Static methods

- def static_func(a) + def static_func(a)
A static method
@@ -97,7 +97,7 @@

Methods

- def func(self, a, b) + def func(self, a, b)
A method
@@ -106,15 +106,15 @@

Properties

- a_property get + a_property get
A property
- deletable_property get del + deletable_property get del
Deletable property
- writable_property get set + writable_property get set
Writable property
@@ -123,35 +123,35 @@

Data

- A_DATA = 'BOO' + A_DATA = 'BOO'

Enum documentation

-
+

- class inspect_string.Foo.InnerEnum(enum.Enum) + class inspect_string.Foo.InnerEnum(enum.Enum)

Inner enum

Enumerators
VALUEVALUE

A value

ANOTHERANOTHER

Another value

YAYYAY
- + - + - + diff --git a/documentation/test_python/inspect_string/inspect_string.Specials.html b/documentation/test_python/inspect_string/inspect_string.Specials.html index 65e68fe4..c8e9c1bd 100644 --- a/documentation/test_python/inspect_string/inspect_string.Specials.html +++ b/documentation/test_python/inspect_string/inspect_string.Specials.html @@ -50,15 +50,15 @@

Special methods

- def __add__(self, other) + def __add__(self, other)
Add a thing
- def __and__(self, other) + def __and__(self, other)
- def __init__(self) + def __init__(self)
The constructor
diff --git a/documentation/test_python/inspect_string/inspect_string.html b/documentation/test_python/inspect_string/inspect_string.html index 72155565..846a56cd 100644 --- a/documentation/test_python/inspect_string/inspect_string.html +++ b/documentation/test_python/inspect_string/inspect_string.html @@ -72,14 +72,14 @@

Enums

- class MyEnum(enum.Enum): VALUE = 0 - ANOTHER = 1 - YAY = 2 + class MyEnum(enum.Enum): VALUE = 0 + ANOTHER = 1 + YAY = 2
An enum
- class UndocumentedEnum(enum.IntFlag): FLAG_ONE = 1 - FLAG_SEVENTEEN = 17 + class UndocumentedEnum(enum.IntFlag): FLAG_ONE = 1 + FLAG_SEVENTEEN = 17
@@ -88,7 +88,7 @@

Functions

- def function() + def function()
A function
@@ -97,43 +97,43 @@

Data

- A_CONSTANT = 3.24 + A_CONSTANT = 3.24
- ENUM_THING + ENUM_THING
- foo + foo

Enum documentation

-
+

- class inspect_string.MyEnum(enum.Enum) + class inspect_string.MyEnum(enum.Enum)

An enum

Enumerators
VALUEVALUE

A value

ANOTHERANOTHER

Another value

YAYYAY
- + - + - + diff --git a/documentation/test_python/link_formatting/c.link_formatting.Class.html b/documentation/test_python/link_formatting/c.link_formatting.Class.html index b54f5c28..4989c9b0 100644 --- a/documentation/test_python/link_formatting/c.link_formatting.Class.html +++ b/documentation/test_python/link_formatting/c.link_formatting.Class.html @@ -48,6 +48,7 @@ Reference @@ -59,6 +60,15 @@
And a nice subclass, oh.
+
+

Properties

+
+
+ property get +
+
A property.
+
+
diff --git a/documentation/test_python/link_formatting/c.link_formatting.pybind.Foo.html b/documentation/test_python/link_formatting/c.link_formatting.pybind.Foo.html new file mode 100644 index 00000000..945727df --- /dev/null +++ b/documentation/test_python/link_formatting/c.link_formatting.pybind.Foo.html @@ -0,0 +1,85 @@ + + + + + link_formatting.pybind.Foo | My Python Project + + + + + +
+
+
+
+
+

+ link_formatting.pybind.Foo class +

+

A class

+
+

Contents

+ +
+
+

Static methods

+
+
+ def a_function(arg0: int, /) -> int +
+
A static function that should have the same hash as takes_int()
+
+
+
+

Methods

+
+
+ def bar(self, + arg0: int, /) -> int +
+
Should have the same hash as foo() but not as a_function()
+
+ def foo(self, + arg0: int, /) -> int +
+
Should have the same hash as bar() but not as a_function()
+
+
+
+
+
+
+ + diff --git a/documentation/test_python/link_formatting/link_formatting/__init__.py b/documentation/test_python/link_formatting/link_formatting/__init__.py index 5ccfb30b..7e1c65d2 100644 --- a/documentation/test_python/link_formatting/link_formatting/__init__.py +++ b/documentation/test_python/link_formatting/link_formatting/__init__.py @@ -1,9 +1,24 @@ """This is a module.""" -from . import sub +import enum + +from . import sub, pybind class Class: """This is a nice class.""" class Sub: """And a nice subclass, oh.""" + + @property + def property(self): + """A property.""" + +def function(): + """A function.""" + +SOME_DATA = 3.14 + +class Enum(enum.Enum): + FIRST_VALUE = 1 + SECOND_VALUE = 2 diff --git a/documentation/test_python/link_formatting/link_formatting/pybind.cpp b/documentation/test_python/link_formatting/link_formatting/pybind.cpp new file mode 100644 index 00000000..9002a073 --- /dev/null +++ b/documentation/test_python/link_formatting/link_formatting/pybind.cpp @@ -0,0 +1,36 @@ +#include + +namespace py = pybind11; + +namespace { + +struct Foo { + static int aFunction(int a) { return 5 + a; } + + int foo(int a) { return 3 + a; } + + int bar(int a) { return 5 + a; } +}; + +int takesInt(int a) { return 3 + a; } + +int anOverloadedFunction(int b, float) { return int(b); } +int anOverloadedFunction(int b) { return b; } +int anOverloadedFunction(int b, Foo) { return b; } + +} + +PYBIND11_MODULE(pybind, m) { + m.doc() = "pybind11 overloaded function link formatting"; + + py::class_{m, "Foo", "A class"} + .def_static("a_function", &Foo::aFunction, "A static function that should have the same hash as takes_int()") + .def("foo", &Foo::foo, "Should have the same hash as bar() but not as a_function()") + .def("bar", &Foo::bar, "Should have the same hash as foo() but not as a_function()"); + + m + .def("takes_int", &takesInt, "Should have the same hash as Foo.a_function()") + .def("an_overloaded_function", static_cast(&anOverloadedFunction), "Each overload should have a different hash") + .def("an_overloaded_function", static_cast(&anOverloadedFunction), "Each overload should have a different hash") + .def("an_overloaded_function", static_cast(&anOverloadedFunction), "Each overload should have a different hash"); +} diff --git a/documentation/test_python/link_formatting/m.link_formatting.html b/documentation/test_python/link_formatting/m.link_formatting.html index cb18ca8b..13a7059a 100644 --- a/documentation/test_python/link_formatting/m.link_formatting.html +++ b/documentation/test_python/link_formatting/m.link_formatting.html @@ -49,6 +49,9 @@ @@ -56,6 +59,8 @@

Modules

+
module pybind
+
pybind11 overloaded function link formatting
module sub
This is a nice submodule.
@@ -67,6 +72,34 @@
This is a nice class.
+
+

Enums

+
+
+ class Enum(enum.Enum): FIRST_VALUE = 1 + SECOND_VALUE = 2 +
+
+
+
+
+

Functions

+
+
+ def function() +
+
A function.
+
+
+
+

Data

+
+
+ SOME_DATA = 3.14 +
+
+
+
diff --git a/documentation/test_python/link_formatting/m.link_formatting.pybind.html b/documentation/test_python/link_formatting/m.link_formatting.pybind.html new file mode 100644 index 00000000..d0210b14 --- /dev/null +++ b/documentation/test_python/link_formatting/m.link_formatting.pybind.html @@ -0,0 +1,91 @@ + + + + + link_formatting.pybind | My Python Project + + + + + +
+
+
+
+
+

+ link_formatting.pybind module +

+

pybind11 overloaded function link formatting

+
+

Contents

+ +
+
+

Classes

+
+
class Foo
+
A class
+
+
+
+

Functions

+
+
+ def an_overloaded_function(arg0: int, + arg1: float, /) -> int +
+
Each overload should have a different hash
+
+ def an_overloaded_function(arg0: int, /) -> int +
+
Each overload should have a different hash
+
+ def an_overloaded_function(arg0: int, + arg1: link_formatting.pybind.Foo, /) -> int +
+
Each overload should have a different hash
+
+ def takes_int(arg0: int, /) -> int +
+
Should have the same hash as Foo.a_function()
+
+
+
+
+
+
+ + diff --git a/documentation/test_python/link_formatting/s.classes.html b/documentation/test_python/link_formatting/s.classes.html index 7c6598b0..6751c5d3 100644 --- a/documentation/test_python/link_formatting/s.classes.html +++ b/documentation/test_python/link_formatting/s.classes.html @@ -42,6 +42,12 @@
  • module link_formatting This is a module.
      +
    • module sub This is a nice submodule.
    • module link_formatting This is a module.
        +
      • module pybind pybind11 overloaded function link formatting
      • module sub This is a nice submodule.
    • diff --git a/documentation/test_python/pybind_enums/pybind_enums.html b/documentation/test_python/pybind_enums/pybind_enums.html index abfbad4e..797aa907 100644 --- a/documentation/test_python/pybind_enums/pybind_enums.html +++ b/documentation/test_python/pybind_enums/pybind_enums.html @@ -27,15 +27,15 @@

      Enums

      - class MyEnum: First = 0 - Second = 1 - Third = 74 - CONSISTANTE = -5 + class MyEnum: First = 0 + Second = 1 + Third = 74 + CONSISTANTE = -5
      An enum without value docs :(
      - class SixtyfourBitFlag: Yes = 1000000000000 - No = 18446744073709551615 + class SixtyfourBitFlag: Yes = 1000000000000 + No = 18446744073709551615
      64-bit flags
      diff --git a/documentation/test_python/pybind_name_mapping/pybind_name_mapping.Class.html b/documentation/test_python/pybind_name_mapping/pybind_name_mapping.Class.html index 50e0a0d1..db2e1717 100644 --- a/documentation/test_python/pybind_name_mapping/pybind_name_mapping.Class.html +++ b/documentation/test_python/pybind_name_mapping/pybind_name_mapping.Class.html @@ -38,7 +38,7 @@

      Static methods

      - def a_thing() -> pybind_name_mapping.Class + def a_thing() -> pybind_name_mapping.Class
      A method
      diff --git a/documentation/test_python/pybind_name_mapping/pybind_name_mapping.html b/documentation/test_python/pybind_name_mapping/pybind_name_mapping.html index b261231a..0c28175e 100644 --- a/documentation/test_python/pybind_name_mapping/pybind_name_mapping.html +++ b/documentation/test_python/pybind_name_mapping/pybind_name_mapping.html @@ -53,7 +53,7 @@

      Functions

      - def foo() -> pybind_name_mapping.Class + def foo() -> pybind_name_mapping.Class
      This function returns Class, *not* _sub.Foo
      diff --git a/documentation/test_python/pybind_name_mapping/pybind_name_mapping.submodule.html b/documentation/test_python/pybind_name_mapping/pybind_name_mapping.submodule.html index 3fc5135c..fcdbee28 100644 --- a/documentation/test_python/pybind_name_mapping/pybind_name_mapping.submodule.html +++ b/documentation/test_python/pybind_name_mapping/pybind_name_mapping.submodule.html @@ -38,7 +38,7 @@

      Functions

      - def foo(arg0: pybind_name_mapping.Class, + def foo(arg0: pybind_name_mapping.Class, arg1: int, /) -> int
      A function
      diff --git a/documentation/test_python/pybind_signatures/pybind_signatures.MyClass.html b/documentation/test_python/pybind_signatures/pybind_signatures.MyClass.html index bbc62020..d4ea689e 100644 --- a/documentation/test_python/pybind_signatures/pybind_signatures.MyClass.html +++ b/documentation/test_python/pybind_signatures/pybind_signatures.MyClass.html @@ -41,7 +41,7 @@

      Static methods

      - def static_function(arg0: int, + def static_function(arg0: int, arg1: float, /) -> pybind_signatures.MyClass
      Static method with positional-only args
      @@ -51,17 +51,17 @@

      Methods

      - def another(self, /) -> int + def another(self, /) -> int
      Instance method with no args, 'self' is thus position-only
      - def instance_function(self, + def instance_function(self, arg0: int, arg1: str, /) -> Tuple[float, int]
      Instance method with positional-only args
      - def instance_function_kwargs(self, + def instance_function_kwargs(self, hey: int, what: str = '<eh?>') -> Tuple[float, int]
      @@ -72,7 +72,7 @@

      Special methods

      - def __init__(self, /) + def __init__(self, /)
      Constructor
      @@ -81,7 +81,7 @@

      Properties

      - foo: float get set + foo: float get set
      A read/write property
      diff --git a/documentation/test_python/pybind_signatures/pybind_signatures.html b/documentation/test_python/pybind_signatures/pybind_signatures.html index ddaa5674..6e31c86b 100644 --- a/documentation/test_python/pybind_signatures/pybind_signatures.html +++ b/documentation/test_python/pybind_signatures/pybind_signatures.html @@ -46,87 +46,87 @@

      Functions

      - def crazy_signature(…) + def crazy_signature(…)
      Function that failed to get parsed
      - def duck(*args, **kwargs) + def duck(*args, **kwargs)
      A function taking args/kwargs directly
      - def overloaded(arg0: int, /) -> str + def overloaded(arg0: int, /) -> str
      Overloaded for ints
      - def overloaded(arg0: float, /) -> bool + def overloaded(arg0: float, /) -> bool
      Overloaded for floats
      - def scale(arg0: int, + def scale(arg0: int, arg1: float, /) -> int
      Scale an integer
      - def scale_kwargs(a: int, + def scale_kwargs(a: int, argument: float) -> int
      Scale an integer, kwargs
      - def taking_a_list_returning_a_tuple(arg0: List[float], /) -> Tuple[int, int, int] + def taking_a_list_returning_a_tuple(arg0: List[float], /) -> Tuple[int, int, int]
      Takes a list, returns a tuple
      - def tenOverloads(arg0: float, + def tenOverloads(arg0: float, arg1: float, /)
      Ten overloads of a function
      - def tenOverloads(arg0: int, + def tenOverloads(arg0: int, arg1: float, /)
      Ten overloads of a function
      - def tenOverloads(arg0: bool, + def tenOverloads(arg0: bool, arg1: float, /)
      Ten overloads of a function
      - def tenOverloads(arg0: float, + def tenOverloads(arg0: float, arg1: int, /)
      Ten overloads of a function
      - def tenOverloads(arg0: int, + def tenOverloads(arg0: int, arg1: int, /)
      Ten overloads of a function
      - def tenOverloads(arg0: bool, + def tenOverloads(arg0: bool, arg1: int, /)
      Ten overloads of a function
      - def tenOverloads(arg0: float, + def tenOverloads(arg0: float, arg1: bool, /)
      Ten overloads of a function
      - def tenOverloads(arg0: int, + def tenOverloads(arg0: int, arg1: bool, /)
      Ten overloads of a function
      - def tenOverloads(arg0: bool, + def tenOverloads(arg0: bool, arg1: bool, /)
      Ten overloads of a function
      - def tenOverloads(arg0: str, + def tenOverloads(arg0: str, arg1: str, /)
      Ten overloads of a function
      - def void_function(arg0: int, /) + def void_function(arg0: int, /)
      Returns nothing
      diff --git a/documentation/test_python/test_link_formatting.py b/documentation/test_python/test_link_formatting.py index 093b6318..bfc9563e 100644 --- a/documentation/test_python/test_link_formatting.py +++ b/documentation/test_python/test_link_formatting.py @@ -28,7 +28,7 @@ import unittest from typing import List from . import BaseInspectTestCase -from python import EntryType +from python import EntryType, default_id_formatter def custom_url_formatter(type: EntryType, path: List[str]) -> str: if type == EntryType.CLASS: @@ -43,6 +43,23 @@ def custom_url_formatter(type: EntryType, path: List[str]) -> str: return filename, filename + "#this-is-an-url" +def custom_id_formatter(type: EntryType, path: List[str]) -> str: + if type == EntryType.FUNCTION: + return 'f-' + '-'.join(path) + if type == EntryType.OVERLOADED_FUNCTION: + # Reuse the original hasher so we can test its behavior + return 'o-' + default_id_formatter(type, path) + if type == EntryType.PROPERTY: + return 'p-' + '-'.join(path) + if type == EntryType.ENUM: + return 'e-' + '-'.join(path) + if type == EntryType.ENUM_VALUE: + return 'v-' + '-'.join(path) + if type == EntryType.DATA: + return 'd-' + '-'.join(path) + + assert False + class Test(BaseInspectTestCase): def __init__(self, *args, **kwargs): super().__init__(__file__, '', *args, **kwargs) @@ -51,13 +68,15 @@ class Test(BaseInspectTestCase): self.run_python({ 'INPUT_PAGES': ['page.rst'], 'URL_FORMATTER': custom_url_formatter, + 'ID_FORMATTER': custom_id_formatter, 'LINKS_NAVBAR1': [ ('Pages', 'pages', []), ('Modules', 'modules', []), ('Classes', 'classes', [])], 'LINKS_NAVBAR2': [('A page', 'page', []), ('A module', 'link_formatting', []), - ('The class', ['link_formatting', 'Class'], [])] + ('The class', ['link_formatting', 'Class'], [])], + 'PYBIND11_COMPATIBILITY': True }) self.assertEqual(*self.actual_expected_contents('m.link_formatting.html')) self.assertEqual(*self.actual_expected_contents('m.link_formatting.sub.html')) @@ -75,3 +94,7 @@ class Test(BaseInspectTestCase): # There's nothing inside s.index.html that wouldn't be already covered # by others self.assertTrue(os.path.exists(os.path.join(self.path, 'output/s.index.html'))) + + # Verify pybind11 overloaded function hashing as well + self.assertEqual(*self.actual_expected_contents('m.link_formatting.pybind.html')) + self.assertEqual(*self.actual_expected_contents('c.link_formatting.pybind.Foo.html'))
  • Enumerators
    VALUEVALUE

    A value

    ANOTHERANOTHER

    Another value

    YAYYAY