behavior is not enabled by default as it *might* have unwanted consequences in
pure Python code, enable it using the :py:`PYBIND11_COMPATIBILITY` option.
-`Function signatures`_
-----------------------
+`Function signatures, property annotations`_
+--------------------------------------------
For reasons explained in :gh:`pybind/pybind11#990`, pybind11 is not able to
provide function signatures through introspection and thus the script falls
arguments are positional-only (shown as :py:`arg0`, :py:`arg1`, ...) and marked
as such in the output.
+Similarly, property types are extracted from getter docstrings.
+
The signature parsing can't handle all cases and, especially when templated C++
type names leak through, it may fail to extract the argument names. If that
happens, the function signature shows just an ellipsis (``…``).
def make_url(path: List[str]) -> str:
return '.'.join(path) + '.html'
-_pybind_name_rx = re.compile('[a-zA-Z0-9_]+')
+_pybind_name_rx = re.compile('[a-zA-Z0-9_]*')
_pybind_arg_name_rx = re.compile('[*a-zA-Z0-9_]+')
_pybind_type_rx = re.compile('[a-zA-Z0-9_.]+')
_pybind_default_value_rx = re.compile('[^,)]+')
return [out]
-def extract_property_doc(path: List[str], property):
+def extract_property_doc(state: State, path: List[str], property):
assert inspect.isdatadescriptor(property)
out = Empty()
signature = inspect.signature(property.fget)
out.type = extract_annotation(signature.return_annotation)
except ValueError:
- out.type = None
+ # pybind11 properties have the type in the docstring
+ if state.config['PYBIND11_COMPATIBILITY']:
+ out.type = parse_pybind_signature(property.fget.__doc__)[3]
+ else:
+ out.type = None
return out
subpath = path + [name]
if not object.__doc__: logging.warning("%s is undocumented", '.'.join(subpath))
- page.properties += [extract_property_doc(subpath, object)]
+ page.properties += [extract_property_doc(state, subpath, object)]
# Get data
# TODO: unify this query
<li><a href="#staticmethods">Static methods</a></li>
<li><a href="#methods">Methods</a></li>
<li><a href="#dunder-methods">Special methods</a></li>
+ <li><a href="#properties">Properties</a></li>
</ul>
</li>
</ul>
<dd>Constructor</dd>
</dl>
</section>
+ <section id="properties">
+ <h2><a href="#properties">Properties</a></h2>
+ <dl class="m-doc">
+ <dt>
+ <a href="" class="m-doc-self">foo</a>: float <span class="m-label m-flat m-success">get set</span>
+ </dt>
+ <dd>A read/write property</dd>
+ </dl>
+ </section>
</div>
</div>
</div>
std::pair<float, int> instanceFunction(int, const std::string&) { return {0.5f, 42}; }
int another() { return 42; }
+
+ float foo() const { return _foo; }
+ void setFoo(float foo) { _foo = foo; }
+
+ private: float _foo = 0.0f;
};
PYBIND11_MODULE(pybind_signatures, m) {
.def(py::init(), "Constructor")
.def("instance_function", &MyClass::instanceFunction, "Instance method with positional-only args")
.def("instance_function_kwargs", &MyClass::instanceFunction, "Instance method with position or keyword args", py::arg("hey"), py::arg("what") = "eh?")
- .def("another", &MyClass::another, "Instance method with no args, 'self' is thus position-only");
+ .def("another", &MyClass::another, "Instance method with no args, 'self' is thus position-only")
+ .def_property("foo", &MyClass::foo, &MyClass::setFoo, "A read/write property");
}
'foo(a: int, b: Math::Vector<4, UnsignedInt>)\n\nThis is text!!'),
('foo', 'This is text!!', [('…', None, None)], None))
+ def test_no_name(self):
+ self.assertEqual(parse_pybind_signature(
+ '(arg0: MyClass) -> float'),
+ ('', '', [('arg0', 'MyClass', None)], 'float'))
+
class Signatures(BaseTestCase):
def __init__(self, *args, **kwargs):
super().__init__(__file__, 'signatures', *args, **kwargs)