feat: remove Python 3.6 support (#5177)

* 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 bbcd0087b2.

* 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 <henryschreineriii@gmail.com>

* Update tests/test_numpy_array.py

* Update test_numpy_array.py

---------

Signed-off-by: Henry Schreiner <henryschreineriii@gmail.com>
Co-authored-by: Henry Schreiner <henryschreineriii@gmail.com>
This commit is contained in:
Ralf W. Grosse-Kunstleve 2024-06-21 21:55:00 -07:00 committed by GitHub
parent 5552cbf205
commit f1a2e03d19
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
84 changed files with 238 additions and 219 deletions

View File

@ -9,7 +9,7 @@ platform:
- x86 - x86
environment: environment:
matrix: matrix:
- PYTHON: 36 - PYTHON: 38
CONFIG: Debug CONFIG: Debug
install: install:
- ps: | - ps: |

View File

@ -32,7 +32,7 @@ jobs:
matrix: matrix:
runs-on: [ubuntu-20.04, windows-2022, macos-13] runs-on: [ubuntu-20.04, windows-2022, macos-13]
python: python:
- '3.6' - '3.8'
- '3.9' - '3.9'
- '3.12' - '3.12'
- '3.13' - '3.13'
@ -48,16 +48,17 @@ jobs:
include: include:
# Just add a key # Just add a key
- runs-on: ubuntu-20.04 - runs-on: ubuntu-20.04
python: '3.6' python: '3.8'
args: > args: >
-DPYBIND11_FINDPYTHON=ON -DPYBIND11_FINDPYTHON=ON
-DCMAKE_CXX_FLAGS="-D_=1" -DCMAKE_CXX_FLAGS="-D_=1"
exercise_D_: 1
- runs-on: ubuntu-20.04 - runs-on: ubuntu-20.04
python: 'pypy-3.8' python: 'pypy-3.8'
args: > args: >
-DPYBIND11_FINDPYTHON=ON -DPYBIND11_FINDPYTHON=ON
- runs-on: windows-2019 - runs-on: windows-2019
python: '3.6' python: '3.8'
args: > args: >
-DPYBIND11_FINDPYTHON=ON -DPYBIND11_FINDPYTHON=ON
# Inject a couple Windows 2019 runs # Inject a couple Windows 2019 runs
@ -82,7 +83,7 @@ jobs:
- name: Setup Boost (Linux) - name: Setup Boost (Linux)
# Can't use boost + define _ # 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 run: sudo apt-get install libboost-dev
- name: Setup Boost (macOS) - name: Setup Boost (macOS)
@ -655,15 +656,13 @@ jobs:
cmake --build build-17 --target test_cmake_build cmake --build build-17 --target test_cmake_build
# Testing on CentOS (manylinux uses a centos base, and this is an easy way # Testing on CentOS (manylinux uses a centos base).
# to get GCC 4.8, which is the manylinux1 compiler).
centos: centos:
runs-on: ubuntu-latest runs-on: ubuntu-latest
strategy: strategy:
fail-fast: false fail-fast: false
matrix: matrix:
container: container:
- "centos:7" # GCC 4.8
- "almalinux:8" - "almalinux:8"
- "almalinux:9" - "almalinux:9"
@ -673,18 +672,13 @@ jobs:
steps: steps:
- name: Latest actions/checkout - name: Latest actions/checkout
uses: actions/checkout@v4 uses: actions/checkout@v4
if: matrix.container != 'centos:7'
- name: Pin actions/checkout as required for centos:7 - name: Add Python 3.8
uses: actions/checkout@v3 if: matrix.container == 'almalinux:8'
if: matrix.container == 'centos:7' run: dnf update -y && dnf install -y python38-devel gcc-c++ make git
- name: Add Python 3 (RHEL 7) - name: Add Python 3 (default)
if: matrix.container == 'centos:7' if: matrix.container != 'almalinux:8'
run: yum update -y && yum install -y python3-devel gcc-c++ make git
- name: Add Python 3 (RHEL 8+)
if: matrix.container != 'centos:7'
run: dnf update -y && dnf install -y python3-devel gcc-c++ make git run: dnf update -y && dnf install -y python3-devel gcc-c++ make git
- name: Update pip - name: Update pip
@ -807,7 +801,6 @@ jobs:
fail-fast: false fail-fast: false
matrix: matrix:
python: python:
- '3.6'
- '3.7' - '3.7'
- '3.8' - '3.8'
- '3.9' - '3.9'

View File

@ -21,19 +21,18 @@ env:
jobs: jobs:
# This builds the sdists and wheels and makes sure the files are exactly as # 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 # expected.
# challenging matrix element.
test-packaging: test-packaging:
name: 🐍 3.6 • 📦 tests • windows-latest name: 🐍 3.8 • 📦 tests • windows-latest
runs-on: windows-latest runs-on: windows-latest
steps: steps:
- uses: actions/checkout@v4 - uses: actions/checkout@v4
- name: Setup 🐍 3.6 - name: Setup 🐍 3.8
uses: actions/setup-python@v5 uses: actions/setup-python@v5
with: with:
python-version: 3.6 python-version: 3.8
- name: Prepare env - name: Prepare env
run: | run: |

View File

@ -34,7 +34,7 @@ dependency.
Think of this library as a tiny self-contained version of Boost.Python 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 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 standard library. This compact implementation was possible thanks to
some C++11 language features (specifically: tuples, lambda functions and some C++11 language features (specifically: tuples, lambda functions and
variadic templates). Since its creation, this library has grown beyond 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 In addition to the core functionality, pybind11 provides some extra
goodies: 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). 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 - It is possible to bind C++11 lambda functions with captured

View File

@ -1,3 +1,5 @@
from __future__ import annotations
import datetime as dt import datetime as dt
import os import os
import random import random

View File

@ -426,7 +426,7 @@ with ``PYTHON_EXECUTABLE``. For example:
.. code-block:: bash .. code-block:: bash
cmake -DPYBIND11_PYTHON_VERSION=3.6 .. cmake -DPYBIND11_PYTHON_VERSION=3.7 ..
# Another method: # Another method:
cmake -DPYTHON_EXECUTABLE=/path/to/python .. cmake -DPYTHON_EXECUTABLE=/path/to/python ..
@ -493,7 +493,7 @@ existing targets instead:
cmake_minimum_required(VERSION 3.15...3.22) cmake_minimum_required(VERSION 3.15...3.22)
project(example LANGUAGES CXX) 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) find_package(pybind11 CONFIG REQUIRED)
# or add_subdirectory(pybind11) # or add_subdirectory(pybind11)

