mirror of
https://github.com/pybind/pybind11.git
synced 2024-11-26 07:02:11 +00:00
Merge pull request #425 from dean0x7d/accessors
Make the accessor interface more complete
This commit is contained in:
commit
0a014e9135
@ -53,6 +53,8 @@ Breaking changes queued for v2.0.0 (Not yet released)
|
|||||||
* Added ``py::dict`` keyword constructor:``auto d = dict("number"_a=42, "name"_a="World");``
|
* Added ``py::dict`` keyword constructor:``auto d = dict("number"_a=42, "name"_a="World");``
|
||||||
* Added ``py::str::format()`` method and ``_s`` literal:
|
* Added ``py::str::format()`` method and ``_s`` literal:
|
||||||
``py::str s = "1 + 2 = {}"_s.format(3);``
|
``py::str s = "1 + 2 = {}"_s.format(3);``
|
||||||
|
* Attribute and item accessors now have a more complete interface which makes it possible
|
||||||
|
to chain attributes ``obj.attr("a")[key].attr("b").attr("method")(1, 2, 3)```.
|
||||||
* Various minor improvements of library internals (no user-visible changes)
|
* Various minor improvements of library internals (no user-visible changes)
|
||||||
|
|
||||||
1.8.1 (July 12, 2016)
|
1.8.1 (July 12, 2016)
|
||||||
|
@ -276,7 +276,7 @@ template <> struct process_attribute<arg_v> : process_attribute_default<arg_v> {
|
|||||||
|
|
||||||
/// Process a parent class attribute
|
/// Process a parent class attribute
|
||||||
template <typename T>
|
template <typename T>
|
||||||
struct process_attribute<T, enable_if_t<std::is_base_of<handle, T>::value>> : process_attribute_default<handle> {
|
struct process_attribute<T, enable_if_t<is_pyobject<T>::value>> : process_attribute_default<handle> {
|
||||||
static void init(const handle &h, type_record *r) { r->bases.append(h); }
|
static void init(const handle &h, type_record *r) { r->bases.append(h); }
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -39,7 +39,10 @@ PYBIND11_NOINLINE inline internals &get_internals() {
|
|||||||
return *internals_ptr;
|
return *internals_ptr;
|
||||||
handle builtins(PyEval_GetBuiltins());
|
handle builtins(PyEval_GetBuiltins());
|
||||||
const char *id = PYBIND11_INTERNALS_ID;
|
const char *id = PYBIND11_INTERNALS_ID;
|
||||||
capsule caps(builtins[id]);
|
capsule caps;
|
||||||
|
if (builtins.contains(id)) {
|
||||||
|
caps = builtins[id];
|
||||||
|
}
|
||||||
if (caps.check()) {
|
if (caps.check()) {
|
||||||
internals_ptr = caps;
|
internals_ptr = caps;
|
||||||
} else {
|
} else {
|
||||||
@ -908,7 +911,7 @@ template <> struct handle_type_name<args> { static PYBIND11_DESCR name() { retur
|
|||||||
template <> struct handle_type_name<kwargs> { static PYBIND11_DESCR name() { return _("**kwargs"); } };
|
template <> struct handle_type_name<kwargs> { static PYBIND11_DESCR name() { return _("**kwargs"); } };
|
||||||
|
|
||||||
template <typename type>
|
template <typename type>
|
||||||
struct type_caster<type, enable_if_t<std::is_base_of<handle, type>::value>> {
|
struct type_caster<type, enable_if_t<is_pyobject<type>::value>> {
|
||||||
public:
|
public:
|
||||||
template <typename T = type, enable_if_t<!std::is_base_of<object, T>::value, int> = 0>
|
template <typename T = type, enable_if_t<!std::is_base_of<object, T>::value, int> = 0>
|
||||||
bool load(handle src, bool /* convert */) { value = type(src); return value.check(); }
|
bool load(handle src, bool /* convert */) { value = type(src); return value.check(); }
|
||||||
@ -1216,12 +1219,12 @@ private:
|
|||||||
|
|
||||||
void process(list &args_list, detail::args_proxy ap) {
|
void process(list &args_list, detail::args_proxy ap) {
|
||||||
for (const auto &a : ap) {
|
for (const auto &a : ap) {
|
||||||
args_list.append(a.cast<object>());
|
args_list.append(a);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void process(list &/*args_list*/, arg_v a) {
|
void process(list &/*args_list*/, arg_v a) {
|
||||||
if (m_kwargs[a.name]) {
|
if (m_kwargs.contains(a.name)) {
|
||||||
#if defined(NDEBUG)
|
#if defined(NDEBUG)
|
||||||
multiple_values_error();
|
multiple_values_error();
|
||||||
#else
|
#else
|
||||||
@ -1240,7 +1243,7 @@ private:
|
|||||||
|
|
||||||
void process(list &/*args_list*/, detail::kwargs_proxy kp) {
|
void process(list &/*args_list*/, detail::kwargs_proxy kp) {
|
||||||
for (const auto &k : dict(kp, true)) {
|
for (const auto &k : dict(kp, true)) {
|
||||||
if (m_kwargs[k.first]) {
|
if (m_kwargs.contains(k.first)) {
|
||||||
#if defined(NDEBUG)
|
#if defined(NDEBUG)
|
||||||
multiple_values_error();
|
multiple_values_error();
|
||||||
#else
|
#else
|
||||||
@ -1296,18 +1299,20 @@ unpacking_collector<policy> collect_arguments(Args &&...args) {
|
|||||||
return { std::forward<Args>(args)... };
|
return { std::forward<Args>(args)... };
|
||||||
}
|
}
|
||||||
|
|
||||||
NAMESPACE_END(detail)
|
template <typename Derived>
|
||||||
|
|
||||||
template <return_value_policy policy, typename... Args>
|
template <return_value_policy policy, typename... Args>
|
||||||
object handle::operator()(Args &&...args) const {
|
object object_api<Derived>::operator()(Args &&...args) const {
|
||||||
return detail::collect_arguments<policy>(std::forward<Args>(args)...).call(m_ptr);
|
return detail::collect_arguments<policy>(std::forward<Args>(args)...).call(derived().ptr());
|
||||||
}
|
}
|
||||||
|
|
||||||
template <return_value_policy policy,
|
template <typename Derived>
|
||||||
typename... Args> object handle::call(Args &&... args) const {
|
template <return_value_policy policy, typename... Args>
|
||||||
|
object object_api<Derived>::call(Args &&...args) const {
|
||||||
return operator()<policy>(std::forward<Args>(args)...);
|
return operator()<policy>(std::forward<Args>(args)...);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
NAMESPACE_END(detail)
|
||||||
|
|
||||||
#define PYBIND11_MAKE_OPAQUE(Type) \
|
#define PYBIND11_MAKE_OPAQUE(Type) \
|
||||||
namespace pybind11 { namespace detail { \
|
namespace pybind11 { namespace detail { \
|
||||||
template<> class type_caster<Type> : public type_caster_base<Type> { }; \
|
template<> class type_caster<Type> : public type_caster_base<Type> { }; \
|
||||||
|
@ -125,11 +125,11 @@ private:
|
|||||||
|
|
||||||
static npy_api lookup() {
|
static npy_api lookup() {
|
||||||
module m = module::import("numpy.core.multiarray");
|
module m = module::import("numpy.core.multiarray");
|
||||||
object c = (object) m.attr("_ARRAY_API");
|
auto c = m.attr("_ARRAY_API");
|
||||||
#if PY_MAJOR_VERSION >= 3
|
#if PY_MAJOR_VERSION >= 3
|
||||||
void **api_ptr = (void **) (c ? PyCapsule_GetPointer(c.ptr(), NULL) : nullptr);
|
void **api_ptr = (void **) PyCapsule_GetPointer(c.ptr(), NULL);
|
||||||
#else
|
#else
|
||||||
void **api_ptr = (void **) (c ? PyCObject_AsVoidPtr(c.ptr()) : nullptr);
|
void **api_ptr = (void **) PyCObject_AsVoidPtr(c.ptr());
|
||||||
#endif
|
#endif
|
||||||
npy_api api;
|
npy_api api;
|
||||||
#define DECL_NPY_API(Func) api.Func##_ = (decltype(api.Func##_)) api_ptr[API_##Func];
|
#define DECL_NPY_API(Func) api.Func##_ = (decltype(api.Func##_)) api_ptr[API_##Func];
|
||||||
@ -220,9 +220,7 @@ private:
|
|||||||
struct field_descr { PYBIND11_STR_TYPE name; object format; pybind11::int_ offset; };
|
struct field_descr { PYBIND11_STR_TYPE name; object format; pybind11::int_ offset; };
|
||||||
std::vector<field_descr> field_descriptors;
|
std::vector<field_descr> field_descriptors;
|
||||||
|
|
||||||
auto fields = attr("fields").cast<object>();
|
for (auto field : attr("fields").attr("items")()) {
|
||||||
auto items = fields.attr("items").cast<object>();
|
|
||||||
for (auto field : items()) {
|
|
||||||
auto spec = object(field, true).cast<tuple>();
|
auto spec = object(field, true).cast<tuple>();
|
||||||
auto name = spec[0].cast<pybind11::str>();
|
auto name = spec[0].cast<pybind11::str>();
|
||||||
auto format = spec[1].cast<tuple>()[0].cast<dtype>();
|
auto format = spec[1].cast<tuple>()[0].cast<dtype>();
|
||||||
|
@ -18,6 +18,7 @@
|
|||||||
# pragma warning(disable: 4800) // warning C4800: 'int': forcing value to bool 'true' or 'false' (performance warning)
|
# pragma warning(disable: 4800) // warning C4800: 'int': forcing value to bool 'true' or 'false' (performance warning)
|
||||||
# pragma warning(disable: 4996) // warning C4996: The POSIX name for this item is deprecated. Instead, use the ISO C and C++ conformant name
|
# pragma warning(disable: 4996) // warning C4996: The POSIX name for this item is deprecated. Instead, use the ISO C and C++ conformant name
|
||||||
# pragma warning(disable: 4702) // warning C4702: unreachable code
|
# pragma warning(disable: 4702) // warning C4702: unreachable code
|
||||||
|
# pragma warning(disable: 4522) // warning C4522: multiple assignment operators specified
|
||||||
#elif defined(__INTEL_COMPILER)
|
#elif defined(__INTEL_COMPILER)
|
||||||
# pragma warning(push)
|
# pragma warning(push)
|
||||||
# pragma warning(disable: 186) // pointless comparison of unsigned integer with zero
|
# pragma warning(disable: 186) // pointless comparison of unsigned integer with zero
|
||||||
@ -176,7 +177,7 @@ protected:
|
|||||||
if (a.descr)
|
if (a.descr)
|
||||||
a.descr = strdup(a.descr);
|
a.descr = strdup(a.descr);
|
||||||
else if (a.value)
|
else if (a.value)
|
||||||
a.descr = strdup(((std::string) ((object) handle(a.value).attr("__repr__"))().str()).c_str());
|
a.descr = strdup(a.value.attr("__repr__")().cast<std::string>().c_str());
|
||||||
}
|
}
|
||||||
|
|
||||||
auto const ®istered_types = detail::get_internals().registered_types_cpp;
|
auto const ®istered_types = detail::get_internals().registered_types_cpp;
|
||||||
@ -278,9 +279,11 @@ protected:
|
|||||||
|
|
||||||
object scope_module;
|
object scope_module;
|
||||||
if (rec->scope) {
|
if (rec->scope) {
|
||||||
scope_module = (object) rec->scope.attr("__module__");
|
if (hasattr(rec->scope, "__module__")) {
|
||||||
if (!scope_module)
|
scope_module = rec->scope.attr("__module__");
|
||||||
scope_module = (object) rec->scope.attr("__name__");
|
} else if (hasattr(rec->scope, "__name__")) {
|
||||||
|
scope_module = rec->scope.attr("__name__");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
m_ptr = PyCFunction_NewEx(rec->def, rec_capsule.ptr(), scope_module.ptr());
|
m_ptr = PyCFunction_NewEx(rec->def, rec_capsule.ptr(), scope_module.ptr());
|
||||||
@ -544,8 +547,8 @@ public:
|
|||||||
|
|
||||||
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_),
|
cpp_function func(std::forward<Func>(f), name(name_), scope(*this),
|
||||||
sibling((handle) attr(name_)), scope(*this), extra...);
|
sibling(getattr(*this, name_, none())), extra...);
|
||||||
/* PyModule_AddObject steals a reference to 'func' */
|
/* PyModule_AddObject steals a reference to 'func' */
|
||||||
PyModule_AddObject(ptr(), name_, func.inc_ref().ptr());
|
PyModule_AddObject(ptr(), name_, func.inc_ref().ptr());
|
||||||
return *this;
|
return *this;
|
||||||
@ -588,16 +591,18 @@ protected:
|
|||||||
object name(PYBIND11_FROM_STRING(rec->name), false);
|
object name(PYBIND11_FROM_STRING(rec->name), false);
|
||||||
object scope_module;
|
object scope_module;
|
||||||
if (rec->scope) {
|
if (rec->scope) {
|
||||||
scope_module = (object) rec->scope.attr("__module__");
|
if (hasattr(rec->scope, "__module__")) {
|
||||||
if (!scope_module)
|
scope_module = rec->scope.attr("__module__");
|
||||||
scope_module = (object) rec->scope.attr("__name__");
|
} else if (hasattr(rec->scope, "__name__")) {
|
||||||
|
scope_module = rec->scope.attr("__name__");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#if PY_MAJOR_VERSION >= 3 && PY_MINOR_VERSION >= 3
|
#if PY_MAJOR_VERSION >= 3 && PY_MINOR_VERSION >= 3
|
||||||
/* Qualified names for Python >= 3.3 */
|
/* Qualified names for Python >= 3.3 */
|
||||||
object scope_qualname;
|
object scope_qualname;
|
||||||
if (rec->scope)
|
if (rec->scope && hasattr(rec->scope, "__qualname__"))
|
||||||
scope_qualname = (object) rec->scope.attr("__qualname__");
|
scope_qualname = rec->scope.attr("__qualname__");
|
||||||
object ht_qualname;
|
object ht_qualname;
|
||||||
if (scope_qualname) {
|
if (scope_qualname) {
|
||||||
ht_qualname = object(PyUnicode_FromFormat(
|
ht_qualname = object(PyUnicode_FromFormat(
|
||||||
@ -719,8 +724,7 @@ protected:
|
|||||||
if (ob_type == &PyType_Type) {
|
if (ob_type == &PyType_Type) {
|
||||||
std::string name_ = std::string(ht_type.tp_name) + "__Meta";
|
std::string name_ = std::string(ht_type.tp_name) + "__Meta";
|
||||||
#if PY_MAJOR_VERSION >= 3 && PY_MINOR_VERSION >= 3
|
#if PY_MAJOR_VERSION >= 3 && PY_MINOR_VERSION >= 3
|
||||||
object ht_qualname(PyUnicode_FromFormat(
|
object ht_qualname(PyUnicode_FromFormat("%U__Meta", attr("__qualname__").ptr()), false);
|
||||||
"%U__Meta", ((object) attr("__qualname__")).ptr()), false);
|
|
||||||
#endif
|
#endif
|
||||||
object name(PYBIND11_FROM_STRING(name_.c_str()), false);
|
object name(PYBIND11_FROM_STRING(name_.c_str()), false);
|
||||||
object type_holder(PyType_Type.tp_alloc(&PyType_Type, 0), false);
|
object type_holder(PyType_Type.tp_alloc(&PyType_Type, 0), false);
|
||||||
@ -894,17 +898,16 @@ public:
|
|||||||
|
|
||||||
template <typename Func, typename... Extra>
|
template <typename Func, typename... Extra>
|
||||||
class_ &def(const char *name_, Func&& f, const Extra&... extra) {
|
class_ &def(const char *name_, Func&& f, const Extra&... extra) {
|
||||||
cpp_function cf(std::forward<Func>(f), name(name_),
|
cpp_function cf(std::forward<Func>(f), name(name_), is_method(*this),
|
||||||
sibling(attr(name_)), is_method(*this),
|
sibling(getattr(*this, name_, none())), extra...);
|
||||||
extra...);
|
|
||||||
attr(cf.name()) = cf;
|
attr(cf.name()) = cf;
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename Func, typename... Extra> class_ &
|
template <typename Func, typename... Extra> class_ &
|
||||||
def_static(const char *name_, Func f, const Extra&... extra) {
|
def_static(const char *name_, Func f, const Extra&... extra) {
|
||||||
cpp_function cf(std::forward<Func>(f), name(name_),
|
cpp_function cf(std::forward<Func>(f), name(name_), scope(*this),
|
||||||
sibling(attr(name_)), scope(*this), extra...);
|
sibling(getattr(*this, name_, none())), extra...);
|
||||||
attr(cf.name()) = cf;
|
attr(cf.name()) = cf;
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
@ -1336,19 +1339,19 @@ NAMESPACE_BEGIN(detail)
|
|||||||
PYBIND11_NOINLINE inline void print(tuple args, dict kwargs) {
|
PYBIND11_NOINLINE inline void print(tuple args, dict kwargs) {
|
||||||
auto strings = tuple(args.size());
|
auto strings = tuple(args.size());
|
||||||
for (size_t i = 0; i < args.size(); ++i) {
|
for (size_t i = 0; i < args.size(); ++i) {
|
||||||
strings[i] = args[i].cast<object>().str();
|
strings[i] = args[i].str();
|
||||||
}
|
}
|
||||||
auto sep = kwargs["sep"] ? kwargs["sep"] : cast(" ");
|
auto sep = kwargs.contains("sep") ? kwargs["sep"] : cast(" ");
|
||||||
auto line = sep.attr("join").cast<object>()(strings);
|
auto line = sep.attr("join")(strings);
|
||||||
|
|
||||||
auto file = kwargs["file"] ? kwargs["file"].cast<object>()
|
auto file = kwargs.contains("file") ? kwargs["file"].cast<object>()
|
||||||
: module::import("sys").attr("stdout");
|
: module::import("sys").attr("stdout");
|
||||||
auto write = file.attr("write").cast<object>();
|
auto write = file.attr("write");
|
||||||
write(line);
|
write(line);
|
||||||
write(kwargs["end"] ? kwargs["end"] : cast("\n"));
|
write(kwargs.contains("end") ? kwargs["end"] : cast("\n"));
|
||||||
|
|
||||||
if (kwargs["flush"] && kwargs["flush"].cast<bool>()) {
|
if (kwargs.contains("flush") && kwargs["flush"].cast<bool>()) {
|
||||||
file.attr("flush").cast<object>()();
|
file.attr("flush")();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
NAMESPACE_END(detail)
|
NAMESPACE_END(detail)
|
||||||
@ -1500,7 +1503,7 @@ inline function get_type_overload(const void *this_ptr, const detail::type_info
|
|||||||
if (cache.find(key) != cache.end())
|
if (cache.find(key) != cache.end())
|
||||||
return function();
|
return function();
|
||||||
|
|
||||||
function overload = (function) py_object.attr(name);
|
function overload = getattr(py_object, name, function());
|
||||||
if (overload.is_cpp_function()) {
|
if (overload.is_cpp_function()) {
|
||||||
cache.insert(key);
|
cache.insert(key);
|
||||||
return function();
|
return function();
|
||||||
|
@ -16,50 +16,88 @@
|
|||||||
NAMESPACE_BEGIN(pybind11)
|
NAMESPACE_BEGIN(pybind11)
|
||||||
|
|
||||||
/* A few forward declarations */
|
/* A few forward declarations */
|
||||||
class object; class str; class iterator;
|
class handle; class object;
|
||||||
|
class str; class iterator;
|
||||||
struct arg; struct arg_v;
|
struct arg; struct arg_v;
|
||||||
namespace detail { class accessor; class args_proxy; class kwargs_proxy; }
|
|
||||||
|
NAMESPACE_BEGIN(detail)
|
||||||
|
class args_proxy;
|
||||||
|
|
||||||
|
// Accessor forward declarations
|
||||||
|
template <typename Policy> class accessor;
|
||||||
|
namespace accessor_policies {
|
||||||
|
struct obj_attr;
|
||||||
|
struct str_attr;
|
||||||
|
struct generic_item;
|
||||||
|
struct list_item;
|
||||||
|
struct tuple_item;
|
||||||
|
}
|
||||||
|
using obj_attr_accessor = accessor<accessor_policies::obj_attr>;
|
||||||
|
using str_attr_accessor = accessor<accessor_policies::str_attr>;
|
||||||
|
using item_accessor = accessor<accessor_policies::generic_item>;
|
||||||
|
using list_accessor = accessor<accessor_policies::list_item>;
|
||||||
|
using tuple_accessor = accessor<accessor_policies::tuple_item>;
|
||||||
|
|
||||||
|
/// Tag and check to identify a class which implements the Python object API
|
||||||
|
class pyobject_tag { };
|
||||||
|
template <typename T> using is_pyobject = std::is_base_of<pyobject_tag, T>;
|
||||||
|
|
||||||
|
/// Mixin which adds common functions to handle, object and various accessors.
|
||||||
|
/// The only requirement for `Derived` is to implement `PyObject *Derived::ptr() const`.
|
||||||
|
template <typename Derived>
|
||||||
|
class object_api : public pyobject_tag {
|
||||||
|
const Derived &derived() const { return static_cast<const Derived &>(*this); }
|
||||||
|
|
||||||
|
public:
|
||||||
|
iterator begin() 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;
|
||||||
|
|
||||||
|
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;
|
||||||
|
|
||||||
|
bool is_none() const { return derived().ptr() == Py_None; }
|
||||||
|
pybind11::str str() const;
|
||||||
|
pybind11::str repr() const;
|
||||||
|
|
||||||
|
int ref_count() const { return static_cast<int>(Py_REFCNT(derived().ptr())); }
|
||||||
|
handle get_type() const;
|
||||||
|
};
|
||||||
|
|
||||||
|
NAMESPACE_END(detail)
|
||||||
|
|
||||||
/// Holds a reference to a Python object (no reference counting)
|
/// Holds a reference to a Python object (no reference counting)
|
||||||
class handle {
|
class handle : public detail::object_api<handle> {
|
||||||
public:
|
public:
|
||||||
handle() : m_ptr(nullptr) { }
|
handle() = default;
|
||||||
handle(const handle &other) : m_ptr(other.m_ptr) { }
|
|
||||||
handle(PyObject *ptr) : m_ptr(ptr) { }
|
handle(PyObject *ptr) : m_ptr(ptr) { }
|
||||||
|
|
||||||
PyObject *ptr() const { return m_ptr; }
|
PyObject *ptr() const { return m_ptr; }
|
||||||
PyObject *&ptr() { return m_ptr; }
|
PyObject *&ptr() { return m_ptr; }
|
||||||
const handle& inc_ref() const { Py_XINCREF(m_ptr); return *this; }
|
const handle& inc_ref() const { Py_XINCREF(m_ptr); return *this; }
|
||||||
const handle& dec_ref() const { Py_XDECREF(m_ptr); return *this; }
|
const handle& dec_ref() const { Py_XDECREF(m_ptr); return *this; }
|
||||||
int ref_count() const { return (int) Py_REFCNT(m_ptr); }
|
|
||||||
handle get_type() const { return handle((PyObject *) Py_TYPE(m_ptr)); }
|
|
||||||
inline iterator begin() const;
|
|
||||||
inline iterator end() const;
|
|
||||||
inline detail::accessor operator[](handle key) const;
|
|
||||||
inline detail::accessor operator[](const char *key) const;
|
|
||||||
inline detail::accessor attr(handle key) const;
|
|
||||||
inline detail::accessor attr(const char *key) const;
|
|
||||||
inline pybind11::str str() const;
|
|
||||||
inline pybind11::str repr() const;
|
|
||||||
bool is_none() const { return m_ptr == Py_None; }
|
|
||||||
template <typename T> T cast() const;
|
template <typename T> T cast() 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;
|
|
||||||
template <return_value_policy policy = return_value_policy::automatic_reference, typename ... Args>
|
|
||||||
object operator()(Args&&... args) const;
|
|
||||||
operator bool() const { return m_ptr != nullptr; }
|
operator bool() const { return m_ptr != nullptr; }
|
||||||
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; }
|
||||||
bool check() const { return m_ptr != nullptr; }
|
bool check() const { return m_ptr != nullptr; }
|
||||||
inline detail::args_proxy operator*() const;
|
|
||||||
protected:
|
protected:
|
||||||
PyObject *m_ptr;
|
PyObject *m_ptr = nullptr;
|
||||||
};
|
};
|
||||||
|
|
||||||
/// Holds a reference to a Python object (with reference counting)
|
/// Holds a reference to a Python object (with reference counting)
|
||||||
class object : public handle {
|
class object : public handle {
|
||||||
public:
|
public:
|
||||||
object() { }
|
object() = default;
|
||||||
object(const object &o) : handle(o) { inc_ref(); }
|
object(const object &o) : handle(o) { inc_ref(); }
|
||||||
object(const handle &h, bool borrowed) : handle(h) { if (borrowed) inc_ref(); }
|
object(const handle &h, bool borrowed) : handle(h) { if (borrowed) inc_ref(); }
|
||||||
object(PyObject *ptr, bool borrowed) : handle(ptr) { if (borrowed) inc_ref(); }
|
object(PyObject *ptr, bool borrowed) : handle(ptr) { if (borrowed) inc_ref(); }
|
||||||
@ -95,6 +133,52 @@ public:
|
|||||||
template <typename T> T cast() &&;
|
template <typename T> T cast() &&;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
inline bool hasattr(handle obj, handle name) {
|
||||||
|
return PyObject_HasAttr(obj.ptr(), name.ptr()) == 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline bool hasattr(handle obj, const char *name) {
|
||||||
|
return PyObject_HasAttrString(obj.ptr(), name) == 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline object getattr(handle obj, handle name) {
|
||||||
|
PyObject *result = PyObject_GetAttr(obj.ptr(), name.ptr());
|
||||||
|
if (!result) { throw error_already_set(); }
|
||||||
|
return {result, false};
|
||||||
|
}
|
||||||
|
|
||||||
|
inline object getattr(handle obj, const char *name) {
|
||||||
|
PyObject *result = PyObject_GetAttrString(obj.ptr(), name);
|
||||||
|
if (!result) { throw error_already_set(); }
|
||||||
|
return {result, false};
|
||||||
|
}
|
||||||
|
|
||||||
|
inline object getattr(handle obj, handle name, handle default_) {
|
||||||
|
if (PyObject *result = PyObject_GetAttr(obj.ptr(), name.ptr())) {
|
||||||
|
return {result, false};
|
||||||
|
} else {
|
||||||
|
PyErr_Clear();
|
||||||
|
return {default_, true};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
inline object getattr(handle obj, const char *name, handle default_) {
|
||||||
|
if (PyObject *result = PyObject_GetAttrString(obj.ptr(), name)) {
|
||||||
|
return {result, false};
|
||||||
|
} else {
|
||||||
|
PyErr_Clear();
|
||||||
|
return {default_, true};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
inline void setattr(handle obj, handle name, handle value) {
|
||||||
|
if (PyObject_SetAttr(obj.ptr(), name.ptr(), value.ptr()) != 0) { throw error_already_set(); }
|
||||||
|
}
|
||||||
|
|
||||||
|
inline void setattr(handle obj, const char *name, handle value) {
|
||||||
|
if (PyObject_SetAttrString(obj.ptr(), name, value.ptr()) != 0) { throw error_already_set(); }
|
||||||
|
}
|
||||||
|
|
||||||
NAMESPACE_BEGIN(detail)
|
NAMESPACE_BEGIN(detail)
|
||||||
inline handle get_function(handle value) {
|
inline handle get_function(handle value) {
|
||||||
if (value) {
|
if (value) {
|
||||||
@ -108,101 +192,98 @@ inline handle get_function(handle value) {
|
|||||||
return value;
|
return value;
|
||||||
}
|
}
|
||||||
|
|
||||||
class accessor {
|
template <typename Policy>
|
||||||
|
class accessor : public object_api<accessor<Policy>> {
|
||||||
|
using key_type = typename Policy::key_type;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
accessor(handle obj, handle key, bool attr)
|
accessor(handle obj, key_type key) : obj(obj), key(std::move(key)) { }
|
||||||
: obj(obj), key(key, true), attr(attr) { }
|
|
||||||
accessor(handle obj, const char *key, bool attr)
|
|
||||||
: obj(obj), key(PyUnicode_FromString(key), false), attr(attr) { }
|
|
||||||
accessor(const accessor &a) : obj(a.obj), key(a.key), attr(a.attr) { }
|
|
||||||
|
|
||||||
void operator=(accessor o) { operator=(object(o)); }
|
void operator=(const accessor &a) && { std::move(*this).operator=(handle(a)); }
|
||||||
|
void operator=(const accessor &a) & { operator=(handle(a)); }
|
||||||
|
void operator=(const object &o) && { std::move(*this).operator=(handle(o)); }
|
||||||
|
void operator=(const object &o) & { operator=(handle(o)); }
|
||||||
|
void operator=(handle value) && { Policy::set(obj, key, value); }
|
||||||
|
void operator=(handle value) & { get_cache() = object(value, true); }
|
||||||
|
|
||||||
void operator=(const handle &value) {
|
operator object() const { return get_cache(); }
|
||||||
if (attr) {
|
PyObject *ptr() const { return get_cache().ptr(); }
|
||||||
if (PyObject_SetAttr(obj.ptr(), key.ptr(), value.ptr()) == -1)
|
template <typename T> T cast() const { return get_cache().template cast<T>(); }
|
||||||
throw error_already_set();
|
|
||||||
} else {
|
private:
|
||||||
if (PyObject_SetItem(obj.ptr(), key.ptr(), value.ptr()) == -1)
|
object &get_cache() const {
|
||||||
throw error_already_set();
|
if (!cache) { cache = Policy::get(obj, key); }
|
||||||
}
|
return cache;
|
||||||
}
|
}
|
||||||
|
|
||||||
operator object() const {
|
|
||||||
object result(attr ? PyObject_GetAttr(obj.ptr(), key.ptr())
|
|
||||||
: PyObject_GetItem(obj.ptr(), key.ptr()), false);
|
|
||||||
if (!result) {PyErr_Clear(); }
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
template <typename T> T cast() const { return operator object().cast<T>(); }
|
|
||||||
|
|
||||||
operator bool() const {
|
|
||||||
if (attr) {
|
|
||||||
return (bool) PyObject_HasAttr(obj.ptr(), key.ptr());
|
|
||||||
} else {
|
|
||||||
object result(PyObject_GetItem(obj.ptr(), key.ptr()), false);
|
|
||||||
if (!result) PyErr_Clear();
|
|
||||||
return (bool) result;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
handle obj;
|
handle obj;
|
||||||
object key;
|
key_type key;
|
||||||
bool attr;
|
mutable object cache;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct list_accessor {
|
NAMESPACE_BEGIN(accessor_policies)
|
||||||
public:
|
struct obj_attr {
|
||||||
list_accessor(handle list, size_t index) : list(list), index(index) { }
|
using key_type = object;
|
||||||
|
static object get(handle obj, handle key) { return getattr(obj, key); }
|
||||||
void operator=(list_accessor o) { return operator=(object(o)); }
|
static void set(handle obj, handle key, handle val) { setattr(obj, key, val); }
|
||||||
|
|
||||||
void operator=(const handle &o) {
|
|
||||||
// PyList_SetItem steals a reference to 'o'
|
|
||||||
if (PyList_SetItem(list.ptr(), (ssize_t) index, o.inc_ref().ptr()) < 0)
|
|
||||||
pybind11_fail("Unable to assign value in Python list!");
|
|
||||||
}
|
|
||||||
|
|
||||||
operator object() const {
|
|
||||||
PyObject *result = PyList_GetItem(list.ptr(), (ssize_t) index);
|
|
||||||
if (!result)
|
|
||||||
pybind11_fail("Unable to retrieve value from Python list!");
|
|
||||||
return object(result, true);
|
|
||||||
}
|
|
||||||
|
|
||||||
template <typename T> T cast() const { return operator object().cast<T>(); }
|
|
||||||
private:
|
|
||||||
handle list;
|
|
||||||
size_t index;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
struct tuple_accessor {
|
struct str_attr {
|
||||||
public:
|
using key_type = const char *;
|
||||||
tuple_accessor(handle tuple, size_t index) : tuple(tuple), index(index) { }
|
static object get(handle obj, const char *key) { return getattr(obj, key); }
|
||||||
|
static void set(handle obj, const char *key, handle val) { setattr(obj, key, val); }
|
||||||
void operator=(tuple_accessor o) { return operator=(object(o)); }
|
|
||||||
|
|
||||||
void operator=(const handle &o) {
|
|
||||||
// PyTuple_SetItem steals a referenceto 'o'
|
|
||||||
if (PyTuple_SetItem(tuple.ptr(), (ssize_t) index, o.inc_ref().ptr()) < 0)
|
|
||||||
pybind11_fail("Unable to assign value in Python tuple!");
|
|
||||||
}
|
|
||||||
|
|
||||||
operator object() const {
|
|
||||||
PyObject *result = PyTuple_GetItem(tuple.ptr(), (ssize_t) index);
|
|
||||||
if (!result)
|
|
||||||
pybind11_fail("Unable to retrieve value from Python tuple!");
|
|
||||||
return object(result, true);
|
|
||||||
}
|
|
||||||
|
|
||||||
template <typename T> T cast() const { return operator object().cast<T>(); }
|
|
||||||
private:
|
|
||||||
handle tuple;
|
|
||||||
size_t index;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct generic_item {
|
||||||
|
using key_type = object;
|
||||||
|
|
||||||
|
static object get(handle obj, handle key) {
|
||||||
|
PyObject *result = PyObject_GetItem(obj.ptr(), key.ptr());
|
||||||
|
if (!result) { throw error_already_set(); }
|
||||||
|
return {result, false};
|
||||||
|
}
|
||||||
|
|
||||||
|
static void set(handle obj, handle key, handle val) {
|
||||||
|
if (PyObject_SetItem(obj.ptr(), key.ptr(), val.ptr()) != 0) { throw error_already_set(); }
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
struct list_item {
|
||||||
|
using key_type = size_t;
|
||||||
|
|
||||||
|
static object get(handle obj, size_t index) {
|
||||||
|
PyObject *result = PyList_GetItem(obj.ptr(), static_cast<ssize_t>(index));
|
||||||
|
if (!result) { throw error_already_set(); }
|
||||||
|
return {result, true};
|
||||||
|
}
|
||||||
|
|
||||||
|
static void set(handle obj, size_t index, handle val) {
|
||||||
|
// PyList_SetItem steals a reference to 'val'
|
||||||
|
if (PyList_SetItem(obj.ptr(), static_cast<ssize_t>(index), val.inc_ref().ptr()) != 0) {
|
||||||
|
throw error_already_set();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
struct tuple_item {
|
||||||
|
using key_type = size_t;
|
||||||
|
|
||||||
|
static object get(handle obj, size_t index) {
|
||||||
|
PyObject *result = PyTuple_GetItem(obj.ptr(), static_cast<ssize_t>(index));
|
||||||
|
if (!result) { throw error_already_set(); }
|
||||||
|
return {result, true};
|
||||||
|
}
|
||||||
|
|
||||||
|
static void set(handle obj, size_t index, handle val) {
|
||||||
|
// PyTuple_SetItem steals a reference to 'val'
|
||||||
|
if (PyTuple_SetItem(obj.ptr(), static_cast<ssize_t>(index), val.inc_ref().ptr()) != 0) {
|
||||||
|
throw error_already_set();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
NAMESPACE_END(accessor_policies)
|
||||||
|
|
||||||
struct dict_iterator {
|
struct dict_iterator {
|
||||||
public:
|
public:
|
||||||
dict_iterator(handle dict = handle(), ssize_t pos = -1) : dict(dict), pos(pos) { }
|
dict_iterator(handle dict = handle(), ssize_t pos = -1) : dict(dict), pos(pos) { }
|
||||||
@ -347,14 +428,6 @@ public:
|
|||||||
PYBIND11_OBJECT_DEFAULT(iterable, object, detail::PyIterable_Check)
|
PYBIND11_OBJECT_DEFAULT(iterable, object, detail::PyIterable_Check)
|
||||||
};
|
};
|
||||||
|
|
||||||
inline detail::accessor handle::operator[](handle key) const { return detail::accessor(*this, key, false); }
|
|
||||||
inline detail::accessor handle::operator[](const char *key) const { return detail::accessor(*this, key, false); }
|
|
||||||
inline detail::accessor handle::attr(handle key) const { return detail::accessor(*this, key, true); }
|
|
||||||
inline detail::accessor handle::attr(const char *key) const { return detail::accessor(*this, key, true); }
|
|
||||||
inline iterator handle::begin() const { return iterator(PyObject_GetIter(ptr()), false); }
|
|
||||||
inline iterator handle::end() const { return iterator(nullptr, false); }
|
|
||||||
inline detail::args_proxy handle::operator*() const { return detail::args_proxy(*this); }
|
|
||||||
|
|
||||||
class bytes;
|
class bytes;
|
||||||
|
|
||||||
class str : public object {
|
class str : public object {
|
||||||
@ -391,7 +464,7 @@ public:
|
|||||||
|
|
||||||
template <typename... Args>
|
template <typename... Args>
|
||||||
str format(Args &&...args) const {
|
str format(Args &&...args) const {
|
||||||
return attr("format").cast<object>()(std::forward<Args>(args)...);
|
return attr("format")(std::forward<Args>(args)...);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -400,24 +473,6 @@ inline namespace literals {
|
|||||||
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}; }
|
||||||
}
|
}
|
||||||
|
|
||||||
inline pybind11::str handle::str() const {
|
|
||||||
PyObject *strValue = PyObject_Str(m_ptr);
|
|
||||||
#if PY_MAJOR_VERSION < 3
|
|
||||||
PyObject *unicode = PyUnicode_FromEncodedObject(strValue, "utf-8", nullptr);
|
|
||||||
Py_XDECREF(strValue); strValue = unicode;
|
|
||||||
#endif
|
|
||||||
return pybind11::str(strValue, false);
|
|
||||||
}
|
|
||||||
|
|
||||||
inline pybind11::str handle::repr() const {
|
|
||||||
PyObject *strValue = PyObject_Repr(m_ptr);
|
|
||||||
#if PY_MAJOR_VERSION < 3
|
|
||||||
PyObject *unicode = PyUnicode_FromEncodedObject(strValue, "utf-8", nullptr);
|
|
||||||
Py_XDECREF(strValue); strValue = unicode;
|
|
||||||
#endif
|
|
||||||
return pybind11::str(strValue, false);
|
|
||||||
}
|
|
||||||
|
|
||||||
class bytes : public object {
|
class bytes : public object {
|
||||||
public:
|
public:
|
||||||
PYBIND11_OBJECT_DEFAULT(bytes, object, PYBIND11_BYTES_CHECK)
|
PYBIND11_OBJECT_DEFAULT(bytes, object, PYBIND11_BYTES_CHECK)
|
||||||
@ -583,7 +638,7 @@ public:
|
|||||||
if (!m_ptr) pybind11_fail("Could not allocate tuple object!");
|
if (!m_ptr) pybind11_fail("Could not allocate tuple object!");
|
||||||
}
|
}
|
||||||
size_t size() const { return (size_t) PyTuple_Size(m_ptr); }
|
size_t size() const { return (size_t) PyTuple_Size(m_ptr); }
|
||||||
detail::tuple_accessor operator[](size_t index) const { return detail::tuple_accessor(*this, index); }
|
detail::tuple_accessor operator[](size_t index) const { return {*this, index}; }
|
||||||
};
|
};
|
||||||
|
|
||||||
class dict : public object {
|
class dict : public object {
|
||||||
@ -602,6 +657,8 @@ public:
|
|||||||
detail::dict_iterator begin() const { return (++detail::dict_iterator(*this, 0)); }
|
detail::dict_iterator begin() const { return (++detail::dict_iterator(*this, 0)); }
|
||||||
detail::dict_iterator end() const { return detail::dict_iterator(); }
|
detail::dict_iterator end() const { return detail::dict_iterator(); }
|
||||||
void clear() const { PyDict_Clear(ptr()); }
|
void clear() const { PyDict_Clear(ptr()); }
|
||||||
|
bool contains(handle key) const { return PyDict_Contains(ptr(), key.ptr()) == 1; }
|
||||||
|
bool contains(const char *key) const { return PyDict_Contains(ptr(), pybind11::str(key).ptr()) == 1; }
|
||||||
};
|
};
|
||||||
|
|
||||||
class list : public object {
|
class list : public object {
|
||||||
@ -611,7 +668,7 @@ public:
|
|||||||
if (!m_ptr) pybind11_fail("Could not allocate list object!");
|
if (!m_ptr) pybind11_fail("Could not allocate list object!");
|
||||||
}
|
}
|
||||||
size_t size() const { return (size_t) PyList_Size(m_ptr); }
|
size_t size() const { return (size_t) PyList_Size(m_ptr); }
|
||||||
detail::list_accessor operator[](size_t index) const { return detail::list_accessor(*this, index); }
|
detail::list_accessor operator[](size_t index) const { return {*this, index}; }
|
||||||
void append(handle h) const { PyList_Append(m_ptr, h.ptr()); }
|
void append(handle h) const { PyList_Append(m_ptr, h.ptr()); }
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -691,4 +748,40 @@ inline size_t len(handle h) {
|
|||||||
return (size_t) result;
|
return (size_t) result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
NAMESPACE_BEGIN(detail)
|
||||||
|
template <typename D> iterator object_api<D>::begin() const { return {PyObject_GetIter(derived().ptr()), false}; }
|
||||||
|
template <typename D> iterator object_api<D>::end() const { return {nullptr, false}; }
|
||||||
|
template <typename D> item_accessor object_api<D>::operator[](handle key) const { return {derived(), object(key, true)}; }
|
||||||
|
template <typename D> item_accessor object_api<D>::operator[](const char *key) const { return {derived(), pybind11::str(key)}; }
|
||||||
|
template <typename D> obj_attr_accessor object_api<D>::attr(handle key) const { return {derived(), object(key, true)}; }
|
||||||
|
template <typename D> str_attr_accessor object_api<D>::attr(const char *key) const { return {derived(), key}; }
|
||||||
|
template <typename D> args_proxy object_api<D>::operator*() const { return {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>
|
||||||
|
pybind11::str object_api<D>::str() const {
|
||||||
|
PyObject *str_value = PyObject_Str(derived().ptr());
|
||||||
|
#if PY_MAJOR_VERSION < 3
|
||||||
|
PyObject *unicode = PyUnicode_FromEncodedObject(str_value, "utf-8", nullptr);
|
||||||
|
Py_XDECREF(str_value); str_value = unicode;
|
||||||
|
#endif
|
||||||
|
return {str_value, false};
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename D>
|
||||||
|
pybind11::str object_api<D>::repr() const {
|
||||||
|
PyObject *str_value = PyObject_Repr(derived().ptr());
|
||||||
|
#if PY_MAJOR_VERSION < 3
|
||||||
|
PyObject *unicode = PyUnicode_FromEncodedObject(str_value, "utf-8", nullptr);
|
||||||
|
Py_XDECREF(str_value); str_value = unicode;
|
||||||
|
#endif
|
||||||
|
return {str_value, false};
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename D>
|
||||||
|
handle object_api<D>::get_type() const { return (PyObject *) Py_TYPE(derived().ptr()); }
|
||||||
|
|
||||||
|
NAMESPACE_END(detail)
|
||||||
NAMESPACE_END(pybind11)
|
NAMESPACE_END(pybind11)
|
||||||
|
@ -103,7 +103,7 @@ public:
|
|||||||
|
|
||||||
int alive() {
|
int alive() {
|
||||||
// Force garbage collection to ensure any pending destructors are invoked:
|
// Force garbage collection to ensure any pending destructors are invoked:
|
||||||
py::module::import("gc").attr("collect").operator py::object()();
|
py::module::import("gc").attr("collect")();
|
||||||
int total = 0;
|
int total = 0;
|
||||||
for (const auto &p : _instances) if (p.second > 0) total += p.second;
|
for (const auto &p : _instances) if (p.second > 0) total += p.second;
|
||||||
return total;
|
return total;
|
||||||
|
@ -39,7 +39,7 @@ PYBIND11_PLUGIN(pybind11_tests) {
|
|||||||
for (const auto &initializer : initializers())
|
for (const auto &initializer : initializers())
|
||||||
initializer(m);
|
initializer(m);
|
||||||
|
|
||||||
if (!m.attr("have_eigen")) m.attr("have_eigen") = py::cast(false);
|
if (!py::hasattr(m, "have_eigen")) m.attr("have_eigen") = py::cast(false);
|
||||||
|
|
||||||
return m.ptr();
|
return m.ptr();
|
||||||
}
|
}
|
||||||
|
@ -60,7 +60,7 @@ public:
|
|||||||
py::list get_list() {
|
py::list get_list() {
|
||||||
py::list list;
|
py::list list;
|
||||||
list.append(py::str("value"));
|
list.append(py::str("value"));
|
||||||
py::print("Entry at position 0:", py::object(list[0]));
|
py::print("Entry at position 0:", list[0]);
|
||||||
list[0] = py::str("overwritten");
|
list[0] = py::str("overwritten");
|
||||||
return list;
|
return list;
|
||||||
}
|
}
|
||||||
@ -203,7 +203,7 @@ test_initializer python_types([](py::module &m) {
|
|||||||
py::print("no new line here", "end"_a=" -- ");
|
py::print("no new line here", "end"_a=" -- ");
|
||||||
py::print("next print");
|
py::print("next print");
|
||||||
|
|
||||||
auto py_stderr = py::module::import("sys").attr("stderr").cast<py::object>();
|
auto py_stderr = py::module::import("sys").attr("stderr");
|
||||||
py::print("this goes to stderr", "file"_a=py_stderr);
|
py::print("this goes to stderr", "file"_a=py_stderr);
|
||||||
|
|
||||||
py::print("flush", "flush"_a=true);
|
py::print("flush", "flush"_a=true);
|
||||||
@ -222,4 +222,71 @@ test_initializer python_types([](py::module &m) {
|
|||||||
auto d2 = py::dict("z"_a=3, **d1);
|
auto d2 = py::dict("z"_a=3, **d1);
|
||||||
return d2;
|
return d2;
|
||||||
});
|
});
|
||||||
|
|
||||||
|
m.def("test_accessor_api", [](py::object o) {
|
||||||
|
auto d = py::dict();
|
||||||
|
|
||||||
|
d["basic_attr"] = o.attr("basic_attr");
|
||||||
|
|
||||||
|
auto l = py::list();
|
||||||
|
for (const auto &item : o.attr("begin_end")) {
|
||||||
|
l.append(item);
|
||||||
|
}
|
||||||
|
d["begin_end"] = l;
|
||||||
|
|
||||||
|
d["operator[object]"] = o.attr("d")["operator[object]"_s];
|
||||||
|
d["operator[char *]"] = o.attr("d")["operator[char *]"];
|
||||||
|
|
||||||
|
d["attr(object)"] = o.attr("sub").attr("attr_obj");
|
||||||
|
d["attr(char *)"] = o.attr("sub").attr("attr_char");
|
||||||
|
try {
|
||||||
|
o.attr("sub").attr("missing").ptr();
|
||||||
|
} catch (const py::error_already_set &) {
|
||||||
|
d["missing_attr_ptr"] = "raised"_s;
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
o.attr("missing").attr("doesn't matter");
|
||||||
|
} catch (const py::error_already_set &) {
|
||||||
|
d["missing_attr_chain"] = "raised"_s;
|
||||||
|
}
|
||||||
|
|
||||||
|
d["is_none"] = py::cast(o.attr("basic_attr").is_none());
|
||||||
|
|
||||||
|
d["operator()"] = o.attr("func")(1);
|
||||||
|
d["operator*"] = o.attr("func")(*o.attr("begin_end"));
|
||||||
|
|
||||||
|
return d;
|
||||||
|
});
|
||||||
|
|
||||||
|
m.def("test_tuple_accessor", [](py::tuple existing_t) {
|
||||||
|
try {
|
||||||
|
existing_t[0] = py::cast(1);
|
||||||
|
} catch (const py::error_already_set &) {
|
||||||
|
// --> Python system error
|
||||||
|
// Only new tuples (refcount == 1) are mutable
|
||||||
|
auto new_t = py::tuple(3);
|
||||||
|
for (size_t i = 0; i < new_t.size(); ++i) {
|
||||||
|
new_t[i] = py::cast(i);
|
||||||
|
}
|
||||||
|
return new_t;
|
||||||
|
}
|
||||||
|
return py::tuple();
|
||||||
|
});
|
||||||
|
|
||||||
|
m.def("test_accessor_assignment", []() {
|
||||||
|
auto l = py::list(1);
|
||||||
|
l[0] = py::cast(0);
|
||||||
|
|
||||||
|
auto d = py::dict();
|
||||||
|
d["get"] = l[0];
|
||||||
|
auto var = l[0];
|
||||||
|
d["deferred_get"] = var;
|
||||||
|
l[0] = py::cast(1);
|
||||||
|
d["set"] = l[0];
|
||||||
|
var = py::cast(99); // this assignment should not overwrite l[0]
|
||||||
|
d["deferred_set"] = l[0];
|
||||||
|
d["var"] = var;
|
||||||
|
|
||||||
|
return d;
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
@ -248,3 +248,42 @@ def test_dict_api():
|
|||||||
from pybind11_tests import test_dict_keyword_constructor
|
from pybind11_tests import test_dict_keyword_constructor
|
||||||
|
|
||||||
assert test_dict_keyword_constructor() == {"x": 1, "y": 2, "z": 3}
|
assert test_dict_keyword_constructor() == {"x": 1, "y": 2, "z": 3}
|
||||||
|
|
||||||
|
|
||||||
|
def test_accessors():
|
||||||
|
from pybind11_tests import test_accessor_api, test_tuple_accessor, test_accessor_assignment
|
||||||
|
|
||||||
|
class SubTestObject:
|
||||||
|
attr_obj = 1
|
||||||
|
attr_char = 2
|
||||||
|
|
||||||
|
class TestObject:
|
||||||
|
basic_attr = 1
|
||||||
|
begin_end = [1, 2, 3]
|
||||||
|
d = {"operator[object]": 1, "operator[char *]": 2}
|
||||||
|
sub = SubTestObject()
|
||||||
|
|
||||||
|
def func(self, x, *args):
|
||||||
|
return self.basic_attr + x + sum(args)
|
||||||
|
|
||||||
|
d = test_accessor_api(TestObject())
|
||||||
|
assert d["basic_attr"] == 1
|
||||||
|
assert d["begin_end"] == [1, 2, 3]
|
||||||
|
assert d["operator[object]"] == 1
|
||||||
|
assert d["operator[char *]"] == 2
|
||||||
|
assert d["attr(object)"] == 1
|
||||||
|
assert d["attr(char *)"] == 2
|
||||||
|
assert d["missing_attr_ptr"] == "raised"
|
||||||
|
assert d["missing_attr_chain"] == "raised"
|
||||||
|
assert d["is_none"] is False
|
||||||
|
assert d["operator()"] == 2
|
||||||
|
assert d["operator*"] == 7
|
||||||
|
|
||||||
|
assert test_tuple_accessor(tuple()) == (0, 1, 2)
|
||||||
|
|
||||||
|
d = test_accessor_assignment()
|
||||||
|
assert d["get"] == 0
|
||||||
|
assert d["deferred_get"] == 0
|
||||||
|
assert d["set"] == 1
|
||||||
|
assert d["deferred_set"] == 1
|
||||||
|
assert d["var"] == 99
|
||||||
|
Loading…
Reference in New Issue
Block a user