Skip to content

Commit

Permalink
Merge branch 'master' into method-pos-only-args
Browse files Browse the repository at this point in the history
  • Loading branch information
XuehaiPan authored Oct 14, 2024
2 parents 9a32ca3 + f7e14e9 commit 93cc71f
Show file tree
Hide file tree
Showing 7 changed files with 72 additions and 17 deletions.
15 changes: 12 additions & 3 deletions include/pybind11/cast.h
Original file line number Diff line number Diff line change
Expand Up @@ -1564,15 +1564,24 @@ struct function_call {
handle init_self;
};

// See PR #5396 for the discussion that led to this
template <typename Base, typename Derived, typename = void>
struct is_same_or_base_of : std::is_same<Base, Derived> {};

// Only evaluate is_base_of if Derived is complete.
// is_base_of raises a compiler error if Derived is incomplete.
template <typename Base, typename Derived>
struct is_same_or_base_of<Base, Derived, decltype(void(sizeof(Derived)))>
: any_of<std::is_same<Base, Derived>, std::is_base_of<Base, Derived>> {};

/// Helper class which loads arguments for C++ functions called from Python
template <typename... Args>
class argument_loader {
using indices = make_index_sequence<sizeof...(Args)>;

template <typename Arg>
using argument_is_args = std::is_base_of<args, intrinsic_t<Arg>>;
using argument_is_args = is_same_or_base_of<args, intrinsic_t<Arg>>;
template <typename Arg>
using argument_is_kwargs = std::is_base_of<kwargs, intrinsic_t<Arg>>;
using argument_is_kwargs = is_same_or_base_of<kwargs, intrinsic_t<Arg>>;
// Get kwargs argument position, or -1 if not present:
static constexpr auto kwargs_pos = constexpr_last<argument_is_kwargs, Args...>();

Expand Down
19 changes: 11 additions & 8 deletions include/pybind11/detail/common.h
Original file line number Diff line number Diff line change
Expand Up @@ -164,14 +164,6 @@
# endif
#endif

#if !defined(PYBIND11_EXPORT_EXCEPTION)
# if defined(__apple_build_version__)
# define PYBIND11_EXPORT_EXCEPTION PYBIND11_EXPORT
# else
# define PYBIND11_EXPORT_EXCEPTION
# endif
#endif

// For CUDA, GCC7, GCC8:
// PYBIND11_NOINLINE_FORCED is incompatible with `-Wattributes -Werror`.
// When defining PYBIND11_NOINLINE_FORCED, it is best to also use `-Wno-attributes`.
Expand Down Expand Up @@ -329,6 +321,17 @@ PYBIND11_WARNING_POP
# endif
#endif

// For libc++, the exceptions should be exported,
// otherwise, the exception translation would be incorrect.
// IMPORTANT: This code block must stay BELOW the #include <exception> above (see PR #5390).
#if !defined(PYBIND11_EXPORT_EXCEPTION)
# if defined(_LIBCPP_EXCEPTION)
# define PYBIND11_EXPORT_EXCEPTION PYBIND11_EXPORT
# else
# define PYBIND11_EXPORT_EXCEPTION
# endif
#endif

// Must be after including <version> or one of the other headers specified by the standard
#if defined(__cpp_lib_char8_t) && __cpp_lib_char8_t >= 201811L
# define PYBIND11_HAS_U8STRING
Expand Down
20 changes: 15 additions & 5 deletions include/pybind11/pytypes.h
Original file line number Diff line number Diff line change
Expand Up @@ -1470,27 +1470,30 @@ class iterator : public object {
PYBIND11_OBJECT_DEFAULT(iterator, object, PyIter_Check)

iterator &operator++() {
init();
advance();
return *this;
}

iterator operator++(int) {
// Note: We must call init() first so that rv.value is
// the same as this->value just before calling advance().
// Otherwise, dereferencing the returned iterator may call
// advance() again and return the 3rd item instead of the 1st.
init();
auto rv = *this;
advance();
return rv;
}

// NOLINTNEXTLINE(readability-const-return-type) // PR #3263
reference operator*() const {
if (m_ptr && !value.ptr()) {
auto &self = const_cast<iterator &>(*this);
self.advance();
}
init();
return value;
}

pointer operator->() const {
operator*();
init();
return &value;
}

Expand All @@ -1513,6 +1516,13 @@ class iterator : public object {
friend bool operator!=(const iterator &a, const iterator &b) { return a->ptr() != b->ptr(); }

private:
void init() const {
if (m_ptr && !value.ptr()) {
auto &self = const_cast<iterator &>(*this);
self.advance();
}
}

void advance() {
value = reinterpret_steal<object>(PyIter_Next(m_ptr));
if (value.ptr() == nullptr && PyErr_Occurred()) {
Expand Down
16 changes: 16 additions & 0 deletions tests/test_class.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -52,8 +52,24 @@ void bind_empty0(py::module_ &m) {
}

} // namespace pr4220_tripped_over_this

namespace pr5396_forward_declared_class {
class ForwardClass;
class Args : public py::args {};
} // namespace pr5396_forward_declared_class

} // namespace test_class

static_assert(py::detail::is_same_or_base_of<py::args, py::args>::value, "");
static_assert(
py::detail::is_same_or_base_of<py::args,
test_class::pr5396_forward_declared_class::Args>::value,
"");
static_assert(!py::detail::is_same_or_base_of<
py::args,
test_class::pr5396_forward_declared_class::ForwardClass>::value,
"");

TEST_SUBMODULE(class_, m) {
m.def("obj_class_name", [](py::handle obj) { return py::detail::obj_class_name(obj.ptr()); });

Expand Down
2 changes: 1 addition & 1 deletion tests/test_exceptions.py
Original file line number Diff line number Diff line change
Expand Up @@ -76,7 +76,7 @@ def test_cross_module_exceptions(msg):

# TODO: FIXME
@pytest.mark.xfail(
"env.MACOS and (env.PYPY or pybind11_tests.compiler_info.startswith('Homebrew Clang')) or sys.platform.startswith('emscripten')",
"env.MACOS and env.PYPY",
raises=RuntimeError,
reason="See Issue #2847, PR #2999, PR #4324",
)
Expand Down
12 changes: 12 additions & 0 deletions tests/test_pytypes.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -150,6 +150,18 @@ TEST_SUBMODULE(pytypes, m) {
m.def("get_iterator", [] { return py::iterator(); });
// test_iterable
m.def("get_iterable", [] { return py::iterable(); });
m.def("get_first_item_from_iterable", [](const py::iterable &iter) {
// This tests the postfix increment operator
py::iterator it = iter.begin();
py::iterator it2 = it++;
return *it2;
});
m.def("get_second_item_from_iterable", [](const py::iterable &iter) {
// This tests the prefix increment operator
py::iterator it = iter.begin();
++it;
return *it;
});
m.def("get_frozenset_from_iterable",
[](const py::iterable &iter) { return py::frozenset(iter); });
m.def("get_list_from_iterable", [](const py::iterable &iter) { return py::list(iter); });
Expand Down
5 changes: 5 additions & 0 deletions tests/test_pytypes.py
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,11 @@ def test_from_iterable(pytype, from_iter_func):

def test_iterable(doc):
assert doc(m.get_iterable) == "get_iterable() -> Iterable"
lins = [1, 2, 3]
i = m.get_first_item_from_iterable(lins)
assert i == 1
i = m.get_second_item_from_iterable(lins)
assert i == 2


def test_float(doc):
Expand Down

0 comments on commit 93cc71f

Please sign in to comment.