View File

@ -11,6 +11,7 @@
# #
# All configuration values have a default; values that are commented out # All configuration values have a default; values that are commented out
# serve to show the default. # serve to show the default.
from __future__ import annotations
import os import os
import re import re

View File

@ -567,16 +567,8 @@ inline void enable_dynamic_attributes(PyHeapTypeObject *heap_type) {
type->tp_traverse = pybind11_traverse; type->tp_traverse = pybind11_traverse;
type->tp_clear = pybind11_clear; type->tp_clear = pybind11_clear;
static PyGetSetDef getset[] = {{ static PyGetSetDef getset[]
#if PY_VERSION_HEX < 0x03070000 = {{"__dict__", PyObject_GenericGetDict, PyObject_GenericSetDict, nullptr, nullptr},
const_cast<char *>("__dict__"),
#else
"__dict__",
#endif
PyObject_GenericGetDict,
PyObject_GenericSetDict,
nullptr,
nullptr},
{nullptr, nullptr, nullptr, nullptr, nullptr}}; {nullptr, nullptr, nullptr, nullptr, nullptr}};
type->tp_getset = getset; type->tp_getset = getset;
} }

View File

@ -272,9 +272,8 @@ PYBIND11_WARNING_DISABLE_MSVC(4505)
#endif #endif
#include <Python.h> #include <Python.h>
// Reminder: WITH_THREAD is always defined if PY_VERSION_HEX >= 0x03070000 #if PY_VERSION_HEX < 0x03070000
#if PY_VERSION_HEX < 0x03060000 # error "PYTHON < 3.7 IS UNSUPPORTED. pybind11 v2.12 was the last to support Python 3.6."
# error "PYTHON < 3.6 IS UNSUPPORTED. pybind11 v2.9 was the last to support Python 2 and 3.5."
#endif #endif
#include <frameobject.h> #include <frameobject.h>
#include <pythread.h> #include <pythread.h>

View File

