Merge branch 'master' into sh_merge_master

This commit is contained in:
Ralf W. Grosse-Kunstleve
2022-06-01 14:39:51 -07:00
22 changed files with 451 additions and 72 deletions

View File

@@ -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());

View File

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

View File

@@ -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>();
}
};

View File

@@ -100,7 +100,7 @@ private:
if (size > remainder) {
str line(pbase(), size - remainder);
pywrite(line);
pywrite(std::move(line));
pyflush();
}

View File

@@ -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>()) {

View File

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

View File

@@ -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();
}