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
This commit is contained in:
Dean Moldovan 2017-01-31 16:54:08 +01:00 committed by Wenzel Jakob
parent cc88aaecc8
commit 57a9bbc6c7
15 changed files with 313 additions and 234 deletions

2
.readthedocs.yml Normal file
View File

@ -0,0 +1,2 @@
conda:
file: docs/environment.yml

View File

@ -51,7 +51,10 @@ matrix:
env: DOCS STYLE LINT env: DOCS STYLE LINT
install: install:
- pip install --upgrade sphinx sphinx_rtd_theme flake8 pep8-naming - 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: script:
- make -C docs html SPHINX_OPTIONS=-W - make -C docs html SPHINX_OPTIONS=-W
- tools/check-style.sh - tools/check-style.sh

19
docs/Doxyfile Normal file
View File

@ -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

View File

@ -4,8 +4,8 @@ Chrono
When including the additional header file :file:`pybind11/chrono.h` conversions When including the additional header file :file:`pybind11/chrono.h` conversions
from C++11 chrono datatypes to python datetime objects are automatically enabled. from C++11 chrono datatypes to python datetime objects are automatically enabled.
This header also enables conversions of python floats (often from sources such This header also enables conversions of python floats (often from sources such
as `time.monotonic()`, `time.perf_counter()` and `time.process_time()`) into as ``time.monotonic()``, ``time.perf_counter()`` and ``time.process_time()``)
durations. into durations.
An overview of clocks in C++11 An overview of clocks in C++11
------------------------------ ------------------------------

View File

@ -14,7 +14,7 @@ lifetime of objects managed by them. This can lead to issues when creating
bindings for functions that return a non-trivial type. Just by looking at the 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 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 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 annotations that can be passed to the :func:`module::def` and
:func:`class_::def` functions. The default policy is :func:`class_::def` functions. The default policy is
:enum:`return_value_policy::automatic`. :enum:`return_value_policy::automatic`.
@ -158,7 +158,7 @@ targeted arguments can be passed through the :class:`cpp_function` constructor:
Additional call policies Additional call policies
======================== ========================
In addition to the above return value policies, further `call policies` can be In addition to the above return value policies, further *call policies* can be
specified to indicate dependencies between parameters. In general, call policies 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 are required when the C++ object is any kind of container and another object is being
added to the container. added to the container.

View File

@ -33,6 +33,8 @@ The reverse direction uses the following syntax:
When conversion fails, both directions throw the exception :class:`cast_error`. When conversion fails, both directions throw the exception :class:`cast_error`.
.. _calling_python_functions:
Calling Python functions Calling Python functions
======================== ========================

View File

@ -38,7 +38,7 @@ The binding code for ``Pet`` looks as follows:
return m.ptr(); 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 structure. :func:`init` is a convenience function that takes the types of a
constructor's parameters as template arguments and wraps the corresponding constructor's parameters as template arguments and wraps the corresponding
constructor (see the :ref:`custom_constructors` section for details). An constructor (see the :ref:`custom_constructors` section for details). An

View File

@ -16,6 +16,7 @@
import sys import sys
import os import os
import shlex import shlex
import subprocess
# If extensions (or modules to document with autodoc) are in another directory, # 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 # add these directories to sys.path here. If the directory is relative to the
@ -30,7 +31,11 @@ import shlex
# Add any Sphinx extension module names here, as strings. They can be # Add any Sphinx extension module names here, as strings. They can be
# extensions coming with Sphinx (named 'sphinx.ext.*') or your custom # extensions coming with Sphinx (named 'sphinx.ext.*') or your custom
# ones. # 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. # Add any paths that contain templates here, relative to this directory.
templates_path = ['.templates'] templates_path = ['.templates']
@ -79,7 +84,7 @@ exclude_patterns = ['.build', 'release.rst']
# The reST default role (used for this markup: `text`) to use for all # The reST default role (used for this markup: `text`) to use for all
# documents. # documents.
#default_role = None default_role = 'any'
# If true, '()' will be appended to :func: etc. cross-reference text. # If true, '()' will be appended to :func: etc. cross-reference text.
#add_function_parentheses = True #add_function_parentheses = True
@ -306,3 +311,22 @@ texinfo_documents = [
primary_domain = 'cpp' primary_domain = 'cpp'
highlight_language = '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)

9
docs/environment.yml Normal file
View File

@ -0,0 +1,9 @@
name: rtd
channels:
- dean0x7d
- defaults
dependencies:
- doxygen
- pip
- pip:
- https://github.com/michaeljones/breathe/archive/master.zip

View File

@ -12,236 +12,69 @@ Reference
Macros Macros
====== ======
.. function:: PYBIND11_PLUGIN(const char *name) .. doxygendefine:: PYBIND11_PLUGIN
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();
}
.. _core_types: .. _core_types:
Convenience classes for arbitrary Python types Convenience classes for arbitrary Python types
============================================== ==============================================
Common member functions
-----------------------
.. doxygenclass:: object_api
:members:
Without reference counting Without reference counting
-------------------------- --------------------------
.. class:: handle .. doxygenclass:: handle
:members:
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.
With reference counting With reference counting
----------------------- -----------------------
.. class:: object : public handle .. doxygenclass:: object
:members:
Like :class:`handle`, the object class is a thin wrapper around an .. doxygenfunction:: reinterpret_borrow
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.
.. function:: object::object(const object &o) .. doxygenfunction:: reinterpret_steal
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()`.
Convenience classes for specific Python types Convenience classes for specific Python types
============================================= =============================================
.. doxygenclass:: module
:members:
.. class:: module : public object .. doxygengroup:: pytypes
:members:
.. 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`.
.. _extras: .. _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

