diff --git a/.github/CONTRIBUTING.md b/.github/CONTRIBUTING.md index e8294c83c..c8ec91ff7 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 @@ -105,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 @@ -115,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 @@ -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/.github/workflows/ci.yml b/.github/workflows/ci.yml index 07580decd..b38d22835 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 @@ -25,7 +27,6 @@ jobs: matrix: runs-on: [ubuntu-latest, windows-2022, macos-latest] python: - - '3.5' - '3.6' - '3.9' - '3.10' @@ -167,7 +168,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 +625,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 +636,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 +705,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 +809,7 @@ jobs: fail-fast: false matrix: python: - - 3.5 + - 3.6 - 3.7 std: - 14 diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 6d44d5e76..564d50042 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: [--py3-plus] + 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,32 +59,37 @@ 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 - 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 # 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 @@ -94,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] @@ -110,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] @@ -128,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$" @@ -136,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 6398db4f0..0edcd9179 100644 --- a/README.rst +++ b/README.rst @@ -32,9 +32,9 @@ 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.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 @@ -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/advanced/cast/overview.rst b/docs/advanced/cast/overview.rst index 6a834a3e5..011bd4c7a 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 bf5b5fa00..69e3d8a1d 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,19 +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. This -feature does *not* require Python 3 to work. - .. 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 ========================= diff --git a/docs/advanced/pycpp/numpy.rst b/docs/advanced/pycpp/numpy.rst index dbc48440a..8ad341004 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/benchmark.py b/docs/benchmark.py index a59534292..2150b6ca7 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/docs/changelog.rst b/docs/changelog.rst index 63c7f41d8..9d7693cdd 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/compiling.rst b/docs/compiling.rst index f7303fd23..4ae9234e1 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 99f3be349..00796fbdb 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/docs/faq.rst b/docs/faq.rst index 69c3442e3..a6b991312 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/requirements.txt b/docs/requirements.txt index b2801b1f0..e452ed261 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/docs/upgrade.rst b/docs/upgrade.rst index d91d51e6f..6a9db2d08 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/cast.h b/include/pybind11/cast.h index b12559ac8..553d7616c 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 ad5e97b02..167ea0e3d 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 a5d98d71f..c1d2de13a 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) @@ -438,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, @@ -454,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. */ @@ -463,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 diff --git a/include/pybind11/detail/type_caster_base.h b/include/pybind11/detail/type_caster_base.h index 226f7a994..ff7d7cf8c 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 7b7a1a05d..22b629f40 100644 --- a/include/pybind11/pybind11.h +++ b/include/pybind11/pybind11.h @@ -1213,7 +1213,7 @@ public: 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,8 +1241,8 @@ public: 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_... - // For Python 2, reinterpret_borrow is correct. + // returned from PyInit_... + // 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 747992f51..93727424c 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 cfa84826d..4b6adcfbd 100644 --- a/noxfile.py +++ b/noxfile.py @@ -2,7 +2,7 @@ import nox 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 faf3892cb..a1be96981 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 9cbcaa922..e3271ca60 100644 --- a/pybind11/setup_helpers.py +++ b/pybind11/setup_helpers.py @@ -200,7 +200,7 @@ class Pybind11Extension(_Extension): # type: ignore[misc] 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] @@ -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 @@ -419,7 +419,7 @@ class ParallelCompile: 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 bd2357e9e..11b4fde8f 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 @@ -46,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/setup.py b/setup.py index 5b46e0c8d..a149755bf 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 @@ to_src = ( # 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 @@ version = loc["__version__"] 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 70dcfb987..a6b13bc5f 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", @@ -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 @@ -257,8 +255,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/extra_setuptools/test_setuphelper.py b/tests/extra_setuptools/test_setuphelper.py index 3a771e558..d5d3093bf 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/pytest.ini b/tests/pytest.ini index a3871d6c3..792ba361f 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 98ca46d28..1130c3fd5 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" diff --git a/tests/test_builtin_casters.py b/tests/test_builtin_casters.py index 74014c9cf..02207f24f 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 74aec21e5..0b1047bbf 100644 --- a/tests/test_callbacks.py +++ b/tests/test_callbacks.py @@ -17,7 +17,7 @@ def test_callbacks(): 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) @@ -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_chrono.py b/tests/test_chrono.py index f419ef387..7f47b37a2 100644 --- a/tests/test_chrono.py +++ b/tests/test_chrono.py @@ -100,7 +100,7 @@ SKIP_TZ_ENV_ON_WIN = pytest.mark.skipif( ) 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 5bf129ea3..807fd43b4 100644 --- a/tests/test_cmake_build/test.py +++ b/tests/test_cmake_build/test.py @@ -5,4 +5,4 @@ import test_cmake_build 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 9a94b35f8..093773a51 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 e0da55dfd..0be61804a 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_array.py b/tests/test_numpy_array.py index 45be592a8..504963b16 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): @@ -192,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 @@ -204,7 +198,8 @@ def test_wrap(): 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 diff --git a/tests/test_numpy_dtypes.py b/tests/test_numpy_dtypes.py index 65fd90d7b..7df60583f 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 8b9d8f59c..5d4f2a1bf 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_pytypes.py b/tests/test_pytypes.py index f2b1f6b6e..07ace0049 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_sequences_and_iterators.py b/tests/test_sequences_and_iterators.py index e1441c07c..062e3b3d3 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 4097df28b..2f204e01b 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/tests/test_virtual_functions.py b/tests/test_virtual_functions.py index 14a8384a8..4d00d3690 100644 --- a/tests/test_virtual_functions.py +++ b/tests/test_virtual_functions.py @@ -13,7 +13,7 @@ def test_override(capture, msg): 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 test_override(capture, msg): 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): diff --git a/tools/FindPythonLibsNew.cmake b/tools/FindPythonLibsNew.cmake index b3acaaae9..7aeffa441 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 5fb20334d..1ac9afbe8 100644 --- a/tools/libsize.py +++ b/tools/libsize.py @@ -13,7 +13,7 @@ lib = sys.argv[1] 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 os.path.exists(save): 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 56e28cf29..9383e8c67 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 dbf41e071..abba0fe0e 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 4ee8e52ce..3d1503df8 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 63257447e..8aa387178 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 00d0fd57b..738d73faa 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)