Merge branch 'master' into sh_merge_master

This commit is contained in:
Ralf W. Grosse-Kunstleve 2023-09-10 10:49:38 -07:00
commit 35b26794ec
21 changed files with 259 additions and 52 deletions

View File

@ -70,7 +70,7 @@ jobs:
runs-on: ${{ matrix.runs-on }} runs-on: ${{ matrix.runs-on }}
steps: steps:
- uses: actions/checkout@v3 - uses: actions/checkout@v4
- name: Setup Python ${{ matrix.python }} - name: Setup Python ${{ matrix.python }}
uses: actions/setup-python@v4 uses: actions/setup-python@v4
@ -206,7 +206,7 @@ jobs:
runs-on: ubuntu-20.04 runs-on: ubuntu-20.04
steps: steps:
- uses: actions/checkout@v3 - uses: actions/checkout@v4
- name: Setup Python ${{ matrix.python-version }} (deadsnakes) - name: Setup Python ${{ matrix.python-version }} (deadsnakes)
uses: deadsnakes/action@v3.0.1 uses: deadsnakes/action@v3.0.1
@ -311,7 +311,7 @@ jobs:
container: "silkeh/clang:${{ matrix.clang }}${{ matrix.container_suffix }}" container: "silkeh/clang:${{ matrix.clang }}${{ matrix.container_suffix }}"
steps: steps:
- uses: actions/checkout@v3 - uses: actions/checkout@v4
- name: Add wget and python3 - name: Add wget and python3
run: apt-get update && apt-get install -y python3-dev python3-numpy python3-pytest libeigen3-dev run: apt-get update && apt-get install -y python3-dev python3-numpy python3-pytest libeigen3-dev
@ -345,7 +345,7 @@ jobs:
container: nvidia/cuda:12.2.0-devel-ubuntu22.04 container: nvidia/cuda:12.2.0-devel-ubuntu22.04
steps: steps:
- uses: actions/checkout@v3 - uses: actions/checkout@v4
# tzdata will try to ask for the timezone, so set the DEBIAN_FRONTEND # tzdata will try to ask for the timezone, so set the DEBIAN_FRONTEND
- name: Install 🐍 3 - name: Install 🐍 3
@ -369,7 +369,7 @@ jobs:
# container: centos:8 # container: centos:8
# #
# steps: # steps:
# - uses: actions/checkout@v3 # - uses: actions/checkout@v4
# #
# - name: Add Python 3 and a few requirements # - name: Add Python 3 and a few requirements
# run: yum update -y && yum install -y git python3-devel python3-numpy python3-pytest make environment-modules # run: yum update -y && yum install -y git python3-devel python3-numpy python3-pytest make environment-modules
@ -414,7 +414,7 @@ jobs:
# tzdata will try to ask for the timezone, so set the DEBIAN_FRONTEND # tzdata will try to ask for the timezone, so set the DEBIAN_FRONTEND
DEBIAN_FRONTEND: 'noninteractive' DEBIAN_FRONTEND: 'noninteractive'
steps: steps:
- uses: actions/checkout@v3 - uses: actions/checkout@v4
- name: Add NVHPC Repo - name: Add NVHPC Repo
run: | run: |
@ -476,7 +476,7 @@ jobs:
container: "gcc:${{ matrix.gcc }}" container: "gcc:${{ matrix.gcc }}"
steps: steps:
- uses: actions/checkout@v3 - uses: actions/checkout@v4
- name: Add Python 3 - name: Add Python 3
run: apt-get update; apt-get install -y python3-dev python3-numpy python3-pytest python3-pip libeigen3-dev run: apt-get update; apt-get install -y python3-dev python3-numpy python3-pytest python3-pip libeigen3-dev
@ -536,7 +536,7 @@ jobs:
name: "🐍 3 • ICC latest • x64" name: "🐍 3 • ICC latest • x64"
steps: steps:
- uses: actions/checkout@v3 - uses: actions/checkout@v4
- name: Add apt repo - name: Add apt repo
run: | run: |
@ -640,7 +640,13 @@ jobs:
container: "${{ matrix.container }}" container: "${{ matrix.container }}"
steps: steps:
- uses: actions/checkout@v3 - name: Latest actions/checkout
uses: actions/checkout@v4
if: matrix.container != 'centos:7'
- name: Pin actions/checkout as required for centos:7
uses: actions/checkout@v3
if: matrix.container == 'centos:7'
- name: Add Python 3 (RHEL 7) - name: Add Python 3 (RHEL 7)
if: matrix.container == 'centos:7' if: matrix.container == 'centos:7'
@ -688,7 +694,7 @@ jobs:
container: i386/debian:buster container: i386/debian:buster
steps: steps:
- uses: actions/checkout@v1 # Required to run inside docker - uses: actions/checkout@v1 # v1 is required to run inside docker
- name: Install requirements - name: Install requirements
run: | run: |
@ -731,7 +737,7 @@ jobs:
runs-on: ubuntu-latest runs-on: ubuntu-latest
steps: steps:
- uses: actions/checkout@v3 - uses: actions/checkout@v4
- uses: actions/setup-python@v4 - uses: actions/setup-python@v4
with: with:
@ -783,7 +789,7 @@ jobs:
runs-on: windows-2019 runs-on: windows-2019
steps: steps:
- uses: actions/checkout@v3 - uses: actions/checkout@v4
- name: Setup Python ${{ matrix.python }} - name: Setup Python ${{ matrix.python }}
uses: actions/setup-python@v4 uses: actions/setup-python@v4
@ -836,7 +842,7 @@ jobs:
runs-on: windows-2019 runs-on: windows-2019
steps: steps:
- uses: actions/checkout@v3 - uses: actions/checkout@v4
- name: Setup Python ${{ matrix.python }} - name: Setup Python ${{ matrix.python }}
uses: actions/setup-python@v4 uses: actions/setup-python@v4
@ -884,7 +890,7 @@ jobs:
runs-on: windows-2022 runs-on: windows-2022
steps: steps:
- uses: actions/checkout@v3 - uses: actions/checkout@v4
- name: Setup Python ${{ matrix.python }} - name: Setup Python ${{ matrix.python }}
uses: actions/setup-python@v4 uses: actions/setup-python@v4
@ -962,7 +968,7 @@ jobs:
mingw-w64-${{matrix.env}}-boost mingw-w64-${{matrix.env}}-boost
mingw-w64-${{matrix.env}}-catch mingw-w64-${{matrix.env}}-catch
- uses: actions/checkout@v3 - uses: actions/checkout@v4
- name: Configure C++11 - name: Configure C++11
# LTO leads to many undefined reference like # LTO leads to many undefined reference like
@ -1033,7 +1039,7 @@ jobs:
run: env run: env
- name: Checkout - name: Checkout
uses: actions/checkout@v3 uses: actions/checkout@v4
- name: Set up Clang - name: Set up Clang
uses: egor-tensin/setup-clang@v1 uses: egor-tensin/setup-clang@v1
@ -1102,7 +1108,7 @@ jobs:
run: env run: env
- name: Checkout - name: Checkout
uses: actions/checkout@v3 uses: actions/checkout@v4
- name: Show Clang++ version before brew install llvm - name: Show Clang++ version before brew install llvm
run: clang++ --version run: clang++ --version

