from enum import Enum
from types import SimpleNamespace as Empty
from importlib.machinery import SourceFileLoader
-from typing import Tuple, Dict, Set, Any, List, Callable
+from typing import Tuple, Dict, Set, Any, List, Callable, Optional
from urllib.parse import urljoin
from distutils.version import LooseVersion
from docutils.transforms import Transform
if entry.type == EntryType.CLASS:
url = state.config['URL_FORMATTER'](entry.type, entry.path)[1]
else:
- assert entry.type == EntryType.ENUM
- parent_entry = state.name_map['.'.join(entry.path[:-1])]
+ if entry.type == EntryType.ENUM:
+ parent_index = -1
+ else:
+ assert entry.type == EntryType.ENUM_VALUE
+ parent_index = -2
+ parent_entry = state.name_map['.'.join(entry.path[:parent_index])]
url = '{}#{}'.format(
state.config['URL_FORMATTER'](parent_entry.type, parent_entry.path)[1],
- state.config['ID_FORMATTER'](entry.type, entry.path[-1:]))
+ state.config['ID_FORMATTER'](entry.type, entry.path[parent_index:]))
return '<a href="{}" class="m-doc">{}</a>'.format(url, '.'.join(shortened_path))
else:
return [parse_pybind_signature(state, referrer_path, doc)]
+# Used to format function default arguments and data values. *Not* pybind's
+# function default arguments, as those are parsed from a string representation.
+def format_value(state: State, referrer_path: List[str], value: str) -> Optional[str]:
+ if value is None: return str(value)
+ if isinstance(value, enum.Enum):
+ return make_name_link(state, referrer_path, '{}.{}.{}'.format(value.__class__.__module__, value.__class__.__qualname__, value.name))
+ # pybind enums have the __members__ attribute instead. Since 2.3 pybind11
+ # has .name like enum.Enum, but we still need to support 2.2 so hammer it
+ # out of a str() instead.
+ elif state.config['PYBIND11_COMPATIBILITY'] and hasattr(value.__class__, '__members__'):
+ return make_name_link(state, referrer_path, '{}.{}.{}'.format(value.__class__.__module__, value.__class__.__qualname__, str(value).partition('.')[2]))
+ elif '__repr__' in type(value).__dict__:
+ # TODO: tuples of non-representable values will still be ugly
+ return html.escape(repr(value))
+ else:
+ return None
+
def extract_summary(state: State, external_docs, path: List[str], doc: str) -> str:
# Prefer external docs, if available
path_str = '.'.join(path)
else:
param.type = type_link
arg_types += [type]
- param.default = html.escape(default or '')
+ if default:
+ # If the type is a registered enum, try to make a link to
+ # the value -- for an enum of type `module.EnumType`,
+ # assuming the default is rendered as `EnumType.VALUE` (not
+ # fully qualified), concatenate it together to have
+ # `module.EnumType.VALUE`
+ if type in state.name_map and state.name_map[type].type == EntryType.ENUM:
+ param.default = make_name_link(state, path, '.'.join(state.name_map[type].path[:-1] + [default]))
+ else: param.default = html.escape(default)
+ else:
+ param.default = None
if type or default: out.has_complex_params = True
# *args / **kwargs can still appear in the parsed signatures if
if i.default is inspect.Signature.empty:
param.default = None
else:
- param.default = repr(i.default)
+ param.default = format_value(state, path, i.default) or '…'
out.has_complex_params = True
param.kind = str(i.kind)
out.params += [param]
else:
out.type = None
- # The autogenerated <foo.bar at 0xbadbeef> is useless, so provide the value
- # only if __repr__ is implemented for given type
- if '__repr__' in type(data).__dict__:
- out.value = html.escape(repr(data))
- else:
- out.value = None
+ out.value = format_value(state, path, data)
# External data summary, if provided
path_str = '.'.join(path)
<section id="functions">
<h2><a href="#functions">Functions</a></h2>
<dl class="m-doc">
+ <dt>
+ <span class="m-doc-wrap-bumper">def <a href="#type_default_values" class="m-doc-self" id="type_default_values">type_default_values</a>(</span><span class="m-doc-wrap">a: <a href="inspect_type_links.second.html#Enum" class="m-doc">Enum</a> = <a href="inspect_type_links.second.html#Enum-SECOND" class="m-doc">Enum.SECOND</a>,
+ b: typing.Tuple[<a href="inspect_type_links.second.Foo.html" class="m-doc">Foo</a>] = (<class 'inspect_type_links.second.Foo'>,),
+ c: <a href="inspect_type_links.second.Foo.html" class="m-doc">Foo</a> = …)</span>
+ </dt>
+ <dd>A function with default values, one enum, one tuple and the third nonrepresentable (yes, the tuple looks ugly)</dd>
<dt>
<span class="m-doc-wrap-bumper">def <a href="#type_enum" class="m-doc-self" id="type_enum">type_enum</a>(</span><span class="m-doc-wrap">a: <a href="inspect_type_links.second.html#Enum" class="m-doc">Enum</a>)</span>
</dt>
<a href="#TYPE_DATA" class="m-doc-self" id="TYPE_DATA">TYPE_DATA</a>: <a href="inspect_type_links.second.Foo.html" class="m-doc">Foo</a>
</dt>
<dd></dd>
+ <dt>
+ <a href="#TYPE_DATA_ENUM" class="m-doc-self" id="TYPE_DATA_ENUM">TYPE_DATA_ENUM</a>: <a href="inspect_type_links.second.html#Enum" class="m-doc">Enum</a> = <a href="inspect_type_links.second.html#Enum-SECOND" class="m-doc">Enum.SECOND</a>
+ </dt>
+ <dd></dd>
<dt>
<a href="#TYPE_DATA_STRING_NESTED" class="m-doc-self" id="TYPE_DATA_STRING_NESTED">TYPE_DATA_STRING_NESTED</a>: typing.Tuple[<a href="inspect_type_links.second.Foo.html" class="m-doc">Foo</a>, typing.List[<a href="inspect_type_links.second.html#Enum" class="m-doc">Enum</a>], typing.Any] = {}
</dt>