test_doxygen/package-lock.json
test_python/*/output/
test_python/build*
-test_python/*/*.so
+test_python/**/*.so
self.config = config
self.class_index: List[IndexEntry] = []
self.page_index: List[IndexEntry] = []
+ self.module_mapping: Dict[str, str] = {}
def is_internal_function_name(name: str) -> bool:
"""If the function name is internal.
"""
return name.startswith('_') and not (name.startswith('__') and name.endswith('__'))
+def map_name_prefix(state: State, type: str) -> str:
+ for prefix, replace in state.module_mapping.items():
+ if type == prefix or type.startswith(prefix + '.'):
+ return replace + type[len(prefix):]
+
+ # No mapping found, return the type as-is
+ return type
+
def is_internal_or_imported_module_member(state: State, parent, path: str, name: str, object) -> bool:
"""If the module member is internal or imported."""
# Variables don't have the __module__ attribute, so check for its
# presence. Right now *any* variable will be present in the output, as
# there is no way to check where it comes from.
- if hasattr(object, '__module__') and object.__module__ != '.'.join(path):
+ if hasattr(object, '__module__') and map_name_prefix(state, object.__module__) != '.'.join(path):
return True
# If this is a module, then things get complicated again and we need to
_pybind_type_rx = re.compile('[a-zA-Z0-9_.]+')
_pybind_default_value_rx = re.compile('[^,)]+')
-def parse_pybind_type(signature: str) -> str:
- type = _pybind_type_rx.match(signature).group(0)
- signature = signature[len(type):]
+def parse_pybind_type(state: State, signature: str) -> str:
+ input_type = _pybind_type_rx.match(signature).group(0)
+ signature = signature[len(input_type):]
+ type = map_name_prefix(state, input_type)
if signature and signature[0] == '[':
type += '['
signature = signature[1:]
while signature[0] != ']':
- inner_type = parse_pybind_type(signature)
- type += inner_type
- signature = signature[len(inner_type):]
+ signature, inner_type = parse_pybind_type(state, signature)
+ type += inner_type
if signature[0] == ']': break
assert signature.startswith(', ')
type += ', '
assert signature[0] == ']'
+ signature = signature[1:]
type += ']'
- return type
+ return signature, type
-def parse_pybind_signature(signature: str) -> Tuple[str, str, List[Tuple[str, str, str]], str]:
+def parse_pybind_signature(state: State, signature: str) -> Tuple[str, str, List[Tuple[str, str, str]], str]:
original_signature = signature # For error reporting
name = _pybind_name_rx.match(signature).group(0)
signature = signature[len(name):]
# Type (optional)
if signature.startswith(': '):
signature = signature[2:]
- arg_type = parse_pybind_type(signature)
- signature = signature[len(arg_type):]
+ signature, arg_type = parse_pybind_type(state, signature)
else:
arg_type = None
# Return type (optional)
if signature.startswith(' -> '):
signature = signature[4:]
- return_type = parse_pybind_type(signature)
- signature = signature[len(return_type):]
+ signature, return_type = parse_pybind_type(state, signature)
else:
return_type = None
return (name, summary, args, return_type)
-def parse_pybind_docstring(name: str, doc: str) -> List[Tuple[str, str, List[Tuple[str, str, str]], str]]:
+def parse_pybind_docstring(state: State, name: str, doc: str) -> List[Tuple[str, str, List[Tuple[str, str, str]], str]]:
# Multiple overloads, parse each separately
overload_header = "{}(*args, **kwargs)\nOverloaded function.\n\n".format(name);
if doc.startswith(overload_header):
next = doc.find('{}. {}('.format(id, name))
# Parse the signature and docs from known slice
- overloads += [parse_pybind_signature(doc[3:next])]
+ overloads += [parse_pybind_signature(state, doc[3:next])]
assert overloads[-1][0] == name
if next == -1: break
# Normal function, parse and return the first signature
else:
- return [parse_pybind_signature(doc)]
+ return [parse_pybind_signature(state, doc)]
def extract_summary(doc: str) -> str:
if not doc: return '' # some modules (xml.etree) have that :(
# builtins (i.e., we want re.Match but not builtins.int).
return (type.__module__ + '.' if type.__module__ != 'builtins' else '') + type.__name__
-def extract_annotation(annotation) -> str:
+def extract_annotation(state: State, annotation) -> str:
# TODO: why this is not None directly?
if annotation is inspect.Signature.empty: return None
# Annotations can be strings, also https://stackoverflow.com/a/33533514
- if type(annotation) == str: return annotation
+ if type(annotation) == str: return map_name_prefix(state, annotation)
# To avoid getting <class 'foo.bar'> for types (and getting foo.bar
# instead) but getting the actual type for types annotated with e.g.
# typing module or it's directly a type. In Python 3.7 this worked with
# inspect.isclass(annotation), but on 3.6 that gives True for annotations
# as well and then we would get just List instead of List[int].
- if annotation.__module__ == 'typing': return str(annotation)
- return extract_type(annotation)
+ if annotation.__module__ == 'typing': return map_name_prefix(state, str(annotation))
+ return map_name_prefix(state, extract_type(annotation))
def render(config, template: str, page, env: jinja2.Environment):
template = env.get_template(template)
# one function in Python may equal more than one function on the C++ side.
# To make the docs usable, list all overloads separately.
if state.config['PYBIND11_COMPATIBILITY'] and function.__doc__.startswith(path[-1]):
- funcs = parse_pybind_docstring(path[-1], function.__doc__)
+ funcs = parse_pybind_docstring(state, path[-1], function.__doc__)
overloads = []
for name, summary, args, type in funcs:
out = Empty()
try:
signature = inspect.signature(function)
- out.type = extract_annotation(signature.return_annotation)
+ out.type = extract_annotation(state, signature.return_annotation)
for i in signature.parameters.values():
param = Empty()
param.name = i.name
- param.type = extract_annotation(i.annotation)
+ param.type = extract_annotation(state, i.annotation)
if param.type:
out.has_complex_params = True
if i.default is inspect.Signature.empty:
try:
signature = inspect.signature(property.fget)
- out.type = extract_annotation(signature.return_annotation)
+ out.type = extract_annotation(state, signature.return_annotation)
except ValueError:
# pybind11 properties have the type in the docstring
if state.config['PYBIND11_COMPATIBILITY']:
- out.type = parse_pybind_signature(property.fget.__doc__)[3]
+ out.type = parse_pybind_signature(state, property.fget.__doc__)[3]
else:
out.type = None
return out
-def extract_data_doc(parent, path: List[str], data):
+def extract_data_doc(state: State, parent, path: List[str], data):
assert not inspect.ismodule(data) and not inspect.isclass(data) and not inspect.isroutine(data) and not inspect.isframe(data) and not inspect.istraceback(data) and not inspect.iscode(data)
out = Empty()
out.summary = ''
out.has_details = False
if hasattr(parent, '__annotations__') and out.name in parent.__annotations__:
- out.type = extract_annotation(parent.__annotations__[out.name])
+ out.type = extract_annotation(state, parent.__annotations__[out.name])
else:
out.type = None
# The autogenerated <foo.bar at 0xbadbeef> is useless, so provide the value
# The __all__ is meant to expose the public API, so we don't filter out
# underscored things.
if hasattr(module, '__all__'):
+ # Names exposed in __all__ could be also imported from elsewhere, for
+ # example this is a common pattern with native libraries and we want
+ # Foo, Bar, submodule and *everything* in submodule to be referred to
+ # as `library.RealName` (`library.submodule.func()`, etc.) instead of
+ # `library._native.Foo`, `library._native.sub.func()` etc.
+ #
+ # from ._native import Foo as PublicName
+ # from ._native import sub as submodule
+ # __all__ = ['PublicName', 'submodule']
+ #
+ # The name references can be cyclic so extract the mapping in a
+ # separate pass before everything else.
for name in module.__all__:
# Everything available in __all__ is already imported, so get those
# directly
object = getattr(module, name)
subpath = path + [name]
+ # Modules have __name__ while other objects have __module__, need
+ # to check both.
+ if inspect.ismodule(object) and object.__name__ != '.'.join(subpath):
+ assert object.__name__ not in state.module_mapping
+ state.module_mapping[object.__name__] = '.'.join(subpath)
+ elif hasattr(object, '__module__'):
+ subname = object.__module__ + '.' + object.__name__
+ if subname != '.'.join(subpath):
+ assert subname not in state.module_mapping
+ state.module_mapping[subname] = '.'.join(subpath)
+
+ # Now extract the actual docs
+ for name in module.__all__:
+ object = getattr(module, name)
+ subpath = path + [name]
+
# We allow undocumented submodules (since they're often in the
# standard lib), but not undocumented classes etc. Render the
# submodules and subclasses recursively.
# https://github.com/python/cpython/blob/d29b3dd9227cfc4a23f77e99d62e20e063272de1/Lib/pydoc.py#L113
# TODO: unify this query
elif not inspect.isframe(object) and not inspect.istraceback(object) and not inspect.iscode(object):
- page.data += [extract_data_doc(module, subpath, object)]
+ page.data += [extract_data_doc(state, module, subpath, object)]
else: # pragma: no cover
logging.warning("unknown symbol %s in %s", name, '.'.join(path))
for name, object in inspect.getmembers(module, lambda o: not inspect.ismodule(o) and not inspect.isclass(o) and not inspect.isroutine(o) and not inspect.isframe(o) and not inspect.istraceback(o) and not inspect.iscode(o)):
if is_internal_or_imported_module_member(state, module, path, name, object): continue
- page.data += [extract_data_doc(module, path + [name], object)]
+ page.data += [extract_data_doc(state, module, path + [name], object)]
render(state.config, 'module.html', page, env)
return index_entry
if name.startswith('_'): continue
subpath = path + [name]
- page.data += [extract_data_doc(class_, subpath, object)]
+ page.data += [extract_data_doc(state, class_, subpath, object)]
render(state.config, 'class.html', page, env)
return index_entry
pybind11_add_module(pybind_${target} pybind_${target}/pybind_${target}.cpp)
set_target_properties(pybind_${target} PROPERTIES LIBRARY_OUTPUT_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/pybind_${target})
endforeach()
+
+# 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
+ OUTPUT_NAME _sub
+ LIBRARY_OUTPUT_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/pybind_name_mapping/pybind_name_mapping)
--- /dev/null
+<!DOCTYPE html>
+<html lang="en">
+<head>
+ <meta charset="UTF-8" />
+ <title>inspect_name_mapping.Class | My Python Project</title>
+ <link rel="stylesheet" href="https://fonts.googleapis.com/css?family=Source+Sans+Pro:400,400i,600,600i%7CSource+Code+Pro:400,400i,600" />
+ <link rel="stylesheet" href="m-dark+documentation.compiled.css" />
+ <meta name="viewport" content="width=device-width, initial-scale=1.0" />
+</head>
+<body>
+<header><nav id="navigation">
+ <div class="m-container">
+ <div class="m-row">
+ <a href="index.html" id="m-navbar-brand" class="m-col-t-8 m-col-m-none m-left-m">My Python Project</a>
+ </div>
+ </div>
+</nav></header>
+<main><article>
+ <div class="m-container m-container-inflatable">
+ <div class="m-row">
+ <div class="m-col-l-10 m-push-l-1">
+ <h1>
+ <span class="m-breadcrumb"><a href="inspect_name_mapping.html">inspect_name_mapping</a>.<wbr/></span>Class <span class="m-thin">class</span>
+ </h1>
+ <p>A class</p>
+ <div class="m-block m-default">
+ <h3>Contents</h3>
+ <ul>
+ <li>
+ Reference
+ <ul>
+ <li><a href="#methods">Methods</a></li>
+ </ul>
+ </li>
+ </ul>
+ </div>
+ <section id="methods">
+ <h2><a href="#methods">Methods</a></h2>
+ <dl class="m-doc">
+ <dt>
+ <span class="m-doc-wrap-bumper">def <a href="" class="m-doc-self">a_thing</a>(</span><span class="m-doc-wrap">self) -> inspect_name_mapping.Class</span>
+ </dt>
+ <dd>A method</dd>
+ </dl>
+ </section>
+ </div>
+ </div>
+ </div>
+</article></main>
+</body>
+</html>
--- /dev/null
+<!DOCTYPE html>
+<html lang="en">
+<head>
+ <meta charset="UTF-8" />
+ <title>inspect_name_mapping | My Python Project</title>
+ <link rel="stylesheet" href="https://fonts.googleapis.com/css?family=Source+Sans+Pro:400,400i,600,600i%7CSource+Code+Pro:400,400i,600" />
+ <link rel="stylesheet" href="m-dark+documentation.compiled.css" />
+ <meta name="viewport" content="width=device-width, initial-scale=1.0" />
+</head>
+<body>
+<header><nav id="navigation">
+ <div class="m-container">
+ <div class="m-row">
+ <a href="index.html" id="m-navbar-brand" class="m-col-t-8 m-col-m-none m-left-m">My Python Project</a>
+ </div>
+ </div>
+</nav></header>
+<main><article>
+ <div class="m-container m-container-inflatable">
+ <div class="m-row">
+ <div class="m-col-l-10 m-push-l-1">
+ <h1>
+ inspect_name_mapping <span class="m-thin">module</span>
+ </h1>
+ <div class="m-block m-default">
+ <h3>Contents</h3>
+ <ul>
+ <li>
+ Reference
+ <ul>
+ <li><a href="#packages">Modules</a></li>
+ <li><a href="#classes">Classes</a></li>
+ <li><a href="#functions">Functions</a></li>
+ </ul>
+ </li>
+ </ul>
+ </div>
+ <section id="namespaces">
+ <h2><a href="#namespaces">Modules</a></h2>
+ <dl class="m-doc">
+ <dt>module <a href="inspect_name_mapping.submodule.html" class="m-doc">submodule</a></dt>
+ <dd>This submodule is renamed from bar to submodule and should have a function member.</dd>
+ </dl>
+ </section>
+ <section id="classes">
+ <h2><a href="#classes">Classes</a></h2>
+ <dl class="m-doc">
+ <dt>class <a href="inspect_name_mapping.Class.html" class="m-doc">Class</a></dt>
+ <dd>A class</dd>
+ </dl>
+ </section>
+ <section id="functions">
+ <h2><a href="#functions">Functions</a></h2>
+ <dl class="m-doc">
+ <dt>
+ <span class="m-doc-wrap-bumper">def <a href="" class="m-doc-self">foo</a>(</span><span class="m-doc-wrap">) -> inspect_name_mapping.Class</span>
+ </dt>
+ <dd>This function returns Class, *not* _sub.Foo</dd>
+ </dl>
+ </section>
+ </div>
+ </div>
+ </div>
+</article></main>
+</body>
+</html>
--- /dev/null
+<!DOCTYPE html>
+<html lang="en">
+<head>
+ <meta charset="UTF-8" />
+ <title>inspect_name_mapping.submodule | My Python Project</title>
+ <link rel="stylesheet" href="https://fonts.googleapis.com/css?family=Source+Sans+Pro:400,400i,600,600i%7CSource+Code+Pro:400,400i,600" />
+ <link rel="stylesheet" href="m-dark+documentation.compiled.css" />
+ <meta name="viewport" content="width=device-width, initial-scale=1.0" />
+</head>
+<body>
+<header><nav id="navigation">
+ <div class="m-container">
+ <div class="m-row">
+ <a href="index.html" id="m-navbar-brand" class="m-col-t-8 m-col-m-none m-left-m">My Python Project</a>
+ </div>
+ </div>
+</nav></header>
+<main><article>
+ <div class="m-container m-container-inflatable">
+ <div class="m-row">
+ <div class="m-col-l-10 m-push-l-1">
+ <h1>
+ <span class="m-breadcrumb"><a href="inspect_name_mapping.html">inspect_name_mapping</a>.<wbr/></span>submodule <span class="m-thin">module</span>
+ </h1>
+ <p>This submodule is renamed from bar to submodule and should have a function member.</p>
+ <div class="m-block m-default">
+ <h3>Contents</h3>
+ <ul>
+ <li>
+ Reference
+ <ul>
+ <li><a href="#functions">Functions</a></li>
+ </ul>
+ </li>
+ </ul>
+ </div>
+ <section id="functions">
+ <h2><a href="#functions">Functions</a></h2>
+ <dl class="m-doc">
+ <dt>
+ <span class="m-doc-wrap-bumper">def <a href="" class="m-doc-self">foo</a>(</span><span class="m-doc-wrap">a: inspect_name_mapping.Class,
+ b: int) -> int</span>
+ </dt>
+ <dd>A function</dd>
+ </dl>
+ </section>
+ </div>
+ </div>
+ </div>
+</article></main>
+</body>
+</html>
--- /dev/null
+from ._sub import Foo as Class
+from ._sub import bar as submodule
+
+# This test is almost the same as pybind_name_mapping, only pure Python
+
+"""This module should have a `submodule`, a `Class` and `foo()`"""
+
+__all__ = ['submodule', 'Class', 'foo']
+
+def foo() -> Class:
+ """This function returns Class, *not* _sub.Foo"""
--- /dev/null
+class Foo:
+ """A class"""
+ # https://stackoverflow.com/a/33533514, have to use a string in Py3
+ def a_thing(self) -> 'inspect_name_mapping._sub.Foo':
+ """A method"""
+ pass
--- /dev/null
+"""This submodule is renamed from bar to submodule and should have a function member."""
+
+from . import Foo
+
+def foo(a: Foo, b: int) -> int:
+ """A function"""
+ return b*2
--- /dev/null
+<!DOCTYPE html>
+<html lang="en">
+<head>
+ <meta charset="UTF-8" />
+ <title>pybind_name_mapping.Class | My Python Project</title>
+ <link rel="stylesheet" href="https://fonts.googleapis.com/css?family=Source+Sans+Pro:400,400i,600,600i%7CSource+Code+Pro:400,400i,600" />
+ <link rel="stylesheet" href="m-dark+documentation.compiled.css" />
+ <meta name="viewport" content="width=device-width, initial-scale=1.0" />
+</head>
+<body>
+<header><nav id="navigation">
+ <div class="m-container">
+ <div class="m-row">
+ <a href="index.html" id="m-navbar-brand" class="m-col-t-8 m-col-m-none m-left-m">My Python Project</a>
+ </div>
+ </div>
+</nav></header>
+<main><article>
+ <div class="m-container m-container-inflatable">
+ <div class="m-row">
+ <div class="m-col-l-10 m-push-l-1">
+ <h1>
+ <span class="m-breadcrumb"><a href="pybind_name_mapping.html">pybind_name_mapping</a>.<wbr/></span>Class <span class="m-thin">class</span>
+ </h1>
+ <p>A class, renamed from Foo to Class</p>
+ <div class="m-block m-default">
+ <h3>Contents</h3>
+ <ul>
+ <li>
+ Reference
+ <ul>
+ <li><a href="#staticmethods">Static methods</a></li>
+ </ul>
+ </li>
+ </ul>
+ </div>
+ <section id="staticmethods">
+ <h2><a href="#staticmethods">Static methods</a></h2>
+ <dl class="m-doc">
+ <dt>
+ <span class="m-doc-wrap-bumper">def <a href="" class="m-doc-self">a_thing</a>(</span><span class="m-doc-wrap">) -> pybind_name_mapping.Class</span>
+ </dt>
+ <dd>A method</dd>
+ </dl>
+ </section>
+ </div>
+ </div>
+ </div>
+</article></main>
+</body>
+</html>
--- /dev/null
+<!DOCTYPE html>
+<html lang="en">
+<head>
+ <meta charset="UTF-8" />
+ <title>pybind_name_mapping | My Python Project</title>
+ <link rel="stylesheet" href="https://fonts.googleapis.com/css?family=Source+Sans+Pro:400,400i,600,600i%7CSource+Code+Pro:400,400i,600" />
+ <link rel="stylesheet" href="m-dark+documentation.compiled.css" />
+ <meta name="viewport" content="width=device-width, initial-scale=1.0" />
+</head>
+<body>
+<header><nav id="navigation">
+ <div class="m-container">
+ <div class="m-row">
+ <a href="index.html" id="m-navbar-brand" class="m-col-t-8 m-col-m-none m-left-m">My Python Project</a>
+ </div>
+ </div>
+</nav></header>
+<main><article>
+ <div class="m-container m-container-inflatable">
+ <div class="m-row">
+ <div class="m-col-l-10 m-push-l-1">
+ <h1>
+ pybind_name_mapping <span class="m-thin">module</span>
+ </h1>
+ <div class="m-block m-default">
+ <h3>Contents</h3>
+ <ul>
+ <li>
+ Reference
+ <ul>
+ <li><a href="#packages">Modules</a></li>
+ <li><a href="#classes">Classes</a></li>
+ <li><a href="#functions">Functions</a></li>
+ </ul>
+ </li>
+ </ul>
+ </div>
+ <section id="namespaces">
+ <h2><a href="#namespaces">Modules</a></h2>
+ <dl class="m-doc">
+ <dt>module <a href="pybind_name_mapping.submodule.html" class="m-doc">submodule</a></dt>
+ <dd>This submodule is renamed from bar to submodule and should have a function member.</dd>
+ </dl>
+ </section>
+ <section id="classes">
+ <h2><a href="#classes">Classes</a></h2>
+ <dl class="m-doc">
+ <dt>class <a href="pybind_name_mapping.Class.html" class="m-doc">Class</a></dt>
+ <dd>A class, renamed from Foo to Class</dd>
+ </dl>
+ </section>
+ <section id="functions">
+ <h2><a href="#functions">Functions</a></h2>
+ <dl class="m-doc">
+ <dt>
+ <span class="m-doc-wrap-bumper">def <a href="" class="m-doc-self">foo</a>(</span><span class="m-doc-wrap">) -> pybind_name_mapping.Class</span>
+ </dt>
+ <dd>This function returns Class, *not* _sub.Foo</dd>
+ </dl>
+ </section>
+ </div>
+ </div>
+ </div>
+</article></main>
+</body>
+</html>
--- /dev/null
+<!DOCTYPE html>
+<html lang="en">
+<head>
+ <meta charset="UTF-8" />
+ <title>pybind_name_mapping.submodule | My Python Project</title>
+ <link rel="stylesheet" href="https://fonts.googleapis.com/css?family=Source+Sans+Pro:400,400i,600,600i%7CSource+Code+Pro:400,400i,600" />
+ <link rel="stylesheet" href="m-dark+documentation.compiled.css" />
+ <meta name="viewport" content="width=device-width, initial-scale=1.0" />
+</head>
+<body>
+<header><nav id="navigation">
+ <div class="m-container">
+ <div class="m-row">
+ <a href="index.html" id="m-navbar-brand" class="m-col-t-8 m-col-m-none m-left-m">My Python Project</a>
+ </div>
+ </div>
+</nav></header>
+<main><article>
+ <div class="m-container m-container-inflatable">
+ <div class="m-row">
+ <div class="m-col-l-10 m-push-l-1">
+ <h1>
+ <span class="m-breadcrumb"><a href="pybind_name_mapping.html">pybind_name_mapping</a>.<wbr/></span>submodule <span class="m-thin">module</span>
+ </h1>
+ <p>This submodule is renamed from bar to submodule and should have a function member.</p>
+ <div class="m-block m-default">
+ <h3>Contents</h3>
+ <ul>
+ <li>
+ Reference
+ <ul>
+ <li><a href="#functions">Functions</a></li>
+ </ul>
+ </li>
+ </ul>
+ </div>
+ <section id="functions">
+ <h2><a href="#functions">Functions</a></h2>
+ <dl class="m-doc">
+ <dt>
+ <span class="m-doc-wrap-bumper">def <a href="" class="m-doc-self">foo</a>(</span><span class="m-doc-wrap">arg0: pybind_name_mapping.Class,
+ arg1: int<span class="m-text m-dim">, /</span>) -> int</span>
+ </dt>
+ <dd>A function</dd>
+ </dl>
+ </section>
+ </div>
+ </div>
+ </div>
+</article></main>
+</body>
+</html>
--- /dev/null
+from ._sub import Foo as Class
+from ._sub import bar as submodule
+
+# This test is almost the same as inspect_name_mapping, only natively
+
+"""This module should have a bar submodule and a Foo class"""
+
+__all__ = ['submodule', 'Class', 'foo']
+
+def foo() -> Class:
+ """This function returns Class, *not* _sub.Foo"""
--- /dev/null
+#include <pybind11/pybind11.h>
+
+struct Foo {
+ static Foo aThing() { return {}; }
+};
+
+PYBIND11_MODULE(_sub, m) {
+ pybind11::class_<Foo>{m, "Foo", "A class, renamed from Foo to Class"}
+ .def("a_thing", &Foo::aThing, "A method");
+
+ pybind11::module bar = m.def_submodule("bar");
+ bar.doc() = "This submodule is renamed from bar to submodule and should have a function member.";
+ bar.def("foo", [](Foo, int a) { return a*2; }, "A function");
+}
assert not hasattr(math, '__all__')
self.assertEqual(*self.actual_expected_contents('math.html', 'math36.html'))
+
+class NameMapping(BaseInspectTestCase):
+ def __init__(self, *args, **kwargs):
+ super().__init__(__file__, 'name_mapping', *args, **kwargs)
+
+ def test(self):
+ self.run_python()
+ self.assertEqual(*self.actual_expected_contents('inspect_name_mapping.html'))
+ self.assertEqual(*self.actual_expected_contents('inspect_name_mapping.Class.html'))
+ self.assertEqual(*self.actual_expected_contents('inspect_name_mapping.submodule.html'))
import sys
import unittest
-from python import parse_pybind_signature
+from python import State, parse_pybind_signature
from . import BaseInspectTestCase
class Signature(unittest.TestCase):
def test(self):
- self.assertEqual(parse_pybind_signature(
+ self.assertEqual(parse_pybind_signature(State({}),
'foo(a: int, a2: module.Thing) -> module.Thing3'),
('foo', '', [
('a', 'int', None),
], 'module.Thing3'))
def test_newline(self):
- self.assertEqual(parse_pybind_signature(
+ self.assertEqual(parse_pybind_signature(State({}),
'foo(a: int, a2: module.Thing) -> module.Thing3\n'),
('foo', '', [
('a', 'int', None),
], 'module.Thing3'))
def test_docs(self):
- self.assertEqual(parse_pybind_signature(
+ self.assertEqual(parse_pybind_signature(State({}),
'foo(a: int, a2: module.Thing) -> module.Thing3\n\nDocs here!!'),
('foo', 'Docs here!!', [
('a', 'int', None),
], 'module.Thing3'))
def test_no_args(self):
- self.assertEqual(parse_pybind_signature(
+ self.assertEqual(parse_pybind_signature(State({}),
'thingy() -> str'),
('thingy', '', [], 'str'))
def test_no_return(self):
- self.assertEqual(parse_pybind_signature(
+ self.assertEqual(parse_pybind_signature(State({}),
'__init__(self: module.Thing)'),
('__init__', '', [
('self', 'module.Thing', None),
], None))
def test_no_arg_types(self):
- self.assertEqual(parse_pybind_signature(
+ self.assertEqual(parse_pybind_signature(State({}),
'thingy(self, the_other_thing)'),
('thingy', '', [
('self', None, None),
], None))
def test_square_brackets(self):
- self.assertEqual(parse_pybind_signature(
+ self.assertEqual(parse_pybind_signature(State({}),
'foo(a: Tuple[int, str], no_really: str) -> List[str]'),
('foo', '', [
('a', 'Tuple[int, str]', None),
], 'List[str]'))
def test_nested_square_brackets(self):
- self.assertEqual(parse_pybind_signature(
+ self.assertEqual(parse_pybind_signature(State({}),
'foo(a: Tuple[int, List[Tuple[int, int]]], another: float) -> Union[str, Any]'),
('foo', '', [
('a', 'Tuple[int, List[Tuple[int, int]]]', None),
], 'Union[str, Any]'))
def test_kwargs(self):
- self.assertEqual(parse_pybind_signature(
+ self.assertEqual(parse_pybind_signature(State({}),
'foo(*args, **kwargs)'),
('foo', '', [
('*args', None, None),
], None))
def test_default_values(self):
- self.assertEqual(parse_pybind_signature(
+ self.assertEqual(parse_pybind_signature(State({}),
'foo(a: float=1.0, b: str=\'hello\')'),
('foo', '', [
('a', 'float', '1.0'),
], None))
def test_crazy_stuff(self):
- self.assertEqual(parse_pybind_signature(
+ self.assertEqual(parse_pybind_signature(State({}),
'foo(a: int, b: Math::Vector<4, UnsignedInt>)'),
('foo', '', [('…', None, None)], None))
def test_crazy_stuff_docs(self):
- self.assertEqual(parse_pybind_signature(
+ self.assertEqual(parse_pybind_signature(State({}),
'foo(a: int, b: Math::Vector<4, UnsignedInt>)\n\nThis is text!!'),
('foo', 'This is text!!', [('…', None, None)], None))
def test_crazy_return(self):
- self.assertEqual(parse_pybind_signature(
+ self.assertEqual(parse_pybind_signature(State({}),
'foo(a: int) -> Math::Vector<4, UnsignedInt>'),
('foo', '', [('…', None, None)], None))
def test_crazy_return_docs(self):
- self.assertEqual(parse_pybind_signature(
+ self.assertEqual(parse_pybind_signature(State({}),
'foo(a: int) -> Math::Vector<4, UnsignedInt>\n\nThis returns!'),
('foo', 'This returns!', [('…', None, None)], None))
def test_no_name(self):
- self.assertEqual(parse_pybind_signature(
+ self.assertEqual(parse_pybind_signature(State({}),
'(arg0: MyClass) -> float'),
('', '', [('arg0', 'MyClass', None)], 'float'))
+ def test_module_mapping(self):
+ state = State({})
+ state.module_mapping['module._module'] = 'module'
+
+ self.assertEqual(parse_pybind_signature(state,
+ 'foo(a: module._module.Foo, b: Tuple[int, module._module.Bar]) -> module._module.Baz'),
+ ('foo', '', [('a', 'module.Foo', None),
+ ('b', 'Tuple[int, module.Bar]', None)], 'module.Baz'))
+
class Signatures(BaseInspectTestCase):
def __init__(self, *args, **kwargs):
super().__init__(__file__, 'signatures', *args, **kwargs)
'PYBIND11_COMPATIBILITY': True
})
self.assertEqual(*self.actual_expected_contents('pybind_submodules.html'))
+
+class NameMapping(BaseInspectTestCase):
+ def __init__(self, *args, **kwargs):
+ super().__init__(__file__, 'name_mapping', *args, **kwargs)
+
+ def test(self):
+ self.run_python({
+ 'PYBIND11_COMPATIBILITY': True
+ })
+ self.assertEqual(*self.actual_expected_contents('pybind_name_mapping.html'))
+ self.assertEqual(*self.actual_expected_contents('pybind_name_mapping.Class.html'))
+ self.assertEqual(*self.actual_expected_contents('pybind_name_mapping.submodule.html'))