mirror of https://github.com/pybind/pybind11
Browse Source
This reverts commit e7e5d6e5bb
.
Signed-off-by: Henry Schreiner <henryschreineriii@gmail.com>
henryiii/revert/pycapsule
9 changed files with 88 additions and 295 deletions
@ -1,208 +0,0 @@
@@ -1,208 +0,0 @@
|
||||
// Copyright (c) 2024-2025 The Pybind Development Team.
|
||||
// All rights reserved. Use of this source code is governed by a
|
||||
// BSD-style license that can be found in the LICENSE file.
|
||||
|
||||
// For background see the description of PR google/pybind11clif#30099.
|
||||
|
||||
#pragma once |
||||
|
||||
#include <pybind11/attr.h> |
||||
#include <pybind11/conduit/pybind11_platform_abi_id.h> |
||||
#include <pybind11/pytypes.h> |
||||
|
||||
#include "common.h" |
||||
|
||||
#include <cstring> |
||||
#include <utility> |
||||
|
||||
PYBIND11_NAMESPACE_BEGIN(PYBIND11_NAMESPACE) |
||||
PYBIND11_NAMESPACE_BEGIN(detail) |
||||
|
||||
struct function_record_PyObject { |
||||
PyObject_HEAD |
||||
function_record *cpp_func_rec; |
||||
}; |
||||
|
||||
PYBIND11_NAMESPACE_BEGIN(function_record_PyTypeObject_methods) |
||||
|
||||
PyObject *tp_new_impl(PyTypeObject *type, PyObject *args, PyObject *kwds); |
||||
PyObject *tp_alloc_impl(PyTypeObject *type, Py_ssize_t nitems); |
||||
int tp_init_impl(PyObject *self, PyObject *args, PyObject *kwds); |
||||
void tp_dealloc_impl(PyObject *self); |
||||
void tp_free_impl(void *self); |
||||
|
||||
static PyObject *reduce_ex_impl(PyObject *self, PyObject *, PyObject *); |
||||
|
||||
static PyMethodDef tp_methods_impl[] |
||||
= {{"__reduce_ex__", |
||||
// reduce_ex_impl is a PyCFunctionWithKeywords, but PyMethodDef
|
||||
// requires a PyCFunction. The cast through void* is safe and
|
||||
// idiomatic with METH_KEYWORDS, and it successfully sidesteps
|
||||
// unhelpful compiler warnings.
|
||||
// NOLINTNEXTLINE(bugprone-casting-through-void)
|
||||
reinterpret_cast<PyCFunction>(reinterpret_cast<void *>(reduce_ex_impl)), |
||||
METH_VARARGS | METH_KEYWORDS, |
||||
nullptr}, |
||||
{nullptr, nullptr, 0, nullptr}}; |
||||
|
||||
// Note that this name is versioned.
|
||||
constexpr char tp_name_impl[] |
||||
= "pybind11_detail_function_record_" PYBIND11_DETAIL_FUNCTION_RECORD_ABI_ID |
||||
"_" PYBIND11_PLATFORM_ABI_ID; |
||||
|
||||
PYBIND11_NAMESPACE_END(function_record_PyTypeObject_methods) |
||||
|
||||
// Designated initializers are a C++20 feature:
|
||||
// https://en.cppreference.com/w/cpp/language/aggregate_initialization#Designated_initializers
|
||||
// MSVC rejects them unless /std:c++20 is used (error code C7555).
|
||||
PYBIND11_WARNING_PUSH |
||||
PYBIND11_WARNING_DISABLE_CLANG("-Wmissing-field-initializers") |
||||
#if defined(__GNUC__) && __GNUC__ >= 8 |
||||
PYBIND11_WARNING_DISABLE_GCC("-Wmissing-field-initializers") |
||||
#endif |
||||
static PyTypeObject function_record_PyTypeObject = { |
||||
PyVarObject_HEAD_INIT(nullptr, 0) |
||||
/* const char *tp_name */ function_record_PyTypeObject_methods::tp_name_impl, |
||||
/* Py_ssize_t tp_basicsize */ sizeof(function_record_PyObject), |
||||
/* Py_ssize_t tp_itemsize */ 0, |
||||
/* destructor tp_dealloc */ function_record_PyTypeObject_methods::tp_dealloc_impl, |
||||
/* Py_ssize_t tp_vectorcall_offset */ 0, |
||||
/* getattrfunc tp_getattr */ nullptr, |
||||
/* setattrfunc tp_setattr */ nullptr, |
||||
/* PyAsyncMethods *tp_as_async */ nullptr, |
||||
/* reprfunc tp_repr */ nullptr, |
||||
/* PyNumberMethods *tp_as_number */ nullptr, |
||||
/* PySequenceMethods *tp_as_sequence */ nullptr, |
||||
/* PyMappingMethods *tp_as_mapping */ nullptr, |
||||
/* hashfunc tp_hash */ nullptr, |
||||
/* ternaryfunc tp_call */ nullptr, |
||||
/* reprfunc tp_str */ nullptr, |
||||
/* getattrofunc tp_getattro */ nullptr, |
||||
/* setattrofunc tp_setattro */ nullptr, |
||||
/* PyBufferProcs *tp_as_buffer */ nullptr, |
||||
/* unsigned long tp_flags */ Py_TPFLAGS_DEFAULT, |
||||
/* const char *tp_doc */ nullptr, |
||||
/* traverseproc tp_traverse */ nullptr, |
||||
/* inquiry tp_clear */ nullptr, |
||||
/* richcmpfunc tp_richcompare */ nullptr, |
||||
/* Py_ssize_t tp_weaklistoffset */ 0, |
||||
/* getiterfunc tp_iter */ nullptr, |
||||
/* iternextfunc tp_iternext */ nullptr, |
||||
/* struct PyMethodDef *tp_methods */ function_record_PyTypeObject_methods::tp_methods_impl, |
||||
/* struct PyMemberDef *tp_members */ nullptr, |
||||
/* struct PyGetSetDef *tp_getset */ nullptr, |
||||
/* struct _typeobject *tp_base */ nullptr, |
||||
/* PyObject *tp_dict */ nullptr, |
||||
/* descrgetfunc tp_descr_get */ nullptr, |
||||
/* descrsetfunc tp_descr_set */ nullptr, |
||||
/* Py_ssize_t tp_dictoffset */ 0, |
||||
/* initproc tp_init */ function_record_PyTypeObject_methods::tp_init_impl, |
||||
/* allocfunc tp_alloc */ function_record_PyTypeObject_methods::tp_alloc_impl, |
||||
/* newfunc tp_new */ function_record_PyTypeObject_methods::tp_new_impl, |
||||
/* freefunc tp_free */ function_record_PyTypeObject_methods::tp_free_impl, |
||||
/* inquiry tp_is_gc */ nullptr, |
||||
/* PyObject *tp_bases */ nullptr, |
||||
/* PyObject *tp_mro */ nullptr, |
||||
/* PyObject *tp_cache */ nullptr, |
||||
/* PyObject *tp_subclasses */ nullptr, |
||||
/* PyObject *tp_weaklist */ nullptr, |
||||
/* destructor tp_del */ nullptr, |
||||
/* unsigned int tp_version_tag */ 0, |
||||
/* destructor tp_finalize */ nullptr, |
||||
/* vectorcallfunc tp_vectorcall */ nullptr, |
||||
}; |
||||
PYBIND11_WARNING_POP |
||||
|
||||
static bool function_record_PyTypeObject_PyType_Ready_first_call = true; |
||||
|
||||
inline void function_record_PyTypeObject_PyType_Ready() { |
||||
if (function_record_PyTypeObject_PyType_Ready_first_call) { |
||||
if (PyType_Ready(&function_record_PyTypeObject) < 0) { |
||||
throw error_already_set(); |
||||
} |
||||
function_record_PyTypeObject_PyType_Ready_first_call = false; |
||||
} |
||||
} |
||||
|
||||
inline bool is_function_record_PyObject(PyObject *obj) { |
||||
if (PyType_Check(obj) != 0) { |
||||
return false; |
||||
} |
||||
PyTypeObject *obj_type = Py_TYPE(obj); |
||||
// Fast path (pointer comparison).
|
||||
if (obj_type == &function_record_PyTypeObject) { |
||||
return true; |
||||
} |
||||
// This works across extension modules. Note that tp_name is versioned.
|
||||
if (strcmp(obj_type->tp_name, function_record_PyTypeObject.tp_name) == 0) { |
||||
return true; |
||||
} |
||||
return false; |
||||
} |
||||
|
||||
inline function_record *function_record_ptr_from_PyObject(PyObject *obj) { |
||||
if (is_function_record_PyObject(obj)) { |
||||
return ((detail::function_record_PyObject *) obj)->cpp_func_rec; |
||||
} |
||||
return nullptr; |
||||
} |
||||
|
||||
inline object function_record_PyObject_New() { |
||||
auto *py_func_rec = PyObject_New(function_record_PyObject, &function_record_PyTypeObject); |
||||
if (py_func_rec == nullptr) { |
||||
throw error_already_set(); |
||||
} |
||||
py_func_rec->cpp_func_rec = nullptr; // For clarity/purity. Redundant in practice.
|
||||
return reinterpret_steal<object>((PyObject *) py_func_rec); |
||||
} |
||||
|
||||
PYBIND11_NAMESPACE_BEGIN(function_record_PyTypeObject_methods) |
||||
|
||||
// Guard against accidents & oversights, in particular when porting to future Python versions.
|
||||
inline PyObject *tp_new_impl(PyTypeObject *, PyObject *, PyObject *) { |
||||
pybind11_fail("UNEXPECTED CALL OF function_record_PyTypeObject_methods::tp_new_impl"); |
||||
// return nullptr; // Unreachable.
|
||||
} |
||||
|
||||
inline PyObject *tp_alloc_impl(PyTypeObject *, Py_ssize_t) { |
||||
pybind11_fail("UNEXPECTED CALL OF function_record_PyTypeObject_methods::tp_alloc_impl"); |
||||
// return nullptr; // Unreachable.
|
||||
} |
||||
|
||||
inline int tp_init_impl(PyObject *, PyObject *, PyObject *) { |
||||
pybind11_fail("UNEXPECTED CALL OF function_record_PyTypeObject_methods::tp_init_impl"); |
||||
// return -1; // Unreachable.
|
||||
} |
||||
|
||||
inline void tp_free_impl(void *) { |
||||
pybind11_fail("UNEXPECTED CALL OF function_record_PyTypeObject_methods::tp_free_impl"); |
||||
} |
||||
|
||||
inline PyObject *reduce_ex_impl(PyObject *self, PyObject *, PyObject *) { |
||||
// Deliberately ignoring the arguments for simplicity (expected is `protocol: int`).
|
||||
const function_record *rec = function_record_ptr_from_PyObject(self); |
||||
if (rec == nullptr) { |
||||
pybind11_fail( |
||||
"FATAL: function_record_PyTypeObject reduce_ex_impl(): cannot obtain cpp_func_rec."); |
||||
} |
||||
if (rec->name != nullptr && rec->name[0] != '\0' && rec->scope |
||||
&& PyModule_Check(rec->scope.ptr()) != 0) { |
||||
object scope_module = get_scope_module(rec->scope); |
||||
if (scope_module) { |
||||
auto builtins = reinterpret_borrow<dict>(PyEval_GetBuiltins()); |
||||
auto builtins_eval = builtins["eval"]; |
||||
auto reconstruct_args = make_tuple(str("__import__('importlib').import_module('") |
||||
+ scope_module + str("')")); |
||||
return make_tuple(std::move(builtins_eval), std::move(reconstruct_args)) |
||||
.release() |
||||
.ptr(); |
||||
} |
||||
} |
||||
set_error(PyExc_RuntimeError, repr(self) + str(" is not pickleable.")); |
||||
return nullptr; |
||||
} |
||||
|
||||
PYBIND11_NAMESPACE_END(function_record_PyTypeObject_methods) |
||||
|
||||
PYBIND11_NAMESPACE_END(detail) |
||||
PYBIND11_NAMESPACE_END(PYBIND11_NAMESPACE) |
Loading…
Reference in new issue