Merge branch 'master' into sh_merge_master

This commit is contained in:
Ralf W. Grosse-Kunstleve
2021-09-12 19:55:42 -07:00
17 changed files with 254 additions and 41 deletions

View File

@@ -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)

View File

@@ -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]))

View File

@@ -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; });

View File

@@ -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) {

View File

@@ -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
View 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
View 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()