From f1a2e03d1966fd778ed40d855f6fcc23abd168cd Mon Sep 17 00:00:00 2001 From: "Ralf W. Grosse-Kunstleve" Date: Fri, 21 Jun 2024 21:55:00 -0700 Subject: [PATCH] feat: remove Python 3.6 support (#5177) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Change Python version guard: PYTHON < 3.7 IS UNSUPPORTED. * Replace or remove Python 3.6 jobs. * Move appveyor to Python 3.8 * Change `[tool.pylint]` `master.py-version` from `3.6` to `3.8` * Change `[tool.pylint]` `master.py-version` to `3.7` * Remove `centos:7` job; Change almalinux:8 job to use Python 3.8 * Try 🐍 3.8 • ubuntu-20.04 • x64 without `-DCMAKE_CXX_FLAGS="-D_=1"` * Update setup.cfg as suggested by @henryiii * Try running `cmake --build . --target cpptest` on all platforms (`standard` job). * Disable deadsnakes jobs entirely. * Apply PR #5179: Add Python 3.10, 3.11, 3.12 to win32 job matrix. * Add back `-DCMAKE_CXX_FLAGS="-D_=1"` but do not install boost in that case. * PY_VERSION_HEX < 3.7 cleanup pass: include/pybind11 * WITH_THREAD cleanup pass: include/pybind11 * Undo incorrect change. * Revert "Disable deadsnakes jobs entirely." This reverts commit bbcd0087b2d52e0130f96792dd5dd03704280a57. * WITH_THREAD cleanup pass: tests/ * Change Python version guard in pybind11/__init__.py: pybind11 does not support Python < 3.7. * Misc cleanup pass * chore: use future imports Signed-off-by: Henry Schreiner * Update tests/test_numpy_array.py * Update test_numpy_array.py --------- Signed-off-by: Henry Schreiner Co-authored-by: Henry Schreiner --- .appveyor.yml | 2 +- .github/workflows/ci.yml | 29 ++--- .github/workflows/pip.yml | 9 +- README.rst | 4 +- docs/benchmark.py | 2 + docs/compiling.rst | 4 +- docs/conf.py | 1 + include/pybind11/detail/class.h | 14 +-- include/pybind11/detail/common.h | 5 +- include/pybind11/detail/internals.h | 122 +++++++------------- include/pybind11/detail/type_caster_base.h | 16 +-- include/pybind11/embed.h | 3 - include/pybind11/gil.h | 48 ++------ include/pybind11/stl/filesystem.h | 3 +- noxfile.py | 2 + pybind11/__init__.py | 6 +- pybind11/__main__.py | 1 + pybind11/_version.py | 4 +- pybind11/commands.py | 2 + pybind11/setup_helpers.py | 30 ++--- pyproject.toml | 4 +- setup.cfg | 3 +- setup.py | 15 ++- tests/conftest.py | 2 + tests/env.py | 2 + tests/extra_python_package/test_files.py | 2 + tests/extra_setuptools/test_setuphelper.py | 2 + tests/requirements.txt | 2 - tests/test_async.py | 2 + tests/test_buffers.py | 2 + tests/test_builtin_casters.py | 2 + tests/test_call_policies.cpp | 2 +- tests/test_call_policies.py | 2 + tests/test_callbacks.py | 2 + tests/test_chrono.py | 2 + tests/test_class.py | 2 + tests/test_cmake_build/test.py | 2 + tests/test_const_name.py | 2 + tests/test_constants_and_functions.py | 2 + tests/test_copy_move.py | 2 + tests/test_custom_type_casters.py | 2 + tests/test_custom_type_setup.py | 2 + tests/test_docstring_options.py | 2 + tests/test_eigen_matrix.py | 2 + tests/test_eigen_tensor.py | 2 + tests/test_embed/test_interpreter.py | 2 + tests/test_embed/test_trampoline.py | 2 + tests/test_enum.py | 1 + tests/test_eval.py | 2 + tests/test_eval_call.py | 1 + tests/test_exceptions.py | 2 + tests/test_factory_constructors.py | 2 + tests/test_gil_scoped.py | 2 + tests/test_iostream.py | 2 + tests/test_kwargs_and_defaults.py | 2 + tests/test_local_bindings.py | 2 + tests/test_methods_and_attributes.py | 2 + tests/test_modules.py | 2 + tests/test_multiple_inheritance.py | 2 + tests/test_numpy_array.py | 8 +- tests/test_numpy_dtypes.py | 2 + tests/test_numpy_vectorize.py | 2 + tests/test_opaque_types.py | 2 + tests/test_operator_overloading.py | 2 + tests/test_pickling.py | 2 + tests/test_python_multiple_inheritance.py | 1 + tests/test_pytypes.py | 2 + tests/test_sequences_and_iterators.py | 2 + tests/test_smart_ptr.py | 2 + tests/test_stl.py | 2 + tests/test_stl_binders.py | 2 + tests/test_tagbased_polymorphic.py | 2 + tests/test_thread.py | 2 + tests/test_type_caster_pyobject_ptr.py | 2 + tests/test_union.py | 2 + tests/test_unnamed_namespace_a.py | 2 + tests/test_unnamed_namespace_b.py | 2 + tests/test_vector_unique_ptr_member.py | 2 + tests/test_virtual_functions.py | 2 + tools/FindPythonLibsNew.cmake | 2 +- tools/codespell_ignore_lines_from_errors.py | 5 +- tools/libsize.py | 2 + tools/pybind11NewTools.cmake | 2 +- tools/pybind11Tools.cmake | 2 +- 84 files changed, 238 insertions(+), 219 deletions(-) diff --git a/.appveyor.yml b/.appveyor.yml index 360760ac8..391cf1071 100644 --- a/.appveyor.yml +++ b/.appveyor.yml @@ -9,7 +9,7 @@ platform: - x86 environment: matrix: - - PYTHON: 36 + - PYTHON: 38 CONFIG: Debug install: - ps: | diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 82c118550..3054d842a 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -32,7 +32,7 @@ jobs: matrix: runs-on: [ubuntu-20.04, windows-2022, macos-13] python: - - '3.6' + - '3.8' - '3.9' - '3.12' - '3.13' @@ -48,16 +48,17 @@ jobs: include: # Just add a key - runs-on: ubuntu-20.04 - python: '3.6' + python: '3.8' args: > -DPYBIND11_FINDPYTHON=ON -DCMAKE_CXX_FLAGS="-D_=1" + exercise_D_: 1 - runs-on: ubuntu-20.04 python: 'pypy-3.8' args: > -DPYBIND11_FINDPYTHON=ON - runs-on: windows-2019 - python: '3.6' + python: '3.8' args: > -DPYBIND11_FINDPYTHON=ON # Inject a couple Windows 2019 runs @@ -82,7 +83,7 @@ jobs: - name: Setup Boost (Linux) # Can't use boost + define _ - if: runner.os == 'Linux' && matrix.python != '3.6' + if: runner.os == 'Linux' && matrix.exercise_D_ != 1 run: sudo apt-get install libboost-dev - name: Setup Boost (macOS) @@ -655,15 +656,13 @@ jobs: cmake --build build-17 --target test_cmake_build - # Testing on CentOS (manylinux uses a centos base, and this is an easy way - # to get GCC 4.8, which is the manylinux1 compiler). + # Testing on CentOS (manylinux uses a centos base). centos: runs-on: ubuntu-latest strategy: fail-fast: false matrix: container: - - "centos:7" # GCC 4.8 - "almalinux:8" - "almalinux:9" @@ -673,18 +672,13 @@ jobs: steps: - name: Latest actions/checkout uses: actions/checkout@v4 - if: matrix.container != 'centos:7' - - name: Pin actions/checkout as required for centos:7 - uses: actions/checkout@v3 - if: matrix.container == 'centos:7' + - name: Add Python 3.8 + if: matrix.container == 'almalinux:8' + run: dnf update -y && dnf install -y python38-devel gcc-c++ make git - - name: Add Python 3 (RHEL 7) - if: matrix.container == 'centos:7' - run: yum update -y && yum install -y python3-devel gcc-c++ make git - - - name: Add Python 3 (RHEL 8+) - if: matrix.container != 'centos:7' + - name: Add Python 3 (default) + if: matrix.container != 'almalinux:8' run: dnf update -y && dnf install -y python3-devel gcc-c++ make git - name: Update pip @@ -807,7 +801,6 @@ jobs: fail-fast: false matrix: python: - - '3.6' - '3.7' - '3.8' - '3.9' diff --git a/.github/workflows/pip.yml b/.github/workflows/pip.yml index 19baf57d9..9aad8df88 100644 --- a/.github/workflows/pip.yml +++ b/.github/workflows/pip.yml @@ -21,19 +21,18 @@ env: jobs: # This builds the sdists and wheels and makes sure the files are exactly as - # expected. Using Windows and Python 3.6, since that is often the most - # challenging matrix element. + # expected. test-packaging: - name: 🐍 3.6 • 📦 tests • windows-latest + name: 🐍 3.8 • 📦 tests • windows-latest runs-on: windows-latest steps: - uses: actions/checkout@v4 - - name: Setup 🐍 3.6 + - name: Setup 🐍 3.8 uses: actions/setup-python@v5 with: - python-version: 3.6 + python-version: 3.8 - name: Prepare env run: | diff --git a/README.rst b/README.rst index 4032f97a5..0d1e1d291 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.6+, or PyPy) and the C++ +lines of code and depend on Python (3.7+, or PyPy) and the C++ standard library. This compact implementation was possible thanks to some C++11 language features (specifically: tuples, lambda functions and variadic templates). Since its creation, this library has grown beyond @@ -79,7 +79,7 @@ Goodies In addition to the core functionality, pybind11 provides some extra goodies: -- Python 3.6+, and PyPy3 7.3 are supported with an implementation-agnostic +- Python 3.7+, 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 diff --git a/docs/benchmark.py b/docs/benchmark.py index fb49fd048..a273674f4 100644 --- a/docs/benchmark.py +++ b/docs/benchmark.py @@ -1,3 +1,5 @@ +from __future__ import annotations + import datetime as dt import os import random diff --git a/docs/compiling.rst b/docs/compiling.rst index 970bd5df8..0b7c178b0 100644 --- a/docs/compiling.rst +++ b/docs/compiling.rst @@ -426,7 +426,7 @@ with ``PYTHON_EXECUTABLE``. For example: .. code-block:: bash - cmake -DPYBIND11_PYTHON_VERSION=3.6 .. + cmake -DPYBIND11_PYTHON_VERSION=3.7 .. # Another method: cmake -DPYTHON_EXECUTABLE=/path/to/python .. @@ -493,7 +493,7 @@ existing targets instead: cmake_minimum_required(VERSION 3.15...3.22) project(example LANGUAGES CXX) - find_package(Python 3.6 COMPONENTS Interpreter Development REQUIRED) + find_package(Python 3.7 COMPONENTS Interpreter Development REQUIRED) find_package(pybind11 CONFIG REQUIRED) # or add_subdirectory(pybind11) diff --git a/docs/conf.py b/docs/conf.py index 9ba106d51..e5cba0382 100644 --- a/docs/conf.py +++ b/docs/conf.py @@ -11,6 +11,7 @@ # # All configuration values have a default; values that are commented out # serve to show the default. +from __future__ import annotations import os import re diff --git a/include/pybind11/detail/class.h b/include/pybind11/detail/class.h index 01f56abb2..d30621c88 100644 --- a/include/pybind11/detail/class.h +++ b/include/pybind11/detail/class.h @@ -567,17 +567,9 @@ inline void enable_dynamic_attributes(PyHeapTypeObject *heap_type) { type->tp_traverse = pybind11_traverse; type->tp_clear = pybind11_clear; - static PyGetSetDef getset[] = {{ -#if PY_VERSION_HEX < 0x03070000 - const_cast("__dict__"), -#else - "__dict__", -#endif - PyObject_GenericGetDict, - PyObject_GenericSetDict, - nullptr, - nullptr}, - {nullptr, nullptr, nullptr, nullptr, nullptr}}; + static PyGetSetDef getset[] + = {{"__dict__", PyObject_GenericGetDict, PyObject_GenericSetDict, nullptr, nullptr}, + {nullptr, nullptr, nullptr, nullptr, nullptr}}; type->tp_getset = getset; } diff --git a/include/pybind11/detail/common.h b/include/pybind11/detail/common.h index f0f3c50d3..698421d84 100644 --- a/include/pybind11/detail/common.h +++ b/include/pybind11/detail/common.h @@ -272,9 +272,8 @@ PYBIND11_WARNING_DISABLE_MSVC(4505) #endif #include -// Reminder: WITH_THREAD is always defined if PY_VERSION_HEX >= 0x03070000 -#if PY_VERSION_HEX < 0x03060000 -# error "PYTHON < 3.6 IS UNSUPPORTED. pybind11 v2.9 was the last to support Python 2 and 3.5." +#if PY_VERSION_HEX < 0x03070000 +# error "PYTHON < 3.7 IS UNSUPPORTED. pybind11 v2.12 was the last to support Python 3.6." #endif #include #include diff --git a/include/pybind11/detail/internals.h b/include/pybind11/detail/internals.h index c7ceda2f9..92a851602 100644 --- a/include/pybind11/detail/internals.h +++ b/include/pybind11/detail/internals.h @@ -11,7 +11,7 @@ #include "common.h" -#if defined(WITH_THREAD) && defined(PYBIND11_SIMPLE_GIL_MANAGEMENT) +#if defined(PYBIND11_SIMPLE_GIL_MANAGEMENT) # include "../gil.h" #endif @@ -64,65 +64,41 @@ inline PyObject *make_object_base_type(PyTypeObject *metaclass); // The old Python Thread Local Storage (TLS) API is deprecated in Python 3.7 in favor of the new // Thread Specific Storage (TSS) API. -#if PY_VERSION_HEX >= 0x03070000 // Avoid unnecessary allocation of `Py_tss_t`, since we cannot use // `Py_LIMITED_API` anyway. -# if PYBIND11_INTERNALS_VERSION > 4 -# define PYBIND11_TLS_KEY_REF Py_tss_t & -# if defined(__clang__) -# define PYBIND11_TLS_KEY_INIT(var) \ - _Pragma("clang diagnostic push") /**/ \ - _Pragma("clang diagnostic ignored \"-Wmissing-field-initializers\"") /**/ \ - Py_tss_t var \ - = Py_tss_NEEDS_INIT; \ - _Pragma("clang diagnostic pop") -# elif defined(__GNUC__) && !defined(__INTEL_COMPILER) -# define PYBIND11_TLS_KEY_INIT(var) \ - _Pragma("GCC diagnostic push") /**/ \ - _Pragma("GCC diagnostic ignored \"-Wmissing-field-initializers\"") /**/ \ - Py_tss_t var \ - = Py_tss_NEEDS_INIT; \ - _Pragma("GCC diagnostic pop") -# else -# define PYBIND11_TLS_KEY_INIT(var) Py_tss_t var = Py_tss_NEEDS_INIT; -# endif -# define PYBIND11_TLS_KEY_CREATE(var) (PyThread_tss_create(&(var)) == 0) -# define PYBIND11_TLS_GET_VALUE(key) PyThread_tss_get(&(key)) -# define PYBIND11_TLS_REPLACE_VALUE(key, value) PyThread_tss_set(&(key), (value)) -# define PYBIND11_TLS_DELETE_VALUE(key) PyThread_tss_set(&(key), nullptr) -# define PYBIND11_TLS_FREE(key) PyThread_tss_delete(&(key)) +#if PYBIND11_INTERNALS_VERSION > 4 +# define PYBIND11_TLS_KEY_REF Py_tss_t & +# if defined(__clang__) +# define PYBIND11_TLS_KEY_INIT(var) \ + _Pragma("clang diagnostic push") /**/ \ + _Pragma("clang diagnostic ignored \"-Wmissing-field-initializers\"") /**/ \ + Py_tss_t var \ + = Py_tss_NEEDS_INIT; \ + _Pragma("clang diagnostic pop") +# elif defined(__GNUC__) && !defined(__INTEL_COMPILER) +# define PYBIND11_TLS_KEY_INIT(var) \ + _Pragma("GCC diagnostic push") /**/ \ + _Pragma("GCC diagnostic ignored \"-Wmissing-field-initializers\"") /**/ \ + Py_tss_t var \ + = Py_tss_NEEDS_INIT; \ + _Pragma("GCC diagnostic pop") # else -# define PYBIND11_TLS_KEY_REF Py_tss_t * -# define PYBIND11_TLS_KEY_INIT(var) Py_tss_t *var = nullptr; -# define PYBIND11_TLS_KEY_CREATE(var) \ - (((var) = PyThread_tss_alloc()) != nullptr && (PyThread_tss_create((var)) == 0)) -# define PYBIND11_TLS_GET_VALUE(key) PyThread_tss_get((key)) -# define PYBIND11_TLS_REPLACE_VALUE(key, value) PyThread_tss_set((key), (value)) -# define PYBIND11_TLS_DELETE_VALUE(key) PyThread_tss_set((key), nullptr) -# define PYBIND11_TLS_FREE(key) PyThread_tss_free(key) +# define PYBIND11_TLS_KEY_INIT(var) Py_tss_t var = Py_tss_NEEDS_INIT; # endif +# define PYBIND11_TLS_KEY_CREATE(var) (PyThread_tss_create(&(var)) == 0) +# define PYBIND11_TLS_GET_VALUE(key) PyThread_tss_get(&(key)) +# define PYBIND11_TLS_REPLACE_VALUE(key, value) PyThread_tss_set(&(key), (value)) +# define PYBIND11_TLS_DELETE_VALUE(key) PyThread_tss_set(&(key), nullptr) +# define PYBIND11_TLS_FREE(key) PyThread_tss_delete(&(key)) #else -// Usually an int but a long on Cygwin64 with Python 3.x -# define PYBIND11_TLS_KEY_REF decltype(PyThread_create_key()) -# define PYBIND11_TLS_KEY_INIT(var) PYBIND11_TLS_KEY_REF var = 0; -# define PYBIND11_TLS_KEY_CREATE(var) (((var) = PyThread_create_key()) != -1) -# define PYBIND11_TLS_GET_VALUE(key) PyThread_get_key_value((key)) -# if defined(PYPY_VERSION) -// On CPython < 3.4 and on PyPy, `PyThread_set_key_value` strangely does not set -// the value if it has already been set. Instead, it must first be deleted and -// then set again. -inline void tls_replace_value(PYBIND11_TLS_KEY_REF key, void *value) { - PyThread_delete_key_value(key); - PyThread_set_key_value(key, value); -} -# define PYBIND11_TLS_DELETE_VALUE(key) PyThread_delete_key_value(key) -# define PYBIND11_TLS_REPLACE_VALUE(key, value) \ - ::pybind11::detail::tls_replace_value((key), (value)) -# else -# define PYBIND11_TLS_DELETE_VALUE(key) PyThread_set_key_value((key), nullptr) -# define PYBIND11_TLS_REPLACE_VALUE(key, value) PyThread_set_key_value((key), (value)) -# endif -# define PYBIND11_TLS_FREE(key) (void) key +# define PYBIND11_TLS_KEY_REF Py_tss_t * +# define PYBIND11_TLS_KEY_INIT(var) Py_tss_t *var = nullptr; +# define PYBIND11_TLS_KEY_CREATE(var) \ + (((var) = PyThread_tss_alloc()) != nullptr && (PyThread_tss_create((var)) == 0)) +# define PYBIND11_TLS_GET_VALUE(key) PyThread_tss_get((key)) +# define PYBIND11_TLS_REPLACE_VALUE(key, value) PyThread_tss_set((key), (value)) +# define PYBIND11_TLS_DELETE_VALUE(key) PyThread_tss_set((key), nullptr) +# define PYBIND11_TLS_FREE(key) PyThread_tss_free(key) #endif // Python loads modules by default with dlopen with the RTLD_LOCAL flag; under libc++ and possibly @@ -216,28 +192,27 @@ struct internals { PyTypeObject *static_property_type; PyTypeObject *default_metaclass; PyObject *instance_base; -#if defined(WITH_THREAD) // Unused if PYBIND11_SIMPLE_GIL_MANAGEMENT is defined: PYBIND11_TLS_KEY_INIT(tstate) -# if PYBIND11_INTERNALS_VERSION > 4 +#if PYBIND11_INTERNALS_VERSION > 4 PYBIND11_TLS_KEY_INIT(loader_life_support_tls_key) -# endif // PYBIND11_INTERNALS_VERSION > 4 +#endif // PYBIND11_INTERNALS_VERSION > 4 // Unused if PYBIND11_SIMPLE_GIL_MANAGEMENT is defined: PyInterpreterState *istate = nullptr; -# if PYBIND11_INTERNALS_VERSION > 4 +#if PYBIND11_INTERNALS_VERSION > 4 // Note that we have to use a std::string to allocate memory to ensure a unique address // We want unique addresses since we use pointer equality to compare function records std::string function_record_capsule_name = internals_function_record_capsule_name; -# endif +#endif internals() = default; internals(const internals &other) = delete; internals &operator=(const internals &other) = delete; ~internals() { -# if PYBIND11_INTERNALS_VERSION > 4 +#if PYBIND11_INTERNALS_VERSION > 4 PYBIND11_TLS_FREE(loader_life_support_tls_key); -# endif // PYBIND11_INTERNALS_VERSION > 4 +#endif // PYBIND11_INTERNALS_VERSION > 4 // This destructor is called *after* Py_Finalize() in finalize_interpreter(). // That *SHOULD BE* fine. The following details what happens when PyThread_tss_free is @@ -248,7 +223,6 @@ struct internals { // that the `tstate` be allocated with the CPython allocator. PYBIND11_TLS_FREE(tstate); } -#endif }; /// Additional type information which does not fit into the PyTypeObject. @@ -333,11 +307,7 @@ struct type_info { #endif #ifndef PYBIND11_INTERNALS_KIND -# if defined(WITH_THREAD) -# define PYBIND11_INTERNALS_KIND "" -# else -# define PYBIND11_INTERNALS_KIND "_without_thread" -# endif +# define PYBIND11_INTERNALS_KIND "" #endif #define PYBIND11_INTERNALS_ID \ @@ -520,10 +490,9 @@ PYBIND11_NOINLINE internals &get_internals() { return **internals_pp; } -#if defined(WITH_THREAD) -# if defined(PYBIND11_SIMPLE_GIL_MANAGEMENT) +#if defined(PYBIND11_SIMPLE_GIL_MANAGEMENT) gil_scoped_acquire gil; -# else +#else // Ensure that the GIL is held since we will need to make Python calls. // Cannot use py::gil_scoped_acquire here since that constructor calls get_internals. struct gil_scoped_acquire_local { @@ -533,7 +502,6 @@ PYBIND11_NOINLINE internals &get_internals() { ~gil_scoped_acquire_local() { PyGILState_Release(state); } const PyGILState_STATE state; } gil; -# endif #endif error_scope err_scope; @@ -558,7 +526,6 @@ PYBIND11_NOINLINE internals &get_internals() { } auto *&internals_ptr = *internals_pp; internals_ptr = new internals(); -#if defined(WITH_THREAD) PyThreadState *tstate = PyThreadState_Get(); // NOLINTNEXTLINE(bugprone-assignment-in-if-condition) @@ -567,15 +534,14 @@ PYBIND11_NOINLINE internals &get_internals() { } PYBIND11_TLS_REPLACE_VALUE(internals_ptr->tstate, tstate); -# if PYBIND11_INTERNALS_VERSION > 4 +#if PYBIND11_INTERNALS_VERSION > 4 // NOLINTNEXTLINE(bugprone-assignment-in-if-condition) if (!PYBIND11_TLS_KEY_CREATE(internals_ptr->loader_life_support_tls_key)) { pybind11_fail("get_internals: could not successfully initialize the " "loader_life_support TSS key!"); } -# endif - internals_ptr->istate = tstate->interp; #endif + internals_ptr->istate = tstate->interp; state_dict[PYBIND11_INTERNALS_ID] = capsule(internals_pp); internals_ptr->registered_exception_translators.push_front(&translate_exception); internals_ptr->static_property_type = make_static_property_type(); @@ -604,7 +570,7 @@ PYBIND11_NOINLINE internals &get_internals() { struct local_internals { type_map registered_types_cpp; std::forward_list registered_exception_translators; -#if defined(WITH_THREAD) && PYBIND11_INTERNALS_VERSION == 4 +#if PYBIND11_INTERNALS_VERSION == 4 // For ABI compatibility, we can't store the loader_life_support TLS key in // the `internals` struct directly. Instead, we store it in `shared_data` and @@ -637,7 +603,7 @@ struct local_internals { loader_life_support_tls_key = static_cast(ptr)->loader_life_support_tls_key; } -#endif // defined(WITH_THREAD) && PYBIND11_INTERNALS_VERSION == 4 +#endif // PYBIND11_INTERNALS_VERSION == 4 }; /// Works like `get_internals`, but for things which are locally registered. diff --git a/include/pybind11/detail/type_caster_base.h b/include/pybind11/detail/type_caster_base.h index 832d849bf..f6234c3d2 100644 --- a/include/pybind11/detail/type_caster_base.h +++ b/include/pybind11/detail/type_caster_base.h @@ -36,14 +36,13 @@ private: loader_life_support *parent = nullptr; std::unordered_set keep_alive; -#if defined(WITH_THREAD) // Store stack pointer in thread-local storage. static PYBIND11_TLS_KEY_REF get_stack_tls_key() { -# if PYBIND11_INTERNALS_VERSION == 4 +#if PYBIND11_INTERNALS_VERSION == 4 return get_local_internals().loader_life_support_tls_key; -# else +#else return get_internals().loader_life_support_tls_key; -# endif +#endif } static loader_life_support *get_stack_top() { return static_cast(PYBIND11_TLS_GET_VALUE(get_stack_tls_key())); @@ -51,15 +50,6 @@ private: static void set_stack_top(loader_life_support *value) { PYBIND11_TLS_REPLACE_VALUE(get_stack_tls_key(), value); } -#else - // Use single global variable for stack. - static loader_life_support **get_stack_pp() { - static loader_life_support *global_stack = nullptr; - return global_stack; - } - static loader_life_support *get_stack_top() { return *get_stack_pp(); } - static void set_stack_top(loader_life_support *value) { *get_stack_pp() = value; } -#endif public: /// A new patient frame is created when a function is entered diff --git a/include/pybind11/embed.h b/include/pybind11/embed.h index caa14f4a0..9d29eb824 100644 --- a/include/pybind11/embed.h +++ b/include/pybind11/embed.h @@ -103,9 +103,6 @@ inline void initialize_interpreter_pre_pyconfig(bool init_signal_handlers, bool add_program_dir_to_path) { detail::precheck_interpreter(); Py_InitializeEx(init_signal_handlers ? 1 : 0); -# if defined(WITH_THREAD) && PY_VERSION_HEX < 0x03070000 - PyEval_InitThreads(); -# endif // Before it was special-cased in python 3.8, passing an empty or null argv // caused a segfault, so we have to reimplement the special case ourselves. diff --git a/include/pybind11/gil.h b/include/pybind11/gil.h index da22f48d7..6b0edaee4 100644 --- a/include/pybind11/gil.h +++ b/include/pybind11/gil.h @@ -13,7 +13,7 @@ #include -#if defined(WITH_THREAD) && !defined(PYBIND11_SIMPLE_GIL_MANAGEMENT) +#if !defined(PYBIND11_SIMPLE_GIL_MANAGEMENT) # include "detail/internals.h" #endif @@ -26,9 +26,7 @@ PyThreadState *get_thread_state_unchecked(); PYBIND11_NAMESPACE_END(detail) -#if defined(WITH_THREAD) - -# if !defined(PYBIND11_SIMPLE_GIL_MANAGEMENT) +#if !defined(PYBIND11_SIMPLE_GIL_MANAGEMENT) /* The functions below essentially reproduce the PyGILState_* API using a RAII * pattern, but there are a few important differences: @@ -69,11 +67,11 @@ public: if (!tstate) { tstate = PyThreadState_New(internals.istate); -# if defined(PYBIND11_DETAILED_ERROR_MESSAGES) +# if defined(PYBIND11_DETAILED_ERROR_MESSAGES) if (!tstate) { pybind11_fail("scoped_acquire: could not create thread state!"); } -# endif +# endif tstate->gilstate_counter = 0; PYBIND11_TLS_REPLACE_VALUE(internals.tstate, tstate); } else { @@ -94,20 +92,20 @@ public: PYBIND11_NOINLINE void dec_ref() { --tstate->gilstate_counter; -# if defined(PYBIND11_DETAILED_ERROR_MESSAGES) +# if defined(PYBIND11_DETAILED_ERROR_MESSAGES) if (detail::get_thread_state_unchecked() != tstate) { pybind11_fail("scoped_acquire::dec_ref(): thread state must be current!"); } if (tstate->gilstate_counter < 0) { pybind11_fail("scoped_acquire::dec_ref(): reference count underflow!"); } -# endif +# endif if (tstate->gilstate_counter == 0) { -# if defined(PYBIND11_DETAILED_ERROR_MESSAGES) +# if defined(PYBIND11_DETAILED_ERROR_MESSAGES) if (!release) { pybind11_fail("scoped_acquire::dec_ref(): internal error!"); } -# endif +# endif PyThreadState_Clear(tstate); if (active) { PyThreadState_DeleteCurrent(); @@ -188,7 +186,7 @@ private: bool active = true; }; -# else // PYBIND11_SIMPLE_GIL_MANAGEMENT +#else // PYBIND11_SIMPLE_GIL_MANAGEMENT class gil_scoped_acquire { PyGILState_STATE state; @@ -216,32 +214,6 @@ public: void disarm() {} }; -# endif // PYBIND11_SIMPLE_GIL_MANAGEMENT - -#else // WITH_THREAD - -class gil_scoped_acquire { -public: - gil_scoped_acquire() { - // Trick to suppress `unused variable` error messages (at call sites). - (void) (this != (this + 1)); - } - gil_scoped_acquire(const gil_scoped_acquire &) = delete; - gil_scoped_acquire &operator=(const gil_scoped_acquire &) = delete; - void disarm() {} -}; - -class gil_scoped_release { -public: - gil_scoped_release() { - // Trick to suppress `unused variable` error messages (at call sites). - (void) (this != (this + 1)); - } - gil_scoped_release(const gil_scoped_release &) = delete; - gil_scoped_release &operator=(const gil_scoped_release &) = delete; - void disarm() {} -}; - -#endif // WITH_THREAD +#endif // PYBIND11_SIMPLE_GIL_MANAGEMENT PYBIND11_NAMESPACE_END(PYBIND11_NAMESPACE) diff --git a/include/pybind11/stl/filesystem.h b/include/pybind11/stl/filesystem.h index e26f42177..85c131efe 100644 --- a/include/pybind11/stl/filesystem.h +++ b/include/pybind11/stl/filesystem.h @@ -14,8 +14,7 @@ #ifdef __has_include # if defined(PYBIND11_CPP17) -# if __has_include() && \ - PY_VERSION_HEX >= 0x03060000 +# if __has_include() # include # define PYBIND11_HAS_FILESYSTEM 1 # elif __has_include() diff --git a/noxfile.py b/noxfile.py index 5fbf09685..be75def5d 100644 --- a/noxfile.py +++ b/noxfile.py @@ -1,3 +1,5 @@ +from __future__ import annotations + import argparse import nox diff --git a/pybind11/__init__.py b/pybind11/__init__.py index 7c10b3057..b14660cae 100644 --- a/pybind11/__init__.py +++ b/pybind11/__init__.py @@ -1,7 +1,9 @@ +from __future__ import annotations + import sys -if sys.version_info < (3, 6): # noqa: UP036 - msg = "pybind11 does not support Python < 3.6. 2.9 was the last release supporting Python 2.7 and 3.5." +if sys.version_info < (3, 7): # noqa: UP036 + msg = "pybind11 does not support Python < 3.7. v2.12 was the last release supporting Python 3.6." raise ImportError(msg) diff --git a/pybind11/__main__.py b/pybind11/__main__.py index 180665c23..b656ce6fe 100644 --- a/pybind11/__main__.py +++ b/pybind11/__main__.py @@ -1,4 +1,5 @@ # pylint: disable=missing-function-docstring +from __future__ import annotations import argparse import sys diff --git a/pybind11/_version.py b/pybind11/_version.py index 917edd74d..f71abbcdb 100644 --- a/pybind11/_version.py +++ b/pybind11/_version.py @@ -1,7 +1,7 @@ -from typing import Union +from __future__ import annotations -def _to_int(s: str) -> Union[int, str]: +def _to_int(s: str) -> int | str: try: return int(s) except ValueError: diff --git a/pybind11/commands.py b/pybind11/commands.py index b11690f46..d535b6cca 100644 --- a/pybind11/commands.py +++ b/pybind11/commands.py @@ -1,3 +1,5 @@ +from __future__ import annotations + import os DIR = os.path.abspath(os.path.dirname(__file__)) diff --git a/pybind11/setup_helpers.py b/pybind11/setup_helpers.py index 16ab76b28..ced506f8c 100644 --- a/pybind11/setup_helpers.py +++ b/pybind11/setup_helpers.py @@ -36,6 +36,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. # # If you copy this file in, you don't # need the .pyi file; it's just an interface file for static type checkers. +from __future__ import annotations import contextlib import os @@ -52,7 +53,6 @@ from pathlib import Path from typing import ( Any, Callable, - Dict, Iterable, Iterator, List, @@ -113,10 +113,10 @@ class Pybind11Extension(_Extension): # flags are prepended, so that they can be further overridden, e.g. by # ``extra_compile_args=["-g"]``. - def _add_cflags(self, flags: List[str]) -> None: + def _add_cflags(self, flags: list[str]) -> None: self.extra_compile_args[:0] = flags - def _add_ldflags(self, flags: List[str]) -> None: + def _add_ldflags(self, flags: list[str]) -> None: self.extra_link_args[:0] = flags def __init__(self, *args: Any, **kwargs: Any) -> None: @@ -250,7 +250,7 @@ cpp_flag_cache = None @lru_cache() -def auto_cpp_level(compiler: Any) -> Union[str, int]: +def auto_cpp_level(compiler: Any) -> str | int: """ Return the max supported C++ std level (17, 14, or 11). Returns latest on Windows. """ @@ -288,8 +288,8 @@ class build_ext(_build_ext): # noqa: N801 def intree_extensions( - paths: Iterable[str], package_dir: Optional[Dict[str, str]] = None -) -> List[Pybind11Extension]: + paths: Iterable[str], package_dir: dict[str, str] | None = None +) -> list[Pybind11Extension]: """ Generate Pybind11Extensions from source files directly located in a Python source tree. @@ -409,7 +409,7 @@ class ParallelCompile: def __init__( self, - envvar: Optional[str] = None, + envvar: str | None = None, default: int = 0, max: int = 0, # pylint: disable=redefined-builtin needs_recompile: Callable[[str, str], bool] = no_recompile, @@ -418,7 +418,7 @@ class ParallelCompile: self.default = default self.max = max self.needs_recompile = needs_recompile - self._old: List[CCompilerMethod] = [] + self._old: list[CCompilerMethod] = [] def function(self) -> CCompilerMethod: """ @@ -427,14 +427,14 @@ class ParallelCompile: def compile_function( compiler: distutils.ccompiler.CCompiler, - sources: List[str], - output_dir: Optional[str] = None, - macros: Optional[List[Union[Tuple[str], Tuple[str, Optional[str]]]]] = None, - include_dirs: Optional[List[str]] = None, + sources: list[str], + output_dir: str | None = None, + macros: list[tuple[str] | tuple[str, str | None]] | None = None, + include_dirs: list[str] | None = None, debug: bool = False, - extra_preargs: Optional[List[str]] = None, - extra_postargs: Optional[List[str]] = None, - depends: Optional[List[str]] = None, + extra_preargs: list[str] | None = None, + extra_postargs: list[str] | None = None, + depends: list[str] | None = None, ) -> Any: # These lines are directly from distutils.ccompiler.CCompiler macros, objects, extra_postargs, pp_opts, build = compiler._setup_compile( # type: ignore[attr-defined] diff --git a/pyproject.toml b/pyproject.toml index 1f011c2f4..71e7f5617 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -30,7 +30,7 @@ ignore_missing_imports = true [tool.pylint] -master.py-version = "3.6" +master.py-version = "3.7" reports.output-format = "colorized" messages_control.disable = [ "design", @@ -76,6 +76,8 @@ ignore = [ ] unfixable = ["T20"] isort.known-first-party = ["env", "pybind11_cross_module_tests", "pybind11_tests"] +isort.required-imports = ["from __future__ import annotations"] + [tool.ruff.lint.per-file-ignores] "tests/**" = ["EM", "N", "E721"] diff --git a/setup.cfg b/setup.cfg index 92e6c953a..79d75d0cd 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.6 Programming Language :: Python :: 3.7 Programming Language :: Python :: 3.8 Programming Language :: Python :: 3.9 @@ -39,5 +38,5 @@ project_urls = Chat = https://gitter.im/pybind/Lobby [options] -python_requires = >=3.6 +python_requires = >=3.7 zip_safe = False diff --git a/setup.py b/setup.py index 9fea7d35c..96563c1a5 100644 --- a/setup.py +++ b/setup.py @@ -1,6 +1,7 @@ #!/usr/bin/env python3 # Setup script for PyPI; use CMakeFile.txt to build extension modules +from __future__ import annotations import contextlib import os @@ -9,9 +10,9 @@ import shutil import string import subprocess import sys +from collections.abc import Generator from pathlib import Path from tempfile import TemporaryDirectory -from typing import Dict, Iterator, List, Union import setuptools.command.sdist @@ -23,7 +24,7 @@ VERSION_FILE = Path("pybind11/_version.py") COMMON_FILE = Path("include/pybind11/detail/common.h") -def build_expected_version_hex(matches: Dict[str, str]) -> str: +def build_expected_version_hex(matches: dict[str, str]) -> str: patch_level_serial = matches["PATCH"] serial = None major = int(matches["MAJOR"]) @@ -64,7 +65,7 @@ to_src = ( # Read the listed version -loc: 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__"] @@ -84,9 +85,7 @@ if version_hex != exp_version_hex: # TODO: use literals & overload (typing extensions or Python 3.8) -def get_and_replace( - filename: Path, binary: bool = False, **opts: str -) -> Union[bytes, str]: +def get_and_replace(filename: Path, binary: bool = False, **opts: str) -> bytes | str: if binary: contents = filename.read_bytes() return string.Template(contents.decode()).substitute(opts).encode() @@ -97,7 +96,7 @@ def get_and_replace( # Use our input files instead when making the SDist (and anything that depends # on it, like a wheel) class SDist(setuptools.command.sdist.sdist): - def make_release_tree(self, base_dir: str, files: List[str]) -> None: + def make_release_tree(self, base_dir: str, files: list[str]) -> None: super().make_release_tree(base_dir, files) for to, src in to_src: @@ -112,7 +111,7 @@ class SDist(setuptools.command.sdist.sdist): # Remove the CMake install directory when done @contextlib.contextmanager -def remove_output(*sources: str) -> Iterator[None]: +def remove_output(*sources: str) -> Generator[None, None, None]: try: yield finally: diff --git a/tests/conftest.py b/tests/conftest.py index 8ebc70222..7de6c2ace 100644 --- a/tests/conftest.py +++ b/tests/conftest.py @@ -4,6 +4,8 @@ Extends output capture as needed by pybind11: ignore constructors, optional unor Adds docstring and exceptions message sanitizers. """ +from __future__ import annotations + import contextlib import difflib import gc diff --git a/tests/env.py b/tests/env.py index 4c60f4bbe..9f5347f2e 100644 --- a/tests/env.py +++ b/tests/env.py @@ -1,3 +1,5 @@ +from __future__ import annotations + import platform import sys import sysconfig diff --git a/tests/extra_python_package/test_files.py b/tests/extra_python_package/test_files.py index 552a687db..5a3f779a7 100644 --- a/tests/extra_python_package/test_files.py +++ b/tests/extra_python_package/test_files.py @@ -1,3 +1,5 @@ +from __future__ import annotations + import contextlib import os import string diff --git a/tests/extra_setuptools/test_setuphelper.py b/tests/extra_setuptools/test_setuphelper.py index d5d3093bf..2c069adff 100644 --- a/tests/extra_setuptools/test_setuphelper.py +++ b/tests/extra_setuptools/test_setuphelper.py @@ -1,3 +1,5 @@ +from __future__ import annotations + import os import subprocess import sys diff --git a/tests/requirements.txt b/tests/requirements.txt index 53ad4b80b..337897bd2 100644 --- a/tests/requirements.txt +++ b/tests/requirements.txt @@ -1,10 +1,8 @@ --only-binary=:all: -build~=0.9; python_version=="3.6" build~=1.0; python_version>="3.7" numpy~=1.20.0; python_version=="3.7" and platform_python_implementation=="PyPy" numpy~=1.23.0; python_version=="3.8" and platform_python_implementation=="PyPy" numpy~=1.25.0; python_version=="3.9" and platform_python_implementation=='PyPy' -numpy~=1.19.3; platform_python_implementation!="PyPy" and 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" numpy~=1.26.0; platform_python_implementation!="PyPy" and python_version>="3.11" and python_version<"3.13" diff --git a/tests/test_async.py b/tests/test_async.py index 83a4c5036..4d33ba65f 100644 --- a/tests/test_async.py +++ b/tests/test_async.py @@ -1,3 +1,5 @@ +from __future__ import annotations + import pytest asyncio = pytest.importorskip("asyncio") diff --git a/tests/test_buffers.py b/tests/test_buffers.py index 5d33625ba..84a301e25 100644 --- a/tests/test_buffers.py +++ b/tests/test_buffers.py @@ -1,3 +1,5 @@ +from __future__ import annotations + import ctypes import io import struct diff --git a/tests/test_builtin_casters.py b/tests/test_builtin_casters.py index dbac1cbc2..9aa5926e9 100644 --- a/tests/test_builtin_casters.py +++ b/tests/test_builtin_casters.py @@ -1,3 +1,5 @@ +from __future__ import annotations + import sys import pytest diff --git a/tests/test_call_policies.cpp b/tests/test_call_policies.cpp index 279012d45..92924cb45 100644 --- a/tests/test_call_policies.cpp +++ b/tests/test_call_policies.cpp @@ -95,7 +95,7 @@ TEST_SUBMODULE(call_policies, m) { }, py::call_guard()); -#if defined(WITH_THREAD) && !defined(PYPY_VERSION) +#if !defined(PYPY_VERSION) // `py::call_guard()` should work in PyPy as well, // but it's unclear how to test it without `PyGILState_GetThisThreadState`. auto report_gil_status = []() { diff --git a/tests/test_call_policies.py b/tests/test_call_policies.py index 616056412..91670deb3 100644 --- a/tests/test_call_policies.py +++ b/tests/test_call_policies.py @@ -1,3 +1,5 @@ +from __future__ import annotations + import pytest import env # noqa: F401 diff --git a/tests/test_callbacks.py b/tests/test_callbacks.py index 86c767455..ce2a6d254 100644 --- a/tests/test_callbacks.py +++ b/tests/test_callbacks.py @@ -1,3 +1,5 @@ +from __future__ import annotations + import time from threading import Thread diff --git a/tests/test_chrono.py b/tests/test_chrono.py index a29316c38..ed889fbd6 100644 --- a/tests/test_chrono.py +++ b/tests/test_chrono.py @@ -1,3 +1,5 @@ +from __future__ import annotations + import datetime import pytest diff --git a/tests/test_class.py b/tests/test_class.py index edaa5b3ca..9b2b1d834 100644 --- a/tests/test_class.py +++ b/tests/test_class.py @@ -1,3 +1,5 @@ +from __future__ import annotations + from unittest import mock import pytest diff --git a/tests/test_cmake_build/test.py b/tests/test_cmake_build/test.py index 807fd43b4..bb4c20e0c 100644 --- a/tests/test_cmake_build/test.py +++ b/tests/test_cmake_build/test.py @@ -1,3 +1,5 @@ +from __future__ import annotations + import sys import test_cmake_build diff --git a/tests/test_const_name.py b/tests/test_const_name.py index a145f0bbb..f52024945 100644 --- a/tests/test_const_name.py +++ b/tests/test_const_name.py @@ -1,3 +1,5 @@ +from __future__ import annotations + import pytest from pybind11_tests import const_name as m diff --git a/tests/test_constants_and_functions.py b/tests/test_constants_and_functions.py index a1142461c..63004e1b6 100644 --- a/tests/test_constants_and_functions.py +++ b/tests/test_constants_and_functions.py @@ -1,3 +1,5 @@ +from __future__ import annotations + import pytest m = pytest.importorskip("pybind11_tests.constants_and_functions") diff --git a/tests/test_copy_move.py b/tests/test_copy_move.py index 9fef08933..405e00132 100644 --- a/tests/test_copy_move.py +++ b/tests/test_copy_move.py @@ -1,3 +1,5 @@ +from __future__ import annotations + import pytest from pybind11_tests import copy_move_policies as m diff --git a/tests/test_custom_type_casters.py b/tests/test_custom_type_casters.py index 3a00ea964..689b1e9cb 100644 --- a/tests/test_custom_type_casters.py +++ b/tests/test_custom_type_casters.py @@ -1,3 +1,5 @@ +from __future__ import annotations + import pytest from pybind11_tests import custom_type_casters as m diff --git a/tests/test_custom_type_setup.py b/tests/test_custom_type_setup.py index e63ff5758..56922c6dd 100644 --- a/tests/test_custom_type_setup.py +++ b/tests/test_custom_type_setup.py @@ -1,3 +1,5 @@ +from __future__ import annotations + import gc import weakref diff --git a/tests/test_docstring_options.py b/tests/test_docstring_options.py index e6f5a9d98..09fc8ac25 100644 --- a/tests/test_docstring_options.py +++ b/tests/test_docstring_options.py @@ -1,3 +1,5 @@ +from __future__ import annotations + from pybind11_tests import docstring_options as m diff --git a/tests/test_eigen_matrix.py b/tests/test_eigen_matrix.py index 9a2cafc0a..e1d7433f1 100644 --- a/tests/test_eigen_matrix.py +++ b/tests/test_eigen_matrix.py @@ -1,3 +1,5 @@ +from __future__ import annotations + import pytest from pybind11_tests import ConstructorStats diff --git a/tests/test_eigen_tensor.py b/tests/test_eigen_tensor.py index 3e7ee6b7f..a2b99d9d7 100644 --- a/tests/test_eigen_tensor.py +++ b/tests/test_eigen_tensor.py @@ -1,3 +1,5 @@ +from __future__ import annotations + import sys import pytest diff --git a/tests/test_embed/test_interpreter.py b/tests/test_embed/test_interpreter.py index f27944972..424d36dea 100644 --- a/tests/test_embed/test_interpreter.py +++ b/tests/test_embed/test_interpreter.py @@ -1,3 +1,5 @@ +from __future__ import annotations + import sys from widget_module import Widget diff --git a/tests/test_embed/test_trampoline.py b/tests/test_embed/test_trampoline.py index 8e14e8ef0..b8ff3eba2 100644 --- a/tests/test_embed/test_trampoline.py +++ b/tests/test_embed/test_trampoline.py @@ -1,3 +1,5 @@ +from __future__ import annotations + import trampoline_module diff --git a/tests/test_enum.py b/tests/test_enum.py index 6b75b7ae5..9914b9001 100644 --- a/tests/test_enum.py +++ b/tests/test_enum.py @@ -1,4 +1,5 @@ # ruff: noqa: SIM201 SIM300 SIM202 +from __future__ import annotations import pytest diff --git a/tests/test_eval.py b/tests/test_eval.py index 51b6b796b..45b68ece7 100644 --- a/tests/test_eval.py +++ b/tests/test_eval.py @@ -1,3 +1,5 @@ +from __future__ import annotations + import os import pytest diff --git a/tests/test_eval_call.py b/tests/test_eval_call.py index fd1da2a5c..a677249d4 100644 --- a/tests/test_eval_call.py +++ b/tests/test_eval_call.py @@ -1,4 +1,5 @@ # This file is called from 'test_eval.py' +from __future__ import annotations if "call_test2" in locals(): call_test2(y) # noqa: F821 undefined name diff --git a/tests/test_exceptions.py b/tests/test_exceptions.py index 01fcb918e..b33997eee 100644 --- a/tests/test_exceptions.py +++ b/tests/test_exceptions.py @@ -1,3 +1,5 @@ +from __future__ import annotations + import sys import pytest diff --git a/tests/test_factory_constructors.py b/tests/test_factory_constructors.py index a9004cbf6..0ddad5e32 100644 --- a/tests/test_factory_constructors.py +++ b/tests/test_factory_constructors.py @@ -1,3 +1,5 @@ +from __future__ import annotations + import re import pytest diff --git a/tests/test_gil_scoped.py b/tests/test_gil_scoped.py index fc8af9b77..a18387684 100644 --- a/tests/test_gil_scoped.py +++ b/tests/test_gil_scoped.py @@ -1,3 +1,5 @@ +from __future__ import annotations + import multiprocessing import sys import threading diff --git a/tests/test_iostream.py b/tests/test_iostream.py index 871269a92..f7eeff502 100644 --- a/tests/test_iostream.py +++ b/tests/test_iostream.py @@ -1,3 +1,5 @@ +from __future__ import annotations + from contextlib import redirect_stderr, redirect_stdout from io import StringIO diff --git a/tests/test_kwargs_and_defaults.py b/tests/test_kwargs_and_defaults.py index d7bc7379b..b9b1a7ea8 100644 --- a/tests/test_kwargs_and_defaults.py +++ b/tests/test_kwargs_and_defaults.py @@ -1,3 +1,5 @@ +from __future__ import annotations + import pytest from pybind11_tests import kwargs_and_defaults as m diff --git a/tests/test_local_bindings.py b/tests/test_local_bindings.py index d64187739..1e83164c7 100644 --- a/tests/test_local_bindings.py +++ b/tests/test_local_bindings.py @@ -1,3 +1,5 @@ +from __future__ import annotations + import pytest import env # noqa: F401 diff --git a/tests/test_methods_and_attributes.py b/tests/test_methods_and_attributes.py index 7fdf4e3af..dfa31f546 100644 --- a/tests/test_methods_and_attributes.py +++ b/tests/test_methods_and_attributes.py @@ -1,3 +1,5 @@ +from __future__ import annotations + import sys import pytest diff --git a/tests/test_modules.py b/tests/test_modules.py index 2f6d825b7..95835e14e 100644 --- a/tests/test_modules.py +++ b/tests/test_modules.py @@ -1,3 +1,5 @@ +from __future__ import annotations + import builtins import pytest diff --git a/tests/test_multiple_inheritance.py b/tests/test_multiple_inheritance.py index 3a1d88d71..d445824b5 100644 --- a/tests/test_multiple_inheritance.py +++ b/tests/test_multiple_inheritance.py @@ -1,3 +1,5 @@ +from __future__ import annotations + import pytest import env # noqa: F401 diff --git a/tests/test_numpy_array.py b/tests/test_numpy_array.py index 25ad09ec3..4726a8e73 100644 --- a/tests/test_numpy_array.py +++ b/tests/test_numpy_array.py @@ -1,3 +1,5 @@ +from __future__ import annotations + import pytest import env # noqa: F401 @@ -198,11 +200,7 @@ 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 - # 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 + assert a.flags.writebackifcopy == b.flags.writebackifcopy assert np.all(a == b) assert not b.flags.owndata assert b.base is base diff --git a/tests/test_numpy_dtypes.py b/tests/test_numpy_dtypes.py index 790f63641..8ae239ed8 100644 --- a/tests/test_numpy_dtypes.py +++ b/tests/test_numpy_dtypes.py @@ -1,3 +1,5 @@ +from __future__ import annotations + import re import pytest diff --git a/tests/test_numpy_vectorize.py b/tests/test_numpy_vectorize.py index f1e8b6254..ce38d72d9 100644 --- a/tests/test_numpy_vectorize.py +++ b/tests/test_numpy_vectorize.py @@ -1,3 +1,5 @@ +from __future__ import annotations + import pytest from pybind11_tests import numpy_vectorize as m diff --git a/tests/test_opaque_types.py b/tests/test_opaque_types.py index 5d4f2a1bf..342086436 100644 --- a/tests/test_opaque_types.py +++ b/tests/test_opaque_types.py @@ -1,3 +1,5 @@ +from __future__ import annotations + import pytest from pybind11_tests import ConstructorStats, UserType diff --git a/tests/test_operator_overloading.py b/tests/test_operator_overloading.py index 9fde305a0..b6760902d 100644 --- a/tests/test_operator_overloading.py +++ b/tests/test_operator_overloading.py @@ -1,3 +1,5 @@ +from __future__ import annotations + import pytest from pybind11_tests import ConstructorStats diff --git a/tests/test_pickling.py b/tests/test_pickling.py index 12361a661..ad67a1df9 100644 --- a/tests/test_pickling.py +++ b/tests/test_pickling.py @@ -1,3 +1,5 @@ +from __future__ import annotations + import pickle import re diff --git a/tests/test_python_multiple_inheritance.py b/tests/test_python_multiple_inheritance.py index 3bddd67df..12216283a 100644 --- a/tests/test_python_multiple_inheritance.py +++ b/tests/test_python_multiple_inheritance.py @@ -1,5 +1,6 @@ # Adapted from: # https://github.com/google/clif/blob/5718e4d0807fd3b6a8187dde140069120b81ecef/clif/testing/python/python_multiple_inheritance_test.py +from __future__ import annotations from pybind11_tests import python_multiple_inheritance as m diff --git a/tests/test_pytypes.py b/tests/test_pytypes.py index 72dac13b8..8e35c7073 100644 --- a/tests/test_pytypes.py +++ b/tests/test_pytypes.py @@ -1,3 +1,5 @@ +from __future__ import annotations + import contextlib import sys import types diff --git a/tests/test_sequences_and_iterators.py b/tests/test_sequences_and_iterators.py index c13f03dd8..f609f553d 100644 --- a/tests/test_sequences_and_iterators.py +++ b/tests/test_sequences_and_iterators.py @@ -1,3 +1,5 @@ +from __future__ import annotations + import pytest from pytest import approx # noqa: PT013 diff --git a/tests/test_smart_ptr.py b/tests/test_smart_ptr.py index 2f204e01b..bf0ae4aeb 100644 --- a/tests/test_smart_ptr.py +++ b/tests/test_smart_ptr.py @@ -1,3 +1,5 @@ +from __future__ import annotations + import pytest m = pytest.importorskip("pybind11_tests.smart_ptr") diff --git a/tests/test_stl.py b/tests/test_stl.py index b08bd4680..65fda54cc 100644 --- a/tests/test_stl.py +++ b/tests/test_stl.py @@ -1,3 +1,5 @@ +from __future__ import annotations + import pytest from pybind11_tests import ConstructorStats, UserType diff --git a/tests/test_stl_binders.py b/tests/test_stl_binders.py index d1bf64aa0..09e784e2e 100644 --- a/tests/test_stl_binders.py +++ b/tests/test_stl_binders.py @@ -1,3 +1,5 @@ +from __future__ import annotations + import pytest from pybind11_tests import stl_binders as m diff --git a/tests/test_tagbased_polymorphic.py b/tests/test_tagbased_polymorphic.py index 84f0ea717..dabf307cf 100644 --- a/tests/test_tagbased_polymorphic.py +++ b/tests/test_tagbased_polymorphic.py @@ -1,3 +1,5 @@ +from __future__ import annotations + from pybind11_tests import tagbased_polymorphic as m diff --git a/tests/test_thread.py b/tests/test_thread.py index e89991f9d..4541a305e 100644 --- a/tests/test_thread.py +++ b/tests/test_thread.py @@ -1,3 +1,5 @@ +from __future__ import annotations + import threading from pybind11_tests import thread as m diff --git a/tests/test_type_caster_pyobject_ptr.py b/tests/test_type_caster_pyobject_ptr.py index f6358d011..ebc24e318 100644 --- a/tests/test_type_caster_pyobject_ptr.py +++ b/tests/test_type_caster_pyobject_ptr.py @@ -1,3 +1,5 @@ +from __future__ import annotations + import pytest from pybind11_tests import type_caster_pyobject_ptr as m diff --git a/tests/test_union.py b/tests/test_union.py index e1866e701..a9de6baf1 100644 --- a/tests/test_union.py +++ b/tests/test_union.py @@ -1,3 +1,5 @@ +from __future__ import annotations + from pybind11_tests import union_ as m diff --git a/tests/test_unnamed_namespace_a.py b/tests/test_unnamed_namespace_a.py index 9d9856c5a..0fa1fa323 100644 --- a/tests/test_unnamed_namespace_a.py +++ b/tests/test_unnamed_namespace_a.py @@ -1,3 +1,5 @@ +from __future__ import annotations + import pytest from pybind11_tests import unnamed_namespace_a as m diff --git a/tests/test_unnamed_namespace_b.py b/tests/test_unnamed_namespace_b.py index 4bcaa7a6c..9e5732822 100644 --- a/tests/test_unnamed_namespace_b.py +++ b/tests/test_unnamed_namespace_b.py @@ -1,3 +1,5 @@ +from __future__ import annotations + from pybind11_tests import unnamed_namespace_b as m diff --git a/tests/test_vector_unique_ptr_member.py b/tests/test_vector_unique_ptr_member.py index 2da3d97c3..969c1a5d6 100644 --- a/tests/test_vector_unique_ptr_member.py +++ b/tests/test_vector_unique_ptr_member.py @@ -1,3 +1,5 @@ +from __future__ import annotations + import pytest from pybind11_tests import vector_unique_ptr_member as m diff --git a/tests/test_virtual_functions.py b/tests/test_virtual_functions.py index c17af7df5..08acaa190 100644 --- a/tests/test_virtual_functions.py +++ b/tests/test_virtual_functions.py @@ -1,3 +1,5 @@ +from __future__ import annotations + import pytest import env # noqa: F401 diff --git a/tools/FindPythonLibsNew.cmake b/tools/FindPythonLibsNew.cmake index 0640a1915..283b4e298 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.6") + set(PythonLibsNew_FIND_VERSION "3.7") endif() if(NOT CMAKE_VERSION VERSION_LESS "3.27") diff --git a/tools/codespell_ignore_lines_from_errors.py b/tools/codespell_ignore_lines_from_errors.py index 4ec9add12..08ced3d4e 100644 --- a/tools/codespell_ignore_lines_from_errors.py +++ b/tools/codespell_ignore_lines_from_errors.py @@ -9,11 +9,12 @@ python3 tools/codespell_ignore_lines_from_errors.py /tmp/codespell_errors.txt > git diff to review changes, then commit, push. """ +from __future__ import annotations + import sys -from typing import List -def run(args: List[str]) -> None: +def run(args: list[str]) -> None: assert len(args) == 1, "codespell_errors.txt" cache = {} done = set() diff --git a/tools/libsize.py b/tools/libsize.py index 1ac9afbe8..ef5fb13c2 100644 --- a/tools/libsize.py +++ b/tools/libsize.py @@ -1,3 +1,5 @@ +from __future__ import annotations + import os import sys diff --git a/tools/pybind11NewTools.cmake b/tools/pybind11NewTools.cmake index f2ec34756..a8b0800bb 100644 --- a/tools/pybind11NewTools.cmake +++ b/tools/pybind11NewTools.cmake @@ -56,7 +56,7 @@ if(NOT Python_FOUND AND NOT Python3_FOUND) endif() find_package( - Python 3.6 REQUIRED COMPONENTS ${_pybind11_interp_component} ${_pybind11_dev_component} + Python 3.7 REQUIRED COMPONENTS ${_pybind11_interp_component} ${_pybind11_dev_component} ${_pybind11_quiet} ${_pybind11_global_keyword}) # If we are in submodule mode, export the Python targets to global targets. diff --git a/tools/pybind11Tools.cmake b/tools/pybind11Tools.cmake index 045e5f1e7..bed5e0803 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.12;3.11;3.10;3.9;3.8;3.7;3.6" + "3.12;3.11;3.10;3.9;3.8;3.7" CACHE INTERNAL "") list(APPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_LIST_DIR}")