View File

@ -50,7 +50,7 @@ jobs:
runs-on: ${{ matrix.runs-on }} runs-on: ${{ matrix.runs-on }}
steps: steps:
- uses: actions/checkout@v3 - uses: actions/checkout@v4
- name: Setup Python 3.7 - name: Setup Python 3.7
uses: actions/setup-python@v4 uses: actions/setup-python@v4

View File

@ -26,7 +26,7 @@ jobs:
name: Format name: Format
runs-on: ubuntu-latest runs-on: ubuntu-latest
steps: steps:
- uses: actions/checkout@v3 - uses: actions/checkout@v4
- uses: actions/setup-python@v4 - uses: actions/setup-python@v4
with: with:
python-version: "3.x" python-version: "3.x"
@ -44,7 +44,7 @@ jobs:
runs-on: ubuntu-latest runs-on: ubuntu-latest
container: silkeh/clang:15-bullseye container: silkeh/clang:15-bullseye
steps: steps:
- uses: actions/checkout@v3 - uses: actions/checkout@v4
- name: Install requirements - name: Install requirements
run: apt-get update && apt-get install -y git python3-dev python3-pytest run: apt-get update && apt-get install -y git python3-dev python3-pytest

View File

@ -29,7 +29,7 @@ jobs:
runs-on: windows-latest runs-on: windows-latest
steps: steps:
- uses: actions/checkout@v3 - uses: actions/checkout@v4
- name: Setup 🐍 3.6 - name: Setup 🐍 3.6
uses: actions/setup-python@v4 uses: actions/setup-python@v4
@ -51,7 +51,7 @@ jobs:
runs-on: ubuntu-latest runs-on: ubuntu-latest
steps: steps:
- uses: actions/checkout@v3 - uses: actions/checkout@v4
- name: Setup 🐍 3.8 - name: Setup 🐍 3.8
uses: actions/setup-python@v4 uses: actions/setup-python@v4