View File

@ -14,6 +14,9 @@
NAMESPACE_BEGIN(pybind11) NAMESPACE_BEGIN(pybind11)
/// \addtogroup annotations
/// @{
/// Annotation for methods /// Annotation for methods
struct is_method { handle class_; is_method(const handle &c) : class_(c) { } }; struct is_method { handle class_; is_method(const handle &c) : class_(c) { } };
@ -56,6 +59,8 @@ struct metaclass { };
/// Annotation to mark enums as an arithmetic type /// Annotation to mark enums as an arithmetic type
struct arithmetic { }; struct arithmetic { };
/// @} annotations
NAMESPACE_BEGIN(detail) NAMESPACE_BEGIN(detail)
/* Forward declarations */ /* Forward declarations */
enum op_id : int; enum op_id : int;

View File

@ -1177,14 +1177,18 @@ template <return_value_policy policy = return_value_policy::automatic_reference,
return result; return result;
} }
/// \ingroup annotations
/// Annotation for keyword arguments /// Annotation for keyword arguments
struct arg { struct arg {
/// Set the name of the argument
constexpr explicit arg(const char *name) : name(name) { } constexpr explicit arg(const char *name) : name(name) { }
/// Assign a value to this argument
template <typename T> arg_v operator=(T &&value) const; template <typename T> arg_v operator=(T &&value) const;
const char *name; const char *name;
}; };
/// \ingroup annotations
/// Annotation for keyword arguments with values /// Annotation for keyword arguments with values
struct arg_v : arg { struct arg_v : arg {
template <typename T> template <typename T>
@ -1213,7 +1217,9 @@ arg_v arg::operator=(T &&value) const { return {name, std::forward<T>(value)}; }
template <typename /*unused*/> using arg_t = arg_v; template <typename /*unused*/> using arg_t = arg_v;
inline namespace literals { 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); } constexpr arg operator"" _a(const char *name, size_t) { return arg(name); }
} }

View File

