From 9e7ada73b4dd613df95e49cec991c5174709fad3 Mon Sep 17 00:00:00 2001 From: Henry Schreiner Date: Thu, 10 Feb 2022 22:37:01 -0500 Subject: [PATCH 1/8] chore: drop Python 3.5 support --- .github/CONTRIBUTING.md | 7 +++---- .pre-commit-config.yaml | 5 ++--- README.rst | 6 +++--- docs/advanced/cast/overview.rst | 3 +-- docs/advanced/functions.rst | 5 ++--- docs/advanced/pycpp/numpy.rst | 2 +- docs/compiling.rst | 9 ++++----- docs/conf.py | 4 ++-- include/pybind11/cast.h | 2 +- include/pybind11/chrono.h | 11 ----------- include/pybind11/detail/common.h | 13 ++----------- include/pybind11/detail/type_caster_base.h | 11 +++++------ include/pybind11/pybind11.h | 2 +- include/pybind11/stl/filesystem.h | 3 +-- noxfile.py | 2 +- pybind11/__init__.py | 4 ++-- pybind11/setup_helpers.py | 4 ++-- setup.cfg | 3 +-- setup.py | 20 +++++++------------- tests/extra_python_package/test_files.py | 14 +++++++------- tests/test_builtin_casters.py | 2 +- tests/test_callbacks.py | 2 +- tests/test_chrono.py | 2 +- tests/test_cmake_build/test.py | 2 +- tests/test_eigen.py | 6 ++---- tests/test_exceptions.py | 2 +- tests/test_numpy_dtypes.py | 4 ++-- tests/test_opaque_types.py | 2 +- tests/test_sequences_and_iterators.py | 21 ++++++--------------- tests/test_smart_ptr.py | 12 +++++------- tools/FindPythonLibsNew.cmake | 2 +- tools/libsize.py | 4 ++-- tools/pybind11Config.cmake.in | 2 +- tools/pybind11NewTools.cmake | 2 +- tools/pybind11Tools.cmake | 2 +- tools/setup_global.py.in | 3 +-- tools/setup_main.py.in | 3 +-- 37 files changed, 77 insertions(+), 126 deletions(-) diff --git a/.github/CONTRIBUTING.md b/.github/CONTRIBUTING.md index e8294c83c3..a346ae63bf 100644 --- a/.github/CONTRIBUTING.md +++ b/.github/CONTRIBUTING.md @@ -93,11 +93,10 @@ cmake --build build -j4 Tips: -* You can use `virtualenv` (from PyPI) instead of `venv` (which is Python 3 - only). +* You can use `virtualenv` (faster, from PyPI) instead of `venv` * You can select any name for your environment folder; if it contains "env" it will be ignored by git. -* If you don’t have CMake 3.14+, just add “cmake” to the pip install command. +* If you don’t have CMake 3.14+, just add "cmake" to the pip install command. * You can use `-DPYBIND11_FINDPYTHON=ON` to use FindPython on CMake 3.12+ * In classic mode, you may need to set `-DPYTHON_EXECUTABLE=/path/to/python`. FindPython uses `-DPython_ROOT_DIR=/path/to` or @@ -257,7 +256,7 @@ The report is sent to stderr; you can pipe it into a file if you wish. ### Build recipes This builds with the Intel compiler (assuming it is in your path, along with a -recent CMake and Python 3): +recent CMake and Python): ```bash python3 -m venv venv diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 6d44d5e76c..03d299c891 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -35,7 +35,7 @@ repos: rev: v2.31.0 hooks: - id: pyupgrade - args: [--py3-plus] + args: [--py36-plus] # Nicely sort includes - repo: https://github.com/PyCQA/isort @@ -76,8 +76,7 @@ repos: - id: python-check-blanket-noqa - id: python-check-blanket-type-ignore - id: python-no-log-warn - # Python 3.6 - # - id: python-use-type-annotations + - id: python-use-type-annotations - id: rst-backticks - id: rst-directive-colons - id: rst-inline-touching-normal diff --git a/README.rst b/README.rst index 6398db4f0b..9365df0296 100644 --- a/README.rst +++ b/README.rst @@ -34,7 +34,7 @@ dependency. Think of this library as a tiny self-contained version of Boost.Python with everything stripped away that isn’t relevant for binding generation. Without comments, the core header files only require ~4K -lines of code and depend on Python (3.5+, or PyPy) and the C++ +lines of code and depend on Python (3.6+, or PyPy) and the C++ standard library. This compact implementation was possible thanks to some of the new C++11 language features (specifically: tuples, lambda functions and variadic templates). Since its creation, this library has @@ -78,8 +78,8 @@ Goodies In addition to the core functionality, pybind11 provides some extra goodies: -- Python 3.5+, and PyPy3 7.3 are supported with an implementation-agnostic - interface (pybind11 2.9 was the last version to support Python 2). +- Python 3.6+, and PyPy3 7.3 are supported with an implementation-agnostic + interface (pybind11 2.9 was the last version to support Python 2 and 3.5). - It is possible to bind C++11 lambda functions with captured variables. The lambda capture data is stored inside the resulting diff --git a/docs/advanced/cast/overview.rst b/docs/advanced/cast/overview.rst index 6a834a3e51..011bd4c7a3 100644 --- a/docs/advanced/cast/overview.rst +++ b/docs/advanced/cast/overview.rst @@ -167,5 +167,4 @@ as arguments and return values, refer to the section on binding :ref:`classes`. +------------------------------------+---------------------------+-----------------------------------+ .. [#] ``std::filesystem::path`` is converted to ``pathlib.Path`` and - ``os.PathLike`` is converted to ``std::filesystem::path``, but this requires - Python 3.6 (for ``__fspath__`` support). + ``os.PathLike`` is converted to ``std::filesystem::path``. diff --git a/docs/advanced/functions.rst b/docs/advanced/functions.rst index bf5b5fa00d..9b82060a1e 100644 --- a/docs/advanced/functions.rst +++ b/docs/advanced/functions.rst @@ -372,7 +372,7 @@ like so: Keyword-only arguments ====================== -Python 3 introduced keyword-only arguments by specifying an unnamed ``*`` +Python implements keyword-only arguments by specifying an unnamed ``*`` argument in a function definition: .. code-block:: python @@ -395,8 +395,7 @@ argument annotations when registering the function: m.def("f", [](int a, int b) { /* ... */ }, py::arg("a"), py::kw_only(), py::arg("b")); -Note that you currently cannot combine this with a ``py::args`` argument. This -feature does *not* require Python 3 to work. +Note that you currently cannot combine this with a ``py::args`` argument. .. versionadded:: 2.6 diff --git a/docs/advanced/pycpp/numpy.rst b/docs/advanced/pycpp/numpy.rst index dbc48440a6..8ad3410045 100644 --- a/docs/advanced/pycpp/numpy.rst +++ b/docs/advanced/pycpp/numpy.rst @@ -395,7 +395,7 @@ uses of ``py::array``: Ellipsis ======== -Python 3 provides a convenient ``...`` ellipsis notation that is often used to +Python provides a convenient ``...`` ellipsis notation that is often used to slice multidimensional arrays. For instance, the following snippet extracts the middle dimensions of a tensor with the first and last index set to zero. diff --git a/docs/compiling.rst b/docs/compiling.rst index f7303fd23f..4ae9234e15 100644 --- a/docs/compiling.rst +++ b/docs/compiling.rst @@ -417,10 +417,10 @@ existing targets instead: .. code-block:: cmake - cmake_minimum_required(VERSION 3.15...3.19) + cmake_minimum_required(VERSION 3.15...3.22) project(example LANGUAGES CXX) - find_package(Python COMPONENTS Interpreter Development REQUIRED) + find_package(Python 3.6 COMPONENTS Interpreter Development REQUIRED) find_package(pybind11 CONFIG REQUIRED) # or add_subdirectory(pybind11) @@ -433,9 +433,8 @@ algorithms from the CMake invocation, with ``-DPYBIND11_FINDPYTHON=ON``. .. warning:: - If you use FindPython2 and FindPython3 to dual-target Python, use the - individual targets listed below, and avoid targets that directly include - Python parts. + If you use FindPython to multi-target Python versions, use the individual + targets listed below, and avoid targets that directly include Python parts. There are `many ways to hint or force a discovery of a specific Python installation `_), diff --git a/docs/conf.py b/docs/conf.py index 99f3be349c..00796fbdbe 100644 --- a/docs/conf.py +++ b/docs/conf.py @@ -344,9 +344,9 @@ def generate_doxygen_xml(app): subprocess.call(["doxygen", "--version"]) retcode = subprocess.call(["doxygen"], cwd=app.confdir) if retcode < 0: - sys.stderr.write("doxygen error code: {}\n".format(-retcode)) + sys.stderr.write(f"doxygen error code: {-retcode}\n") except OSError as e: - sys.stderr.write("doxygen execution failed: {}\n".format(e)) + sys.stderr.write(f"doxygen execution failed: {e}\n") def prepare(app): diff --git a/include/pybind11/cast.h b/include/pybind11/cast.h index b12559ac8b..553d7616c1 100644 --- a/include/pybind11/cast.h +++ b/include/pybind11/cast.h @@ -1585,7 +1585,7 @@ unpacking_collector collect_arguments(Args &&...args) { template template object object_api::operator()(Args &&...args) const { -#if !defined(NDEBUG) && PY_VERSION_HEX >= 0x03060000 +#ifndef NDEBUG if (!PyGILState_Check()) { pybind11_fail("pybind11::object_api<>::operator() PyGILState_Check() failure."); } diff --git a/include/pybind11/chrono.h b/include/pybind11/chrono.h index ad5e97b024..167ea0e3d1 100644 --- a/include/pybind11/chrono.h +++ b/include/pybind11/chrono.h @@ -18,17 +18,6 @@ #include #include -// Backport the PyDateTime_DELTA functions from Python3.3 if required -#ifndef PyDateTime_DELTA_GET_DAYS -# define PyDateTime_DELTA_GET_DAYS(o) (((PyDateTime_Delta *) o)->days) -#endif -#ifndef PyDateTime_DELTA_GET_SECONDS -# define PyDateTime_DELTA_GET_SECONDS(o) (((PyDateTime_Delta *) o)->seconds) -#endif -#ifndef PyDateTime_DELTA_GET_MICROSECONDS -# define PyDateTime_DELTA_GET_MICROSECONDS(o) (((PyDateTime_Delta *) o)->microseconds) -#endif - PYBIND11_NAMESPACE_BEGIN(PYBIND11_NAMESPACE) PYBIND11_NAMESPACE_BEGIN(detail) diff --git a/include/pybind11/detail/common.h b/include/pybind11/detail/common.h index a5d98d71f8..66ad266d47 100644 --- a/include/pybind11/detail/common.h +++ b/include/pybind11/detail/common.h @@ -211,8 +211,8 @@ #endif #include -#if PY_VERSION_HEX < 0x030500f0 -# error "PYTHON 2 IS NO LONGER SUPPORTED. pybind11 v2.9 was the last to support Python 2." +#if PY_VERSION_HEX < 0x03060000 +# error "PYTHON < 3.6 IS UNSUPPORTED. pybind11 v2.9 was the last to support Python 2 and 3.5." #endif #include #include @@ -301,15 +301,6 @@ extern "C" PYBIND11_MAYBE_UNUSED PYBIND11_EXPORT PyObject *PyInit_##name(); \ extern "C" PYBIND11_EXPORT PyObject *PyInit_##name() -#if PY_VERSION_HEX >= 0x03050000 && PY_VERSION_HEX < 0x03050200 -extern "C" { -struct _Py_atomic_address { - void *value; -}; -PyAPI_DATA(_Py_atomic_address) _PyThreadState_Current; -} -#endif - #define PYBIND11_TRY_NEXT_OVERLOAD ((PyObject *) 1) // special failure return code #define PYBIND11_STRINGIFY(x) #x #define PYBIND11_TOSTRING(x) PYBIND11_STRINGIFY(x) diff --git a/include/pybind11/detail/type_caster_base.h b/include/pybind11/detail/type_caster_base.h index 226f7a994f..ff7d7cf8c2 100644 --- a/include/pybind11/detail/type_caster_base.h +++ b/include/pybind11/detail/type_caster_base.h @@ -439,10 +439,11 @@ PYBIND11_NOINLINE void instance::allocate_layout() { // instance_registered) // Allocate space for flags, values, and holders, and initialize it to 0 (flags and values, - // in particular, need to be 0). Use Python's memory allocation functions: in Python 3.6 - // they default to using pymalloc, which is designed to be efficient for small allocations - // like the one we're doing here; in earlier versions (and for larger allocations) they are - // just wrappers around malloc. + // in particular, need to be 0). Use Python's memory allocation + // functions: Python is using pymalloc, which is designed to be + // efficient for small allocations like the one we're doing here; + // for larger allocations they are just wrappers around malloc. + // TODO: is this still true for pure Python 3.6? nonsimple.values_and_holders = (void **) PyMem_Calloc(space, sizeof(void *)); if (!nonsimple.values_and_holders) { throw std::bad_alloc(); @@ -538,8 +539,6 @@ PYBIND11_NOINLINE handle get_object_handle(const void *ptr, const detail::type_i inline PyThreadState *get_thread_state_unchecked() { #if defined(PYPY_VERSION) return PyThreadState_GET(); -#elif PY_VERSION_HEX < 0x03050200 - return (PyThreadState *) _PyThreadState_Current.value; #else return _PyThreadState_UncheckedGet(); #endif diff --git a/include/pybind11/pybind11.h b/include/pybind11/pybind11.h index 7b7a1a05dd..840cb573f4 100644 --- a/include/pybind11/pybind11.h +++ b/include/pybind11/pybind11.h @@ -1242,7 +1242,7 @@ class module_ : public object { } // TODO: Should be reinterpret_steal for Python 3, but Python also steals it again when // returned from PyInit_... - // For Python 2, reinterpret_borrow is correct. + // For Python 2, reinterpret_borrow was correct. return reinterpret_borrow(m); } }; diff --git a/include/pybind11/stl/filesystem.h b/include/pybind11/stl/filesystem.h index 747992f51c..93727424c9 100644 --- a/include/pybind11/stl/filesystem.h +++ b/include/pybind11/stl/filesystem.h @@ -13,8 +13,7 @@ #include #ifdef __has_include -# if defined(PYBIND11_CPP17) && __has_include() && \ - PY_VERSION_HEX >= 0x03060000 +# if defined(PYBIND11_CPP17) && __has_include() # include # define PYBIND11_HAS_FILESYSTEM 1 # endif diff --git a/noxfile.py b/noxfile.py index cfa84826d2..4b6adcfbd7 100644 --- a/noxfile.py +++ b/noxfile.py @@ -2,7 +2,7 @@ nox.options.sessions = ["lint", "tests", "tests_packaging"] -PYTHON_VERSIONS = ["3.5", "3.6", "3.7", "3.8", "3.9", "3.10", "3.11"] +PYTHON_VERSIONS = ["3.6", "3.7", "3.8", "3.9", "3.10", "3.11"] @nox.session(reuse_venv=True) diff --git a/pybind11/__init__.py b/pybind11/__init__.py index faf3892cb6..a1be969819 100644 --- a/pybind11/__init__.py +++ b/pybind11/__init__.py @@ -1,7 +1,7 @@ import sys -if sys.version_info < (3, 5): - msg = "pybind11 does not support Python < 3.5. 2.9 was the last release supporting older Pythons." +if sys.version_info < (3, 6): + msg = "pybind11 does not support Python < 3.6. 2.9 was the last release supporting Python 2.7 and 3.5." raise ImportError(msg) diff --git a/pybind11/setup_helpers.py b/pybind11/setup_helpers.py index 9cbcaa9224..8f121eaee7 100644 --- a/pybind11/setup_helpers.py +++ b/pybind11/setup_helpers.py @@ -200,7 +200,7 @@ def cxx_std(self, level: int) -> None: current_macos = tuple(int(x) for x in platform.mac_ver()[0].split(".")[:2]) desired_macos = (10, 9) if level < 17 else (10, 14) macos_string = ".".join(str(x) for x in min(current_macos, desired_macos)) - macosx_min = "-mmacosx-version-min={}".format(macos_string) + macosx_min = f"-mmacosx-version-min={macos_string}" cflags += [macosx_min] ldflags += [macosx_min] @@ -419,7 +419,7 @@ def __init__( self.default = default self.max = max self.needs_recompile = needs_recompile - self._old = [] # type: List[CCompilerMethod] + self._old: List[CCompilerMethod] = [] def function(self) -> CCompilerMethod: """ diff --git a/setup.cfg b/setup.cfg index bd2357e9e8..0e7b16e0f5 100644 --- a/setup.cfg +++ b/setup.cfg @@ -14,7 +14,6 @@ classifiers = Topic :: Utilities Programming Language :: C++ Programming Language :: Python :: 3 :: Only - Programming Language :: Python :: 3.5 Programming Language :: Python :: 3.6 Programming Language :: Python :: 3.7 Programming Language :: Python :: 3.8 @@ -38,7 +37,7 @@ project_urls = Chat = https://gitter.im/pybind/Lobby [options] -python_requires = >=3.5 +python_requires = >=3.6 zip_safe = False diff --git a/setup.py b/setup.py index 5b46e0c8d8..a149755bf6 100644 --- a/setup.py +++ b/setup.py @@ -1,4 +1,4 @@ -#!/usr/bin/env python +#!/usr/bin/env python3 # Setup script for PyPI; use CMakeFile.txt to build extension modules @@ -41,12 +41,10 @@ def build_expected_version_hex(matches: Dict[str, str]) -> str: serial = int(level_serial[len(level) :]) break if serial is None: - msg = 'Invalid PYBIND11_VERSION_PATCH: "{}"'.format(patch_level_serial) + msg = f'Invalid PYBIND11_VERSION_PATCH: "{patch_level_serial}"' raise RuntimeError(msg) - version_hex_str = "{:02x}{:02x}{:02x}{}{:x}".format( - major, minor, patch, level[:1], serial - ) - return "0x{}".format(version_hex_str.upper()) + version_hex_str = f"{major:02x}{minor:02x}{patch:02x}{level[:1]}{serial:x}" + return f"0x{version_hex_str.upper()}" # PYBIND11_GLOBAL_SDIST will build a different sdist, with the python-headers @@ -66,7 +64,7 @@ def build_expected_version_hex(matches: Dict[str, str]) -> str: # Read the listed version -loc = {} # type: Dict[str, str] +loc: Dict[str, str] = {} code = compile(VERSION_FILE.read_text(encoding="utf-8"), "pybind11/_version.py", "exec") exec(code, loc) version = loc["__version__"] @@ -75,17 +73,13 @@ def build_expected_version_hex(matches: Dict[str, str]) -> str: matches = dict(VERSION_REGEX.findall(COMMON_FILE.read_text(encoding="utf8"))) cpp_version = "{MAJOR}.{MINOR}.{PATCH}".format(**matches) if version != cpp_version: - msg = "Python version {} does not match C++ version {}!".format( - version, cpp_version - ) + msg = f"Python version {version} does not match C++ version {cpp_version}!" raise RuntimeError(msg) version_hex = matches.get("HEX", "MISSING") exp_version_hex = build_expected_version_hex(matches) if version_hex != exp_version_hex: - msg = "PYBIND11_VERSION_HEX {} does not match expected value {}!".format( - version_hex, exp_version_hex - ) + msg = f"PYBIND11_VERSION_HEX {version_hex} does not match expected value {exp_version_hex}!" raise RuntimeError(msg) diff --git a/tests/extra_python_package/test_files.py b/tests/extra_python_package/test_files.py index 70dcfb987a..2660d9d2a2 100644 --- a/tests/extra_python_package/test_files.py +++ b/tests/extra_python_package/test_files.py @@ -145,9 +145,9 @@ def test_build_sdist(monkeypatch, tmpdir): contents = f.read().decode("utf8") assert 'set(pybind11_INCLUDE_DIR "${PACKAGE_PREFIX_DIR}/include")' in contents - files = {"pybind11/{}".format(n) for n in all_files} + files = {f"pybind11/{n}" for n in all_files} files |= sdist_files - files |= {"pybind11{}".format(n) for n in local_sdist_files} + files |= {f"pybind11{n}" for n in local_sdist_files} files.add("pybind11.egg-info/entry_points.txt") files.add("pybind11.egg-info/requires.txt") assert simpler == files @@ -200,9 +200,9 @@ def test_build_global_dist(monkeypatch, tmpdir): ) as f: pyproject_toml = f.read() - files = {"pybind11/{}".format(n) for n in all_files} + files = {f"pybind11/{n}" for n in all_files} files |= sdist_files - files |= {"pybind11_global{}".format(n) for n in local_sdist_files} + files |= {f"pybind11_global{n}" for n in local_sdist_files} assert simpler == files with open(os.path.join(MAIN_DIR, "tools", "setup_global.py.in"), "rb") as f: @@ -227,7 +227,7 @@ def tests_build_wheel(monkeypatch, tmpdir): (wheel,) = tmpdir.visit("*.whl") - files = {"pybind11/{}".format(n) for n in all_files} + files = {f"pybind11/{n}" for n in all_files} files |= { "dist-info/LICENSE", "dist-info/METADATA", @@ -257,8 +257,8 @@ def tests_build_global_wheel(monkeypatch, tmpdir): (wheel,) = tmpdir.visit("*.whl") - files = {"data/data/{}".format(n) for n in src_files} - files |= {"data/headers/{}".format(n[8:]) for n in headers} + files = {f"data/data/{n}" for n in src_files} + files |= {f"data/headers/{n[8:]}" for n in headers} files |= { "dist-info/LICENSE", "dist-info/METADATA", diff --git a/tests/test_builtin_casters.py b/tests/test_builtin_casters.py index 74014c9cf4..02207f24fc 100644 --- a/tests/test_builtin_casters.py +++ b/tests/test_builtin_casters.py @@ -50,7 +50,7 @@ def test_single_char_arguments(): """Tests failures for passing invalid inputs to char-accepting functions""" def toobig_message(r): - return "Character code point not in range({:#x})".format(r) + return f"Character code point not in range({r:#x})" toolong_message = "Expected a character, but multi-character string found" diff --git a/tests/test_callbacks.py b/tests/test_callbacks.py index 74aec21e5e..e7e6137f95 100644 --- a/tests/test_callbacks.py +++ b/tests/test_callbacks.py @@ -17,7 +17,7 @@ def func2(a, b, c, d): return "func2", a, b, c, d def func3(a): - return "func3({})".format(a) + return f"func3({a})" assert m.test_callback1(func1) == "func1" assert m.test_callback2(func2) == ("func2", "Hello", "x", True, 5) diff --git a/tests/test_chrono.py b/tests/test_chrono.py index f419ef387f..7f47b37a25 100644 --- a/tests/test_chrono.py +++ b/tests/test_chrono.py @@ -100,7 +100,7 @@ def test_chrono_system_clock_roundtrip_date(): ) def test_chrono_system_clock_roundtrip_time(time1, tz, monkeypatch): if tz is not None: - monkeypatch.setenv("TZ", "/usr/share/zoneinfo/{}".format(tz)) + monkeypatch.setenv("TZ", f"/usr/share/zoneinfo/{tz}") # Roundtrip the time datetime2 = m.test_chrono2(time1) diff --git a/tests/test_cmake_build/test.py b/tests/test_cmake_build/test.py index 5bf129ea33..807fd43b4a 100644 --- a/tests/test_cmake_build/test.py +++ b/tests/test_cmake_build/test.py @@ -5,4 +5,4 @@ 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])) +print(f"{sys.argv[1]} imports, runs, and adds: 1 + 2 = 3") diff --git a/tests/test_eigen.py b/tests/test_eigen.py index 9a94b35f8b..093773a514 100644 --- a/tests/test_eigen.py +++ b/tests/test_eigen.py @@ -221,9 +221,7 @@ def test_nonunit_stride_to_python(): assert np.all(m.diagonal(ref) == ref.diagonal()) assert np.all(m.diagonal_1(ref) == ref.diagonal(1)) for i in range(-5, 7): - assert np.all( - m.diagonal_n(ref, i) == ref.diagonal(i) - ), "m.diagonal_n({})".format(i) + assert np.all(m.diagonal_n(ref, i) == ref.diagonal(i)), f"m.diagonal_n({i})" assert np.all(m.block(ref, 2, 1, 3, 3) == ref[2:5, 1:4]) assert np.all(m.block(ref, 1, 4, 4, 2) == ref[1:, 4:]) @@ -236,7 +234,7 @@ def test_eigen_ref_to_python(): mymat = chol(np.array([[1.0, 2, 4], [2, 13, 23], [4, 23, 77]])) assert np.all( mymat == np.array([[1, 0, 0], [2, 3, 0], [4, 5, 6]]) - ), "cholesky{}".format(i) + ), f"cholesky{i}" def assign_both(a1, a2, r, c, v): diff --git a/tests/test_exceptions.py b/tests/test_exceptions.py index e0da55dfd6..0be61804a6 100644 --- a/tests/test_exceptions.py +++ b/tests/test_exceptions.py @@ -88,7 +88,7 @@ def test_python_call_in_catch(): def ignore_pytest_unraisable_warning(f): unraisable = "PytestUnraisableExceptionWarning" if hasattr(pytest, unraisable): # Python >= 3.8 and pytest >= 6 - dec = pytest.mark.filterwarnings("ignore::pytest.{}".format(unraisable)) + dec = pytest.mark.filterwarnings(f"ignore::pytest.{unraisable}") return dec(f) else: return f diff --git a/tests/test_numpy_dtypes.py b/tests/test_numpy_dtypes.py index 65fd90d7bc..7df60583f8 100644 --- a/tests/test_numpy_dtypes.py +++ b/tests/test_numpy_dtypes.py @@ -14,7 +14,7 @@ def simple_dtype(): return np.dtype( { "names": ["bool_", "uint_", "float_", "ldbl_"], - "formats": ["?", "u4", "f4", "f{}".format(ld.itemsize)], + "formats": ["?", "u4", "f4", f"f{ld.itemsize}"], "offsets": [0, 4, 8, (16 if ld.alignment > 4 else 12)], } ) @@ -125,7 +125,7 @@ def test_dtype(simple_dtype): assert [x.replace(" ", "") for x in m.print_dtypes()] == [ simple_dtype_fmt(), packed_dtype_fmt(), - "[('a',{}),('b',{})]".format(simple_dtype_fmt(), packed_dtype_fmt()), + f"[('a',{simple_dtype_fmt()}),('b',{packed_dtype_fmt()})]", partial_dtype_fmt(), partial_nested_fmt(), "[('a','S3'),('b','S3')]", diff --git a/tests/test_opaque_types.py b/tests/test_opaque_types.py index 8b9d8f59ce..5d4f2a1bf4 100644 --- a/tests/test_opaque_types.py +++ b/tests/test_opaque_types.py @@ -12,7 +12,7 @@ def test_string_list(): assert lst.back() == "Element 2" for i, k in enumerate(lst, start=1): - assert k == "Element {}".format(i) + assert k == f"Element {i}" lst.pop_back() assert m.print_opaque_list(lst) == "Opaque list: [Element 1]" diff --git a/tests/test_sequences_and_iterators.py b/tests/test_sequences_and_iterators.py index e1441c07cd..062e3b3d30 100644 --- a/tests/test_sequences_and_iterators.py +++ b/tests/test_sequences_and_iterators.py @@ -1,20 +1,10 @@ import pytest +from pytest import approx from pybind11_tests import ConstructorStats from pybind11_tests import sequences_and_iterators as m -def isclose(a, b, rel_tol=1e-05, abs_tol=0.0): - """Like math.isclose() from Python 3.5""" - return abs(a - b) <= max(rel_tol * max(abs(a), abs(b)), abs_tol) - - -def allclose(a_list, b_list, rel_tol=1e-05, abs_tol=0.0): - return all( - isclose(a, b, rel_tol=rel_tol, abs_tol=abs_tol) for a, b in zip(a_list, b_list) - ) - - def test_slice_constructors(): assert m.make_forward_slice_size_t() == slice(0, -1, 1) assert m.make_reversed_slice_object() == slice(None, None, -1) @@ -117,7 +107,8 @@ def test_sequence(): assert 12.34 not in s s[0], s[3] = 12.34, 56.78 assert 12.34 in s - assert isclose(s[0], 12.34) and isclose(s[3], 56.78) + assert s[0] == approx(12.34, rel=1e-05) + assert s[3] == approx(56.78, rel=1e-05) rev = reversed(s) assert cstats.values() == ["of size", "5"] @@ -132,14 +123,14 @@ def test_sequence(): assert cstats.values() == ["of size", "0"] expected = [0, 56.78, 0, 0, 12.34] - assert allclose(rev, expected) - assert allclose(rev2, expected) + assert rev == approx(expected, rel=1e-05) + assert rev2 == approx(expected, rel=1e-05) assert rev == rev2 rev[0::2] = m.Sequence([2.0, 2.0, 2.0]) assert cstats.values() == ["of size", "3", "from std::vector"] - assert allclose(rev, [2, 56.78, 2, 0, 2]) + assert rev == approx([2, 56.78, 2, 0, 2], rel=1e-05) assert cstats.alive() == 4 del it diff --git a/tests/test_smart_ptr.py b/tests/test_smart_ptr.py index 4097df28b4..2f204e01b1 100644 --- a/tests/test_smart_ptr.py +++ b/tests/test_smart_ptr.py @@ -15,7 +15,7 @@ def test_smart_ptr(capture): m.print_object_2(o) m.print_object_3(o) m.print_object_4(o) - assert capture == "MyObject1[{i}]\n".format(i=i) * 4 + assert capture == f"MyObject1[{i}]\n" * 4 for i, o in enumerate( [m.make_myobject1_1(), m.make_myobject1_2(), m.MyObject1(6), 7], start=4 @@ -33,13 +33,11 @@ def test_smart_ptr(capture): m.print_myobject1_4(o) times = 4 if isinstance(o, int) else 8 - assert capture == "MyObject1[{i}]\n".format(i=i) * times + assert capture == f"MyObject1[{i}]\n" * times cstats = ConstructorStats.get(m.MyObject1) assert cstats.alive() == 0 - expected_values = ["MyObject1[{}]".format(i) for i in range(1, 7)] + [ - "MyObject1[7]" - ] * 4 + expected_values = [f"MyObject1[{i}]" for i in range(1, 7)] + ["MyObject1[7]"] * 4 assert cstats.values() == expected_values assert cstats.default_constructions == 0 assert cstats.copy_constructions == 0 @@ -57,7 +55,7 @@ def test_smart_ptr(capture): m.print_myobject2_2(o) m.print_myobject2_3(o) m.print_myobject2_4(o) - assert capture == "MyObject2[{i}]\n".format(i=i) * 4 + assert capture == f"MyObject2[{i}]\n" * 4 cstats = ConstructorStats.get(m.MyObject2) assert cstats.alive() == 1 @@ -80,7 +78,7 @@ def test_smart_ptr(capture): m.print_myobject3_2(o) m.print_myobject3_3(o) m.print_myobject3_4(o) - assert capture == "MyObject3[{i}]\n".format(i=i) * 4 + assert capture == f"MyObject3[{i}]\n" * 4 cstats = ConstructorStats.get(m.MyObject3) assert cstats.alive() == 1 diff --git a/tools/FindPythonLibsNew.cmake b/tools/FindPythonLibsNew.cmake index b3acaaae92..7aeffa4412 100644 --- a/tools/FindPythonLibsNew.cmake +++ b/tools/FindPythonLibsNew.cmake @@ -92,7 +92,7 @@ endif() # Use the Python interpreter to find the libs. if(NOT PythonLibsNew_FIND_VERSION) - set(PythonLibsNew_FIND_VERSION "3.5") + set(PythonLibsNew_FIND_VERSION "3.6") endif() find_package(PythonInterp ${PythonLibsNew_FIND_VERSION} ${_pythonlibs_required} diff --git a/tools/libsize.py b/tools/libsize.py index 5fb20334d8..1ac9afbe81 100644 --- a/tools/libsize.py +++ b/tools/libsize.py @@ -13,7 +13,7 @@ save = sys.argv[2] if not os.path.exists(lib): - sys.exit("Error: requested file ({}) does not exist".format(lib)) + sys.exit(f"Error: requested file ({lib}) does not exist") libsize = os.path.getsize(lib) @@ -28,7 +28,7 @@ if change == 0: print(" (no change)") else: - print(" (change of {:+} bytes = {:+.2%})".format(change, change / oldsize)) + print(f" (change of {change:+} bytes = {change / oldsize:+.2%})") else: print() diff --git a/tools/pybind11Config.cmake.in b/tools/pybind11Config.cmake.in index 56e28cf291..9383e8c671 100644 --- a/tools/pybind11Config.cmake.in +++ b/tools/pybind11Config.cmake.in @@ -193,7 +193,7 @@ Using ``find_package`` with version info is not recommended except for release v .. code-block:: cmake find_package(pybind11 CONFIG) - find_package(pybind11 2.0 EXACT CONFIG REQUIRED) + find_package(pybind11 2.9 EXACT CONFIG REQUIRED) #]=============================================================================] @PACKAGE_INIT@ diff --git a/tools/pybind11NewTools.cmake b/tools/pybind11NewTools.cmake index dbf41e0711..abba0fe0e2 100644 --- a/tools/pybind11NewTools.cmake +++ b/tools/pybind11NewTools.cmake @@ -32,7 +32,7 @@ if(NOT Python_FOUND AND NOT Python3_FOUND) set(Python_ROOT_DIR "$ENV{pythonLocation}") endif() - find_package(Python 3.5 REQUIRED COMPONENTS Interpreter Development ${_pybind11_quiet}) + find_package(Python 3.6 REQUIRED COMPONENTS Interpreter Development ${_pybind11_quiet}) # If we are in submodule mode, export the Python targets to global targets. # If this behavior is not desired, FindPython _before_ pybind11. diff --git a/tools/pybind11Tools.cmake b/tools/pybind11Tools.cmake index 4ee8e52ce9..3d1503df86 100644 --- a/tools/pybind11Tools.cmake +++ b/tools/pybind11Tools.cmake @@ -43,7 +43,7 @@ endif() # A user can set versions manually too set(Python_ADDITIONAL_VERSIONS - "3.11;3.10;3.9;3.8;3.7;3.6;3.5" + "3.11;3.10;3.9;3.8;3.7;3.6" CACHE INTERNAL "") list(APPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_LIST_DIR}") diff --git a/tools/setup_global.py.in b/tools/setup_global.py.in index 63257447e8..8aa3871783 100644 --- a/tools/setup_global.py.in +++ b/tools/setup_global.py.in @@ -1,5 +1,4 @@ -#!/usr/bin/env python -# -*- coding: utf-8 -*- +#!/usr/bin/env python3 # Setup script for pybind11-global (in the sdist or in tools/setup_global.py in the repository) # This package is targeted for easy use from CMake. diff --git a/tools/setup_main.py.in b/tools/setup_main.py.in index 00d0fd57b3..738d73faad 100644 --- a/tools/setup_main.py.in +++ b/tools/setup_main.py.in @@ -1,5 +1,4 @@ -#!/usr/bin/env python -# -*- coding: utf-8 -*- +#!/usr/bin/env python3 # Setup script (in the sdist or in tools/setup_main.py in the repository) From 677a232a80f28ca102979c9e4e5b9d79073fb1cc Mon Sep 17 00:00:00 2001 From: Henry Schreiner Date: Thu, 10 Feb 2022 23:16:46 -0500 Subject: [PATCH 2/8] chore: more fstrings with flynt's help --- docs/benchmark.py | 25 ++++++++++------------ pybind11/setup_helpers.py | 6 +++--- tests/extra_python_package/test_files.py | 4 +--- tests/extra_setuptools/test_setuphelper.py | 4 ++-- tests/test_callbacks.py | 10 ++------- tests/test_numpy_array.py | 8 ++----- tests/test_pytypes.py | 4 ++-- tests/test_virtual_functions.py | 4 ++-- 8 files changed, 25 insertions(+), 40 deletions(-) diff --git a/docs/benchmark.py b/docs/benchmark.py index a595342926..2150b6ca78 100644 --- a/docs/benchmark.py +++ b/docs/benchmark.py @@ -11,20 +11,20 @@ def generate_dummy_code_pybind11(nclasses=10): bindings = "" for cl in range(nclasses): - decl += "class cl%03i;\n" % cl + decl += f"class cl{cl:03};\n" decl += "\n" for cl in range(nclasses): - decl += "class cl%03i {\n" % cl + decl += f"class {cl:03} {{\n" decl += "public:\n" - bindings += ' py::class_(m, "cl%03i")\n' % (cl, cl) + bindings += f' py::class_(m, "cl{cl:03}")\n' for fn in range(nfns): ret = random.randint(0, nclasses - 1) params = [random.randint(0, nclasses - 1) for i in range(nargs)] - decl += " cl%03i *fn_%03i(" % (ret, fn) - decl += ", ".join("cl%03i *" % p for p in params) + decl += f" cl{ret:03} *fn_{fn:03}(" + decl += ", ".join(f"cl{p:03} *" for p in params) decl += ");\n" - bindings += ' .def("fn_%03i", &cl%03i::fn_%03i)\n' % (fn, cl, fn) + bindings += f' .def("fn_{fn:03}", &cl{cl:03}::fn_{fn:03})\n' decl += "};\n\n" bindings += " ;\n" @@ -42,23 +42,20 @@ def generate_dummy_code_boost(nclasses=10): bindings = "" for cl in range(nclasses): - decl += "class cl%03i;\n" % cl + decl += f"class cl{cl:03};\n" decl += "\n" for cl in range(nclasses): decl += "class cl%03i {\n" % cl decl += "public:\n" - bindings += ' py::class_("cl%03i")\n' % (cl, cl) + bindings += f' py::class_("cl{cl:03}")\n' for fn in range(nfns): ret = random.randint(0, nclasses - 1) params = [random.randint(0, nclasses - 1) for i in range(nargs)] - decl += " cl%03i *fn_%03i(" % (ret, fn) - decl += ", ".join("cl%03i *" % p for p in params) + decl += f" cl{ret:03} *fn_{fn:03}(" + decl += ", ".join(f"cl{p:03} *" for p in params) decl += ");\n" - bindings += ( - ' .def("fn_%03i", &cl%03i::fn_%03i, py::return_value_policy())\n' - % (fn, cl, fn) - ) + bindings += f' .def("fn_{fn:03}", &cl{cl:03}::fn_{fn:03}, py::return_value_policy())\n' decl += "};\n\n" bindings += " ;\n" diff --git a/pybind11/setup_helpers.py b/pybind11/setup_helpers.py index 8f121eaee7..e3271ca60d 100644 --- a/pybind11/setup_helpers.py +++ b/pybind11/setup_helpers.py @@ -322,9 +322,9 @@ def intree_extensions( if not exts: msg = ( - "path {path} is not a child of any of the directories listed " - "in 'package_dir' ({package_dir})" - ).format(path=path, package_dir=package_dir) + f"path {path} is not a child of any of the directories listed " + f"in 'package_dir' ({package_dir})" + ) raise ValueError(msg) return exts diff --git a/tests/extra_python_package/test_files.py b/tests/extra_python_package/test_files.py index 2660d9d2a2..a6b13bc5f0 100644 --- a/tests/extra_python_package/test_files.py +++ b/tests/extra_python_package/test_files.py @@ -241,9 +241,7 @@ def tests_build_wheel(monkeypatch, tmpdir): names = z.namelist() trimmed = {n for n in names if "dist-info" not in n} - trimmed |= { - "dist-info/{}".format(n.split("/", 1)[-1]) for n in names if "dist-info" in n - } + trimmed |= {f"dist-info/{n.split('/', 1)[-1]}" for n in names if "dist-info" in n} assert files == trimmed diff --git a/tests/extra_setuptools/test_setuphelper.py b/tests/extra_setuptools/test_setuphelper.py index 3a771e558d..d5d3093bf0 100644 --- a/tests/extra_setuptools/test_setuphelper.py +++ b/tests/extra_setuptools/test_setuphelper.py @@ -18,7 +18,7 @@ def test_simple_setup_py(monkeypatch, tmpdir, parallel, std): (tmpdir / "setup.py").write_text( dedent( - """\ + f"""\ import sys sys.path.append({MAIN_DIR!r}) @@ -51,7 +51,7 @@ def test_simple_setup_py(monkeypatch, tmpdir, parallel, std): ext_modules=ext_modules, ) """ - ).format(MAIN_DIR=MAIN_DIR, std=std, parallel=parallel), + ), encoding="ascii", ) diff --git a/tests/test_callbacks.py b/tests/test_callbacks.py index e7e6137f95..0b1047bbf2 100644 --- a/tests/test_callbacks.py +++ b/tests/test_callbacks.py @@ -188,14 +188,8 @@ def test_callback_num_times(): if not rep: print() print( - "callback_num_times: {:d} million / {:.3f} seconds = {:.3f} million / second".format( - num_millions, td, rate - ) + f"callback_num_times: {num_millions:d} million / {td:.3f} seconds = {rate:.3f} million / second" ) if len(rates) > 1: print("Min Mean Max") - print( - "{:6.3f} {:6.3f} {:6.3f}".format( - min(rates), sum(rates) / len(rates), max(rates) - ) - ) + print(f"{min(rates):6.3f} {sum(rates) / len(rates):6.3f} {max(rates):6.3f}") diff --git a/tests/test_numpy_array.py b/tests/test_numpy_array.py index 45be592a84..f3cabfa43f 100644 --- a/tests/test_numpy_array.py +++ b/tests/test_numpy_array.py @@ -18,9 +18,7 @@ def test_dtypes(): assert check.numpy == check.pybind11, check if check.numpy.num != check.pybind11.num: print( - "NOTE: typenum mismatch for {}: {} != {}".format( - check, check.numpy.num, check.pybind11.num - ) + f"NOTE: typenum mismatch for {check}: {check.numpy.num} != {check.pybind11.num}" ) @@ -116,9 +114,7 @@ def test_at_fail(arr, dim): for func in m.at_t, m.mutate_at_t: with pytest.raises(IndexError) as excinfo: func(arr, *([0] * dim)) - assert str(excinfo.value) == "index dimension mismatch: {} (ndim = 2)".format( - dim - ) + assert str(excinfo.value) == f"index dimension mismatch: {dim} (ndim = 2)" def test_at(arr): diff --git a/tests/test_pytypes.py b/tests/test_pytypes.py index f2b1f6b6eb..07ace00491 100644 --- a/tests/test_pytypes.py +++ b/tests/test_pytypes.py @@ -305,8 +305,8 @@ def test_non_converting_constructors(): for move in [True, False]: with pytest.raises(TypeError) as excinfo: m.nonconverting_constructor(t, v, move) - expected_error = "Object of type '{}' is not an instance of '{}'".format( - type(v).__name__, t + expected_error = ( + f"Object of type '{type(v).__name__}' is not an instance of '{t}'" ) assert str(excinfo.value) == expected_error diff --git a/tests/test_virtual_functions.py b/tests/test_virtual_functions.py index 14a8384a8a..4d00d3690d 100644 --- a/tests/test_virtual_functions.py +++ b/tests/test_virtual_functions.py @@ -13,7 +13,7 @@ def __init__(self, state): self.data = "Hello world" def run(self, value): - print("ExtendedExampleVirt::run(%i), calling parent.." % value) + print(f"ExtendedExampleVirt::run({value}), calling parent..") return super().run(value + 1) def run_bool(self): @@ -24,7 +24,7 @@ def get_string1(self): return "override1" def pure_virtual(self): - print("ExtendedExampleVirt::pure_virtual(): %s" % self.data) + print(f"ExtendedExampleVirt::pure_virtual(): {self.data}") class ExtendedExampleVirt2(ExtendedExampleVirt): def __init__(self, state): From a4661972ceafdfbda2f31b8af1803a657d639bf1 Mon Sep 17 00:00:00 2001 From: Henry Schreiner Date: Thu, 10 Feb 2022 23:44:42 -0500 Subject: [PATCH 3/8] ci: drop Python 3.5 --- .github/workflows/ci.yml | 13 +++++-------- 1 file changed, 5 insertions(+), 8 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 07580decd0..b57c489c6f 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -25,7 +25,6 @@ jobs: matrix: runs-on: [ubuntu-latest, windows-2022, macos-latest] python: - - '3.5' - '3.6' - '3.9' - '3.10' @@ -167,7 +166,7 @@ jobs: # setuptools - name: Setuptools helpers test run: pytest tests/extra_setuptools - if: "!(matrix.python == '3.5' && matrix.runs-on == 'windows-2022')" + if: "!(matrix.runs-on == 'windows-2022')" deadsnakes: @@ -624,9 +623,9 @@ jobs: # This tests an "install" with the CMake tools install-classic: - name: "🐍 3.5 • Debian • x86 • Install" + name: "🐍 3.7 • Debian • x86 • Install" runs-on: ubuntu-latest - container: i386/debian:stretch + container: i386/debian:buster steps: - uses: actions/checkout@v1 @@ -635,7 +634,7 @@ jobs: run: | apt-get update apt-get install -y git make cmake g++ libeigen3-dev python3-dev python3-pip - pip3 install "pytest==3.1.*" + pip3 install "pytest==6.*" - name: Configure for install run: > @@ -704,12 +703,10 @@ jobs: fail-fast: false matrix: python: - - 3.5 - 3.6 - 3.7 - 3.8 - 3.9 - - pypy-3.6 include: - python: 3.9 @@ -810,7 +807,7 @@ jobs: fail-fast: false matrix: python: - - 3.5 + - 3.6 - 3.7 std: - 14 From d36dbbf905b6d1e2a61004f4c671eb13d7eea429 Mon Sep 17 00:00:00 2001 From: Henry Schreiner Date: Fri, 11 Feb 2022 00:09:11 -0500 Subject: [PATCH 4/8] chore: bump dependency versions --- .github/workflows/ci.yml | 2 ++ docs/requirements.txt | 8 ++++---- setup.cfg | 13 ++----------- tests/pytest.ini | 9 ++++++--- tests/requirements.txt | 16 ++++++---------- 5 files changed, 20 insertions(+), 28 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index b57c489c6f..b38d228353 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -15,6 +15,8 @@ concurrency: env: PIP_ONLY_BINARY: numpy + FORCE_COLOR: 3 + PYTEST_TIMEOUT: 300 jobs: # This is the "main" test suite, which tests a large number of different diff --git a/docs/requirements.txt b/docs/requirements.txt index b2801b1f0d..e452ed261f 100644 --- a/docs/requirements.txt +++ b/docs/requirements.txt @@ -1,5 +1,5 @@ -breathe==4.31.0 -sphinx==3.5.4 +breathe==4.32.0 +sphinx==4.4.0 sphinx_rtd_theme==1.0.0 -sphinxcontrib-moderncmakedomain==3.19 -sphinxcontrib-svg2pdfconverter==1.1.1 +sphinxcontrib-moderncmakedomain==3.21.4 +sphinxcontrib-svg2pdfconverter==1.2.0 diff --git a/setup.cfg b/setup.cfg index 0e7b16e0f5..11b4fde8f3 100644 --- a/setup.cfg +++ b/setup.cfg @@ -45,14 +45,5 @@ zip_safe = False max-line-length = 120 show_source = True exclude = .git, __pycache__, build, dist, docs, tools, venv -ignore = - # required for pretty matrix formatting: multiple spaces after `,` and `[` - E201, E241, W504, - # camelcase 'cPickle' imported as lowercase 'pickle' - N813 - # Black conflict - W503, E203 - - -[tool:pytest] -timeout = 300 +extend-ignore = E203, E722, B950 +select = C,E,F,N,W,B,B9 diff --git a/tests/pytest.ini b/tests/pytest.ini index a3871d6c3a..792ba361f7 100644 --- a/tests/pytest.ini +++ b/tests/pytest.ini @@ -1,12 +1,15 @@ [pytest] -minversion = 3.1 +minversion = 3.10 norecursedirs = test_* extra_* xfail_strict = True addopts = - # show summary of skipped tests - -rs + # show summary of tests + -ra # capture only Python print and C++ py::print, but not C output (low-level Python errors) --capture=sys + # Show local info when a failure occurs + --showlocals +log_cli_level = info filterwarnings = # make warnings into errors but ignore certain third-party extension issues error diff --git a/tests/requirements.txt b/tests/requirements.txt index 98ca46d28a..1130c3fd5d 100644 --- a/tests/requirements.txt +++ b/tests/requirements.txt @@ -1,12 +1,8 @@ -numpy==1.16.6; python_version<"3.6" and sys_platform!="win32" and platform_python_implementation!="PyPy" -numpy==1.19.0; platform_python_implementation=="PyPy" and sys_platform=="linux" and python_version=="3.6" -numpy==1.20.0; platform_python_implementation=="PyPy" and sys_platform=="linux" and python_version=="3.7" +numpy==1.21.5; platform_python_implementation=="PyPy" and sys_platform=="linux" and python_version=="3.7" numpy==1.19.3; platform_python_implementation!="PyPy" and python_version=="3.6" -numpy==1.21.3; platform_python_implementation!="PyPy" and python_version>="3.7" and python_version<"3.11" -py @ git+https://github.com/pytest-dev/py; python_version>="3.11" -pytest==4.6.9; python_version<"3.5" -pytest==6.1.2; python_version=="3.5" -pytest==6.2.4; python_version>="3.6" +numpy==1.21.5; platform_python_implementation!="PyPy" and python_version>="3.7" and python_version<"3.10" +numpy==1.22.2; platform_python_implementation!="PyPy" and python_version>="3.10" and python_version<"3.11" +pytest==7.0.0 pytest-timeout -scipy==1.2.3; platform_python_implementation!="PyPy" and python_version<"3.6" -scipy==1.5.4; platform_python_implementation!="PyPy" and python_version>="3.6" and python_version<"3.10" +scipy==1.5.4; platform_python_implementation!="PyPy" and python_version<"3.10" +scipy==1.8.0; platform_python_implementation!="PyPy" and python_version=="3.10" From 09295f526448a7f24d27820da12d2a51a33a5549 Mon Sep 17 00:00:00 2001 From: Henry Schreiner Date: Fri, 11 Feb 2022 11:05:22 -0500 Subject: [PATCH 5/8] docs: touch up py::args --- docs/advanced/functions.rst | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/docs/advanced/functions.rst b/docs/advanced/functions.rst index 9b82060a1e..69e3d8a1df 100644 --- a/docs/advanced/functions.rst +++ b/docs/advanced/functions.rst @@ -395,18 +395,18 @@ argument annotations when registering the function: m.def("f", [](int a, int b) { /* ... */ }, py::arg("a"), py::kw_only(), py::arg("b")); -Note that you currently cannot combine this with a ``py::args`` argument. - .. versionadded:: 2.6 -As of pybind11 2.9, a ``py::args`` argument implies that any following arguments -are keyword-only, as if ``py::kw_only()`` had been specified in the same -relative location of the argument list as the ``py::args`` argument. The -``py::kw_only()`` may be included to be explicit about this, but is not -required. (Prior to 2.9 ``py::args`` may only occur at the end of the argument -list, or immediately before a ``py::kwargs`` argument at the end). +A ``py::args`` argument implies that any following arguments are keyword-only, +as if ``py::kw_only()`` had been specified in the same relative location of the +argument list as the ``py::args`` argument. The ``py::kw_only()`` may be +included to be explicit about this, but is not required. + +.. versionchanged:: 2.9 + This can now be combined with ``py::args``. Before, ``py::args`` could only + occur at the end of the argument list, or immediately before a ``py::kwargs`` + argument at the end. -.. versionadded:: 2.9 Positional-only arguments ========================= From 8fef1bcddb4b80fc691a7406ff5a2b0e02f7b0da Mon Sep 17 00:00:00 2001 From: Henry Schreiner Date: Fri, 11 Feb 2022 11:05:49 -0500 Subject: [PATCH 6/8] tests: remove deprecation warning --- tests/test_numpy_array.py | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/tests/test_numpy_array.py b/tests/test_numpy_array.py index f3cabfa43f..504963b166 100644 --- a/tests/test_numpy_array.py +++ b/tests/test_numpy_array.py @@ -188,8 +188,6 @@ def test_make_empty_shaped_array(): def test_wrap(): def assert_references(a, b, base=None): - from distutils.version import LooseVersion - if base is None: base = a assert a is not b @@ -200,7 +198,8 @@ def assert_references(a, b, base=None): assert a.flags.f_contiguous == b.flags.f_contiguous assert a.flags.writeable == b.flags.writeable assert a.flags.aligned == b.flags.aligned - if LooseVersion(np.__version__) >= LooseVersion("1.14.0"): + # 1.13 supported Python 3.6 + if tuple(int(x) for x in np.__version__.split(".")[:2]) >= (1, 14): assert a.flags.writebackifcopy == b.flags.writebackifcopy else: assert a.flags.updateifcopy == b.flags.updateifcopy From bca56c04ffddd390672c880b3deb68479068f923 Mon Sep 17 00:00:00 2001 From: Aaron Gokaslan Date: Fri, 11 Feb 2022 11:03:43 -0500 Subject: [PATCH 7/8] Ban smartquotes --- .github/CONTRIBUTING.md | 6 +++--- .pre-commit-config.yaml | 34 +++++++++++++++++++------------- README.rst | 8 ++++---- docs/changelog.rst | 2 +- docs/faq.rst | 2 +- docs/upgrade.rst | 2 +- include/pybind11/detail/common.h | 6 +++--- 7 files changed, 33 insertions(+), 27 deletions(-) diff --git a/.github/CONTRIBUTING.md b/.github/CONTRIBUTING.md index a346ae63bf..7ccf193d00 100644 --- a/.github/CONTRIBUTING.md +++ b/.github/CONTRIBUTING.md @@ -96,7 +96,7 @@ Tips: * You can use `virtualenv` (faster, from PyPI) instead of `venv` * You can select any name for your environment folder; if it contains "env" it will be ignored by git. -* If you don’t have CMake 3.14+, just add "cmake" to the pip install command. +* If you don't have CMake 3.14+, just add "cmake" to the pip install command. * You can use `-DPYBIND11_FINDPYTHON=ON` to use FindPython on CMake 3.12+ * In classic mode, you may need to set `-DPYTHON_EXECUTABLE=/path/to/python`. FindPython uses `-DPython_ROOT_DIR=/path/to` or @@ -104,7 +104,7 @@ Tips: ### Configuration options -In CMake, configuration options are given with “-D”. Options are stored in the +In CMake, configuration options are given with "-D". Options are stored in the build directory, in the `CMakeCache.txt` file, so they are remembered for each build directory. Two selections are special - the generator, given with `-G`, and the compiler, which is selected based on environment variables `CXX` and @@ -114,7 +114,7 @@ after the initial run. The valid options are: * `-DCMAKE_BUILD_TYPE`: Release, Debug, MinSizeRel, RelWithDebInfo -* `-DPYBIND11_FINDPYTHON=ON`: Use CMake 3.12+’s FindPython instead of the +* `-DPYBIND11_FINDPYTHON=ON`: Use CMake 3.12+'s FindPython instead of the classic, deprecated, custom FindPythonLibs * `-DPYBIND11_NOPYTHON=ON`: Disable all Python searching (disables tests) * `-DBUILD_TESTING=ON`: Enable the tests diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 03d299c891..564d50042c 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -15,7 +15,7 @@ repos: # Standard hooks - repo: https://github.com/pre-commit/pre-commit-hooks - rev: v4.1.0 + rev: "v4.1.0" hooks: - id: check-added-large-files - id: check-case-conflict @@ -32,26 +32,26 @@ repos: # Upgrade old Python syntax - repo: https://github.com/asottile/pyupgrade - rev: v2.31.0 + rev: "v2.31.0" hooks: - id: pyupgrade args: [--py36-plus] # Nicely sort includes - repo: https://github.com/PyCQA/isort - rev: 5.10.1 + rev: "5.10.1" hooks: - id: isort # Black, the code formatter, natively supports pre-commit - repo: https://github.com/psf/black - rev: 22.1.0 # Keep in sync with blacken-docs + rev: "22.1.0" # Keep in sync with blacken-docs hooks: - id: black # Also code format the docs - repo: https://github.com/asottile/blacken-docs - rev: v1.12.1 + rev: "v1.12.1" hooks: - id: blacken-docs additional_dependencies: @@ -59,19 +59,25 @@ repos: # Changes tabs to spaces - repo: https://github.com/Lucas-C/pre-commit-hooks - rev: v1.1.11 + rev: "v1.1.11" hooks: - id: remove-tabs +- repo: https://github.com/sirosen/texthooks + rev: "0.2.2" + hooks: + - id: fix-ligatures + - id: fix-smartquotes + # Autoremoves unused imports - repo: https://github.com/hadialqattan/pycln - rev: v1.1.0 + rev: "v1.1.0" hooks: - id: pycln # Checking for common mistakes - repo: https://github.com/pre-commit/pygrep-hooks - rev: v1.9.0 + rev: "v1.9.0" hooks: - id: python-check-blanket-noqa - id: python-check-blanket-type-ignore @@ -83,7 +89,7 @@ repos: # Flake8 also supports pre-commit natively (same author) - repo: https://github.com/PyCQA/flake8 - rev: 4.0.1 + rev: "4.0.1" hooks: - id: flake8 additional_dependencies: &flake8_dependencies @@ -93,14 +99,14 @@ repos: # Automatically remove noqa that are not used - repo: https://github.com/asottile/yesqa - rev: v1.3.0 + rev: "v1.3.0" hooks: - id: yesqa additional_dependencies: *flake8_dependencies # CMake formatting - repo: https://github.com/cheshirekow/cmake-format-precommit - rev: v0.6.13 + rev: "v0.6.13" hooks: - id: cmake-format additional_dependencies: [pyyaml] @@ -109,7 +115,7 @@ repos: # Check static types with mypy - repo: https://github.com/pre-commit/mirrors-mypy - rev: v0.931 + rev: "v0.931" hooks: - id: mypy args: [--show-error-codes] @@ -127,7 +133,7 @@ repos: # Check for spelling - repo: https://github.com/codespell-project/codespell - rev: v2.1.0 + rev: "v2.1.0" hooks: - id: codespell exclude: ".supp$" @@ -135,7 +141,7 @@ repos: # Check for common shell mistakes - repo: https://github.com/shellcheck-py/shellcheck-py - rev: v0.8.0.4 + rev: "v0.8.0.4" hooks: - id: shellcheck diff --git a/README.rst b/README.rst index 9365df0296..0edcd9179a 100644 --- a/README.rst +++ b/README.rst @@ -32,7 +32,7 @@ this heavy machinery has become an excessively large and unnecessary dependency. Think of this library as a tiny self-contained version of Boost.Python -with everything stripped away that isn’t relevant for binding +with everything stripped away that isn't relevant for binding generation. Without comments, the core header files only require ~4K lines of code and depend on Python (3.6+, or PyPy) and the C++ standard library. This compact implementation was possible thanks to @@ -88,8 +88,8 @@ goodies: - pybind11 uses C++11 move constructors and move assignment operators whenever possible to efficiently transfer custom data types. -- It’s easy to expose the internal storage of custom data types through - Pythons’ buffer protocols. This is handy e.g. for fast conversion +- It's easy to expose the internal storage of custom data types through + Pythons' buffer protocols. This is handy e.g. for fast conversion between C++ matrix classes like Eigen and NumPy without expensive copy operations. @@ -119,7 +119,7 @@ goodies: Supported compilers ------------------- -1. Clang/LLVM 3.3 or newer (for Apple Xcode’s clang, this is 5.0.0 or +1. Clang/LLVM 3.3 or newer (for Apple Xcode's clang, this is 5.0.0 or newer) 2. GCC 4.8 or newer 3. Microsoft Visual Studio 2015 Update 3 or newer diff --git a/docs/changelog.rst b/docs/changelog.rst index 63c7f41d8f..9d7693cddc 100644 --- a/docs/changelog.rst +++ b/docs/changelog.rst @@ -800,7 +800,7 @@ Packaging / building improvements: `#2338 `_ and `#2370 `_ - * Full integration with CMake’s C++ standard system and compile features + * Full integration with CMake's C++ standard system and compile features replaces ``PYBIND11_CPP_STANDARD``. * Generated config file is now portable to different Python/compiler/CMake diff --git a/docs/faq.rst b/docs/faq.rst index 69c3442e3b..a6b9913126 100644 --- a/docs/faq.rst +++ b/docs/faq.rst @@ -145,7 +145,7 @@ using C++14 template metaprogramming. .. _`faq:hidden_visibility`: -"‘SomeClass’ declared with greater visibility than the type of its field ‘SomeClass::member’ [-Wattributes]" +"'SomeClass' declared with greater visibility than the type of its field 'SomeClass::member' [-Wattributes]" ============================================================================================================ This error typically indicates that you are compiling without the required diff --git a/docs/upgrade.rst b/docs/upgrade.rst index d91d51e6f2..6a9db2d08f 100644 --- a/docs/upgrade.rst +++ b/docs/upgrade.rst @@ -524,7 +524,7 @@ include a declaration of the form: PYBIND11_DECLARE_HOLDER_TYPE(T, std::shared_ptr) -Continuing to do so won’t cause an error or even a deprecation warning, +Continuing to do so won't cause an error or even a deprecation warning, but it's completely redundant. diff --git a/include/pybind11/detail/common.h b/include/pybind11/detail/common.h index 66ad266d47..c1d2de13a7 100644 --- a/include/pybind11/detail/common.h +++ b/include/pybind11/detail/common.h @@ -429,7 +429,7 @@ enum class return_value_policy : uint8_t { /** Reference an existing object (i.e. do not create a new copy) and take ownership. Python will call the destructor and delete operator when the - object’s reference count reaches zero. Undefined behavior ensues when + object's reference count reaches zero. Undefined behavior ensues when the C++ side does the same.. */ take_ownership, @@ -445,7 +445,7 @@ enum class return_value_policy : uint8_t { move, /** Reference an existing object, but do not take ownership. The C++ side - is responsible for managing the object’s lifetime and deallocating it + is responsible for managing the object's lifetime and deallocating it when it is no longer used. Warning: undefined behavior will ensue when the C++ side deletes an object that is still referenced and used by Python. */ @@ -454,7 +454,7 @@ enum class return_value_policy : uint8_t { /** This policy only applies to methods and properties. It references the object without taking ownership similar to the above return_value_policy::reference policy. In contrast to that policy, the - function or property’s implicit this argument (called the parent) is + function or property's implicit this argument (called the parent) is considered to be the the owner of the return value (the child). pybind11 then couples the lifetime of the parent to the child via a reference relationship that ensures that the parent cannot be garbage From 7800e7faeddd132994057e99f04fbdf7274329ce Mon Sep 17 00:00:00 2001 From: "Ralf W. Grosse-Kunstleve" Date: Fri, 11 Feb 2022 14:48:54 -0800 Subject: [PATCH 8/8] Very minor tweaks (by-product of reviewing PR #3719). --- .github/CONTRIBUTING.md | 2 +- include/pybind11/pybind11.h | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/CONTRIBUTING.md b/.github/CONTRIBUTING.md index 7ccf193d00..c8ec91ff7a 100644 --- a/.github/CONTRIBUTING.md +++ b/.github/CONTRIBUTING.md @@ -93,7 +93,7 @@ cmake --build build -j4 Tips: -* You can use `virtualenv` (faster, from PyPI) instead of `venv` +* You can use `virtualenv` (faster, from PyPI) instead of `venv`. * You can select any name for your environment folder; if it contains "env" it will be ignored by git. * If you don't have CMake 3.14+, just add "cmake" to the pip install command. diff --git a/include/pybind11/pybind11.h b/include/pybind11/pybind11.h index 840cb573f4..22b629f40d 100644 --- a/include/pybind11/pybind11.h +++ b/include/pybind11/pybind11.h @@ -1213,7 +1213,7 @@ class module_ : public object { PyModule_AddObject(ptr(), name, obj.inc_ref().ptr() /* steals a reference */); } - using module_def = PyModuleDef; + using module_def = PyModuleDef; // TODO: Can this be removed (it was needed only for Python 2)? /** \rst Create a new top-level module that can be used as the main module of a C extension. @@ -1241,7 +1241,7 @@ class module_ : public object { pybind11_fail("Internal error in module_::create_extension_module()"); } // TODO: Should be reinterpret_steal for Python 3, but Python also steals it again when - // returned from PyInit_... + // returned from PyInit_... // For Python 2, reinterpret_borrow was correct. return reinterpret_borrow(m); }