mirror of
https://github.com/RYDE-WORK/pybind11.git
synced 2026-02-04 22:46:15 +08:00
Moving tp_class access, and consistent fully-qualified naming for PyPy, to detail::get_tp_name (#2520)
* Moving tp_class access, and consistent fully-qualified naming for PyPy, to detail::get_tp_name * Change get_tp_name to get_fully_qualified_tp_name
This commit is contained in:
parent
3232e59b83
commit
c72708a746
@ -39,6 +39,9 @@
|
|||||||
PYBIND11_NAMESPACE_BEGIN(PYBIND11_NAMESPACE)
|
PYBIND11_NAMESPACE_BEGIN(PYBIND11_NAMESPACE)
|
||||||
PYBIND11_NAMESPACE_BEGIN(detail)
|
PYBIND11_NAMESPACE_BEGIN(detail)
|
||||||
|
|
||||||
|
// Forward-declaration; see detail/class.h
|
||||||
|
std::string get_fully_qualified_tp_name(PyTypeObject*);
|
||||||
|
|
||||||
/// A life support system for temporary objects created by `type_caster::load()`.
|
/// A life support system for temporary objects created by `type_caster::load()`.
|
||||||
/// Adding a patient will keep it alive up until the enclosing function returns.
|
/// Adding a patient will keep it alive up until the enclosing function returns.
|
||||||
class loader_life_support {
|
class loader_life_support {
|
||||||
@ -342,8 +345,8 @@ PYBIND11_NOINLINE inline value_and_holder instance::get_value_and_holder(const t
|
|||||||
"(compile in debug mode for type details)");
|
"(compile in debug mode for type details)");
|
||||||
#else
|
#else
|
||||||
pybind11_fail("pybind11::detail::instance::get_value_and_holder: `" +
|
pybind11_fail("pybind11::detail::instance::get_value_and_holder: `" +
|
||||||
std::string(find_type->type->tp_name) + "' is not a pybind11 base of the given `" +
|
get_fully_qualified_tp_name(find_type->type) + "' is not a pybind11 base of the given `" +
|
||||||
std::string(Py_TYPE(this)->tp_name) + "' instance");
|
get_fully_qualified_tp_name(Py_TYPE(this)) + "' instance");
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -24,6 +24,14 @@ PYBIND11_NAMESPACE_BEGIN(detail)
|
|||||||
# define PYBIND11_SET_OLDPY_QUALNAME(obj, nameobj) setattr((PyObject *) obj, "__qualname__", nameobj)
|
# define PYBIND11_SET_OLDPY_QUALNAME(obj, nameobj) setattr((PyObject *) obj, "__qualname__", nameobj)
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
inline std::string get_fully_qualified_tp_name(PyTypeObject *type) {
|
||||||
|
#if !defined(PYPY_VERSION)
|
||||||
|
return type->tp_name;
|
||||||
|
#else
|
||||||
|
return handle((PyObject *) type).attr("__module__").cast<std::string>() + "." + type->tp_name;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
inline PyTypeObject *type_incref(PyTypeObject *type) {
|
inline PyTypeObject *type_incref(PyTypeObject *type) {
|
||||||
Py_INCREF(type);
|
Py_INCREF(type);
|
||||||
return type;
|
return type;
|
||||||
@ -172,7 +180,7 @@ extern "C" inline PyObject *pybind11_meta_call(PyObject *type, PyObject *args, P
|
|||||||
for (const auto &vh : values_and_holders(instance)) {
|
for (const auto &vh : values_and_holders(instance)) {
|
||||||
if (!vh.holder_constructed()) {
|
if (!vh.holder_constructed()) {
|
||||||
PyErr_Format(PyExc_TypeError, "%.200s.__init__() must be called when overriding __init__",
|
PyErr_Format(PyExc_TypeError, "%.200s.__init__() must be called when overriding __init__",
|
||||||
vh.type->type->tp_name);
|
get_fully_qualified_tp_name(vh.type->type).c_str());
|
||||||
Py_DECREF(self);
|
Py_DECREF(self);
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
@ -304,12 +312,7 @@ extern "C" inline PyObject *pybind11_object_new(PyTypeObject *type, PyObject *,
|
|||||||
/// following default function will be used which simply throws an exception.
|
/// following default function will be used which simply throws an exception.
|
||||||
extern "C" inline int pybind11_object_init(PyObject *self, PyObject *, PyObject *) {
|
extern "C" inline int pybind11_object_init(PyObject *self, PyObject *, PyObject *) {
|
||||||
PyTypeObject *type = Py_TYPE(self);
|
PyTypeObject *type = Py_TYPE(self);
|
||||||
std::string msg;
|
std::string msg = get_fully_qualified_tp_name(type) + ": No constructor defined!";
|
||||||
#if defined(PYPY_VERSION)
|
|
||||||
msg += handle((PyObject *) type).attr("__module__").cast<std::string>() + ".";
|
|
||||||
#endif
|
|
||||||
msg += type->tp_name;
|
|
||||||
msg += ": No constructor defined!";
|
|
||||||
PyErr_SetString(PyExc_TypeError, msg.c_str());
|
PyErr_SetString(PyExc_TypeError, msg.c_str());
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
@ -448,7 +451,7 @@ extern "C" inline PyObject *pybind11_get_dict(PyObject *self, void *) {
|
|||||||
extern "C" inline int pybind11_set_dict(PyObject *self, PyObject *new_dict, void *) {
|
extern "C" inline int pybind11_set_dict(PyObject *self, PyObject *new_dict, void *) {
|
||||||
if (!PyDict_Check(new_dict)) {
|
if (!PyDict_Check(new_dict)) {
|
||||||
PyErr_Format(PyExc_TypeError, "__dict__ must be set to a dictionary, not a '%.200s'",
|
PyErr_Format(PyExc_TypeError, "__dict__ must be set to a dictionary, not a '%.200s'",
|
||||||
Py_TYPE(new_dict)->tp_name);
|
get_fully_qualified_tp_name(Py_TYPE(new_dict)).c_str());
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
PyObject *&dict = *_PyObject_GetDictPtr(self);
|
PyObject *&dict = *_PyObject_GetDictPtr(self);
|
||||||
@ -476,9 +479,8 @@ extern "C" inline int pybind11_clear(PyObject *self) {
|
|||||||
inline void enable_dynamic_attributes(PyHeapTypeObject *heap_type) {
|
inline void enable_dynamic_attributes(PyHeapTypeObject *heap_type) {
|
||||||
auto type = &heap_type->ht_type;
|
auto type = &heap_type->ht_type;
|
||||||
#if defined(PYPY_VERSION) && (PYPY_VERSION_NUM < 0x06000000)
|
#if defined(PYPY_VERSION) && (PYPY_VERSION_NUM < 0x06000000)
|
||||||
pybind11_fail(std::string(type->tp_name) + ": dynamic attributes are "
|
pybind11_fail(get_fully_qualified_tp_name(type) + ": dynamic attributes are currently not "
|
||||||
"currently not supported in "
|
"supported in conjunction with PyPy!");
|
||||||
"conjunction with PyPy!");
|
|
||||||
#endif
|
#endif
|
||||||
type->tp_flags |= Py_TPFLAGS_HAVE_GC;
|
type->tp_flags |= Py_TPFLAGS_HAVE_GC;
|
||||||
type->tp_dictoffset = type->tp_basicsize; // place dict at the end
|
type->tp_dictoffset = type->tp_basicsize; // place dict at the end
|
||||||
|
|||||||
@ -242,7 +242,7 @@ protected:
|
|||||||
|
|
||||||
#if !defined(NDEBUG) && !defined(PYBIND11_DISABLE_NEW_STYLE_INIT_WARNING)
|
#if !defined(NDEBUG) && !defined(PYBIND11_DISABLE_NEW_STYLE_INIT_WARNING)
|
||||||
if (rec->is_constructor && !rec->is_new_style_constructor) {
|
if (rec->is_constructor && !rec->is_new_style_constructor) {
|
||||||
const auto class_name = std::string(((PyTypeObject *) rec->scope.ptr())->tp_name);
|
const auto class_name = detail::get_fully_qualified_tp_name((PyTypeObject *) rec->scope.ptr());
|
||||||
const auto func_name = std::string(rec->name);
|
const auto func_name = std::string(rec->name);
|
||||||
PyErr_WarnEx(
|
PyErr_WarnEx(
|
||||||
PyExc_FutureWarning,
|
PyExc_FutureWarning,
|
||||||
@ -1039,7 +1039,7 @@ protected:
|
|||||||
if (!type->ht_type.tp_as_buffer)
|
if (!type->ht_type.tp_as_buffer)
|
||||||
pybind11_fail(
|
pybind11_fail(
|
||||||
"To be able to register buffer protocol support for the type '" +
|
"To be able to register buffer protocol support for the type '" +
|
||||||
std::string(tinfo->type->tp_name) +
|
get_fully_qualified_tp_name(tinfo->type) +
|
||||||
"' the associated class<>(..) invocation must "
|
"' the associated class<>(..) invocation must "
|
||||||
"include the pybind11::buffer_protocol() annotation!");
|
"include the pybind11::buffer_protocol() annotation!");
|
||||||
|
|
||||||
|
|||||||
@ -152,10 +152,8 @@ def test_inheritance_init(msg):
|
|||||||
pass
|
pass
|
||||||
with pytest.raises(TypeError) as exc_info:
|
with pytest.raises(TypeError) as exc_info:
|
||||||
Python()
|
Python()
|
||||||
expected = ["m.class_.Pet.__init__() must be called when overriding __init__",
|
expected = "m.class_.Pet.__init__() must be called when overriding __init__"
|
||||||
"Pet.__init__() must be called when overriding __init__"] # PyPy?
|
assert msg(exc_info.value) == expected
|
||||||
# TODO: fix PyPy error message wrt. tp_name/__qualname__?
|
|
||||||
assert msg(exc_info.value) in expected
|
|
||||||
|
|
||||||
# Multiple bases
|
# Multiple bases
|
||||||
class RabbitHamster(m.Rabbit, m.Hamster):
|
class RabbitHamster(m.Rabbit, m.Hamster):
|
||||||
@ -164,9 +162,8 @@ def test_inheritance_init(msg):
|
|||||||
|
|
||||||
with pytest.raises(TypeError) as exc_info:
|
with pytest.raises(TypeError) as exc_info:
|
||||||
RabbitHamster()
|
RabbitHamster()
|
||||||
expected = ["m.class_.Hamster.__init__() must be called when overriding __init__",
|
expected = "m.class_.Hamster.__init__() must be called when overriding __init__"
|
||||||
"Hamster.__init__() must be called when overriding __init__"] # PyPy
|
assert msg(exc_info.value) == expected
|
||||||
assert msg(exc_info.value) in expected
|
|
||||||
|
|
||||||
|
|
||||||
def test_automatic_upcasting():
|
def test_automatic_upcasting():
|
||||||
|
|||||||
@ -155,7 +155,7 @@ def test_internal_locals_differ():
|
|||||||
assert m.local_cpp_types_addr() != cm.local_cpp_types_addr()
|
assert m.local_cpp_types_addr() != cm.local_cpp_types_addr()
|
||||||
|
|
||||||
|
|
||||||
@pytest.mark.xfail("env.PYPY")
|
@pytest.mark.xfail("env.PYPY and sys.pypy_version_info < (7, 3, 2)")
|
||||||
def test_stl_caster_vs_stl_bind(msg):
|
def test_stl_caster_vs_stl_bind(msg):
|
||||||
"""One module uses a generic vector caster from `<pybind11/stl.h>` while the other
|
"""One module uses a generic vector caster from `<pybind11/stl.h>` while the other
|
||||||
exports `std::vector<int>` via `py:bind_vector` and `py::module_local`"""
|
exports `std::vector<int>` via `py:bind_vector` and `py::module_local`"""
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user