Skip to content

Commit dfa1a22

Browse files
committed
Merge branch 'skylion007/311-testing' of https://github.com/skylion007/pybind11 into skylion007/311-testing
2 parents 574bd95 + 1cd2513 commit dfa1a22

8 files changed

+128
-67
lines changed

include/pybind11/embed.h

Lines changed: 54 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -86,37 +86,6 @@ inline wchar_t *widen_chars(const char *safe_arg) {
8686
return widened_arg;
8787
}
8888

89-
/// Python 2.x/3.x-compatible version of `PySys_SetArgv`
90-
inline void set_interpreter_argv(int argc, const char *const *argv, bool add_program_dir_to_path) {
91-
// Before it was special-cased in python 3.8, passing an empty or null argv
92-
// caused a segfault, so we have to reimplement the special case ourselves.
93-
bool special_case = (argv == nullptr || argc <= 0);
94-
95-
const char *const empty_argv[]{"\0"};
96-
const char *const *safe_argv = special_case ? empty_argv : argv;
97-
if (special_case) {
98-
argc = 1;
99-
}
100-
101-
auto argv_size = static_cast<size_t>(argc);
102-
// SetArgv* on python 3 takes wchar_t, so we have to convert.
103-
std::unique_ptr<wchar_t *[]> widened_argv(new wchar_t *[argv_size]);
104-
std::vector<std::unique_ptr<wchar_t[], wide_char_arg_deleter>> widened_argv_entries;
105-
widened_argv_entries.reserve(argv_size);
106-
for (size_t ii = 0; ii < argv_size; ++ii) {
107-
widened_argv_entries.emplace_back(widen_chars(safe_argv[ii]));
108-
if (!widened_argv_entries.back()) {
109-
// A null here indicates a character-encoding failure or the python
110-
// interpreter out of memory. Give up.
111-
return;
112-
}
113-
widened_argv[ii] = widened_argv_entries.back().get();
114-
}
115-
116-
auto *pysys_argv = widened_argv.get();
117-
PySys_SetArgvEx(argc, pysys_argv, static_cast<int>(add_program_dir_to_path));
118-
}
119-
12089
PYBIND11_NAMESPACE_END(detail)
12190

