mirror of
https://github.com/pybind/pybind11.git
synced 2026-05-24 06:45:03 +00:00
Merge branch 'master' into sh_merge_master
This commit is contained in:
@@ -426,6 +426,7 @@ PYBIND11_NOINLINE internals &get_internals() {
|
||||
~gil_scoped_acquire_local() { PyGILState_Release(state); }
|
||||
const PyGILState_STATE state;
|
||||
} gil;
|
||||
error_scope err_scope;
|
||||
|
||||
PYBIND11_STR_TYPE id(PYBIND11_INTERNALS_ID);
|
||||
auto builtins = handle(PyEval_GetBuiltins());
|
||||
|
||||
@@ -470,13 +470,20 @@ PYBIND11_NOINLINE bool isinstance_generic(handle obj, const std::type_info &tp)
|
||||
return isinstance(obj, type);
|
||||
}
|
||||
|
||||
PYBIND11_NOINLINE std::string error_string() {
|
||||
if (!PyErr_Occurred()) {
|
||||
PyErr_SetString(PyExc_RuntimeError, "Unknown internal error occurred");
|
||||
return "Unknown internal error occurred";
|
||||
PYBIND11_NOINLINE std::string error_string(const char *called) {
|
||||
error_scope scope; // Fetch error state (will be restored when this function returns).
|
||||
if (scope.type == nullptr) {
|
||||
if (called == nullptr) {
|
||||
called = "pybind11::detail::error_string()";
|
||||
}
|
||||
pybind11_fail("Internal error: " + std::string(called)
|
||||
+ " called while Python error indicator not set.");
|
||||
}
|
||||
|
||||
error_scope scope; // Preserve error state
|
||||
PyErr_NormalizeException(&scope.type, &scope.value, &scope.trace);
|
||||
if (scope.trace != nullptr) {
|
||||
PyException_SetTraceback(scope.value, scope.trace);
|
||||
}
|
||||
|
||||
std::string errorString;
|
||||
if (scope.type) {
|
||||
@@ -487,12 +494,6 @@ PYBIND11_NOINLINE std::string error_string() {
|
||||
errorString += (std::string) str(scope.value);
|
||||
}
|
||||
|
||||
PyErr_NormalizeException(&scope.type, &scope.value, &scope.trace);
|
||||
|
||||
if (scope.trace != nullptr) {
|
||||
PyException_SetTraceback(scope.value, scope.trace);
|
||||
}
|
||||
|
||||
#if !defined(PYPY_VERSION)
|
||||
if (scope.trace) {
|
||||
auto *trace = (PyTracebackObject *) scope.trace;
|
||||
|
||||
@@ -98,8 +98,8 @@ public:
|
||||
explicit func_wrapper(func_handle &&hf) noexcept : hfunc(std::move(hf)) {}
|
||||
Return operator()(Args... args) const {
|
||||
gil_scoped_acquire acq;
|
||||
object retval(hfunc.f(std::forward<Args>(args)...));
|
||||
return retval.template cast<Return>();
|
||||
// casts the returned object as a rvalue to the return type
|
||||
return object(hfunc.f(std::forward<Args>(args)...)).template cast<Return>();
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
@@ -100,7 +100,7 @@ private:
|
||||
|
||||
if (size > remainder) {
|
||||
str line(pbase(), size - remainder);
|
||||
pywrite(line);
|
||||
pywrite(std::move(line));
|
||||
pyflush();
|
||||
}
|
||||
|
||||
|
||||
@@ -1174,9 +1174,16 @@ public:
|
||||
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);
|
||||
auto result = reinterpret_borrow<module_>(PyImport_AddModule(full_name.c_str()));
|
||||
const char *this_name = PyModule_GetName(m_ptr);
|
||||
if (this_name == nullptr) {
|
||||
throw error_already_set();
|
||||
}
|
||||
std::string full_name = std::string(this_name) + '.' + name;
|
||||
handle submodule = PyImport_AddModule(full_name.c_str());
|
||||
if (!submodule) {
|
||||
throw error_already_set();
|
||||
}
|
||||
auto result = reinterpret_borrow<module_>(submodule);
|
||||
if (doc && options::show_user_defined_docstrings()) {
|
||||
result.attr("__doc__") = pybind11::str(doc);
|
||||
}
|
||||
@@ -1796,7 +1803,8 @@ public:
|
||||
scope(*this),
|
||||
sibling(getattr(*this, name_, none())),
|
||||
extra...);
|
||||
attr(cf.name()) = staticmethod(cf);
|
||||
auto cf_name = cf.name();
|
||||
attr(std::move(cf_name)) = staticmethod(std::move(cf));
|
||||
return *this;
|
||||
}
|
||||
|
||||
@@ -1850,7 +1858,7 @@ public:
|
||||
if (!caster.load(obj, false)) {
|
||||
return nullptr;
|
||||
}
|
||||
return new buffer_info(((capture *) ptr)->func(caster));
|
||||
return new buffer_info(((capture *) ptr)->func(std::move(caster)));
|
||||
},
|
||||
ptr);
|
||||
weakref(m_ptr, cpp_function([ptr](handle wr) {
|
||||
@@ -2316,12 +2324,12 @@ struct enum_base {
|
||||
str name(name_);
|
||||
if (entries.contains(name)) {
|
||||
std::string type_name = (std::string) str(m_base.attr("__name__"));
|
||||
throw value_error(type_name + ": element \"" + std::string(name_)
|
||||
throw value_error(std::move(type_name) + ": element \"" + std::string(name_)
|
||||
+ "\" already exists!");
|
||||
}
|
||||
|
||||
entries[name] = std::make_pair(value, doc);
|
||||
m_base.attr(name) = value;
|
||||
m_base.attr(std::move(name)) = std::move(value);
|
||||
}
|
||||
|
||||
PYBIND11_NOINLINE void export_values() {
|
||||
@@ -2580,7 +2588,7 @@ template <typename Access,
|
||||
typename Sentinel,
|
||||
typename ValueType,
|
||||
typename... Extra>
|
||||
iterator make_iterator_impl(Iterator first, Sentinel last, Extra &&...extra) {
|
||||
iterator make_iterator_impl(Iterator &&first, Sentinel &&last, Extra &&...extra) {
|
||||
using state = detail::iterator_state<Access, Policy, Iterator, Sentinel, ValueType, Extra...>;
|
||||
// TODO: state captures only the types of Extra, not the values
|
||||
|
||||
@@ -2606,7 +2614,7 @@ iterator make_iterator_impl(Iterator first, Sentinel last, Extra &&...extra) {
|
||||
Policy);
|
||||
}
|
||||
|
||||
return cast(state{first, last, true});
|
||||
return cast(state{std::forward<Iterator>(first), std::forward<Sentinel>(last), true});
|
||||
}
|
||||
|
||||
PYBIND11_NAMESPACE_END(detail)
|
||||
@@ -2617,13 +2625,15 @@ template <return_value_policy Policy = return_value_policy::reference_internal,
|
||||
typename Sentinel,
|
||||
typename ValueType = typename detail::iterator_access<Iterator>::result_type,
|
||||
typename... Extra>
|
||||
iterator make_iterator(Iterator first, Sentinel last, Extra &&...extra) {
|
||||
iterator make_iterator(Iterator &&first, Sentinel &&last, Extra &&...extra) {
|
||||
return detail::make_iterator_impl<detail::iterator_access<Iterator>,
|
||||
Policy,
|
||||
Iterator,
|
||||
Sentinel,
|
||||
ValueType,
|
||||
Extra...>(first, last, std::forward<Extra>(extra)...);
|
||||
Extra...>(std::forward<Iterator>(first),
|
||||
std::forward<Sentinel>(last),
|
||||
std::forward<Extra>(extra)...);
|
||||
}
|
||||
|
||||
/// Makes a python iterator over the keys (`.first`) of a iterator over pairs from a
|
||||
@@ -2633,13 +2643,15 @@ template <return_value_policy Policy = return_value_policy::reference_internal,
|
||||
typename Sentinel,
|
||||
typename KeyType = typename detail::iterator_key_access<Iterator>::result_type,
|
||||
typename... Extra>
|
||||
iterator make_key_iterator(Iterator first, Sentinel last, Extra &&...extra) {
|
||||
iterator make_key_iterator(Iterator &&first, Sentinel &&last, Extra &&...extra) {
|
||||
return detail::make_iterator_impl<detail::iterator_key_access<Iterator>,
|
||||
Policy,
|
||||
Iterator,
|
||||
Sentinel,
|
||||
KeyType,
|
||||
Extra...>(first, last, std::forward<Extra>(extra)...);
|
||||
Extra...>(std::forward<Iterator>(first),
|
||||
std::forward<Sentinel>(last),
|
||||
std::forward<Extra>(extra)...);
|
||||
}
|
||||
|
||||
/// Makes a python iterator over the values (`.second`) of a iterator over pairs from a
|
||||
@@ -2649,13 +2661,15 @@ template <return_value_policy Policy = return_value_policy::reference_internal,
|
||||
typename Sentinel,
|
||||
typename ValueType = typename detail::iterator_value_access<Iterator>::result_type,
|
||||
typename... Extra>
|
||||
iterator make_value_iterator(Iterator first, Sentinel last, Extra &&...extra) {
|
||||
iterator make_value_iterator(Iterator &&first, Sentinel &&last, Extra &&...extra) {
|
||||
return detail::make_iterator_impl<detail::iterator_value_access<Iterator>,
|
||||
Policy,
|
||||
Iterator,
|
||||
Sentinel,
|
||||
ValueType,
|
||||
Extra...>(first, last, std::forward<Extra>(extra)...);
|
||||
Extra...>(std::forward<Iterator>(first),
|
||||
std::forward<Sentinel>(last),
|
||||
std::forward<Extra>(extra)...);
|
||||
}
|
||||
|
||||
/// Makes an iterator over values of an stl container or other container supporting
|
||||
@@ -2714,7 +2728,7 @@ void implicitly_convertible() {
|
||||
};
|
||||
|
||||
if (auto *tinfo = detail::get_type_info(typeid(OutputType))) {
|
||||
tinfo->implicit_conversions.push_back(implicit_caster);
|
||||
tinfo->implicit_conversions.emplace_back(std::move(implicit_caster));
|
||||
} else {
|
||||
pybind11_fail("implicitly_convertible: Unable to find type " + type_id<OutputType>());
|
||||
}
|
||||
@@ -2851,7 +2865,7 @@ PYBIND11_NOINLINE void print(const tuple &args, const dict &kwargs) {
|
||||
}
|
||||
|
||||
auto write = file.attr("write");
|
||||
write(line);
|
||||
write(std::move(line));
|
||||
write(kwargs.contains("end") ? kwargs["end"] : str("\n"));
|
||||
|
||||
if (kwargs.contains("flush") && kwargs["flush"].cast<bool>()) {
|
||||
|
||||
@@ -85,7 +85,9 @@ public:
|
||||
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)
|
||||
/// See above (the only difference is that the key's reference is stolen)
|
||||
item_accessor operator[](object &&key) const;
|
||||
/// See above (the only difference is that the key is provided as a string literal)
|
||||
item_accessor operator[](const char *key) const;
|
||||
|
||||
/** \rst
|
||||
@@ -95,7 +97,9 @@ public:
|
||||
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)
|
||||
/// See above (the only difference is that the key's reference is stolen)
|
||||
obj_attr_accessor attr(object &&key) const;
|
||||
/// See above (the only difference is that the key is provided as a string literal)
|
||||
str_attr_accessor attr(const char *key) const;
|
||||
|
||||
/** \rst
|
||||
@@ -180,6 +184,10 @@ private:
|
||||
|
||||
PYBIND11_NAMESPACE_END(detail)
|
||||
|
||||
#if !defined(PYBIND11_HANDLE_REF_DEBUG) && !defined(NDEBUG)
|
||||
# define PYBIND11_HANDLE_REF_DEBUG
|
||||
#endif
|
||||
|
||||
/** \rst
|
||||
Holds a reference to a Python object (no reference counting)
|
||||
|
||||
@@ -209,6 +217,9 @@ public:
|
||||
this function automatically. Returns a reference to itself.
|
||||
\endrst */
|
||||
const handle &inc_ref() const & {
|
||||
#ifdef PYBIND11_HANDLE_REF_DEBUG
|
||||
inc_ref_counter(1);
|
||||
#endif
|
||||
Py_XINCREF(m_ptr);
|
||||
return *this;
|
||||
}
|
||||
@@ -244,6 +255,18 @@ public:
|
||||
|
||||
protected:
|
||||
PyObject *m_ptr = nullptr;
|
||||
|
||||
#ifdef PYBIND11_HANDLE_REF_DEBUG
|
||||
private:
|
||||
static std::size_t inc_ref_counter(std::size_t add) {
|
||||
thread_local std::size_t counter = 0;
|
||||
counter += add;
|
||||
return counter;
|
||||
}
|
||||
|
||||
public:
|
||||
static std::size_t inc_ref_counter() { return inc_ref_counter(0); }
|
||||
#endif
|
||||
};
|
||||
|
||||
/** \rst
|
||||
@@ -360,7 +383,7 @@ T reinterpret_steal(handle h) {
|
||||
}
|
||||
|
||||
PYBIND11_NAMESPACE_BEGIN(detail)
|
||||
std::string error_string();
|
||||
std::string error_string(const char *called = nullptr);
|
||||
PYBIND11_NAMESPACE_END(detail)
|
||||
|
||||
#if defined(_MSC_VER)
|
||||
@@ -375,20 +398,27 @@ PYBIND11_NAMESPACE_END(detail)
|
||||
/// python).
|
||||
class PYBIND11_EXPORT_EXCEPTION error_already_set : public std::runtime_error {
|
||||
public:
|
||||
/// Constructs a new exception from the current Python error indicator, if any. The current
|
||||
/// Constructs a new exception from the current Python error indicator. The current
|
||||
/// Python error indicator will be cleared.
|
||||
error_already_set() : std::runtime_error(detail::error_string()) {
|
||||
error_already_set() : std::runtime_error(detail::error_string("pybind11::error_already_set")) {
|
||||
PyErr_Fetch(&m_type.ptr(), &m_value.ptr(), &m_trace.ptr());
|
||||
}
|
||||
|
||||
/// WARNING: The GIL must be held when this copy constructor is invoked!
|
||||
error_already_set(const error_already_set &) = default;
|
||||
error_already_set(error_already_set &&) = default;
|
||||
|
||||
/// WARNING: This destructor needs to acquire the Python GIL. This can lead to
|
||||
/// crashes (undefined behavior) if the Python interpreter is finalizing.
|
||||
inline ~error_already_set() override;
|
||||
|
||||
/// Give the currently-held error back to Python, if any. If there is currently a Python error
|
||||
/// already set it is cleared first. After this call, the current object no longer stores the
|
||||
/// error variables (but the `.what()` string is still available).
|
||||
/// Restores the currently-held Python error (which will clear the Python error indicator first
|
||||
/// if already set). After this call, the current object no longer stores the error variables.
|
||||
/// NOTE: Any copies of this object may still store the error variables. Currently there is no
|
||||
// protection against calling restore() from multiple copies.
|
||||
/// NOTE: This member function will always restore the normalized exception, which may or may
|
||||
/// not be the original Python exception.
|
||||
/// WARNING: The GIL must be held when this member function is called!
|
||||
void restore() {
|
||||
PyErr_Restore(m_type.release().ptr(), m_value.release().ptr(), m_trace.release().ptr());
|
||||
}
|
||||
@@ -405,6 +435,7 @@ public:
|
||||
}
|
||||
/// An alternate version of `discard_as_unraisable()`, where a string provides information on
|
||||
/// the location of the error. For example, `__func__` could be helpful.
|
||||
/// WARNING: The GIL must be held when this member function is called!
|
||||
void discard_as_unraisable(const char *err_context) {
|
||||
discard_as_unraisable(reinterpret_steal<object>(PYBIND11_FROM_STRING(err_context)));
|
||||
}
|
||||
@@ -657,7 +688,7 @@ public:
|
||||
}
|
||||
template <typename T>
|
||||
void operator=(T &&value) & {
|
||||
get_cache() = reinterpret_borrow<object>(object_or_cast(std::forward<T>(value)));
|
||||
get_cache() = ensure_object(object_or_cast(std::forward<T>(value)));
|
||||
}
|
||||
|
||||
template <typename T = Policy>
|
||||
@@ -685,6 +716,9 @@ public:
|
||||
}
|
||||
|
||||
private:
|
||||
static object ensure_object(object &&o) { return std::move(o); }
|
||||
static object ensure_object(handle h) { return reinterpret_borrow<object>(h); }
|
||||
|
||||
object &get_cache() const {
|
||||
if (!cache) {
|
||||
cache = Policy::get(obj, key);
|
||||
@@ -1581,6 +1615,8 @@ public:
|
||||
|
||||
capsule(const void *value, void (*destructor)(void *)) {
|
||||
m_ptr = PyCapsule_New(const_cast<void *>(value), nullptr, [](PyObject *o) {
|
||||
// guard if destructor called while err indicator is set
|
||||
error_scope error_guard;
|
||||
auto destructor = reinterpret_cast<void (*)(void *)>(PyCapsule_GetContext(o));
|
||||
if (destructor == nullptr) {
|
||||
if (PyErr_Occurred()) {
|
||||
@@ -1682,7 +1718,10 @@ public:
|
||||
size_t size() const { return (size_t) PyTuple_Size(m_ptr); }
|
||||
bool empty() const { return size() == 0; }
|
||||
detail::tuple_accessor operator[](size_t index) const { return {*this, index}; }
|
||||
detail::item_accessor operator[](handle h) const { return object::operator[](h); }
|
||||
template <typename T, detail::enable_if_t<detail::is_pyobject<T>::value, int> = 0>
|
||||
detail::item_accessor operator[](T &&o) const {
|
||||
return object::operator[](std::forward<T>(o));
|
||||
}
|
||||
detail::tuple_iterator begin() const { return {*this, 0}; }
|
||||
detail::tuple_iterator end() const { return {*this, PyTuple_GET_SIZE(m_ptr)}; }
|
||||
};
|
||||
@@ -1742,7 +1781,10 @@ public:
|
||||
}
|
||||
bool empty() const { return size() == 0; }
|
||||
detail::sequence_accessor operator[](size_t index) const { return {*this, index}; }
|
||||
detail::item_accessor operator[](handle h) const { return object::operator[](h); }
|
||||
template <typename T, detail::enable_if_t<detail::is_pyobject<T>::value, int> = 0>
|
||||
detail::item_accessor operator[](T &&o) const {
|
||||
return object::operator[](std::forward<T>(o));
|
||||
}
|
||||
detail::sequence_iterator begin() const { return {*this, 0}; }
|
||||
detail::sequence_iterator end() const { return {*this, PySequence_Size(m_ptr)}; }
|
||||
};
|
||||
@@ -1761,7 +1803,10 @@ public:
|
||||
size_t size() const { return (size_t) PyList_Size(m_ptr); }
|
||||
bool empty() const { return size() == 0; }
|
||||
detail::list_accessor operator[](size_t index) const { return {*this, index}; }
|
||||
detail::item_accessor operator[](handle h) const { return object::operator[](h); }
|
||||
template <typename T, detail::enable_if_t<detail::is_pyobject<T>::value, int> = 0>
|
||||
detail::item_accessor operator[](T &&o) const {
|
||||
return object::operator[](std::forward<T>(o));
|
||||
}
|
||||
detail::list_iterator begin() const { return {*this, 0}; }
|
||||
detail::list_iterator end() const { return {*this, PyList_GET_SIZE(m_ptr)}; }
|
||||
template <typename T>
|
||||
@@ -2061,6 +2106,10 @@ item_accessor object_api<D>::operator[](handle key) const {
|
||||
return {derived(), reinterpret_borrow<object>(key)};
|
||||
}
|
||||
template <typename D>
|
||||
item_accessor object_api<D>::operator[](object &&key) const {
|
||||
return {derived(), std::move(key)};
|
||||
}
|
||||
template <typename D>
|
||||
item_accessor object_api<D>::operator[](const char *key) const {
|
||||
return {derived(), pybind11::str(key)};
|
||||
}
|
||||
@@ -2069,6 +2118,10 @@ obj_attr_accessor object_api<D>::attr(handle key) const {
|
||||
return {derived(), reinterpret_borrow<object>(key)};
|
||||
}
|
||||
template <typename D>
|
||||
obj_attr_accessor object_api<D>::attr(object &&key) const {
|
||||
return {derived(), std::move(key)};
|
||||
}
|
||||
template <typename D>
|
||||
str_attr_accessor object_api<D>::attr(const char *key) const {
|
||||
return {derived(), key};
|
||||
}
|
||||
|
||||
@@ -128,7 +128,7 @@ struct map_caster {
|
||||
if (!key || !value) {
|
||||
return handle();
|
||||
}
|
||||
d[key] = value;
|
||||
d[std::move(key)] = std::move(value);
|
||||
}
|
||||
return d.release();
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user