Automate generation of reference docs with doxygen and breathe (#598)
* Make 'any' the default markup role for Sphinx docs
* Automate generation of reference docs with doxygen and breathe
* Improve reference docs coverage
diff --git a/.readthedocs.yml b/.readthedocs.yml
new file mode 100644
index 0000000..004a03a
--- /dev/null
+++ b/.readthedocs.yml
@@ -0,0 +1,2 @@
+conda:
+ file: docs/environment.yml
diff --git a/.travis.yml b/.travis.yml
index e8c5884..7a9d763 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -51,7 +51,10 @@
env: DOCS STYLE LINT
install:
- pip install --upgrade sphinx sphinx_rtd_theme flake8 pep8-naming
- - pip install docutils==0.12
+ - |
+ curl -fsSL ftp://ftp.stack.nl/pub/users/dimitri/doxygen-1.8.12.linux.bin.tar.gz | tar xz
+ export PATH="$PWD/doxygen-1.8.12/bin:$PATH"
+ pip install https://github.com/michaeljones/breathe/archive/master.zip
script:
- make -C docs html SPHINX_OPTIONS=-W
- tools/check-style.sh
diff --git a/docs/Doxyfile b/docs/Doxyfile
new file mode 100644
index 0000000..4dc8bf0
--- /dev/null
+++ b/docs/Doxyfile
@@ -0,0 +1,19 @@
+PROJECT_NAME = pybind11
+INPUT = ../include/pybind11/
+
+GENERATE_HTML = NO
+GENERATE_LATEX = NO
+GENERATE_XML = YES
+XML_OUTPUT = .build/doxygenxml
+XML_PROGRAMLISTING = YES
+
+MACRO_EXPANSION = YES
+EXPAND_ONLY_PREDEF = YES
+EXPAND_AS_DEFINED = PYBIND11_RUNTIME_EXCEPTION
+
+ALIASES = "rst=\verbatim embed:rst"
+ALIASES += "endrst=\endverbatim"
+
+QUIET = YES
+WARNINGS = YES
+WARN_IF_UNDOCUMENTED = NO
diff --git a/docs/advanced/cast/chrono.rst b/docs/advanced/cast/chrono.rst
index 6d4a5ee..8c6b3d7 100644
--- a/docs/advanced/cast/chrono.rst
+++ b/docs/advanced/cast/chrono.rst
@@ -4,8 +4,8 @@
When including the additional header file :file:`pybind11/chrono.h` conversions
from C++11 chrono datatypes to python datetime objects are automatically enabled.
This header also enables conversions of python floats (often from sources such
-as `time.monotonic()`, `time.perf_counter()` and `time.process_time()`) into
-durations.
+as ``time.monotonic()``, ``time.perf_counter()`` and ``time.process_time()``)
+into durations.
An overview of clocks in C++11
------------------------------
diff --git a/docs/advanced/functions.rst b/docs/advanced/functions.rst
index 8788885..7c97a0f 100644
--- a/docs/advanced/functions.rst
+++ b/docs/advanced/functions.rst
@@ -14,7 +14,7 @@
bindings for functions that return a non-trivial type. Just by looking at the
type information, it is not clear whether Python should take charge of the
returned value and eventually free its resources, or if this is handled on the
-C++ side. For this reason, pybind11 provides a several `return value policy`
+C++ side. For this reason, pybind11 provides a several *return value policy*
annotations that can be passed to the :func:`module::def` and
:func:`class_::def` functions. The default policy is
:enum:`return_value_policy::automatic`.
@@ -24,11 +24,11 @@
.. code-block:: cpp
- /* Function declaration */
+ /* Function declaration */
Data *get_data() { return _data; /* (pointer to a static data structure) */ }
...
- /* Binding code */
+ /* Binding code */
m.def("get_data", &get_data); // <-- KABOOM, will cause crash when called from Python
What's going on here? When ``get_data()`` is called from Python, the return
@@ -44,7 +44,7 @@
In the above example, the policy :enum:`return_value_policy::reference` should have
been specified so that the global data instance is only *referenced* without any
-implied transfer of ownership, i.e.:
+implied transfer of ownership, i.e.:
.. code-block:: cpp
@@ -158,9 +158,9 @@
Additional call policies
========================
-In addition to the above return value policies, further `call policies` can be
-specified to indicate dependencies between parameters. In general, call policies
-are required when the C++ object is any kind of container and another object is being
+In addition to the above return value policies, further *call policies* can be
+specified to indicate dependencies between parameters. In general, call policies
+are required when the C++ object is any kind of container and another object is being
added to the container.
There is currently just
diff --git a/docs/advanced/pycpp/object.rst b/docs/advanced/pycpp/object.rst
index 8e737cc..ae58876 100644
--- a/docs/advanced/pycpp/object.rst
+++ b/docs/advanced/pycpp/object.rst
@@ -33,6 +33,8 @@
When conversion fails, both directions throw the exception :class:`cast_error`.
+.. _calling_python_functions:
+
Calling Python functions
========================
diff --git a/docs/classes.rst b/docs/classes.rst
index 0bddfe2..2c1ff2a 100644
--- a/docs/classes.rst
+++ b/docs/classes.rst
@@ -38,7 +38,7 @@
return m.ptr();
}
-:class:`class_` creates bindings for a C++ `class` or `struct`-style data
+:class:`class_` creates bindings for a C++ *class* or *struct*-style data
structure. :func:`init` is a convenience function that takes the types of a
constructor's parameters as template arguments and wraps the corresponding
constructor (see the :ref:`custom_constructors` section for details). An
diff --git a/docs/conf.py b/docs/conf.py
index c8f9644..82dfe26 100644
--- a/docs/conf.py
+++ b/docs/conf.py
@@ -16,6 +16,7 @@
import sys
import os
import shlex
+import subprocess
# If extensions (or modules to document with autodoc) are in another directory,
# add these directories to sys.path here. If the directory is relative to the
@@ -30,7 +31,11 @@
# Add any Sphinx extension module names here, as strings. They can be
# extensions coming with Sphinx (named 'sphinx.ext.*') or your custom
# ones.
-extensions = []
+extensions = ['breathe']
+
+breathe_projects = {'pybind11': '.build/doxygenxml/'}
+breathe_default_project = 'pybind11'
+breathe_domain_by_extension = {'h': 'cpp'}
# Add any paths that contain templates here, relative to this directory.
templates_path = ['.templates']
@@ -79,7 +84,7 @@
# The reST default role (used for this markup: `text`) to use for all
# documents.
-#default_role = None
+default_role = 'any'
# If true, '()' will be appended to :func: etc. cross-reference text.
#add_function_parentheses = True
@@ -306,3 +311,22 @@
primary_domain = 'cpp'
highlight_language = 'cpp'
+
+
+def generate_doxygen_xml(app):
+ build_dir = '.build'
+ if not os.path.exists(build_dir):
+ os.mkdir(build_dir)
+
+ try:
+ subprocess.call(['doxygen', '--version'])
+ retcode = subprocess.call(['doxygen'])
+ if retcode < 0:
+ sys.stderr.write("doxygen error code: {}\n".format(-retcode))
+ except OSError as e:
+ sys.stderr.write("doxygen execution failed: {}\n".format(e))
+
+
+def setup(app):
+ """Add hook for building doxygen xml when needed"""
+ app.connect("builder-inited", generate_doxygen_xml)
diff --git a/docs/environment.yml b/docs/environment.yml
new file mode 100644
index 0000000..5a3332b
--- /dev/null
+++ b/docs/environment.yml
@@ -0,0 +1,9 @@
+name: rtd
+channels:
+- dean0x7d
+- defaults
+dependencies:
+- doxygen
+- pip
+- pip:
+ - https://github.com/michaeljones/breathe/archive/master.zip
diff --git a/docs/reference.rst b/docs/reference.rst
index 542259e..3d211f7 100644
--- a/docs/reference.rst
+++ b/docs/reference.rst
@@ -12,236 +12,69 @@
Macros
======
-.. function:: PYBIND11_PLUGIN(const char *name)
-
- This macro creates the entry point that will be invoked when the Python
- interpreter imports a plugin library. Please create a
- :class:`module` in the function body and return the pointer to its
- underlying Python object at the end.
-
- .. code-block:: cpp
-
- PYBIND11_PLUGIN(example) {
- pybind11::module m("example", "pybind11 example plugin");
- /// Set up bindings here
- return m.ptr();
- }
+.. doxygendefine:: PYBIND11_PLUGIN
.. _core_types:
Convenience classes for arbitrary Python types
==============================================
+Common member functions
+-----------------------
+
+.. doxygenclass:: object_api
+ :members:
+
Without reference counting
--------------------------
-.. class:: handle
-
- The :class:`handle` class is a thin wrapper around an arbitrary Python
- object (i.e. a ``PyObject *`` in Python's C API). It does not perform any
- automatic reference counting and merely provides a basic C++ interface to
- various Python API functions.
-
-.. seealso::
-
- The :class:`object` class inherits from :class:`handle` and adds automatic
- reference counting features.
-
-.. function:: handle::handle()
-
- The default constructor creates a handle with a ``nullptr``-valued pointer.
-
-.. function:: handle::handle(const handle&)
-
- Copy constructor
-
-.. function:: handle::handle(PyObject *)
-
- Creates a :class:`handle` from the given raw Python object pointer.
-
-.. function:: PyObject * handle::ptr() const
-
- Return the ``PyObject *`` underlying a :class:`handle`.
-
-.. function:: const handle& handle::inc_ref() const
-
- Manually increase the reference count of the Python object. Usually, it is
- preferable to use the :class:`object` class which derives from
- :class:`handle` and calls this function automatically. Returns a reference
- to itself.
-
-.. function:: const handle& handle::dec_ref() const
-
- Manually decrease the reference count of the Python object. Usually, it is
- preferable to use the :class:`object` class which derives from
- :class:`handle` and calls this function automatically. Returns a reference
- to itself.
-
-.. function:: void handle::ref_count() const
-
- Return the object's current reference count
-
-.. function:: handle handle::get_type() const
-
- Return a handle to the Python type object underlying the instance
-
-.. function detail::accessor handle::operator[](handle key) const
-
- Return an internal functor to invoke the object's sequence protocol.
- Casting the returned ``detail::accessor`` instance to a :class:`handle` or
- :class:`object` subclass causes a corresponding call to ``__getitem__``.
- Assigning a :class:`handle` or :class:`object` subclass causes a call to
- ``__setitem__``.
-
-.. function detail::accessor handle::operator[](const char *key) const
-
- See the above function (the only difference is that they key is provided as
- a string literal).
-
-.. function detail::accessor handle::attr(handle key) const
-
- Return an internal functor to access the object's attributes.
- Casting the returned ``detail::accessor`` instance to a :class:`handle` or
- :class:`object` subclass causes a corresponding call to ``__getattr``.
- Assigning a :class:`handle` or :class:`object` subclass causes a call to
- ``__setattr``.
-
-.. function detail::accessor handle::attr(const char *key) const
-
- See the above function (the only difference is that they key is provided as
- a string literal).
-
-.. function operator handle::bool() const
-
- Return ``true`` when the :class:`handle` wraps a valid Python object.
-
-.. function str handle::str() const
-
- Return a string representation of the object. This is analogous to
- the ``str()`` function in Python.
-
-.. function:: template <typename T> T handle::cast() const
-
- Attempt to cast the Python object into the given C++ type. A
- :class:`cast_error` will be throw upon failure.
-
-.. function:: template <typename ... Args> object handle::call(Args&&... args) const
-
- Assuming the Python object is a function or implements the ``__call__``
- protocol, ``call()`` invokes the underlying function, passing an arbitrary
- set of parameters. The result is returned as a :class:`object` and may need
- to be converted back into a Python object using :func:`handle::cast`.
-
- When some of the arguments cannot be converted to Python objects, the
- function will throw a :class:`cast_error` exception. When the Python
- function call fails, a :class:`error_already_set` exception is thrown.
+.. doxygenclass:: handle
+ :members:
With reference counting
-----------------------
-.. class:: object : public handle
+.. doxygenclass:: object
+ :members:
- Like :class:`handle`, the object class is a thin wrapper around an
- arbitrary Python object (i.e. a ``PyObject *`` in Python's C API). In
- contrast to :class:`handle`, it optionally increases the object's reference
- count upon construction, and it *always* decreases the reference count when
- the :class:`object` instance goes out of scope and is destructed. When
- using :class:`object` instances consistently, it is much easier to get
- reference counting right at the first attempt.
+.. doxygenfunction:: reinterpret_borrow
-.. function:: object::object(const object &o)
-
- Copy constructor; always increases the reference count
-
-.. function:: object::object(const handle &h, bool borrowed)
-
- Creates a :class:`object` from the given :class:`handle`. The reference
- count is only increased if the ``borrowed`` parameter is set to ``true``.
-
-.. function:: object::object(PyObject *ptr, bool borrowed)
-
- Creates a :class:`object` from the given raw Python object pointer. The
- reference count is only increased if the ``borrowed`` parameter is set to
- ``true``.
-
-.. function:: object::object(object &&other)
-
- Move constructor; steals the object from ``other`` and preserves its
- reference count.
-
-.. function:: handle object::release()
-
- Resets the internal pointer to ``nullptr`` without without decreasing the
- object's reference count. The function returns a raw handle to the original
- Python object.
-
-.. function:: object::~object()
-
- Destructor, which automatically calls :func:`handle::dec_ref()`.
+.. doxygenfunction:: reinterpret_steal
Convenience classes for specific Python types
=============================================
+.. doxygenclass:: module
+ :members:
-.. class:: module : public object
-
-.. function:: module::module(const char *name, const char *doc = nullptr)
-
- Create a new top-level Python module with the given name and docstring
-
-.. function:: module module::def_submodule(const char *name, const char *doc = nullptr)
-
- Create and return a new Python submodule with the given name and docstring.
- This also works recursively, i.e.
-
- .. code-block:: cpp
-
- pybind11::module m("example", "pybind11 example plugin");
- pybind11::module m2 = m.def_submodule("sub", "A submodule of 'example'");
- pybind11::module m3 = m2.def_submodule("subsub", "A submodule of 'example.sub'");
-
-.. cpp:function:: template <typename Func, typename ... Extra> module& module::def(const char *name, Func && f, Extra && ... extra)
-
- Create Python binding for a new function within the module scope. ``Func``
- can be a plain C++ function, a function pointer, or a lambda function. For
- details on the ``Extra&& ... extra`` argument, see section :ref:`extras`.
+.. doxygengroup:: pytypes
+ :members:
.. _extras:
-Passing extra arguments to the def function
-===========================================
+Passing extra arguments to ``def`` or ``class_``
+================================================
-.. class:: arg
+.. doxygengroup:: annotations
+ :members:
-.. function:: arg::arg(const char *name)
+Python build-in functions
+=========================
-.. function:: template <typename T> arg_v arg::operator=(T &&value)
+.. doxygengroup:: python_builtins
+ :members:
-.. class:: arg_v : public arg
+Exceptions
+==========
- Represents a named argument with a default value
+.. doxygenclass:: error_already_set
+ :members:
-.. class:: sibling
+.. doxygenclass:: builtin_exception
+ :members:
- Used to specify a handle to an existing sibling function; used internally
- to implement function overloading in :func:`module::def` and
- :func:`class_::def`.
-.. function:: sibling::sibling(handle handle)
+Literals
+========
-.. class doc
-
- This is class is internally used by pybind11.
-
-.. function:: doc::doc(const char *value)
-
- Create a new docstring with the specified value
-
-.. class name
-
- This is class is internally used by pybind11.
-
-.. function:: name::name(const char *value)
-
- Used to specify the function name
-
+.. doxygennamespace:: literals
diff --git a/include/pybind11/attr.h b/include/pybind11/attr.h
index 740d3be..41f59e7 100644
--- a/include/pybind11/attr.h
+++ b/include/pybind11/attr.h
@@ -14,6 +14,9 @@
NAMESPACE_BEGIN(pybind11)
+/// \addtogroup annotations
+/// @{
+
/// Annotation for methods
struct is_method { handle class_; is_method(const handle &c) : class_(c) { } };
@@ -56,6 +59,8 @@
/// Annotation to mark enums as an arithmetic type
struct arithmetic { };
+/// @} annotations
+
NAMESPACE_BEGIN(detail)
/* Forward declarations */
enum op_id : int;
diff --git a/include/pybind11/cast.h b/include/pybind11/cast.h
index 9077dbb..a52d843 100644
--- a/include/pybind11/cast.h
+++ b/include/pybind11/cast.h
@@ -1177,14 +1177,18 @@
return result;
}
+/// \ingroup annotations
/// Annotation for keyword arguments
struct arg {
+ /// Set the name of the argument
constexpr explicit arg(const char *name) : name(name) { }
+ /// Assign a value to this argument
template <typename T> arg_v operator=(T &&value) const;
const char *name;
};
+/// \ingroup annotations
/// Annotation for keyword arguments with values
struct arg_v : arg {
template <typename T>
@@ -1213,7 +1217,9 @@
template <typename /*unused*/> using arg_t = arg_v;
inline namespace literals {
-/// String literal version of arg
+/** \rst
+ String literal version of `arg`
+ \endrst */
constexpr arg operator"" _a(const char *name, size_t) { return arg(name); }
}
diff --git a/include/pybind11/common.h b/include/pybind11/common.h
index ce0c2ed..a0894ea 100644
--- a/include/pybind11/common.h
+++ b/include/pybind11/common.h
@@ -159,6 +159,19 @@
#define PYBIND11_INTERNALS_ID "__pybind11_" \
PYBIND11_TOSTRING(PYBIND11_VERSION_MAJOR) "_" PYBIND11_TOSTRING(PYBIND11_VERSION_MINOR) "__"
+/** \rst
+ This macro creates the entry point that will be invoked when the Python interpreter
+ imports a plugin library. Please create a `module` in the function body and return
+ the pointer to its underlying Python object at the end.
+
+ .. code-block:: cpp
+
+ PYBIND11_PLUGIN(example) {
+ pybind11::module m("example", "pybind11 example plugin");
+ /// Set up bindings here
+ return m.ptr();
+ }
+\endrst */
#define PYBIND11_PLUGIN(name) \
static PyObject *pybind11_init(); \
PYBIND11_PLUGIN_IMPL(name) { \
@@ -388,7 +401,7 @@
template <class T> using negation = bool_constant<!T::value>;
#endif
-/// Compile-time all/any/none of that check the ::value of all template types
+/// Compile-time all/any/none of that check the boolean value of all template types
#ifdef PYBIND11_CPP17
template <class... Ts> using all_of = bool_constant<(Ts::value && ...)>;
template <class... Ts> using any_of = bool_constant<(Ts::value || ...)>;
@@ -532,7 +545,8 @@
class builtin_exception : public std::runtime_error {
public:
using std::runtime_error::runtime_error;
- virtual void set_error() const = 0; /// Set the error using the Python C API
+ /// Set the error using the Python C API
+ virtual void set_error() const = 0;
};
#define PYBIND11_RUNTIME_EXCEPTION(name, type) \
diff --git a/include/pybind11/pybind11.h b/include/pybind11/pybind11.h
index 99b1f72..81a3d1e 100644
--- a/include/pybind11/pybind11.h
+++ b/include/pybind11/pybind11.h
@@ -544,6 +544,7 @@
public:
PYBIND11_OBJECT_DEFAULT(module, object, PyModule_Check)
+ /// Create a new top-level Python module with the given name and docstring
explicit module(const char *name, const char *doc = nullptr) {
if (!options::show_user_defined_docstrings()) doc = nullptr;
#if PY_MAJOR_VERSION >= 3
@@ -562,6 +563,11 @@
inc_ref();
}
+ /** \rst
+ Create Python binding for a new function within the module scope. ``Func``
+ can be a plain C++ function, a function pointer, or a lambda function. For
+ details on the ``Extra&& ... extra`` argument, see section :ref:`extras`.
+ \endrst */
template <typename Func, typename... Extra>
module &def(const char *name_, Func &&f, const Extra& ... extra) {
cpp_function func(std::forward<Func>(f), name(name_), scope(*this),
@@ -572,6 +578,16 @@
return *this;
}
+ /** \rst
+ Create and return a new Python submodule with the given name and docstring.
+ This also works recursively, i.e.
+
+ .. code-block:: cpp
+
+ py::module m("example", "pybind11 example plugin");
+ py::module m2 = m.def_submodule("sub", "A submodule of 'example'");
+ py::module m3 = m2.def_submodule("subsub", "A submodule of 'example.sub'");
+ \endrst */
module def_submodule(const char *name, const char *doc = nullptr) {
std::string full_name = std::string(PyModule_GetName(m_ptr))
+ std::string(".") + std::string(name);
@@ -582,6 +598,7 @@
return result;
}
+ /// Import and return a module or throws `error_already_set`.
static module import(const char *name) {
PyObject *obj = PyImport_ImportModule(name);
if (!obj)
diff --git a/include/pybind11/pytypes.h b/include/pybind11/pytypes.h
index a89aad7..bc806de 100644
--- a/include/pybind11/pytypes.h
+++ b/include/pybind11/pytypes.h
@@ -45,51 +45,130 @@
class pyobject_tag { };
template <typename T> using is_pyobject = std::is_base_of<pyobject_tag, typename std::remove_reference<T>::type>;
-/// Mixin which adds common functions to handle, object and various accessors.
-/// The only requirement for `Derived` is to implement `PyObject *Derived::ptr() const`.
+/** \rst
+ A mixin class which adds common functions to `handle`, `object` and various accessors.
+ The only requirement for `Derived` is to implement ``PyObject *Derived::ptr() const``.
+\endrst */
template <typename Derived>
class object_api : public pyobject_tag {
const Derived &derived() const { return static_cast<const Derived &>(*this); }
public:
+ /** \rst
+ Return an iterator equivalent to calling ``iter()`` in Python. The object
+ must be a collection which supports the iteration protocol.
+ \endrst */
iterator begin() const;
+ /// Return a sentinel which ends iteration.
iterator end() const;
- item_accessor operator[](handle key) const;
- item_accessor operator[](const char *key) const;
- obj_attr_accessor attr(handle key) const;
- str_attr_accessor attr(const char *key) const;
- args_proxy operator*() const;
- template <typename T> bool contains(T &&key) const;
+ /** \rst
+ Return an internal functor to invoke the object's sequence protocol. Casting
+ the returned ``detail::item_accessor`` instance to a `handle` or `object`
+ subclass causes a corresponding call to ``__getitem__``. Assigning a `handle`
+ or `object` subclass causes a call to ``__setitem__``.
+ \endrst */
+ item_accessor operator[](handle key) const;
+ /// See above (the only difference is that they key is provided as a string literal)
+ item_accessor operator[](const char *key) const;
+
+ /** \rst
+ Return an internal functor to access the object's attributes. Casting the
+ returned ``detail::obj_attr_accessor`` instance to a `handle` or `object`
+ subclass causes a corresponding call to ``getattr``. Assigning a `handle`
+ or `object` subclass causes a call to ``setattr``.
+ \endrst */
+ obj_attr_accessor attr(handle key) const;
+ /// See above (the only difference is that they key is provided as a string literal)
+ str_attr_accessor attr(const char *key) const;
+
+ /** \rst
+ Matches * unpacking in Python, e.g. to unpack arguments out of a ``tuple``
+ or ``list`` for a function call. Applying another * to the result yields
+ ** unpacking, e.g. to unpack a dict as function keyword arguments.
+ See :ref:`calling_python_functions`.
+ \endrst */
+ args_proxy operator*() const;
+
+ /// Check if the given item is contained within this object, i.e. ``item in obj``.
+ template <typename T> bool contains(T &&item) const;
+
+ /** \rst
+ Assuming the Python object is a function or implements the ``__call__``
+ protocol, ``operator()`` invokes the underlying function, passing an
+ arbitrary set of parameters. The result is returned as a `object` and
+ may need to be converted back into a Python object using `handle::cast()`.
+
+ When some of the arguments cannot be converted to Python objects, the
+ function will throw a `cast_error` exception. When the Python function
+ call fails, a `error_already_set` exception is thrown.
+ \endrst */
template <return_value_policy policy = return_value_policy::automatic_reference, typename... Args>
object operator()(Args &&...args) const;
template <return_value_policy policy = return_value_policy::automatic_reference, typename... Args>
PYBIND11_DEPRECATED("call(...) was deprecated in favor of operator()(...)")
object call(Args&&... args) const;
+ /// Equivalent to ``obj is None`` in Python.
bool is_none() const { return derived().ptr() == Py_None; }
- PYBIND11_DEPRECATED("Instead of obj.str(), use py::str(obj)")
+ PYBIND11_DEPRECATED("Use py::str(obj) instead")
pybind11::str str() const;
+ /// Return the object's current reference count
int ref_count() const { return static_cast<int>(Py_REFCNT(derived().ptr())); }
+ /// Return a handle to the Python type object underlying the instance
handle get_type() const;
};
NAMESPACE_END(detail)
-/// Holds a reference to a Python object (no reference counting)
+/** \rst
+ Holds a reference to a Python object (no reference counting)
+
+ The `handle` class is a thin wrapper around an arbitrary Python object (i.e. a
+ ``PyObject *`` in Python's C API). It does not perform any automatic reference
+ counting and merely provides a basic C++ interface to various Python API functions.
+
+ .. seealso::
+ The `object` class inherits from `handle` and adds automatic reference
+ counting features.
+\endrst */
class handle : public detail::object_api<handle> {
public:
+ /// The default constructor creates a handle with a ``nullptr``-valued pointer
handle() = default;
+ /// Creates a ``handle`` from the given raw Python object pointer
handle(PyObject *ptr) : m_ptr(ptr) { } // Allow implicit conversion from PyObject*
+ /// Return the underlying ``PyObject *`` pointer
PyObject *ptr() const { return m_ptr; }
PyObject *&ptr() { return m_ptr; }
+
+ /** \rst
+ Manually increase the reference count of the Python object. Usually, it is
+ preferable to use the `object` class which derives from `handle` and calls
+ this function automatically. Returns a reference to itself.
+ \endrst */
const handle& inc_ref() const { Py_XINCREF(m_ptr); return *this; }
+
+ /** \rst
+ Manually decrease the reference count of the Python object. Usually, it is
+ preferable to use the `object` class which derives from `handle` and calls
+ this function automatically. Returns a reference to itself.
+ \endrst */
const handle& dec_ref() const { Py_XDECREF(m_ptr); return *this; }
+ /** \rst
+ Attempt to cast the Python object into the given C++ type. A `cast_error`
+ will be throw upon failure.
+ \endrst */
template <typename T> T cast() const;
+ /// Return ``true`` when the `handle` wraps a valid Python object
explicit operator bool() const { return m_ptr != nullptr; }
+ /** \rst
+ Check that the underlying pointers are the same.
+ Equivalent to ``obj1 is obj2`` in Python.
+ \endrst */
bool operator==(const handle &h) const { return m_ptr == h.m_ptr; }
bool operator!=(const handle &h) const { return m_ptr != h.m_ptr; }
PYBIND11_DEPRECATED("Use handle::operator bool() instead")
@@ -98,16 +177,33 @@
PyObject *m_ptr = nullptr;
};
-/// Holds a reference to a Python object (with reference counting)
+/** \rst
+ Holds a reference to a Python object (with reference counting)
+
+ Like `handle`, the `object` class is a thin wrapper around an arbitrary Python
+ object (i.e. a ``PyObject *`` in Python's C API). In contrast to `handle`, it
+ optionally increases the object's reference count upon construction, and it
+ *always* decreases the reference count when the `object` instance goes out of
+ scope and is destructed. When using `object` instances consistently, it is much
+ easier to get reference counting right at the first attempt.
+\endrst */
class object : public handle {
public:
object() = default;
PYBIND11_DEPRECATED("Use reinterpret_borrow<object>() or reinterpret_steal<object>()")
object(handle h, bool is_borrowed) : handle(h) { if (is_borrowed) inc_ref(); }
+ /// Copy constructor; always increases the reference count
object(const object &o) : handle(o) { inc_ref(); }
+ /// Move constructor; steals the object from ``other`` and preserves its reference count
object(object &&other) noexcept { m_ptr = other.m_ptr; other.m_ptr = nullptr; }
+ /// Destructor; automatically calls `handle::dec_ref()`
~object() { dec_ref(); }
+ /** \rst
+ Resets the internal pointer to ``nullptr`` without without decreasing the
+ object's reference count. The function returns a raw handle to the original
+ Python object.
+ \endrst */
handle release() {
PyObject *tmp = m_ptr;
m_ptr = nullptr;
@@ -150,12 +246,41 @@
object(handle h, stolen_t) : handle(h) { }
};
-/** The following functions don't do any kind of conversion, they simply declare
- that a PyObject is a certain type and borrow or steal the reference. */
+/** \rst
+ Declare that a `handle` or ``PyObject *`` is a certain type and borrow the reference.
+ The target type ``T`` must be `object` or one of its derived classes. The function
+ doesn't do any conversions or checks. It's up to the user to make sure that the
+ target type is correct.
+
+ .. code-block:: cpp
+
+ PyObject *result = PySequence_GetItem(obj, index);
+ py::object o = reinterpret_borrow<py::object>(p);
+ // or
+ py::tuple t = reinterpret_borrow<py::tuple>(p); // <-- `p` must be already be a `tuple`
+\endrst */
template <typename T> T reinterpret_borrow(handle h) { return {h, object::borrowed}; }
+
+/** \rst
+ Like `reinterpret_borrow`, but steals the reference.
+
+ .. code-block:: cpp
+
+ PyObject *p = PyObject_Str(obj);
+ py::str s = reinterpret_steal<py::str>(p); // <-- `p` must be already be a `str`
+\endrst */
template <typename T> T reinterpret_steal(handle h) { return {h, object::stolen}; }
-/// Check if `obj` is an instance of type `T`
+/** \defgroup python_builtins _
+ Unless stated otherwise, the following C++ functions behave the same
+ as their Python counterparts.
+ */
+
+/** \ingroup python_builtins
+ \rst
+ Return true if ``obj`` is an instance of ``T``. Type ``T`` must be a subclass of
+ `object` or a class which was exposed to Python as ``py::class_<T>``.
+\endrst */
template <typename T, detail::enable_if_t<std::is_base_of<object, T>::value, int> = 0>
bool isinstance(handle obj) { return T::_check(obj); }
@@ -165,6 +290,8 @@
template <> inline bool isinstance<handle>(handle obj) = delete;
template <> inline bool isinstance<object>(handle obj) { return obj.ptr() != nullptr; }
+/// \ingroup python_builtins
+/// Return true if ``obj`` is an instance of the ``type``.
inline bool isinstance(handle obj, handle type) {
const auto result = PyObject_IsInstance(obj.ptr(), type.ptr());
if (result == -1)
@@ -172,6 +299,8 @@
return result != 0;
}
+/// \addtogroup python_builtins
+/// @{
inline bool hasattr(handle obj, handle name) {
return PyObject_HasAttr(obj.ptr(), name.ptr()) == 1;
}
@@ -217,6 +346,7 @@
inline void setattr(handle obj, const char *name, handle value) {
if (PyObject_SetAttrString(obj.ptr(), name, value.ptr()) != 0) { throw error_already_set(); }
}
+/// @} python_builtins
NAMESPACE_BEGIN(detail)
inline handle get_function(handle value) {
@@ -459,6 +589,8 @@
PYBIND11_OBJECT(Name, Parent, CheckFun) \
Name() : Parent() { }
+/// \addtogroup pytypes
+/// @{
class iterator : public object {
public:
/** Caveat: copying an iterator does not (and cannot) clone the internal
@@ -528,6 +660,10 @@
explicit str(const bytes &b);
+ /** \rst
+ Return a string representation of the object. This is analogous to
+ the ``str()`` function in Python.
+ \endrst */
explicit str(handle h) : object(raw_str(h.ptr()), stolen) { }
operator std::string() const {
@@ -561,12 +697,17 @@
return str_value;
}
};
+/// @} pytypes
inline namespace literals {
-/// String literal version of str
+/** \rst
+ String literal version of `str`
+ \endrst */
inline str operator"" _s(const char *s, size_t size) { return {s, size}; }
}
+/// \addtogroup pytypes
+/// @{
class bytes : public object {
public:
PYBIND11_OBJECT(bytes, object, PYBIND11_BYTES_CHECK)
@@ -870,7 +1011,10 @@
PYBIND11_OBJECT_CVT(memoryview, object, PyMemoryView_Check, PyMemoryView_FromObject)
};
+/// @} pytypes
+/// \addtogroup python_builtins
+/// @{
inline size_t len(handle h) {
ssize_t result = PyObject_Length(h.ptr());
if (result < 0)
@@ -888,6 +1032,7 @@
#endif
return reinterpret_steal<str>(str_value);
}
+/// @} python_builtins
NAMESPACE_BEGIN(detail)
template <typename D> iterator object_api<D>::begin() const {
@@ -911,8 +1056,8 @@
template <typename D> args_proxy object_api<D>::operator*() const {
return args_proxy(derived().ptr());
}
-template <typename D> template <typename T> bool object_api<D>::contains(T &&key) const {
- return attr("__contains__")(std::forward<T>(key)).template cast<bool>();
+template <typename D> template <typename T> bool object_api<D>::contains(T &&item) const {
+ return attr("__contains__")(std::forward<T>(item)).template cast<bool>();
}
template <typename D>