Merge branch 'pybind:master' into master

This commit is contained in:
Steve R. Sun 2022-05-29 09:45:52 +08:00 committed by GitHub
commit dfc0689c34
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 57 additions and 12 deletions

View File

@ -1173,9 +1173,16 @@ public:
py::module_ m3 = m2.def_submodule("subsub", "A submodule of 'example.sub'"); py::module_ m3 = m2.def_submodule("subsub", "A submodule of 'example.sub'");
\endrst */ \endrst */
module_ def_submodule(const char *name, const char *doc = nullptr) { module_ def_submodule(const char *name, const char *doc = nullptr) {
std::string full_name const char *this_name = PyModule_GetName(m_ptr);
= std::string(PyModule_GetName(m_ptr)) + std::string(".") + std::string(name); if (this_name == nullptr) {
auto result = reinterpret_borrow<module_>(PyImport_AddModule(full_name.c_str())); 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()) { if (doc && options::show_user_defined_docstrings()) {
result.attr("__doc__") = pybind11::str(doc); result.attr("__doc__") = pybind11::str(doc);
} }
@ -2326,7 +2333,7 @@ template <typename Access,
typename Sentinel, typename Sentinel,
typename ValueType, typename ValueType,
typename... Extra> 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...>; using state = detail::iterator_state<Access, Policy, Iterator, Sentinel, ValueType, Extra...>;
// TODO: state captures only the types of Extra, not the values // TODO: state captures only the types of Extra, not the values
@ -2352,7 +2359,7 @@ iterator make_iterator_impl(Iterator first, Sentinel last, Extra &&...extra) {
Policy); Policy);
} }
return cast(state{first, last, true}); return cast(state{std::forward<Iterator>(first), std::forward<Sentinel>(last), true});
} }
PYBIND11_NAMESPACE_END(detail) PYBIND11_NAMESPACE_END(detail)
@ -2363,13 +2370,15 @@ template <return_value_policy Policy = return_value_policy::reference_internal,
typename Sentinel, typename Sentinel,
typename ValueType = typename detail::iterator_access<Iterator>::result_type, typename ValueType = typename detail::iterator_access<Iterator>::result_type,
typename... Extra> 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>, return detail::make_iterator_impl<detail::iterator_access<Iterator>,
Policy, Policy,
Iterator, Iterator,
Sentinel, Sentinel,
ValueType, 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 /// Makes a python iterator over the keys (`.first`) of a iterator over pairs from a
@ -2379,13 +2388,15 @@ template <return_value_policy Policy = return_value_policy::reference_internal,
typename Sentinel, typename Sentinel,
typename KeyType = typename detail::iterator_key_access<Iterator>::result_type, typename KeyType = typename detail::iterator_key_access<Iterator>::result_type,
typename... Extra> 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>, return detail::make_iterator_impl<detail::iterator_key_access<Iterator>,
Policy, Policy,
Iterator, Iterator,
Sentinel, Sentinel,
KeyType, 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 /// Makes a python iterator over the values (`.second`) of a iterator over pairs from a
@ -2395,13 +2406,15 @@ template <return_value_policy Policy = return_value_policy::reference_internal,
typename Sentinel, typename Sentinel,
typename ValueType = typename detail::iterator_value_access<Iterator>::result_type, typename ValueType = typename detail::iterator_value_access<Iterator>::result_type,
typename... Extra> 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>, return detail::make_iterator_impl<detail::iterator_value_access<Iterator>,
Policy, Policy,
Iterator, Iterator,
Sentinel, Sentinel,
ValueType, 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 /// Makes an iterator over values of an stl container or other container supporting
@ -2460,7 +2473,7 @@ void implicitly_convertible() {
}; };
if (auto *tinfo = detail::get_type_info(typeid(OutputType))) { 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 { } else {
pybind11_fail("implicitly_convertible: Unable to find type " + type_id<OutputType>()); pybind11_fail("implicitly_convertible: Unable to find type " + type_id<OutputType>());
} }

View File

@ -120,4 +120,6 @@ TEST_SUBMODULE(modules, m) {
return failures; return failures;
}); });
m.def("def_submodule", [](py::module_ m, const char *name) { return m.def_submodule(name); });
} }

View File

@ -1,3 +1,6 @@
import pytest
import env
from pybind11_tests import ConstructorStats from pybind11_tests import ConstructorStats
from pybind11_tests import modules as m from pybind11_tests import modules as m
from pybind11_tests.modules import subsubmodule as ms from pybind11_tests.modules import subsubmodule as ms
@ -89,3 +92,30 @@ def test_builtin_key_type():
keys = __builtins__.__dict__.keys() keys = __builtins__.__dict__.keys()
assert {type(k) for k in keys} == {str} assert {type(k) for k in keys} == {str}
@pytest.mark.xfail("env.PYPY", reason="PyModule_GetName()")
def test_def_submodule_failures():
sm = m.def_submodule(m, b"ScratchSubModuleName") # Using bytes to show it works.
assert sm.__name__ == m.__name__ + "." + "ScratchSubModuleName"
malformed_utf8 = b"\x80"
if env.PYPY:
# It is not worth the effort finding a trigger for a failure when running with PyPy.
pytest.skip("Sufficiently exercised on platforms other than PyPy.")
else:
# Meant to trigger PyModule_GetName() failure:
sm_name_orig = sm.__name__
sm.__name__ = malformed_utf8
try:
with pytest.raises(Exception):
# Seen with Python 3.9: SystemError: nameless module
# But we do not want to exercise the internals of PyModule_GetName(), which could
# change in future versions of Python, but a bad __name__ is very likely to cause
# some kind of failure indefinitely.
m.def_submodule(sm, b"SubSubModuleName")
finally:
# Clean up to ensure nothing gets upset by a module with an invalid __name__.
sm.__name__ = sm_name_orig # Purely precautionary.
# Meant to trigger PyImport_AddModule() failure:
with pytest.raises(UnicodeDecodeError):
m.def_submodule(sm, malformed_utf8)