mirror of
https://github.com/pybind/pybind11.git
synced 2026-05-11 17:00:34 +00:00
Merge branch 'master' into sh_merge_master
This commit is contained in:
@@ -143,6 +143,7 @@ set(PYBIND11_TEST_FILES
|
||||
test_stl.cpp
|
||||
test_stl_binders.cpp
|
||||
test_tagbased_polymorphic.cpp
|
||||
test_thread.cpp
|
||||
test_union.cpp
|
||||
test_virtual_functions.cpp)
|
||||
|
||||
|
||||
@@ -3,5 +3,8 @@ import sys
|
||||
|
||||
import test_cmake_build
|
||||
|
||||
if str is not bytes: # If not Python2
|
||||
assert isinstance(__file__, str) # Test this is properly set
|
||||
|
||||
assert test_cmake_build.add(1, 2) == 3
|
||||
print("{} imports, runs, and adds: 1 + 2 = 3".format(sys.argv[1]))
|
||||
|
||||
@@ -178,6 +178,7 @@ TEST_SUBMODULE(eigen, m) {
|
||||
ReturnTester() { print_created(this); }
|
||||
~ReturnTester() { print_destroyed(this); }
|
||||
static Eigen::MatrixXd create() { return Eigen::MatrixXd::Ones(10, 10); }
|
||||
// NOLINTNEXTLINE(readability-const-return-type)
|
||||
static const Eigen::MatrixXd createConst() { return Eigen::MatrixXd::Ones(10, 10); }
|
||||
Eigen::MatrixXd &get() { return mat; }
|
||||
Eigen::MatrixXd *getPtr() { return &mat; }
|
||||
@@ -244,6 +245,9 @@ TEST_SUBMODULE(eigen, m) {
|
||||
|
||||
// test_fixed, and various other tests
|
||||
m.def("fixed_r", [mat]() -> FixedMatrixR { return FixedMatrixR(mat); });
|
||||
// Our Eigen does a hack which respects constness through the numpy writeable flag.
|
||||
// Therefore, the const return actually affects this type despite being an rvalue.
|
||||
// NOLINTNEXTLINE(readability-const-return-type)
|
||||
m.def("fixed_r_const", [mat]() -> const FixedMatrixR { return FixedMatrixR(mat); });
|
||||
m.def("fixed_c", [mat]() -> FixedMatrixC { return FixedMatrixC(mat); });
|
||||
m.def("fixed_copy_r", [](const FixedMatrixR &m) -> FixedMatrixR { return m; });
|
||||
|
||||
@@ -462,6 +462,49 @@ TEST_SUBMODULE(pytypes, m) {
|
||||
m.def("weakref_from_object_and_function",
|
||||
[](py::object o, py::function f) { return py::weakref(std::move(o), std::move(f)); });
|
||||
|
||||
// See PR #3263 for background (https://github.com/pybind/pybind11/pull/3263):
|
||||
// pytypes.h could be changed to enforce the "most correct" user code below, by removing
|
||||
// `const` from iterator `reference` using type aliases, but that will break existing
|
||||
// user code.
|
||||
#if (defined(__APPLE__) && defined(__clang__)) || defined(PYPY_VERSION)
|
||||
// This is "most correct" and enforced on these platforms.
|
||||
# define PYBIND11_AUTO_IT auto it
|
||||
#else
|
||||
// This works on many platforms and is (unfortunately) reflective of existing user code.
|
||||
// NOLINTNEXTLINE(bugprone-macro-parentheses)
|
||||
# define PYBIND11_AUTO_IT auto &it
|
||||
#endif
|
||||
|
||||
m.def("tuple_iterator", []() {
|
||||
auto tup = py::make_tuple(5, 7);
|
||||
int tup_sum = 0;
|
||||
for (PYBIND11_AUTO_IT : tup) {
|
||||
tup_sum += it.cast<int>();
|
||||
}
|
||||
return tup_sum;
|
||||
});
|
||||
|
||||
m.def("dict_iterator", []() {
|
||||
py::dict dct;
|
||||
dct[py::int_(3)] = 5;
|
||||
dct[py::int_(7)] = 11;
|
||||
int kv_sum = 0;
|
||||
for (PYBIND11_AUTO_IT : dct) {
|
||||
kv_sum += it.first.cast<int>() * 100 + it.second.cast<int>();
|
||||
}
|
||||
return kv_sum;
|
||||
});
|
||||
|
||||
m.def("passed_iterator", [](const py::iterator &py_it) {
|
||||
int elem_sum = 0;
|
||||
for (PYBIND11_AUTO_IT : py_it) {
|
||||
elem_sum += it.cast<int>();
|
||||
}
|
||||
return elem_sum;
|
||||
});
|
||||
|
||||
#undef PYBIND11_AUTO_IT
|
||||
|
||||
// Tests below this line are for pybind11 IMPLEMENTATION DETAILS:
|
||||
|
||||
m.def("sequence_item_get_ssize_t", [](const py::object &o) {
|
||||
|
||||
@@ -623,6 +623,12 @@ def test_weakref(create_weakref, create_weakref_with_callback):
|
||||
assert callback.called
|
||||
|
||||
|
||||
def test_cpp_iterators():
|
||||
assert m.tuple_iterator() == 12
|
||||
assert m.dict_iterator() == 305 + 711
|
||||
assert m.passed_iterator(iter((-7, 3))) == -4
|
||||
|
||||
|
||||
def test_implementation_details():
|
||||
lst = [39, 43, 92, 49, 22, 29, 93, 98, 26, 57, 8]
|
||||
tup = tuple(lst)
|
||||
|
||||
66
tests/test_thread.cpp
Normal file
66
tests/test_thread.cpp
Normal file
@@ -0,0 +1,66 @@
|
||||
/*
|
||||
tests/test_thread.cpp -- call pybind11 bound methods in threads
|
||||
|
||||
Copyright (c) 2021 Laramie Leavitt (Google LLC) <lar@google.com>
|
||||
|
||||
All rights reserved. Use of this source code is governed by a
|
||||
BSD-style license that can be found in the LICENSE file.
|
||||
*/
|
||||
|
||||
#include <pybind11/cast.h>
|
||||
#include <pybind11/pybind11.h>
|
||||
|
||||
#include <chrono>
|
||||
#include <thread>
|
||||
|
||||
#include "pybind11_tests.h"
|
||||
|
||||
namespace py = pybind11;
|
||||
|
||||
namespace {
|
||||
|
||||
struct IntStruct {
|
||||
explicit IntStruct(int v) : value(v) {};
|
||||
~IntStruct() { value = -value; }
|
||||
IntStruct(const IntStruct&) = default;
|
||||
IntStruct& operator=(const IntStruct&) = default;
|
||||
|
||||
int value;
|
||||
};
|
||||
|
||||
} // namespace
|
||||
|
||||
TEST_SUBMODULE(thread, m) {
|
||||
|
||||
py::class_<IntStruct>(m, "IntStruct").def(py::init([](const int i) { return IntStruct(i); }));
|
||||
|
||||
// implicitly_convertible uses loader_life_support when an implicit
|
||||
// conversion is required in order to lifetime extend the reference.
|
||||
//
|
||||
// This test should be run with ASAN for better effectiveness.
|
||||
py::implicitly_convertible<int, IntStruct>();
|
||||
|
||||
m.def("test", [](int expected, const IntStruct &in) {
|
||||
{
|
||||
py::gil_scoped_release release;
|
||||
std::this_thread::sleep_for(std::chrono::milliseconds(5));
|
||||
}
|
||||
|
||||
if (in.value != expected) {
|
||||
throw std::runtime_error("Value changed!!");
|
||||
}
|
||||
});
|
||||
|
||||
m.def(
|
||||
"test_no_gil",
|
||||
[](int expected, const IntStruct &in) {
|
||||
std::this_thread::sleep_for(std::chrono::milliseconds(5));
|
||||
if (in.value != expected) {
|
||||
throw std::runtime_error("Value changed!!");
|
||||
}
|
||||
},
|
||||
py::call_guard<py::gil_scoped_release>());
|
||||
|
||||
// NOTE: std::string_view also uses loader_life_support to ensure that
|
||||
// the string contents remain alive, but that's a C++ 17 feature.
|
||||
}
|
||||
44
tests/test_thread.py
Normal file
44
tests/test_thread.py
Normal file
@@ -0,0 +1,44 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
import threading
|
||||
|
||||
from pybind11_tests import thread as m
|
||||
|
||||
|
||||
class Thread(threading.Thread):
|
||||
def __init__(self, fn):
|
||||
super(Thread, self).__init__()
|
||||
self.fn = fn
|
||||
self.e = None
|
||||
|
||||
def run(self):
|
||||
try:
|
||||
for i in range(10):
|
||||
self.fn(i, i)
|
||||
except Exception as e:
|
||||
self.e = e
|
||||
|
||||
def join(self):
|
||||
super(Thread, self).join()
|
||||
if self.e:
|
||||
raise self.e
|
||||
|
||||
|
||||
def test_implicit_conversion():
|
||||
a = Thread(m.test)
|
||||
b = Thread(m.test)
|
||||
c = Thread(m.test)
|
||||
for x in [a, b, c]:
|
||||
x.start()
|
||||
for x in [c, b, a]:
|
||||
x.join()
|
||||
|
||||
|
||||
def test_implicit_conversion_no_gil():
|
||||
a = Thread(m.test_no_gil)
|
||||
b = Thread(m.test_no_gil)
|
||||
c = Thread(m.test_no_gil)
|
||||
for x in [a, b, c]:
|
||||
x.start()
|
||||
for x in [c, b, a]:
|
||||
x.join()
|
||||
Reference in New Issue
Block a user