@ -11,7 +11,7 @@
#include "common.h" #include "common.h"
#if defined(WITH_THREAD) && defined(PYBIND11_SIMPLE_GIL_MANAGEMENT) #if defined(PYBIND11_SIMPLE_GIL_MANAGEMENT)
# include "../gil.h" # include "../gil.h"
#endif #endif
@ -64,7 +64,6 @@ 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 // The old Python Thread Local Storage (TLS) API is deprecated in Python 3.7 in favor of the new
// Thread Specific Storage (TSS) API. // Thread Specific Storage (TSS) API.
#if PY_VERSION_HEX >= 0x03070000
// Avoid unnecessary allocation of `Py_tss_t`, since we cannot use // Avoid unnecessary allocation of `Py_tss_t`, since we cannot use
// `Py_LIMITED_API` anyway. // `Py_LIMITED_API` anyway.
#if PYBIND11_INTERNALS_VERSION > 4 #if PYBIND11_INTERNALS_VERSION > 4
@ -101,29 +100,6 @@ inline PyObject *make_object_base_type(PyTypeObject *metaclass);
# define PYBIND11_TLS_DELETE_VALUE(key) PyThread_tss_set((key), nullptr) # define PYBIND11_TLS_DELETE_VALUE(key) PyThread_tss_set((key), nullptr)
# define PYBIND11_TLS_FREE(key) PyThread_tss_free(key) # define PYBIND11_TLS_FREE(key) PyThread_tss_free(key)
#endif #endif
#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
#endif
// Python loads modules by default with dlopen with the RTLD_LOCAL flag; under libc++ and possibly // Python loads modules by default with dlopen with the RTLD_LOCAL flag; under libc++ and possibly
// other STLs, this means `typeid(A)` from one module won't equal `typeid(A)` from another module // other STLs, this means `typeid(A)` from one module won't equal `typeid(A)` from another module
@ -216,7 +192,6 @@ struct internals {
PyTypeObject *static_property_type; PyTypeObject *static_property_type;
PyTypeObject *default_metaclass; PyTypeObject *default_metaclass;
PyObject *instance_base; PyObject *instance_base;
#if defined(WITH_THREAD)
// Unused if PYBIND11_SIMPLE_GIL_MANAGEMENT is defined: // Unused if PYBIND11_SIMPLE_GIL_MANAGEMENT is defined:
PYBIND11_TLS_KEY_INIT(tstate) PYBIND11_TLS_KEY_INIT(tstate)
#if PYBIND11_INTERNALS_VERSION > 4 #if PYBIND11_INTERNALS_VERSION > 4
@ -248,7 +223,6 @@ struct internals {
// that the `tstate` be allocated with the CPython allocator. // that the `tstate` be allocated with the CPython allocator.
PYBIND11_TLS_FREE(tstate); PYBIND11_TLS_FREE(tstate);
} }
#endif
}; };
/// Additional type information which does not fit into the PyTypeObject. /// Additional type information which does not fit into the PyTypeObject.
@ -333,11 +307,7 @@ struct type_info {
#endif #endif
#ifndef PYBIND11_INTERNALS_KIND #ifndef PYBIND11_INTERNALS_KIND
# if defined(WITH_THREAD)
# define PYBIND11_INTERNALS_KIND "" # define PYBIND11_INTERNALS_KIND ""
# else
# define PYBIND11_INTERNALS_KIND "_without_thread"
# endif
#endif #endif
#define PYBIND11_INTERNALS_ID \ #define PYBIND11_INTERNALS_ID \
@ -520,7 +490,6 @@ PYBIND11_NOINLINE internals &get_internals() {
return **internals_pp; return **internals_pp;
} }
#if defined(WITH_THREAD)
#if defined(PYBIND11_SIMPLE_GIL_MANAGEMENT) #if defined(PYBIND11_SIMPLE_GIL_MANAGEMENT)
gil_scoped_acquire gil; gil_scoped_acquire gil;
#else #else
@ -533,7 +502,6 @@ PYBIND11_NOINLINE internals &get_internals() {
~gil_scoped_acquire_local() { PyGILState_Release(state); } ~gil_scoped_acquire_local() { PyGILState_Release(state); }
const PyGILState_STATE state; const PyGILState_STATE state;
} gil; } gil;
# endif
#endif #endif
error_scope err_scope; error_scope err_scope;
@ -558,7 +526,6 @@ PYBIND11_NOINLINE internals &get_internals() {
} }
auto *&internals_ptr = *internals_pp; auto *&internals_ptr = *internals_pp;
internals_ptr = new internals(); internals_ptr = new internals();
#if defined(WITH_THREAD)
PyThreadState *tstate = PyThreadState_Get(); PyThreadState *tstate = PyThreadState_Get();
// NOLINTNEXTLINE(bugprone-assignment-in-if-condition) // NOLINTNEXTLINE(bugprone-assignment-in-if-condition)
@ -575,7 +542,6 @@ PYBIND11_NOINLINE internals &get_internals() {
} }
#endif #endif
internals_ptr->istate = tstate->interp; internals_ptr->istate = tstate->interp;
#endif
state_dict[PYBIND11_INTERNALS_ID] = capsule(internals_pp); state_dict[PYBIND11_INTERNALS_ID] = capsule(internals_pp);
internals_ptr->registered_exception_translators.push_front(&translate_exception); internals_ptr->registered_exception_translators.push_front(&translate_exception);
internals_ptr->static_property_type = make_static_property_type(); internals_ptr->static_property_type = make_static_property_type();
@ -604,7 +570,7 @@ PYBIND11_NOINLINE internals &get_internals() {
struct local_internals { struct local_internals {
type_map<type_info *> registered_types_cpp; type_map<type_info *> registered_types_cpp;
std::forward_list<ExceptionTranslator> registered_exception_translators; std::forward_list<ExceptionTranslator> 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 // 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 // the `internals` struct directly. Instead, we store it in `shared_data` and
@ -637,7 +603,7 @@ struct local_internals {
loader_life_support_tls_key loader_life_support_tls_key
= static_cast<shared_loader_life_support_data *>(ptr)->loader_life_support_tls_key; = static_cast<shared_loader_life_support_data *>(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. /// Works like `get_internals`, but for things which are locally registered.

View File

@ -36,7 +36,6 @@ private:
loader_life_support *parent = nullptr; loader_life_support *parent = nullptr;
std::unordered_set<PyObject *> keep_alive; std::unordered_set<PyObject *> keep_alive;
#if defined(WITH_THREAD)
// Store stack pointer in thread-local storage. // Store stack pointer in thread-local storage.
static PYBIND11_TLS_KEY_REF get_stack_tls_key() { static PYBIND11_TLS_KEY_REF get_stack_tls_key() {
#if PYBIND11_INTERNALS_VERSION == 4 #if PYBIND11_INTERNALS_VERSION == 4
@ -51,15 +50,6 @@ private:
static void set_stack_top(loader_life_support *value) { static void set_stack_top(loader_life_support *value) {
PYBIND11_TLS_REPLACE_VALUE(get_stack_tls_key(), 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: public:
/// A new patient frame is created when a function is entered /// A new patient frame is created when a function is entered

View File

@ -103,9 +103,6 @@ inline void initialize_interpreter_pre_pyconfig(bool init_signal_handlers,
bool add_program_dir_to_path) { bool add_program_dir_to_path) {
detail::precheck_interpreter(); detail::precheck_interpreter();
Py_InitializeEx(init_signal_handlers ? 1 : 0); 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 // 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. // caused a segfault, so we have to reimplement the special case ourselves.

View File

@ -13,7 +13,7 @@
#include <cassert> #include <cassert>
#if defined(WITH_THREAD) && !defined(PYBIND11_SIMPLE_GIL_MANAGEMENT) #if !defined(PYBIND11_SIMPLE_GIL_MANAGEMENT)
# include "detail/internals.h" # include "detail/internals.h"
#endif #endif
@ -26,8 +26,6 @@ PyThreadState *get_thread_state_unchecked();
PYBIND11_NAMESPACE_END(detail) 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 /* The functions below essentially reproduce the PyGILState_* API using a RAII
@ -218,30 +216,4 @@ public:
#endif // PYBIND11_SIMPLE_GIL_MANAGEMENT #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
PYBIND11_NAMESPACE_END(PYBIND11_NAMESPACE) PYBIND11_NAMESPACE_END(PYBIND11_NAMESPACE)

View File

@ -14,8 +14,7 @@
#ifdef __has_include #ifdef __has_include
# if defined(PYBIND11_CPP17) # if defined(PYBIND11_CPP17)
# if __has_include(<filesystem>) && \ # if __has_include(<filesystem>)
PY_VERSION_HEX >= 0x03060000
# include <filesystem> # include <filesystem>
# define PYBIND11_HAS_FILESYSTEM 1 # define PYBIND11_HAS_FILESYSTEM 1
# elif __has_include(<experimental/filesystem>) # elif __has_include(<experimental/filesystem>)

View File

@ -1,3 +1,5 @@
from __future__ import annotations
import argparse import argparse
import nox import nox

View File

@ -1,7 +1,9 @@
from __future__ import annotations
import sys import sys
if sys.version_info < (3, 6): # noqa: UP036 if sys.version_info < (3, 7): # noqa: UP036
msg = "pybind11 does not support Python < 3.6. 2.9 was the last release supporting Python 2.7 and 3.5." msg = "pybind11 does not support Python < 3.7. v2.12 was the last release supporting Python 3.6."
raise ImportError(msg) raise ImportError(msg)

View File

@ -1,4 +1,5 @@
# pylint: disable=missing-function-docstring # pylint: disable=missing-function-docstring
from __future__ import annotations
import argparse import argparse
import sys import sys

View File

@ -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: try:
return int(s) return int(s)
except ValueError: except ValueError:

View File

@ -1,3 +1,5 @@
from __future__ import annotations
import os import os
DIR = os.path.abspath(os.path.dirname(__file__)) DIR = os.path.abspath(os.path.dirname(__file__))

View File

@ -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 # If you copy this file in, you don't
# need the .pyi file; it's just an interface file for static type checkers. # need the .pyi file; it's just an interface file for static type checkers.
from __future__ import annotations
import contextlib import contextlib
import os import os
@ -52,7 +53,6 @@ from pathlib import Path
from typing import ( from typing import (
Any, Any,
Callable, Callable,
Dict,
Iterable, Iterable,
Iterator, Iterator,
List, List,
@ -113,10 +113,10 @@ class Pybind11Extension(_Extension):
# flags are prepended, so that they can be further overridden, e.g. by # flags are prepended, so that they can be further overridden, e.g. by
# ``extra_compile_args=["-g"]``. # ``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 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 self.extra_link_args[:0] = flags
def __init__(self, *args: Any, **kwargs: Any) -> None: def __init__(self, *args: Any, **kwargs: Any) -> None:
@ -250,7 +250,7 @@ cpp_flag_cache = None
@lru_cache() @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. 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( def intree_extensions(
paths: Iterable[str], package_dir: Optional[Dict[str, str]] = None paths: Iterable[str], package_dir: dict[str, str] | None = None
) -> List[Pybind11Extension]: ) -> list[Pybind11Extension]:
""" """
Generate Pybind11Extensions from source files directly located in a Python Generate Pybind11Extensions from source files directly located in a Python
source tree. source tree.
@ -409,7 +409,7 @@ class ParallelCompile:
def __init__( def __init__(
self, self,
envvar: Optional[str] = None, envvar: str | None = None,
default: int = 0, default: int = 0,
max: int = 0, # pylint: disable=redefined-builtin max: int = 0, # pylint: disable=redefined-builtin
needs_recompile: Callable[[str, str], bool] = no_recompile, needs_recompile: Callable[[str, str], bool] = no_recompile,
@ -418,7 +418,7 @@ class ParallelCompile:
self.default = default self.default = default
self.max = max self.max = max
self.needs_recompile = needs_recompile self.needs_recompile = needs_recompile
self._old: List[CCompilerMethod] = [] self._old: list[CCompilerMethod] = []
def function(self) -> CCompilerMethod: def function(self) -> CCompilerMethod:
""" """
@ -427,14 +427,14 @@ class ParallelCompile:
def compile_function( def compile_function(
compiler: distutils.ccompiler.CCompiler, compiler: distutils.ccompiler.CCompiler,
sources: List[str], sources: list[str],
output_dir: Optional[str] = None, output_dir: str | None = None,
macros: Optional[List[Union[Tuple[str], Tuple[str, Optional[str]]]]] = None, macros: list[tuple[str] | tuple[str, str | None]] | None = None,
include_dirs: Optional[List[str]] = None, include_dirs: list[str] | None = None,
debug: bool = False, debug: bool = False,
extra_preargs: Optional[List[str]] = None, extra_preargs: list[str] | None = None,
extra_postargs: Optional[List[str]] = None, extra_postargs: list[str] | None = None,
depends: Optional[List[str]] = None, depends: list[str] | None = None,
) -> Any: ) -> Any:
# These lines are directly from distutils.ccompiler.CCompiler # These lines are directly from distutils.ccompiler.CCompiler
macros, objects, extra_postargs, pp_opts, build = compiler._setup_compile( # type: ignore[attr-defined] macros, objects, extra_postargs, pp_opts, build = compiler._setup_compile( # type: ignore[attr-defined]

View File

@ -30,7 +30,7 @@ ignore_missing_imports = true
[tool.pylint] [tool.pylint]
master.py-version = "3.6" master.py-version = "3.7"
reports.output-format = "colorized" reports.output-format = "colorized"
messages_control.disable = [ messages_control.disable = [
"design", "design",
@ -76,6 +76,8 @@ ignore = [
] ]
unfixable = ["T20"] unfixable = ["T20"]
isort.known-first-party = ["env", "pybind11_cross_module_tests", "pybind11_tests"] isort.known-first-party = ["env", "pybind11_cross_module_tests", "pybind11_tests"]
isort.required-imports = ["from __future__ import annotations"]
[tool.ruff.lint.per-file-ignores] [tool.ruff.lint.per-file-ignores]
"tests/**" = ["EM", "N", "E721"] "tests/**" = ["EM", "N", "E721"]

View File

@ -14,7 +14,6 @@ classifiers =
Topic :: Utilities Topic :: Utilities
Programming Language :: C++ Programming Language :: C++
Programming Language :: Python :: 3 :: Only Programming Language :: Python :: 3 :: Only
Programming Language :: Python :: 3.6
Programming Language :: Python :: 3.7 Programming Language :: Python :: 3.7
Programming Language :: Python :: 3.8 Programming Language :: Python :: 3.8
Programming Language :: Python :: 3.9 Programming Language :: Python :: 3.9
@ -39,5 +38,5 @@ project_urls =
Chat = https://gitter.im/pybind/Lobby Chat = https://gitter.im/pybind/Lobby
[options] [options]
python_requires = >=3.6 python_requires = >=3.7
zip_safe = False zip_safe = False

View File

@ -1,6 +1,7 @@
#!/usr/bin/env python3 #!/usr/bin/env python3
# Setup script for PyPI; use CMakeFile.txt to build extension modules # Setup script for PyPI; use CMakeFile.txt to build extension modules
from __future__ import annotations
import contextlib import contextlib
import os import os
@ -9,9 +10,9 @@ import shutil
import string import string
import subprocess import subprocess
import sys import sys
from collections.abc import Generator
from pathlib import Path from pathlib import Path
from tempfile import TemporaryDirectory from tempfile import TemporaryDirectory
from typing import Dict, Iterator, List, Union
import setuptools.command.sdist import setuptools.command.sdist
@ -23,7 +24,7 @@ VERSION_FILE = Path("pybind11/_version.py")
COMMON_FILE = Path("include/pybind11/detail/common.h") 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"] patch_level_serial = matches["PATCH"]
serial = None serial = None
major = int(matches["MAJOR"]) major = int(matches["MAJOR"])
@ -64,7 +65,7 @@ to_src = (
# Read the listed version # 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") code = compile(VERSION_FILE.read_text(encoding="utf-8"), "pybind11/_version.py", "exec")
exec(code, loc) exec(code, loc)
version = loc["__version__"] version = loc["__version__"]
@ -84,9 +85,7 @@ if version_hex != exp_version_hex:
# TODO: use literals & overload (typing extensions or Python 3.8) # TODO: use literals & overload (typing extensions or Python 3.8)
def get_and_replace( def get_and_replace(filename: Path, binary: bool = False, **opts: str) -> bytes | str:
filename: Path, binary: bool = False, **opts: str
) -> Union[bytes, str]:
if binary: if binary:
contents = filename.read_bytes() contents = filename.read_bytes()
return string.Template(contents.decode()).substitute(opts).encode() 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 # Use our input files instead when making the SDist (and anything that depends
# on it, like a wheel) # on it, like a wheel)
class SDist(setuptools.command.sdist.sdist): 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) super().make_release_tree(base_dir, files)
for to, src in to_src: for to, src in to_src:
@ -112,7 +111,7 @@ class SDist(setuptools.command.sdist.sdist):
# Remove the CMake install directory when done # Remove the CMake install directory when done
@contextlib.contextmanager @contextlib.contextmanager
def remove_output(*sources: str) -> Iterator[None]: def remove_output(*sources: str) -> Generator[None, None, None]:
try: try:
yield yield
finally: finally:

View File

@ -4,6 +4,8 @@ Extends output capture as needed by pybind11: ignore constructors, optional unor
Adds docstring and exceptions message sanitizers. Adds docstring and exceptions message sanitizers.
""" """
from __future__ import annotations
import contextlib import contextlib
import difflib import difflib
import gc import gc

View File

@ -1,3 +1,5 @@
from __future__ import annotations
import platform import platform
import sys import sys
import sysconfig import sysconfig

View File

@ -1,3 +1,5 @@
from __future__ import annotations
import contextlib import contextlib
import os import os
import string import string

View File

@ -1,3 +1,5 @@
from __future__ import annotations
import os import os
import subprocess import subprocess
import sys import sys

View File

@ -1,10 +1,8 @@
--only-binary=:all: --only-binary=:all:
build~=0.9; python_version=="3.6"
build~=1.0; python_version>="3.7" build~=1.0; python_version>="3.7"
numpy~=1.20.0; python_version=="3.7" and platform_python_implementation=="PyPy" 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.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.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.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.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" numpy~=1.26.0; platform_python_implementation!="PyPy" and python_version>="3.11" and python_version<"3.13"

View File

@ -1,3 +1,5 @@
from __future__ import annotations
import pytest import pytest
asyncio = pytest.importorskip("asyncio") asyncio = pytest.importorskip("asyncio")

View File

@ -1,3 +1,5 @@
from __future__ import annotations
import ctypes import ctypes
import io import io
import struct import struct

View File

@ -1,3 +1,5 @@
from __future__ import annotations
import sys import sys
import pytest import pytest

View File

@ -95,7 +95,7 @@ TEST_SUBMODULE(call_policies, m) {
}, },
py::call_guard<DependentGuard, CustomGuard>()); py::call_guard<DependentGuard, CustomGuard>());
#if defined(WITH_THREAD) && !defined(PYPY_VERSION) #if !defined(PYPY_VERSION)
// `py::call_guard<py::gil_scoped_release>()` should work in PyPy as well, // `py::call_guard<py::gil_scoped_release>()` should work in PyPy as well,
// but it's unclear how to test it without `PyGILState_GetThisThreadState`. // but it's unclear how to test it without `PyGILState_GetThisThreadState`.
auto report_gil_status = []() { auto report_gil_status = []() {

View File

@ -1,3 +1,5 @@
from __future__ import annotations
import pytest import pytest
import env # noqa: F401 import env # noqa: F401

View File

@ -1,3 +1,5 @@
from __future__ import annotations
import time import time
from threading import Thread from threading import Thread

View File

@ -1,3 +1,5 @@
from __future__ import annotations
import datetime import datetime
import pytest import pytest

View File

@ -1,3 +1,5 @@
from __future__ import annotations
from unittest import mock from unittest import mock
import pytest import pytest

View File

@ -1,3 +1,5 @@
from __future__ import annotations
import sys import sys
import test_cmake_build import test_cmake_build

View File

@ -1,3 +1,5 @@
from __future__ import annotations
import pytest import pytest
from pybind11_tests import const_name as m from pybind11_tests import const_name as m

View File

@ -1,3 +1,5 @@
from __future__ import annotations
import pytest import pytest
m = pytest.importorskip("pybind11_tests.constants_and_functions") m = pytest.importorskip("pybind11_tests.constants_and_functions")

View File

@ -1,3 +1,5 @@
from __future__ import annotations
import pytest import pytest
from pybind11_tests import copy_move_policies as m from pybind11_tests import copy_move_policies as m

View File

@ -1,3 +1,5 @@
from __future__ import annotations
import pytest import pytest
from pybind11_tests import custom_type_casters as m from pybind11_tests import custom_type_casters as m

View File

@ -1,3 +1,5 @@
from __future__ import annotations
import gc import gc
import weakref import weakref

View File

@ -1,3 +1,5 @@
from __future__ import annotations
from pybind11_tests import docstring_options as m from pybind11_tests import docstring_options as m

View File

@ -1,3 +1,5 @@
from __future__ import annotations
import pytest import pytest
from pybind11_tests import ConstructorStats from pybind11_tests import ConstructorStats

View File

@ -1,3 +1,5 @@
from __future__ import annotations
import sys import sys
import pytest import pytest

View File

@ -1,3 +1,5 @@
from __future__ import annotations
import sys import sys
from widget_module import Widget from widget_module import Widget

View File

@ -1,3 +1,5 @@
from __future__ import annotations
import trampoline_module import trampoline_module

View File

@ -1,4 +1,5 @@
# ruff: noqa: SIM201 SIM300 SIM202 # ruff: noqa: SIM201 SIM300 SIM202
from __future__ import annotations
import pytest import pytest

View File

@ -1,3 +1,5 @@
from __future__ import annotations
import os import os
import pytest import pytest

View File

@ -1,4 +1,5 @@
# This file is called from 'test_eval.py' # This file is called from 'test_eval.py'
from __future__ import annotations
if "call_test2" in locals(): if "call_test2" in locals():
call_test2(y) # noqa: F821 undefined name call_test2(y) # noqa: F821 undefined name

View File

@ -1,3 +1,5 @@
from __future__ import annotations
import sys import sys
import pytest import pytest

View File

@ -1,3 +1,5 @@
from __future__ import annotations
import re import re
import pytest import pytest

View File

@ -1,3 +1,5 @@
from __future__ import annotations
import multiprocessing import multiprocessing
import sys import sys
import threading import threading

View File

@ -1,3 +1,5 @@
from __future__ import annotations
from contextlib import redirect_stderr, redirect_stdout from contextlib import redirect_stderr, redirect_stdout
from io import StringIO from io import StringIO

View File

@ -1,3 +1,5 @@
from __future__ import annotations
import pytest import pytest
from pybind11_tests import kwargs_and_defaults as m from pybind11_tests import kwargs_and_defaults as m

View File

@ -1,3 +1,5 @@
from __future__ import annotations
import pytest import pytest
import env # noqa: F401 import env # noqa: F401

View File

@ -1,3 +1,5 @@
from __future__ import annotations
import sys import sys
import pytest import pytest

View File

@ -1,3 +1,5 @@
from __future__ import annotations
import builtins import builtins
import pytest import pytest

View File

@ -1,3 +1,5 @@
from __future__ import annotations
import pytest import pytest
import env # noqa: F401 import env # noqa: F401

View File

@ -1,3 +1,5 @@
from __future__ import annotations
import pytest import pytest
import env # noqa: F401 import env # noqa: F401
@ -198,11 +200,7 @@ def test_wrap():
assert a.flags.f_contiguous == b.flags.f_contiguous assert a.flags.f_contiguous == b.flags.f_contiguous
assert a.flags.writeable == b.flags.writeable assert a.flags.writeable == b.flags.writeable
assert a.flags.aligned == b.flags.aligned 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 assert a.flags.writebackifcopy == b.flags.writebackifcopy
else:
assert a.flags.updateifcopy == b.flags.updateifcopy
assert np.all(a == b) assert np.all(a == b)
assert not b.flags.owndata assert not b.flags.owndata
assert b.base is base assert b.base is base

View File

@ -1,3 +1,5 @@
from __future__ import annotations
import re import re
import pytest import pytest

View File

@ -1,3 +1,5 @@
from __future__ import annotations
import pytest import pytest
from pybind11_tests import numpy_vectorize as m from pybind11_tests import numpy_vectorize as m

View File

@ -1,3 +1,5 @@
from __future__ import annotations
import pytest import pytest
from pybind11_tests import ConstructorStats, UserType from pybind11_tests import ConstructorStats, UserType

View File

@ -1,3 +1,5 @@
from __future__ import annotations
import pytest import pytest
from pybind11_tests import ConstructorStats from pybind11_tests import ConstructorStats

View File

@ -1,3 +1,5 @@
from __future__ import annotations
import pickle import pickle
import re import re

View File

@ -1,5 +1,6 @@
# Adapted from: # Adapted from:
# https://github.com/google/clif/blob/5718e4d0807fd3b6a8187dde140069120b81ecef/clif/testing/python/python_multiple_inheritance_test.py # 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 from pybind11_tests import python_multiple_inheritance as m

View File

@ -1,3 +1,5 @@
from __future__ import annotations
import contextlib import contextlib
import sys import sys
import types import types

View File

@ -1,3 +1,5 @@
from __future__ import annotations
import pytest import pytest
from pytest import approx # noqa: PT013 from pytest import approx # noqa: PT013

View File

@ -1,3 +1,5 @@
from __future__ import annotations
import pytest import pytest
m = pytest.importorskip("pybind11_tests.smart_ptr") m = pytest.importorskip("pybind11_tests.smart_ptr")

View File

@ -1,3 +1,5 @@
from __future__ import annotations
import pytest import pytest
from pybind11_tests import ConstructorStats, UserType from pybind11_tests import ConstructorStats, UserType

View File

@ -1,3 +1,5 @@
from __future__ import annotations
import pytest import pytest
from pybind11_tests import stl_binders as m from pybind11_tests import stl_binders as m

View File

@ -1,3 +1,5 @@
from __future__ import annotations
from pybind11_tests import tagbased_polymorphic as m from pybind11_tests import tagbased_polymorphic as m

View File

@ -1,3 +1,5 @@
from __future__ import annotations
import threading import threading
from pybind11_tests import thread as m from pybind11_tests import thread as m

View File

@ -1,3 +1,5 @@
from __future__ import annotations
import pytest import pytest
from pybind11_tests import type_caster_pyobject_ptr as m from pybind11_tests import type_caster_pyobject_ptr as m

View File

@ -1,3 +1,5 @@
from __future__ import annotations
from pybind11_tests import union_ as m from pybind11_tests import union_ as m

View File

@ -1,3 +1,5 @@
from __future__ import annotations
import pytest import pytest
from pybind11_tests import unnamed_namespace_a as m from pybind11_tests import unnamed_namespace_a as m

View File

@ -1,3 +1,5 @@
from __future__ import annotations
from pybind11_tests import unnamed_namespace_b as m from pybind11_tests import unnamed_namespace_b as m

View File

@ -1,3 +1,5 @@
from __future__ import annotations
import pytest import pytest
from pybind11_tests import vector_unique_ptr_member as m from pybind11_tests import vector_unique_ptr_member as m

View File

@ -1,3 +1,5 @@
from __future__ import annotations
import pytest import pytest
import env # noqa: F401 import env # noqa: F401

View File

@ -92,7 +92,7 @@ endif()
# Use the Python interpreter to find the libs. # Use the Python interpreter to find the libs.
if(NOT PythonLibsNew_FIND_VERSION) if(NOT PythonLibsNew_FIND_VERSION)
set(PythonLibsNew_FIND_VERSION "3.6") set(PythonLibsNew_FIND_VERSION "3.7")
endif() endif()
if(NOT CMAKE_VERSION VERSION_LESS "3.27") if(NOT CMAKE_VERSION VERSION_LESS "3.27")

View File

@ -9,11 +9,12 @@ python3 tools/codespell_ignore_lines_from_errors.py /tmp/codespell_errors.txt >
git diff to review changes, then commit, push. git diff to review changes, then commit, push.
""" """
from __future__ import annotations
import sys 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" assert len(args) == 1, "codespell_errors.txt"
cache = {} cache = {}
done = set() done = set()

View File

@ -1,3 +1,5 @@
from __future__ import annotations
import os import os
import sys import sys

View File

@ -56,7 +56,7 @@ if(NOT Python_FOUND AND NOT Python3_FOUND)
endif() endif()
find_package( 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}) ${_pybind11_quiet} ${_pybind11_global_keyword})
# If we are in submodule mode, export the Python targets to global targets. # If we are in submodule mode, export the Python targets to global targets.

View File

@ -43,7 +43,7 @@ endif()
# A user can set versions manually too # A user can set versions manually too
set(Python_ADDITIONAL_VERSIONS 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 "") CACHE INTERNAL "")
list(APPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_LIST_DIR}") list(APPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_LIST_DIR}")