@ -159,6 +159,19 @@ extern "C" {
#define PYBIND11_INTERNALS_ID "__pybind11_" \ #define PYBIND11_INTERNALS_ID "__pybind11_" \
PYBIND11_TOSTRING(PYBIND11_VERSION_MAJOR) "_" PYBIND11_TOSTRING(PYBIND11_VERSION_MINOR) "__" 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) \ #define PYBIND11_PLUGIN(name) \
static PyObject *pybind11_init(); \ static PyObject *pybind11_init(); \
PYBIND11_PLUGIN_IMPL(name) { \ PYBIND11_PLUGIN_IMPL(name) { \
@ -388,7 +401,7 @@ template <bool B> using bool_constant = std::integral_constant<bool, B>;
template <class T> using negation = bool_constant<!T::value>; template <class T> using negation = bool_constant<!T::value>;
#endif #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 #ifdef PYBIND11_CPP17
template <class... Ts> using all_of = bool_constant<(Ts::value && ...)>; template <class... Ts> using all_of = bool_constant<(Ts::value && ...)>;
template <class... Ts> using any_of = bool_constant<(Ts::value || ...)>; template <class... Ts> using any_of = bool_constant<(Ts::value || ...)>;
@ -532,7 +545,8 @@ private:
class builtin_exception : public std::runtime_error { class builtin_exception : public std::runtime_error {
public: public:
using std::runtime_error::runtime_error; 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) \ #define PYBIND11_RUNTIME_EXCEPTION(name, type) \

View File

@ -544,6 +544,7 @@ class module : public object {
public: public:
PYBIND11_OBJECT_DEFAULT(module, object, PyModule_Check) 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) { explicit module(const char *name, const char *doc = nullptr) {
if (!options::show_user_defined_docstrings()) doc = nullptr; if (!options::show_user_defined_docstrings()) doc = nullptr;
#if PY_MAJOR_VERSION >= 3 #if PY_MAJOR_VERSION >= 3
@ -562,6 +563,11 @@ public:
inc_ref(); 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> template <typename Func, typename... Extra>
module &def(const char *name_, Func &&f, const Extra& ... extra) { module &def(const char *name_, Func &&f, const Extra& ... extra) {
cpp_function func(std::forward<Func>(f), name(name_), scope(*this), cpp_function func(std::forward<Func>(f), name(name_), scope(*this),
@ -572,6 +578,16 @@ public:
return *this; 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) { module def_submodule(const char *name, const char *doc = nullptr) {
std::string full_name = std::string(PyModule_GetName(m_ptr)) std::string full_name = std::string(PyModule_GetName(m_ptr))
+ std::string(".") + std::string(name); + std::string(".") + std::string(name);
@ -582,6 +598,7 @@ public:
return result; return result;
} }
/// Import and return a module or throws `error_already_set`.
static module import(const char *name) { static module import(const char *name) {
PyObject *obj = PyImport_ImportModule(name); PyObject *obj = PyImport_ImportModule(name);
if (!obj) if (!obj)

View File

@ -45,51 +45,130 @@ using tuple_accessor = accessor<accessor_policies::tuple_item>;
class pyobject_tag { }; class pyobject_tag { };
template <typename T> using is_pyobject = std::is_base_of<pyobject_tag, typename std::remove_reference<T>::type>; 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. /** \rst
/// The only requirement for `Derived` is to implement `PyObject *Derived::ptr() const`. 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> template <typename Derived>
class object_api : public pyobject_tag { class object_api : public pyobject_tag {
const Derived &derived() const { return static_cast<const Derived &>(*this); } const Derived &derived() const { return static_cast<const Derived &>(*this); }
public: 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; iterator begin() const;
/// Return a sentinel which ends iteration.
iterator end() const; 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> template <return_value_policy policy = return_value_policy::automatic_reference, typename... Args>
object operator()(Args &&...args) const; object operator()(Args &&...args) const;
template <return_value_policy policy = return_value_policy::automatic_reference, typename... Args> template <return_value_policy policy = return_value_policy::automatic_reference, typename... Args>
PYBIND11_DEPRECATED("call(...) was deprecated in favor of operator()(...)") PYBIND11_DEPRECATED("call(...) was deprecated in favor of operator()(...)")
object call(Args&&... args) const; object call(Args&&... args) const;
/// Equivalent to ``obj is None`` in Python.
bool is_none() const { return derived().ptr() == Py_None; } 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; pybind11::str str() const;
/// Return the object's current reference count
int ref_count() const { return static_cast<int>(Py_REFCNT(derived().ptr())); } 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; handle get_type() const;
}; };
NAMESPACE_END(detail) 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> { class handle : public detail::object_api<handle> {
public: public:
/// The default constructor creates a handle with a ``nullptr``-valued pointer
handle() = default; handle() = default;
/// Creates a ``handle`` from the given raw Python object pointer
handle(PyObject *ptr) : m_ptr(ptr) { } // Allow implicit conversion from PyObject* handle(PyObject *ptr) : m_ptr(ptr) { } // Allow implicit conversion from PyObject*
/// Return the underlying ``PyObject *`` pointer
PyObject *ptr() const { return m_ptr; } PyObject *ptr() const { return m_ptr; }
PyObject *&ptr() { 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; } 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; } 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; template <typename T> T cast() const;
/// Return ``true`` when the `handle` wraps a valid Python object
explicit operator bool() const { return m_ptr != nullptr; } 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; }
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") PYBIND11_DEPRECATED("Use handle::operator bool() instead")
@ -98,16 +177,33 @@ protected:
PyObject *m_ptr = nullptr; 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 { class object : public handle {
public: public:
object() = default; object() = default;
PYBIND11_DEPRECATED("Use reinterpret_borrow<object>() or reinterpret_steal<object>()") PYBIND11_DEPRECATED("Use reinterpret_borrow<object>() or reinterpret_steal<object>()")
object(handle h, bool is_borrowed) : handle(h) { if (is_borrowed) inc_ref(); } 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(); } 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; } object(object &&other) noexcept { m_ptr = other.m_ptr; other.m_ptr = nullptr; }
/// Destructor; automatically calls `handle::dec_ref()`
~object() { 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() { handle release() {
PyObject *tmp = m_ptr; PyObject *tmp = m_ptr;
m_ptr = nullptr; m_ptr = nullptr;
@ -150,12 +246,41 @@ public:
object(handle h, stolen_t) : handle(h) { } object(handle h, stolen_t) : handle(h) { }
}; };
/** The following functions don't do any kind of conversion, they simply declare /** \rst
that a PyObject is a certain type and borrow or steal the reference. */ 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}; } 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}; } 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> template <typename T, detail::enable_if_t<std::is_base_of<object, T>::value, int> = 0>
bool isinstance(handle obj) { return T::_check(obj); } bool isinstance(handle obj) { return T::_check(obj); }
@ -165,6 +290,8 @@ bool isinstance(handle obj) { return detail::isinstance_generic(obj, typeid(T));
template <> inline bool isinstance<handle>(handle obj) = delete; template <> inline bool isinstance<handle>(handle obj) = delete;
template <> inline bool isinstance<object>(handle obj) { return obj.ptr() != nullptr; } 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) { inline bool isinstance(handle obj, handle type) {
const auto result = PyObject_IsInstance(obj.ptr(), type.ptr()); const auto result = PyObject_IsInstance(obj.ptr(), type.ptr());
if (result == -1) if (result == -1)
@ -172,6 +299,8 @@ inline bool isinstance(handle obj, handle type) {
return result != 0; return result != 0;
} }
/// \addtogroup python_builtins
/// @{
inline bool hasattr(handle obj, handle name) { inline bool hasattr(handle obj, handle name) {
return PyObject_HasAttr(obj.ptr(), name.ptr()) == 1; return PyObject_HasAttr(obj.ptr(), name.ptr()) == 1;
} }
@ -217,6 +346,7 @@ inline void setattr(handle obj, handle name, handle value) {
inline void setattr(handle obj, const char *name, handle value) { inline void setattr(handle obj, const char *name, handle value) {
if (PyObject_SetAttrString(obj.ptr(), name, value.ptr()) != 0) { throw error_already_set(); } if (PyObject_SetAttrString(obj.ptr(), name, value.ptr()) != 0) { throw error_already_set(); }
} }
/// @} python_builtins
NAMESPACE_BEGIN(detail) NAMESPACE_BEGIN(detail)
inline handle get_function(handle value) { inline handle get_function(handle value) {
@ -459,6 +589,8 @@ NAMESPACE_END(detail)
PYBIND11_OBJECT(Name, Parent, CheckFun) \ PYBIND11_OBJECT(Name, Parent, CheckFun) \
Name() : Parent() { } Name() : Parent() { }
/// \addtogroup pytypes
/// @{
class iterator : public object { class iterator : public object {
public: public:
/** Caveat: copying an iterator does not (and cannot) clone the internal /** Caveat: copying an iterator does not (and cannot) clone the internal
@ -528,6 +660,10 @@ public:
explicit str(const bytes &b); 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) { } explicit str(handle h) : object(raw_str(h.ptr()), stolen) { }
operator std::string() const { operator std::string() const {
@ -561,12 +697,17 @@ private:
return str_value; return str_value;
} }
}; };
/// @} pytypes
inline namespace literals { 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}; } inline str operator"" _s(const char *s, size_t size) { return {s, size}; }
} }
/// \addtogroup pytypes
/// @{
class bytes : public object { class bytes : public object {
public: public:
PYBIND11_OBJECT(bytes, object, PYBIND11_BYTES_CHECK) PYBIND11_OBJECT(bytes, object, PYBIND11_BYTES_CHECK)
@ -870,7 +1011,10 @@ public:
PYBIND11_OBJECT_CVT(memoryview, object, PyMemoryView_Check, PyMemoryView_FromObject) PYBIND11_OBJECT_CVT(memoryview, object, PyMemoryView_Check, PyMemoryView_FromObject)
}; };
/// @} pytypes
/// \addtogroup python_builtins
/// @{
inline size_t len(handle h) { inline size_t len(handle h) {
ssize_t result = PyObject_Length(h.ptr()); ssize_t result = PyObject_Length(h.ptr());
if (result < 0) if (result < 0)
@ -888,6 +1032,7 @@ inline str repr(handle h) {
#endif #endif
return reinterpret_steal<str>(str_value); return reinterpret_steal<str>(str_value);
} }
/// @} python_builtins
NAMESPACE_BEGIN(detail) NAMESPACE_BEGIN(detail)
template <typename D> iterator object_api<D>::begin() const { template <typename D> iterator object_api<D>::begin() const {
@ -911,8 +1056,8 @@ template <typename D> str_attr_accessor object_api<D>::attr(const char *key) con
template <typename D> args_proxy object_api<D>::operator*() const { template <typename D> args_proxy object_api<D>::operator*() const {
return args_proxy(derived().ptr()); return args_proxy(derived().ptr());
} }
template <typename D> template <typename T> bool object_api<D>::contains(T &&key) const { template <typename D> template <typename T> bool object_api<D>::contains(T &&item) const {
return attr("__contains__")(std::forward<T>(key)).template cast<bool>(); return attr("__contains__")(std::forward<T>(item)).template cast<bool>();
} }
template <typename D> template <typename D>