12291
/** \rst
@@ -146,9 +115,62 @@ inline void initialize_interpreter(bool init_signal_handlers = true,
146115
pybind11_fail("The interpreter is already running");
147116
}
148117

118+
#if PY_VERSION_HEX < 0x030B0000
119+
149120
Py_InitializeEx(init_signal_handlers ? 1 : 0);
150121

151-
detail::set_interpreter_argv(argc, argv, add_program_dir_to_path);
122+
// Before it was special-cased in python 3.8, passing an empty or null argv
123+
// caused a segfault, so we have to reimplement the special case ourselves.
124+
bool special_case = (argv == nullptr || argc <= 0);
125+
126+
const char *const empty_argv[]{"\0"};
127+
const char *const *safe_argv = special_case ? empty_argv : argv;
128+
if (special_case) {
129+
argc = 1;
130+
}
131+
132+
auto argv_size = static_cast<size_t>(argc);
133+
// SetArgv* on python 3 takes wchar_t, so we have to convert.
134+
std::unique_ptr<wchar_t *[]> widened_argv(new wchar_t *[argv_size]);
135+
std::vector<std::unique_ptr<wchar_t[], detail::wide_char_arg_deleter>> widened_argv_entries;
136+
widened_argv_entries.reserve(argv_size);
137+
for (size_t ii = 0; ii < argv_size; ++ii) {
138+
widened_argv_entries.emplace_back(detail::widen_chars(safe_argv[ii]));
139+
if (!widened_argv_entries.back()) {
140+
// A null here indicates a character-encoding failure or the python
141+
// interpreter out of memory. Give up.
142+
return;
143+
}
144+
widened_argv[ii] = widened_argv_entries.back().get();
145+
}
146+
147+
auto *pysys_argv = widened_argv.get();
148+
149+
PySys_SetArgvEx(argc, pysys_argv, static_cast<int>(add_program_dir_to_path));
150+
#else
151+
PyConfig config;
152+
PyConfig_InitIsolatedConfig(&config);
153+
config.install_signal_handlers = init_signal_handlers ? 1 : 0;
154+
155+
PyStatus status = PyConfig_SetBytesArgv(&config, argc, const_cast<char *const *>(argv));
156+
if (PyStatus_Exception(status)) {
157+
// A failure here indicates a character-encoding failure or the python
158+
// interpreter out of memory. Give up.
159+
PyConfig_Clear(&config);
160+
throw std::runtime_error("Failed to prepare CPython");
161+
}
162+
status = Py_InitializeFromConfig(&config);
163+
PyConfig_Clear(&config);
164+
if (PyStatus_Exception(status)) {
165+
throw std::runtime_error("Failed to init CPython");
166+
}
167+
if (add_program_dir_to_path) {
168+
PyRun_SimpleString("import sys, os.path; "
169+
"sys.path.insert(0, "
170+
"os.path.abspath(os.path.dirname(sys.argv[0])) "
171+
"if sys.argv and os.path.exists(sys.argv[0]) else '')");
172+
}
173+
#endif
152174
}
153175

154176
/** \rst

include/pybind11/functional.h

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -98,8 +98,8 @@ struct type_caster<std::function<Return(Args...)>> {
9898
explicit func_wrapper(func_handle &&hf) noexcept : hfunc(std::move(hf)) {}
9999
Return operator()(Args... args) const {
100100
gil_scoped_acquire acq;
101-
object retval(hfunc.f(std::forward<Args>(args)...));
102-
return retval.template cast<Return>();
101+
// casts the returned object as a rvalue to the return type
102+
return object(hfunc.f(std::forward<Args>(args)...)).template cast<Return>();
103103
}
104104
};
105105

tests/requirements.txt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
build==0.7.0
1+
build==0.8.0
22
numpy==1.21.5; platform_python_implementation=="PyPy" and sys_platform=="linux" and python_version=="3.7"
33
numpy==1.19.3; platform_python_implementation!="PyPy" and python_version=="3.6"
44
numpy==1.21.5; platform_python_implementation!="PyPy" and python_version>="3.7" and python_version<"3.10"

tests/test_builtin_casters.cpp

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -267,7 +267,8 @@ TEST_SUBMODULE(builtin_casters, m) {
267267
m.def("lvalue_nested", []() -> const decltype(lvnested) & { return lvnested; });
268268

269269
static std::pair<int, std::string> int_string_pair{2, "items"};
270-
m.def("int_string_pair", []() { return &int_string_pair; });
270+
m.def(
271+
"int_string_pair", []() { return &int_string_pair; }, py::return_value_policy::reference);
271272

272273
// test_builtins_cast_return_none
273274
m.def("return_none_string", []() -> std::string * { return nullptr; });

tests/test_methods_and_attributes.py

Lines changed: 21 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,21 @@
1+
import sys
2+
13
import pytest
24

35
import env # noqa: F401
46
from pybind11_tests import ConstructorStats
57
from pybind11_tests import methods_and_attributes as m
68

9+
NO_GETTER_MSG = (
10+
"unreadable attribute" if sys.version_info < (3, 11) else "object has no getter"
11+
)
12+
NO_SETTER_MSG = (
13+
"can't set attribute" if sys.version_info < (3, 11) else "object has no setter"
14+
)
15+
NO_DELETER_MSG = (
16+
"can't delete attribute" if sys.version_info < (3, 11) else "object has no deleter"
17+
)
18+
719

820
def test_methods_and_attributes():
921
instance1 = m.ExampleMandA()
@@ -102,47 +114,47 @@ def test_properties():
102114

103115
with pytest.raises(AttributeError) as excinfo:
104116
dummy = instance.def_property_writeonly # unused var
105-
assert "unreadable attribute" in str(excinfo.value)
117+
assert NO_GETTER_MSG in str(excinfo.value)
106118

107119
instance.def_property_writeonly = 4
108120
assert instance.def_property_readonly == 4
109121

110122
with pytest.raises(AttributeError) as excinfo:
111123
dummy = instance.def_property_impossible # noqa: F841 unused var
112-
assert "unreadable attribute" in str(excinfo.value)
124+
assert NO_GETTER_MSG in str(excinfo.value)
113125

114126
with pytest.raises(AttributeError) as excinfo:
115127
instance.def_property_impossible = 5
116-
assert "can't set attribute" in str(excinfo.value)
128+
assert NO_SETTER_MSG in str(excinfo.value)
117129

118130

119131
def test_static_properties():
120132
assert m.TestProperties.def_readonly_static == 1
121133
with pytest.raises(AttributeError) as excinfo:
122134
m.TestProperties.def_readonly_static = 2
123-
assert "can't set attribute" in str(excinfo.value)
135+
assert NO_SETTER_MSG in str(excinfo.value)
124136

125137
m.TestProperties.def_readwrite_static = 2
126138
assert m.TestProperties.def_readwrite_static == 2
127139

128140
with pytest.raises(AttributeError) as excinfo:
129141
dummy = m.TestProperties.def_writeonly_static # unused var
130-
assert "unreadable attribute" in str(excinfo.value)
142+
assert NO_GETTER_MSG in str(excinfo.value)
131143

132144
m.TestProperties.def_writeonly_static = 3
133145
assert m.TestProperties.def_readonly_static == 3
134146

135147
assert m.TestProperties.def_property_readonly_static == 3
136148
with pytest.raises(AttributeError) as excinfo:
137149
m.TestProperties.def_property_readonly_static = 99
138-
assert "can't set attribute" in str(excinfo.value)
150+
assert NO_SETTER_MSG in str(excinfo.value)
139151

140152
m.TestProperties.def_property_static = 4
141153
assert m.TestProperties.def_property_static == 4
142154

143155
with pytest.raises(AttributeError) as excinfo:
144156
dummy = m.TestProperties.def_property_writeonly_static
145-
assert "unreadable attribute" in str(excinfo.value)
157+
assert NO_GETTER_MSG in str(excinfo.value)
146158

147159
m.TestProperties.def_property_writeonly_static = 5
148160
assert m.TestProperties.def_property_static == 5
@@ -160,7 +172,7 @@ def test_static_properties():
160172

161173
with pytest.raises(AttributeError) as excinfo:
162174
dummy = instance.def_property_writeonly_static # noqa: F841 unused var
163-
assert "unreadable attribute" in str(excinfo.value)
175+
assert NO_GETTER_MSG in str(excinfo.value)
164176

165177
instance.def_property_writeonly_static = 4
166178
assert instance.def_property_static == 4
@@ -180,7 +192,7 @@ def test_static_properties():
180192
properties_override = m.TestPropertiesOverride()
181193
with pytest.raises(AttributeError) as excinfo:
182194
del properties_override.def_readonly
183-
assert "can't delete attribute" in str(excinfo.value)
195+
assert NO_DELETER_MSG in str(excinfo.value)
184196

185197

186198
def test_static_cls():

tests/test_stl.cpp

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -177,7 +177,8 @@ TEST_SUBMODULE(stl, m) {
177177
[](const std::vector<bool> &v) { return v.at(0) == true && v.at(1) == false; });
178178
// Unnumbered regression (caused by #936): pointers to stl containers aren't castable
179179
static std::vector<RValueCaster> lvv{2};
180-
m.def("cast_ptr_vector", []() { return &lvv; });
180+
m.def(
181+
"cast_ptr_vector", []() { return &lvv; }, py::return_value_policy::reference);
181182

182183
// test_deque
183184
m.def("cast_deque", []() { return std::deque<int>{1}; });

tools/FindPythonLibsNew.cmake

Lines changed: 21 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -151,26 +151,36 @@ if(NOT _PYTHON_SUCCESS MATCHES 0)
151151
return()
152152
endif()
153153

154+
# Can manually set values when cross-compiling
155+
macro(_PYBIND11_GET_IF_UNDEF lst index name)
156+
if(NOT DEFINED "${name}")
157+
list(GET "${lst}" "${index}" "${name}")
158+
endif()
159+
endmacro()
160+
154161
# Convert the process output into a list
155162
if(WIN32)
156163
string(REGEX REPLACE "\\\\" "/" _PYTHON_VALUES ${_PYTHON_VALUES})
157164
endif()
158165
string(REGEX REPLACE ";" "\\\\;" _PYTHON_VALUES ${_PYTHON_VALUES})
159166
string(REGEX REPLACE "\n" ";" _PYTHON_VALUES ${_PYTHON_VALUES})
160-
list(GET _PYTHON_VALUES 0 _PYTHON_VERSION_LIST)
161-
list(GET _PYTHON_VALUES 1 PYTHON_PREFIX)
162-
list(GET _PYTHON_VALUES 2 PYTHON_INCLUDE_DIR)
163-
list(GET _PYTHON_VALUES 3 PYTHON_SITE_PACKAGES)
164-
list(GET _PYTHON_VALUES 4 PYTHON_MODULE_EXTENSION)
165-
list(GET _PYTHON_VALUES 5 PYTHON_IS_DEBUG)
166-
list(GET _PYTHON_VALUES 6 PYTHON_SIZEOF_VOID_P)
167-
list(GET _PYTHON_VALUES 7 PYTHON_LIBRARY_SUFFIX)
168-
list(GET _PYTHON_VALUES 8 PYTHON_LIBDIR)
169-
list(GET _PYTHON_VALUES 9 PYTHON_MULTIARCH)
167+
_pybind11_get_if_undef(_PYTHON_VALUES 0 _PYTHON_VERSION_LIST)
168+
_pybind11_get_if_undef(_PYTHON_VALUES 1 PYTHON_PREFIX)
169+
_pybind11_get_if_undef(_PYTHON_VALUES 2 PYTHON_INCLUDE_DIR)
170+
_pybind11_get_if_undef(_PYTHON_VALUES 3 PYTHON_SITE_PACKAGES)
171+
_pybind11_get_if_undef(_PYTHON_VALUES 4 PYTHON_MODULE_EXTENSION)
172+
_pybind11_get_if_undef(_PYTHON_VALUES 5 PYTHON_IS_DEBUG)
173+
_pybind11_get_if_undef(_PYTHON_VALUES 6 PYTHON_SIZEOF_VOID_P)
174+
_pybind11_get_if_undef(_PYTHON_VALUES 7 PYTHON_LIBRARY_SUFFIX)
175+
_pybind11_get_if_undef(_PYTHON_VALUES 8 PYTHON_LIBDIR)
176+
_pybind11_get_if_undef(_PYTHON_VALUES 9 PYTHON_MULTIARCH)
170177

171178
# Make sure the Python has the same pointer-size as the chosen compiler
172179
# Skip if CMAKE_SIZEOF_VOID_P is not defined
173-
if(CMAKE_SIZEOF_VOID_P AND (NOT "${PYTHON_SIZEOF_VOID_P}" STREQUAL "${CMAKE_SIZEOF_VOID_P}"))
180+
# This should be skipped for (non-Apple) cross-compiles (like EMSCRIPTEN)
181+
if(NOT CMAKE_CROSSCOMPILING
182+
AND CMAKE_SIZEOF_VOID_P
183+
AND (NOT "${PYTHON_SIZEOF_VOID_P}" STREQUAL "${CMAKE_SIZEOF_VOID_P}"))
174184
if(PythonLibsNew_FIND_REQUIRED)
175185
math(EXPR _PYTHON_BITS "${PYTHON_SIZEOF_VOID_P} * 8")
176186
math(EXPR _CMAKE_BITS "${CMAKE_SIZEOF_VOID_P} * 8")

tools/pybind11Tools.cmake

Lines changed: 25 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -115,17 +115,32 @@ if(PYTHON_IS_DEBUG)
115115
PROPERTY INTERFACE_COMPILE_DEFINITIONS Py_DEBUG)
116116
endif()
117117

118-
set_property(
119-
TARGET pybind11::module
120-
APPEND
121-
PROPERTY
122-
INTERFACE_LINK_LIBRARIES pybind11::python_link_helper
123-
"$<$<OR:$<PLATFORM_ID:Windows>,$<PLATFORM_ID:Cygwin>>:$<BUILD_INTERFACE:${PYTHON_LIBRARIES}>>")
118+
if(CMAKE_VERSION VERSION_LESS 3.11)
119+
set_property(
120+
TARGET pybind11::module
121+
APPEND
122+
PROPERTY
123+
INTERFACE_LINK_LIBRARIES
124+
pybind11::python_link_helper
125+
"$<$<OR:$<PLATFORM_ID:Windows>,$<PLATFORM_ID:Cygwin>>:$<BUILD_INTERFACE:${PYTHON_LIBRARIES}>>"
126+
)
124127

125-
set_property(
126-
TARGET pybind11::embed
127-
APPEND
128-
PROPERTY INTERFACE_LINK_LIBRARIES pybind11::pybind11 $<BUILD_INTERFACE:${PYTHON_LIBRARIES}>)
128+
set_property(
129+
TARGET pybind11::embed
130+
APPEND
131+
PROPERTY INTERFACE_LINK_LIBRARIES pybind11::pybind11 $<BUILD_INTERFACE:${PYTHON_LIBRARIES}>)
132+
else()
133+
target_link_libraries(
134+
pybind11::module
135+
INTERFACE
136+
pybind11::python_link_helper
137+
"$<$<OR:$<PLATFORM_ID:Windows>,$<PLATFORM_ID:Cygwin>>:$<BUILD_INTERFACE:${PYTHON_LIBRARIES}>>"
138+
)
139+
140+
target_link_libraries(pybind11::embed INTERFACE pybind11::pybind11
141+
$<BUILD_INTERFACE:${PYTHON_LIBRARIES}>)
142+
143+
endif()
129144

130145
function(pybind11_extension name)
131146
# The prefix and extension are provided by FindPythonLibsNew.cmake

0 commit comments

Comments
 (0)