View File

@ -25,7 +25,7 @@ jobs:
if: "contains(github.event.pull_request.labels.*.name, 'python dev')" if: "contains(github.event.pull_request.labels.*.name, 'python dev')"
steps: steps:
- uses: actions/checkout@v3 - uses: actions/checkout@v4
- name: Setup Python 3.12 - name: Setup Python 3.12
uses: actions/setup-python@v4 uses: actions/setup-python@v4

View File

@ -31,21 +31,21 @@ repos:
types_or: [c++, c, cuda] types_or: [c++, c, cuda]
# Black, the code formatter, natively supports pre-commit # Black, the code formatter, natively supports pre-commit
- repo: https://github.com/psf/black - repo: https://github.com/psf/black-pre-commit-mirror
rev: "23.7.0" # Keep in sync with blacken-docs rev: "23.7.0" # Keep in sync with blacken-docs
hooks: hooks:
- id: black - id: black
# Ruff, the Python auto-correcting linter written in Rust # Ruff, the Python auto-correcting linter written in Rust
- repo: https://github.com/astral-sh/ruff-pre-commit - repo: https://github.com/astral-sh/ruff-pre-commit
rev: v0.0.281 rev: v0.0.287
hooks: hooks:
- id: ruff - id: ruff
args: ["--fix", "--show-fixes"] args: ["--fix", "--show-fixes"]
# Check static types with mypy # Check static types with mypy
- repo: https://github.com/pre-commit/mirrors-mypy - repo: https://github.com/pre-commit/mirrors-mypy
rev: "v1.4.1" rev: "v1.5.1"
hooks: hooks:
- id: mypy - id: mypy
args: [] args: []
@ -85,7 +85,7 @@ repos:
# Also code format the docs # Also code format the docs
- repo: https://github.com/asottile/blacken-docs - repo: https://github.com/asottile/blacken-docs
rev: "1.15.0" rev: "1.16.0"
hooks: hooks:
- id: blacken-docs - id: blacken-docs
additional_dependencies: additional_dependencies:
@ -93,7 +93,7 @@ repos:
# Changes tabs to spaces # Changes tabs to spaces
- repo: https://github.com/Lucas-C/pre-commit-hooks - repo: https://github.com/Lucas-C/pre-commit-hooks
rev: "v1.5.1" rev: "v1.5.4"
hooks: hooks:
- id: remove-tabs - id: remove-tabs
exclude: (^docs/.*|\.patch)?$ exclude: (^docs/.*|\.patch)?$
@ -149,7 +149,7 @@ repos:
# PyLint has native support - not always usable, but works for us # PyLint has native support - not always usable, but works for us
- repo: https://github.com/PyCQA/pylint - repo: https://github.com/PyCQA/pylint
rev: "v3.0.0a6" rev: "v3.0.0a7"
hooks: hooks:
- id: pylint - id: pylint
files: ^pybind11 files: ^pybind11

View File

@ -1,3 +1,20 @@
# https://blog.readthedocs.com/migrate-configuration-v2/
version: 2
build:
os: ubuntu-22.04
apt_packages:
- librsvg2-bin
tools:
python: "3.11"
sphinx:
configuration: docs/conf.py
python: python:
version: 3 install:
requirements_file: docs/requirements.txt - requirements: docs/requirements.txt
formats:
- pdf

View File

