Skip to content

Commit 686783b

Browse files
committed
Merge branch 'master' into sh_merge_master
2 parents c6e71cf + a67d786 commit 686783b

File tree

10 files changed

+195
-28
lines changed

10 files changed

+195
-28
lines changed

.github/workflows/ci.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -210,7 +210,7 @@ jobs:
210210
- uses: actions/checkout@v4
211211

212212
- name: Setup Python ${{ matrix.python-version }} (deadsnakes)
213-
uses: deadsnakes/action@v3.0.1
213+
uses: deadsnakes/action@v3.1.0
214214
with:
215215
python-version: ${{ matrix.python-version }}
216216
debug: ${{ matrix.python-debug }}

CMakeLists.txt

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -296,7 +296,21 @@ if(PYBIND11_INSTALL)
296296

297297
# pkg-config support
298298
if(NOT prefix_for_pc_file)
299-
set(prefix_for_pc_file "${CMAKE_INSTALL_PREFIX}")
299+
if(IS_ABSOLUTE "${CMAKE_INSTALL_DATAROOTDIR}")
300+
set(prefix_for_pc_file "${CMAKE_INSTALL_PREFIX}")
301+
else()
302+
set(pc_datarootdir "${CMAKE_INSTALL_DATAROOTDIR}")
303+
if(CMAKE_VERSION VERSION_LESS 3.20)
304+
set(prefix_for_pc_file "\${pcfiledir}/..")
305+
while(pc_datarootdir)
306+
get_filename_component(pc_datarootdir "${pc_datarootdir}" DIRECTORY)
307+
string(APPEND prefix_for_pc_file "/..")
308+
endwhile()
309+
else()
310+
cmake_path(RELATIVE_PATH CMAKE_INSTALL_PREFIX BASE_DIRECTORY CMAKE_INSTALL_DATAROOTDIR
311+
OUTPUT_VARIABLE prefix_for_pc_file)
312+
endif()
313+
endif()
300314
endif()
301315
join_paths(includedir_for_pc_file "\${prefix}" "${CMAKE_INSTALL_INCLUDEDIR}")
302316
configure_file("${CMAKE_CURRENT_SOURCE_DIR}/tools/pybind11.pc.in"

include/pybind11/stl_bind.h

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -525,7 +525,7 @@ class_<Vector, holder_type> bind_vector(handle scope, std::string const &name, A
525525
[](const Vector &v) -> bool { return !v.empty(); },
526526
"Check whether the list is nonempty");
527527

528-
cl.def("__len__", &Vector::size);
528+
cl.def("__len__", [](const Vector &vec) { return vec.size(); });
529529

530530
#if 0
531531
// C++ style functions deprecated, leaving it here as an example
@@ -843,7 +843,8 @@ class_<Map, holder_type> bind_map(handle scope, const std::string &name, Args &&
843843
m.erase(it);
844844
});
845845

846-
cl.def("__len__", &Map::size);
846+
// Always use a lambda in case of `using` declaration
847+
cl.def("__len__", [](const Map &m) { return m.size(); });
847848

848849
return cl;
849850
}

noxfile.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -57,7 +57,7 @@ def tests_packaging(session: nox.Session) -> None:
5757
Run the packaging tests.
5858
"""
5959

60-
session.install("-r", "tests/requirements.txt", "--prefer-binary")
60+
session.install("-r", "tests/requirements.txt")
6161
session.run("pytest", "tests/extra_python_package", *session.posargs)
6262

6363

tests/requirements.txt

Lines changed: 14 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,15 @@
1-
build==0.8.0
2-
numpy==1.21.5; platform_python_implementation=="PyPy" and sys_platform=="linux" and python_version=="3.7"
3-
numpy==1.19.3; platform_python_implementation!="PyPy" and python_version=="3.6"
4-
numpy==1.21.5; platform_python_implementation!="PyPy" and python_version>="3.7" and python_version<"3.10"
5-
numpy==1.22.2; platform_python_implementation!="PyPy" and python_version>="3.10" and python_version<"3.11"
6-
pytest==7.0.0; platform_python_implementation!="PyPy" and python_version=="3.6"
7-
pytest==7.2.0; platform_python_implementation!="PyPy" and python_version>="3.7"
1+
--only-binary=:all:
2+
build~=0.9; python_version=="3.6"
3+
build~=1.0; python_version>="3.7"
4+
numpy~=1.20.0; python_version=="3.7" and platform_python_implementation=="PyPy"
5+
numpy~=1.23.0; python_version=="3.8" and platform_python_implementation=="PyPy"
6+
numpy~=1.25.0; python_version=="3.9" and platform_python_implementation=='PyPy'
7+
numpy~=1.19.3; platform_python_implementation!="PyPy" and python_version=="3.6"
8+
numpy~=1.21.5; platform_python_implementation!="PyPy" and python_version>="3.7" and python_version<"3.10"
9+
numpy~=1.22.2; platform_python_implementation!="PyPy" and python_version=="3.10"
10+
numpy~=1.26.0; platform_python_implementation!="PyPy" and python_version>="3.11"
11+
pytest~=7.0
812
pytest-timeout
9-
scipy==1.5.4; platform_python_implementation!="PyPy" and python_version<"3.10"
10-
scipy==1.10.0; platform_python_implementation!="PyPy" and python_version=="3.10"
13+
scipy~=1.5.4; platform_python_implementation!="PyPy" and python_version<"3.10"
14+
scipy~=1.8.0; platform_python_implementation!="PyPy" and python_version=="3.10"
15+
scipy~=1.11.1; platform_python_implementation!="PyPy" and python_version>="3.11"

tests/test_stl_binders.cpp

Lines changed: 70 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@
1515
#include <deque>
1616
#include <map>
1717
#include <unordered_map>
18+
#include <vector>
1819

1920
class El {
2021
public:
@@ -83,6 +84,71 @@ struct RecursiveMap : std::map<int, RecursiveMap> {
8384
using Parent::Parent;
8485
};
8586

87+
class UserVectorLike : private std::vector<int> {
88+
public:
89+
// This is only a subset of the member functions, as needed at the time.
90+
using Base = std::vector<int>;
91+
using typename Base::const_iterator;
92+
using typename Base::difference_type;
93+
using typename Base::iterator;
94+
using typename Base::size_type;
95+
using typename Base::value_type;
96+
97+
using Base::at;
98+
using Base::back;
99+
using Base::Base;
100+
using Base::begin;
101+
using Base::cbegin;
102+
using Base::cend;
103+
using Base::clear;
104+
using Base::empty;
105+
using Base::end;
106+
using Base::erase;
107+
using Base::front;
108+
using Base::insert;
109+
using Base::pop_back;
110+
using Base::push_back;
111+
using Base::reserve;
112+
using Base::shrink_to_fit;
113+
using Base::swap;
114+
using Base::operator[];
115+
using Base::capacity;
116+
using Base::size;
117+
};
118+
119+
bool operator==(UserVectorLike const &, UserVectorLike const &) { return true; }
120+
bool operator!=(UserVectorLike const &, UserVectorLike const &) { return false; }
121+
122+
class UserMapLike : private std::map<int, int> {
123+
public:
124+
// This is only a subset of the member functions, as needed at the time.
125+
using Base = std::map<int, int>;
126+
using typename Base::const_iterator;
127+
using typename Base::iterator;
128+
using typename Base::key_type;
129+
using typename Base::mapped_type;
130+
using typename Base::size_type;
131+
using typename Base::value_type;
132+
133+
using Base::at;
134+
using Base::Base;
135+
using Base::begin;
136+
using Base::cbegin;
137+
using Base::cend;
138+
using Base::clear;
139+
using Base::emplace;
140+
using Base::emplace_hint;
141+
using Base::empty;
142+
using Base::end;
143+
using Base::erase;
144+
using Base::find;
145+
using Base::insert;
146+
using Base::max_size;
147+
using Base::swap;
148+
using Base::operator[];
149+
using Base::size;
150+
};
151+
86152
/*
87153
* Pybind11 does not catch more complicated recursion schemes, such as mutual
88154
* recursion.
@@ -173,6 +239,10 @@ TEST_SUBMODULE(stl_binders, m) {
173239
py::bind_map<MutuallyRecursiveContainerPairMV>(m, "MutuallyRecursiveContainerPairMV");
174240
py::bind_vector<MutuallyRecursiveContainerPairVM>(m, "MutuallyRecursiveContainerPairVM");
175241

242+
// Bind with private inheritance + `using` directives.
243+
py::bind_vector<UserVectorLike>(m, "UserVectorLike");
244+
py::bind_map<UserMapLike>(m, "UserMapLike");
245+
176246
// The rest depends on numpy:
177247
try {
178248
py::module_::import("numpy");

tests/test_stl_binders.py

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -353,3 +353,17 @@ def test_recursive_map():
353353
recursive_map[100][101] = m.RecursiveMap()
354354
recursive_map[100][102] = m.RecursiveMap()
355355
assert list(recursive_map[100].keys()) == [101, 102]
356+
357+
358+
def test_user_vector_like():
359+
vec = m.UserVectorLike()
360+
vec.append(2)
361+
assert vec[0] == 2
362+
assert len(vec) == 1
363+
364+
365+
def test_user_like_map():
366+
map = m.UserMapLike()
367+
map[33] = 44
368+
assert map[33] == 44
369+
assert len(map) == 1

tools/make_changelog.py

Lines changed: 27 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
#!/usr/bin/env python3
2+
from __future__ import annotations
23

34
import re
45

@@ -29,21 +30,46 @@
2930
)
3031
issues = (issue for page in issues_pages for issue in page)
3132
missing = []
33+
cats_descr = {
34+
"feat": "New Features",
35+
"fix": "Bug fixes",
36+
"fix(types)": "",
37+
"fix(cmake)": "",
38+
"docs": "Documentation",
39+
"tests": "Tests",
40+
"ci": "CI",
41+
"chore": "Other",
42+
"unknown": "Uncategorised",
43+
}
44+
cats: dict[str, list[str]] = {c: [] for c in cats_descr}
3245

3346
for issue in issues:
3447
changelog = ENTRY.findall(issue.body or "")
3548
if not changelog or not changelog[0]:
3649
missing.append(issue)
3750
else:
3851
(msg,) = changelog
52+
if msg.startswith("- "):
53+
msg = msg[2:]
3954
if not msg.startswith("* "):
4055
msg = "* " + msg
4156
if not msg.endswith("."):
4257
msg += "."
4358

4459
msg += f"\n `#{issue.number} <{issue.html_url}>`_"
60+
for cat in cats:
61+
if issue.title.lower().startswith(f"{cat}:"):
62+
cats[cat].append(msg)
63+
break
64+
else:
65+
cats["unknown"].append(msg)
4566

46-
print(Syntax(msg, "rst", theme="ansi_light", word_wrap=True))
67+
for cat, msgs in cats.items():
68+
if msgs:
69+
desc = cats_descr[cat]
70+
print(f"[bold]{desc}:\n" if desc else "")
71+
for msg in msgs:
72+
print(Syntax(msg, "rst", theme="ansi_light", word_wrap=True))
4773
print()
4874

4975
if missing:

tools/pybind11Common.cmake

Lines changed: 21 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -218,8 +218,15 @@ if(NOT _pybind11_nopython)
218218

219219
execute_process(
220220
COMMAND
221-
${${_Python}_EXECUTABLE} -c
222-
"from pkg_resources import get_distribution; print(get_distribution('${PYPI_NAME}').version)"
221+
${${_Python}_EXECUTABLE} -c "
222+
try:
223+
from importlib.metadata import version
224+
except ImportError:
225+
from pkg_resources import get_distribution
226+
def version(s):
227+
return get_distribution(s).version
228+
print(version('${PYPI_NAME}'))
229+
"
223230
RESULT_VARIABLE RESULT_PRESENT
224231
OUTPUT_VARIABLE PKG_VERSION
225232
ERROR_QUIET)
@@ -300,21 +307,24 @@ function(_pybind11_generate_lto target prefer_thin_lto)
300307
set(cxx_append ";-fno-fat-lto-objects")
301308
endif()
302309

303-
if(CMAKE_SYSTEM_PROCESSOR MATCHES "ppc64le" OR CMAKE_SYSTEM_PROCESSOR MATCHES "mips64")
304-
set(NO_FLTO_ARCH TRUE)
310+
if(prefer_thin_lto)
311+
set(thin "=thin")
305312
else()
306-
set(NO_FLTO_ARCH FALSE)
313+
set(thin "")
307314
endif()
308315

309-
if(CMAKE_CXX_COMPILER_ID MATCHES "Clang"
310-
AND prefer_thin_lto
311-
AND NOT NO_FLTO_ARCH)
316+
if(CMAKE_SYSTEM_PROCESSOR MATCHES "ppc64le" OR CMAKE_SYSTEM_PROCESSOR MATCHES "mips64")
317+
# Do nothing
318+
elseif(CMAKE_SYSTEM_PROCESSOR MATCHES emscripten)
319+
# This compile is very costly when cross-compiling, so set this without checking
320+
set(PYBIND11_LTO_CXX_FLAGS "-flto${thin}${cxx_append}")
321+
set(PYBIND11_LTO_LINKER_FLAGS "-flto${thin}${linker_append}")
322+
elseif(CMAKE_CXX_COMPILER_ID MATCHES "Clang")
312323
_pybind11_return_if_cxx_and_linker_flags_work(
313-
HAS_FLTO_THIN "-flto=thin${cxx_append}" "-flto=thin${linker_append}"
324+
HAS_FLTO_THIN "-flto${thin}${cxx_append}" "-flto=${thin}${linker_append}"
314325
PYBIND11_LTO_CXX_FLAGS PYBIND11_LTO_LINKER_FLAGS)
315326
endif()
316-
317-
if(NOT HAS_FLTO_THIN AND NOT NO_FLTO_ARCH)
327+
if(NOT HAS_FLTO_THIN)
318328
_pybind11_return_if_cxx_and_linker_flags_work(
319329
HAS_FLTO "-flto${cxx_append}" "-flto${linker_append}" PYBIND11_LTO_CXX_FLAGS
320330
PYBIND11_LTO_LINKER_FLAGS)

tools/pybind11NewTools.cmake

Lines changed: 29 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -39,12 +39,23 @@ if(NOT Python_FOUND AND NOT Python3_FOUND)
3939
set(_pybind11_dev_component Development.Module OPTIONAL_COMPONENTS Development.Embed)
4040
endif()
4141

42+
# Callers need to be able to access Python_EXECUTABLE
43+
set(_pybind11_global_keyword "")
44+
if(NOT is_config AND NOT DEFINED Python_ARTIFACTS_INTERACTIVE)
45+
set(Python_ARTIFACTS_INTERACTIVE TRUE)
46+
if(NOT CMAKE_VERSION VERSION_LESS 3.24)
47+
set(_pybind11_global_keyword "GLOBAL")
48+
endif()
49+
endif()
50+
4251
find_package(Python 3.6 REQUIRED COMPONENTS Interpreter ${_pybind11_dev_component}
43-
${_pybind11_quiet})
52+
${_pybind11_quiet} ${_pybind11_global_keyword})
4453

4554
# If we are in submodule mode, export the Python targets to global targets.
4655
# If this behavior is not desired, FindPython _before_ pybind11.
47-
if(NOT is_config)
56+
if(NOT is_config
57+
AND NOT Python_ARTIFACTS_INTERACTIVE
58+
AND _pybind11_global_keyword STREQUAL "")
4859
if(TARGET Python::Python)
4960
set_property(TARGET Python::Python PROPERTY IMPORTED_GLOBAL TRUE)
5061
endif()
@@ -53,6 +64,22 @@ if(NOT Python_FOUND AND NOT Python3_FOUND)
5364
set_property(TARGET Python::Module PROPERTY IMPORTED_GLOBAL TRUE)
5465
endif()
5566
endif()
67+
68+
# Explicitly export version for callers (including our own functions)
69+
if(NOT is_config AND Python_ARTIFACTS_INTERACTIVE)
70+
set(Python_VERSION
71+
"${Python_VERSION}"
72+
CACHE INTERNAL "")
73+
set(Python_VERSION_MAJOR
74+
"${Python_VERSION_MAJOR}"
75+
CACHE INTERNAL "")
76+
set(Python_VERSION_MINOR
77+
"${Python_VERSION_MINOR}"
78+
CACHE INTERNAL "")
79+
set(Python_VERSION_PATCH
80+
"${Python_VERSION_PATCH}"
81+
CACHE INTERNAL "")
82+
endif()
5683
endif()
5784

5885
if(Python_FOUND)

0 commit comments

Comments
 (0)