@ -16,7 +16,7 @@ lifetime of objects managed by them. This can lead to issues when creating
bindings for functions that return a non-trivial type. Just by looking at the bindings for functions that return a non-trivial type. Just by looking at the
type information, it is not clear whether Python should take charge of the type information, it is not clear whether Python should take charge of the
returned value and eventually free its resources, or if this is handled on the returned value and eventually free its resources, or if this is handled on the
C++ side. For this reason, pybind11 provides a several *return value policy* C++ side. For this reason, pybind11 provides several *return value policy*
annotations that can be passed to the :func:`module_::def` and annotations that can be passed to the :func:`module_::def` and
:func:`class_::def` functions. The default policy is :func:`class_::def` functions. The default policy is
:enum:`return_value_policy::automatic`. :enum:`return_value_policy::automatic`.

View File

@ -70,7 +70,7 @@ def generate_dummy_code_boost(nclasses=10):
for codegen in [generate_dummy_code_pybind11, generate_dummy_code_boost]: for codegen in [generate_dummy_code_pybind11, generate_dummy_code_boost]:
print("{") print("{")
for i in range(0, 10): for i in range(10):
nclasses = 2**i nclasses = 2**i
with open("test.cpp", "w") as f: with open("test.cpp", "w") as f:
f.write(codegen(nclasses)) f.write(codegen(nclasses))

View File

@ -936,6 +936,10 @@ struct handle_type_name<float_> {
static constexpr auto name = const_name("float"); static constexpr auto name = const_name("float");
}; };
template <> template <>
struct handle_type_name<function> {
static constexpr auto name = const_name("Callable");
};
template <>
struct handle_type_name<none> { struct handle_type_name<none> {
static constexpr auto name = const_name("None"); static constexpr auto name = const_name("None");
}; };

View File

@ -35,8 +35,9 @@
/// further ABI-incompatible changes may be made before the ABI is officially /// further ABI-incompatible changes may be made before the ABI is officially
/// changed to the new version. /// changed to the new version.
#ifndef PYBIND11_INTERNALS_VERSION #ifndef PYBIND11_INTERNALS_VERSION
# if PY_VERSION_HEX >= 0x030C0000 # if PY_VERSION_HEX >= 0x030C0000 || defined(_MSC_VER)
// Version bump for Python 3.12+, before first 3.12 beta release. // Version bump for Python 3.12+, before first 3.12 beta release.
// Version bump for MSVC piggy-backed on PR #4779. See comments there.
# define PYBIND11_INTERNALS_VERSION 5 # define PYBIND11_INTERNALS_VERSION 5
# else # else
# define PYBIND11_INTERNALS_VERSION 4 # define PYBIND11_INTERNALS_VERSION 4
@ -292,9 +293,12 @@ struct type_info {
#endif #endif
/// On Linux/OSX, changes in __GXX_ABI_VERSION__ indicate ABI incompatibility. /// On Linux/OSX, changes in __GXX_ABI_VERSION__ indicate ABI incompatibility.
/// On MSVC, changes in _MSC_VER may indicate ABI incompatibility (#2898).
#ifndef PYBIND11_BUILD_ABI #ifndef PYBIND11_BUILD_ABI
# if defined(__GXX_ABI_VERSION) # if defined(__GXX_ABI_VERSION)
# define PYBIND11_BUILD_ABI "_cxxabi" PYBIND11_TOSTRING(__GXX_ABI_VERSION) # define PYBIND11_BUILD_ABI "_cxxabi" PYBIND11_TOSTRING(__GXX_ABI_VERSION)
# elif defined(_MSC_VER)
# define PYBIND11_BUILD_ABI "_mscver" PYBIND11_TOSTRING(_MSC_VER)
# else # else
# define PYBIND11_BUILD_ABI "" # define PYBIND11_BUILD_ABI ""
# endif # endif

View File

@ -53,6 +53,45 @@ PYBIND11_WARNING_DISABLE_MSVC(4127)
PYBIND11_NAMESPACE_BEGIN(detail) PYBIND11_NAMESPACE_BEGIN(detail)
inline std::string replace_newlines_and_squash(const char *text) {
const char *whitespaces = " \t\n\r\f\v";
std::string result(text);
bool previous_is_whitespace = false;
// Do not modify string representations
char first_char = result[0];
char last_char = result[result.size() - 1];
if (first_char == last_char && first_char == '\'') {
return result;
}
result.clear();
// Replace characters in whitespaces array with spaces and squash consecutive spaces
while (*text != '\0') {
if (std::strchr(whitespaces, *text)) {
if (!previous_is_whitespace) {
result += ' ';
previous_is_whitespace = true;
}
} else {
result += *text;
previous_is_whitespace = false;
}
++text;
}
// Strip leading and trailing whitespaces
const size_t str_begin = result.find_first_not_of(whitespaces);
if (str_begin == std::string::npos) {
return "";
}
const size_t str_end = result.find_last_not_of(whitespaces);
const size_t str_range = str_end - str_begin + 1;
return result.substr(str_begin, str_range);
}
// Apply all the extensions translators from a list // Apply all the extensions translators from a list
// Return true if one of the translators completed without raising an exception // Return true if one of the translators completed without raising an exception
// itself. Return of false indicates that if there are other translators // itself. Return of false indicates that if there are other translators
@ -425,7 +464,7 @@ protected:
// Write default value if available. // Write default value if available.
if (!is_starred && arg_index < rec->args.size() && rec->args[arg_index].descr) { if (!is_starred && arg_index < rec->args.size() && rec->args[arg_index].descr) {
signature += " = "; signature += " = ";
signature += rec->args[arg_index].descr; signature += detail::replace_newlines_and_squash(rec->args[arg_index].descr);
} }
// Separator for positional-only arguments (placed after the // Separator for positional-only arguments (placed after the
// argument, rather than before like * // argument, rather than before like *
@ -681,7 +720,7 @@ protected:
/* Iterator over the list of potentially admissible overloads */ /* Iterator over the list of potentially admissible overloads */
const function_record *overloads = reinterpret_cast<function_record *>( const function_record *overloads = reinterpret_cast<function_record *>(
PyCapsule_GetPointer(self, get_function_record_capsule_name())), PyCapsule_GetPointer(self, get_function_record_capsule_name())),
*it = overloads; *current_overload = overloads;
assert(overloads != nullptr); assert(overloads != nullptr);
/* Need to know how many arguments + keyword arguments there are to pick the right /* Need to know how many arguments + keyword arguments there are to pick the right
@ -719,9 +758,10 @@ protected:
std::vector<function_call> second_pass; std::vector<function_call> second_pass;
// However, if there are no overloads, we can just skip the no-convert pass entirely // However, if there are no overloads, we can just skip the no-convert pass entirely
const bool overloaded = it != nullptr && it->next != nullptr; const bool overloaded
= current_overload != nullptr && current_overload->next != nullptr;
for (; it != nullptr; it = it->next) { for (; current_overload != nullptr; current_overload = current_overload->next) {
/* For each overload: /* For each overload:
1. Copy all positional arguments we were given, also checking to make sure that 1. Copy all positional arguments we were given, also checking to make sure that
@ -742,7 +782,7 @@ protected:
a result other than PYBIND11_TRY_NEXT_OVERLOAD. a result other than PYBIND11_TRY_NEXT_OVERLOAD.
*/ */
const function_record &func = *it; const function_record &func = *current_overload;
size_t num_args = func.nargs; // Number of positional arguments that we need size_t num_args = func.nargs; // Number of positional arguments that we need
if (func.has_args) { if (func.has_args) {
--num_args; // (but don't count py::args --num_args; // (but don't count py::args
@ -980,10 +1020,10 @@ protected:
} }
if (result.ptr() != PYBIND11_TRY_NEXT_OVERLOAD) { if (result.ptr() != PYBIND11_TRY_NEXT_OVERLOAD) {
// The error reporting logic below expects 'it' to be valid, as it would be // The error reporting logic below expects 'current_overload' to be valid,
// if we'd encountered this failure in the first-pass loop. // as it would be if we'd encountered this failure in the first-pass loop.
if (!result) { if (!result) {
it = &call.func; current_overload = &call.func;
} }
break; break;
} }
@ -1130,7 +1170,8 @@ protected:
if (!result) { if (!result) {
std::string msg = "Unable to convert function return value to a " std::string msg = "Unable to convert function return value to a "
"Python type! The signature was\n\t"; "Python type! The signature was\n\t";
msg += it->signature; assert(current_overload != nullptr);
msg += current_overload->signature;
append_note_if_missing_header_is_suspected(msg); append_note_if_missing_header_is_suspected(msg);
// Attach additional error info to the exception if supported // Attach additional error info to the exception if supported
if (PyErr_Occurred()) { if (PyErr_Occurred()) {
@ -2235,7 +2276,7 @@ struct enum_base {
object type_name = type::handle_of(arg).attr("__name__"); object type_name = type::handle_of(arg).attr("__name__");
return pybind11::str("{}.{}").format(std::move(type_name), enum_name(arg)); return pybind11::str("{}.{}").format(std::move(type_name), enum_name(arg));
}, },
name("name"), name("__str__"),
is_method(m_base)); is_method(m_base));
if (options::show_enum_members_docstring()) { if (options::show_enum_members_docstring()) {
@ -2653,7 +2694,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)
@ -2670,7 +2711,9 @@ iterator make_iterator(Iterator first, Sentinel last, Extra &&...extra) {
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
@ -2686,7 +2729,9 @@ iterator make_key_iterator(Iterator first, Sentinel last, Extra &&...extra) {
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
@ -2702,7 +2747,9 @@ iterator make_value_iterator(Iterator first, Sentinel last, Extra &&...extra) {
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

View File

@ -94,5 +94,5 @@ line-length = 120
isort.known-first-party = ["env", "pybind11_cross_module_tests", "pybind11_tests"] isort.known-first-party = ["env", "pybind11_cross_module_tests", "pybind11_tests"]
[tool.ruff.per-file-ignores] [tool.ruff.per-file-ignores]
"tests/**" = ["EM", "N"] "tests/**" = ["EM", "N", "E721"]
"tests/test_call_policies.py" = ["PLC1901"] "tests/test_call_policies.py" = ["PLC1901"]

View File

@ -216,3 +216,10 @@ def test_custom_func():
def test_custom_func2(): def test_custom_func2():
assert m.custom_function2(3) == 27 assert m.custom_function2(3) == 27
assert m.roundtrip(m.custom_function2)(3) == 27 assert m.roundtrip(m.custom_function2)(3) == 27
def test_callback_docstring():
assert (
m.test_tuple_unpacking.__doc__.strip()
== "test_tuple_unpacking(arg0: Callable) -> object"
)

View File

@ -330,6 +330,23 @@ TEST_SUBMODULE(eigen_matrix, m) {
m.def("dense_c", [mat]() -> DenseMatrixC { return DenseMatrixC(mat); }); m.def("dense_c", [mat]() -> DenseMatrixC { return DenseMatrixC(mat); });
m.def("dense_copy_r", [](const DenseMatrixR &m) -> DenseMatrixR { return m; }); m.def("dense_copy_r", [](const DenseMatrixR &m) -> DenseMatrixR { return m; });
m.def("dense_copy_c", [](const DenseMatrixC &m) -> DenseMatrixC { return m; }); m.def("dense_copy_c", [](const DenseMatrixC &m) -> DenseMatrixC { return m; });
// test_defaults
bool have_numpy = true;
try {
py::module_::import("numpy");
} catch (const py::error_already_set &) {
have_numpy = false;
}
if (have_numpy) {
py::module_::import("numpy");
Eigen::Matrix<double, 3, 3> defaultMatrix = Eigen::Matrix3d::Identity();
m.def(
"defaults_mat", [](const Eigen::Matrix3d &) {}, py::arg("mat") = defaultMatrix);
Eigen::VectorXd defaultVector = Eigen::VectorXd::Ones(32);
m.def(
"defaults_vec", [](const Eigen::VectorXd &) {}, py::arg("vec") = defaultMatrix);
}
// test_sparse, test_sparse_signature // test_sparse, test_sparse_signature
m.def("sparse_r", [mat]() -> SparseMatrixR { m.def("sparse_r", [mat]() -> SparseMatrixR {
// NOLINTNEXTLINE(clang-analyzer-core.uninitialized.UndefReturn) // NOLINTNEXTLINE(clang-analyzer-core.uninitialized.UndefReturn)

View File

@ -716,6 +716,11 @@ def test_dense_signature(doc):
) )
def test_defaults(doc):
assert "\n" not in str(doc(m.defaults_mat))
assert "\n" not in str(doc(m.defaults_vec))
def test_named_arguments(): def test_named_arguments():
a = np.array([[1.0, 2], [3, 4], [5, 6]]) a = np.array([[1.0, 2], [3, 4], [5, 6]])
b = np.ones((2, 1)) b = np.ones((2, 1))

View File

@ -264,3 +264,8 @@ def test_docstring_signatures():
for attr in enum_type.__dict__.values(): for attr in enum_type.__dict__.values():
# Issue #2623/PR #2637: Add argument names to enum_ methods # Issue #2623/PR #2637: Add argument names to enum_ methods
assert "arg0" not in (attr.__doc__ or "") assert "arg0" not in (attr.__doc__ or "")
def test_str_signature():
for enum_type in [m.ScopedEnum, m.UnscopedEnum]:
assert enum_type.__str__.__doc__.startswith("__str__")

View File

@ -42,6 +42,50 @@ TEST_SUBMODULE(kwargs_and_defaults, m) {
m.def("kw_func_udl", kw_func, "x"_a, "y"_a = 300); m.def("kw_func_udl", kw_func, "x"_a, "y"_a = 300);
m.def("kw_func_udl_z", kw_func, "x"_a, "y"_a = 0); m.def("kw_func_udl_z", kw_func, "x"_a, "y"_a = 0);
// test line breaks in default argument representation
struct CustomRepr {
std::string repr_string;
explicit CustomRepr(const std::string &repr) : repr_string(repr) {}
std::string __repr__() const { return repr_string; }
};
py::class_<CustomRepr>(m, "CustomRepr")
.def(py::init<const std::string &>())
.def("__repr__", &CustomRepr::__repr__);
m.def(
"kw_lb_func0",
[](const CustomRepr &) {},
py::arg("custom") = CustomRepr(" array([[A, B], [C, D]]) "));
m.def(
"kw_lb_func1",
[](const CustomRepr &) {},
py::arg("custom") = CustomRepr(" array([[A, B],\n[C, D]]) "));
m.def(
"kw_lb_func2",
[](const CustomRepr &) {},
py::arg("custom") = CustomRepr("\v\n array([[A, B], [C, D]])"));
m.def(
"kw_lb_func3",
[](const CustomRepr &) {},
py::arg("custom") = CustomRepr("array([[A, B], [C, D]]) \f\n"));
m.def(
"kw_lb_func4",
[](const CustomRepr &) {},
py::arg("custom") = CustomRepr("array([[A, B],\n\f\n[C, D]])"));
m.def(
"kw_lb_func5",
[](const CustomRepr &) {},
py::arg("custom") = CustomRepr("array([[A, B],\r [C, D]])"));
m.def(
"kw_lb_func6", [](const CustomRepr &) {}, py::arg("custom") = CustomRepr(" \v\t "));
m.def(
"kw_lb_func7",
[](const std::string &) {},
py::arg("str_arg") = "First line.\n Second line.");
// test_args_and_kwargs // test_args_and_kwargs
m.def("args_function", [](py::args args) -> py::tuple { m.def("args_function", [](py::args args) -> py::tuple {
PYBIND11_WARNING_PUSH PYBIND11_WARNING_PUSH

View File

@ -23,6 +23,38 @@ def test_function_signatures(doc):
doc(m.KWClass.foo1) doc(m.KWClass.foo1)
== "foo1(self: m.kwargs_and_defaults.KWClass, x: int, y: float) -> None" == "foo1(self: m.kwargs_and_defaults.KWClass, x: int, y: float) -> None"
) )
assert (
doc(m.kw_lb_func0)
== "kw_lb_func0(custom: m.kwargs_and_defaults.CustomRepr = array([[A, B], [C, D]])) -> None"
)
assert (
doc(m.kw_lb_func1)
== "kw_lb_func1(custom: m.kwargs_and_defaults.CustomRepr = array([[A, B], [C, D]])) -> None"
)
assert (
doc(m.kw_lb_func2)
== "kw_lb_func2(custom: m.kwargs_and_defaults.CustomRepr = array([[A, B], [C, D]])) -> None"
)
assert (
doc(m.kw_lb_func3)
== "kw_lb_func3(custom: m.kwargs_and_defaults.CustomRepr = array([[A, B], [C, D]])) -> None"
)
assert (
doc(m.kw_lb_func4)
== "kw_lb_func4(custom: m.kwargs_and_defaults.CustomRepr = array([[A, B], [C, D]])) -> None"
)
assert (
doc(m.kw_lb_func5)
== "kw_lb_func5(custom: m.kwargs_and_defaults.CustomRepr = array([[A, B], [C, D]])) -> None"
)
assert (
doc(m.kw_lb_func6)
== "kw_lb_func6(custom: m.kwargs_and_defaults.CustomRepr = ) -> None"
)
assert (
doc(m.kw_lb_func7)
== "kw_lb_func7(str_arg: str = 'First line.\\n Second line.') -> None"
)
def test_named_arguments(): def test_named_arguments():

View File

@ -28,6 +28,13 @@ class NonZeroIterator {
public: public:
explicit NonZeroIterator(const T *ptr) : ptr_(ptr) {} explicit NonZeroIterator(const T *ptr) : ptr_(ptr) {}
// Make the iterator non-copyable and movable
NonZeroIterator(const NonZeroIterator &) = delete;
NonZeroIterator(NonZeroIterator &&) noexcept = default;
NonZeroIterator &operator=(const NonZeroIterator &) = delete;
NonZeroIterator &operator=(NonZeroIterator &&) noexcept = default;
const T &operator*() const { return *ptr_; } const T &operator*() const { return *ptr_; }
NonZeroIterator &operator++() { NonZeroIterator &operator++() {
++ptr_; ++ptr_;
@ -78,6 +85,7 @@ private:
int value_; int value_;
}; };
using NonCopyableIntPair = std::pair<NonCopyableInt, NonCopyableInt>; using NonCopyableIntPair = std::pair<NonCopyableInt, NonCopyableInt>;
PYBIND11_MAKE_OPAQUE(std::vector<NonCopyableInt>); PYBIND11_MAKE_OPAQUE(std::vector<NonCopyableInt>);
PYBIND11_MAKE_OPAQUE(std::vector<NonCopyableIntPair>); PYBIND11_MAKE_OPAQUE(std::vector<NonCopyableIntPair>);
@ -375,6 +383,17 @@ TEST_SUBMODULE(sequences_and_iterators, m) {
private: private:
std::vector<std::pair<int, int>> data_; std::vector<std::pair<int, int>> data_;
}; };
{
// #4383 : Make sure `py::make_*iterator` functions work with move-only iterators
using iterator_t = NonZeroIterator<std::pair<int, int>>;
static_assert(std::is_move_assignable<iterator_t>::value, "");
static_assert(std::is_move_constructible<iterator_t>::value, "");
static_assert(!std::is_copy_assignable<iterator_t>::value, "");
static_assert(!std::is_copy_constructible<iterator_t>::value, "");
}
py::class_<IntPairs>(m, "IntPairs") py::class_<IntPairs>(m, "IntPairs")
.def(py::init<std::vector<std::pair<int, int>>>()) .def(py::init<std::vector<std::pair<int, int>>>())
.def( .def(

View File

@ -209,7 +209,7 @@ def test_map_string_double_const():
def test_noncopyable_containers(): def test_noncopyable_containers():
# std::vector # std::vector
vnc = m.get_vnc(5) vnc = m.get_vnc(5)
for i in range(0, 5): for i in range(5):
assert vnc[i].value == i + 1 assert vnc[i].value == i + 1
for i, j in enumerate(vnc, start=1): for i, j in enumerate(vnc, start=1):
@ -217,7 +217,7 @@ def test_noncopyable_containers():
# std::deque # std::deque
dnc = m.get_dnc(5) dnc = m.get_dnc(5)
for i in range(0, 5): for i in range(5):
assert dnc[i].value == i + 1 assert dnc[i].value == i + 1
i = 1 i = 1
@ -252,7 +252,7 @@ def test_noncopyable_containers():
# nested std::map<std::vector> # nested std::map<std::vector>
nvnc = m.get_nvnc(5) nvnc = m.get_nvnc(5)
for i in range(1, 6): for i in range(1, 6):
for j in range(0, 5): for j in range(5):
assert nvnc[i][j].value == j + 1 assert nvnc[i][j].value == j + 1
# Note: maps do not have .values() # Note: maps do not have .values()