diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml
index bbecdf481b6..564b3e5464e 100644
--- a/.github/workflows/build.yml
+++ b/.github/workflows/build.yml
@@ -15,7 +15,7 @@ on:
platform:
description: 'Platform'
required: true
- default: 'ubuntu-jammy-standard'
+ default: 'ubuntu-noble-standard'
docker_tag:
description: 'Docker tag'
required: true
@@ -68,8 +68,8 @@ concurrency:
env:
# Adapted from docker.yml
- TOX_ENV: "docker-${{ github.event.inputs.platform || 'ubuntu-jammy-standard' }}-incremental"
- BUILD_IMAGE: "localhost:5000/${{ github.repository }}/sage-${{ github.event.inputs.platform || 'ubuntu-jammy-standard' }}-with-targets:ci"
+ TOX_ENV: "docker-${{ github.event.inputs.platform || 'ubuntu-noble-standard' }}-incremental"
+ BUILD_IMAGE: "localhost:5000/${{ github.repository }}/sage-${{ github.event.inputs.platform || 'ubuntu-noble-standard' }}-with-targets:ci"
FROM_DOCKER_REPOSITORY: "ghcr.io/sagemath/sage/"
FROM_DOCKER_TARGET: "with-targets"
FROM_DOCKER_TAG: ${{ github.event.inputs.docker_tag || 'dev'}}
diff --git a/.github/workflows/dist.yml b/.github/workflows/dist.yml
index b8800c8854b..ccd3e9f1a94 100644
--- a/.github/workflows/dist.yml
+++ b/.github/workflows/dist.yml
@@ -216,7 +216,7 @@ jobs:
#
CIBW_ARCHS: ${{ matrix.arch }}
# https://cibuildwheel.readthedocs.io/en/stable/options/#requires-python
- CIBW_PROJECT_REQUIRES_PYTHON: ">=3.9, <3.13"
+ CIBW_PROJECT_REQUIRES_PYTHON: ">=3.11, <3.13"
# Environment during wheel build
CIBW_ENVIRONMENT: "PATH=$(pwd)/prefix/bin:$PATH CPATH=$(pwd)/prefix/include:$CPATH LIBRARY_PATH=$(pwd)/prefix/lib:$LIBRARY_PATH LD_LIBRARY_PATH=$(pwd)/prefix/lib:$LD_LIBRARY_PATH PKG_CONFIG_PATH=$(pwd)/prefix/share/pkgconfig:$PKG_CONFIG_PATH ACLOCAL_PATH=/usr/share/aclocal PIP_CONSTRAINT=$(pwd)/constraints.txt PIP_FIND_LINKS=file://$(pwd)/wheelhouse SAGE_NUM_THREADS=6"
# Use 'build', not 'pip wheel'
diff --git a/.github/workflows/doc-build-pdf.yml b/.github/workflows/doc-build-pdf.yml
index dce25a132c9..f8d30cd32b6 100644
--- a/.github/workflows/doc-build-pdf.yml
+++ b/.github/workflows/doc-build-pdf.yml
@@ -9,7 +9,7 @@ on:
platform:
description: 'Platform'
required: true
- default: 'ubuntu-jammy-standard'
+ default: 'ubuntu-noble-standard'
docker_tag:
description: 'Docker tag'
required: true
@@ -22,8 +22,8 @@ concurrency:
env:
# Same as in build.yml
- TOX_ENV: "docker-${{ github.event.inputs.platform || 'ubuntu-jammy-standard' }}-incremental"
- BUILD_IMAGE: "localhost:5000/${{ github.repository }}/sage-${{ github.event.inputs.platform || 'ubuntu-jammy-standard' }}-with-targets:ci"
+ TOX_ENV: "docker-${{ github.event.inputs.platform || 'ubuntu-noble-standard' }}-incremental"
+ BUILD_IMAGE: "localhost:5000/${{ github.repository }}/sage-${{ github.event.inputs.platform || 'ubuntu-noble-standard' }}-with-targets:ci"
FROM_DOCKER_REPOSITORY: "ghcr.io/sagemath/sage/"
FROM_DOCKER_TARGET: "with-targets"
FROM_DOCKER_TAG: ${{ github.event.inputs.docker_tag || 'dev'}}
diff --git a/.github/workflows/doc-build.yml b/.github/workflows/doc-build.yml
index f46317ecda7..3d80d4c30a8 100644
--- a/.github/workflows/doc-build.yml
+++ b/.github/workflows/doc-build.yml
@@ -20,7 +20,7 @@ on:
platform:
description: 'Platform'
required: true
- default: 'ubuntu-jammy-standard'
+ default: 'ubuntu-noble-standard'
docker_tag:
description: 'Docker tag'
required: true
@@ -33,8 +33,8 @@ concurrency:
env:
# Same as in build.yml
- TOX_ENV: "docker-${{ github.event.inputs.platform || 'ubuntu-jammy-standard' }}-incremental"
- BUILD_IMAGE: "localhost:5000/${{ github.repository }}/sage-${{ github.event.inputs.platform || 'ubuntu-jammy-standard' }}-with-targets:ci"
+ TOX_ENV: "docker-${{ github.event.inputs.platform || 'ubuntu-noble-standard' }}-incremental"
+ BUILD_IMAGE: "localhost:5000/${{ github.repository }}/sage-${{ github.event.inputs.platform || 'ubuntu-noble-standard' }}-with-targets:ci"
FROM_DOCKER_REPOSITORY: "ghcr.io/sagemath/sage/"
FROM_DOCKER_TARGET: "with-targets"
FROM_DOCKER_TAG: ${{ github.event.inputs.docker_tag || 'dev'}}
diff --git a/.github/workflows/pyright.yml b/.github/workflows/pyright.yml
index eef1aad5976..97e12442b03 100644
--- a/.github/workflows/pyright.yml
+++ b/.github/workflows/pyright.yml
@@ -18,7 +18,7 @@ concurrency:
jobs:
pyright:
runs-on: ubuntu-latest
- container: ghcr.io/sagemath/sage/sage-ubuntu-jammy-standard-with-targets:dev
+ container: ghcr.io/sagemath/sage/sage-ubuntu-noble-standard-with-targets:dev
steps:
- name: Checkout
id: checkout
diff --git a/.gitignore b/.gitignore
index b8bfc364a26..e274a25c738 100644
--- a/.gitignore
+++ b/.gitignore
@@ -158,7 +158,6 @@ __pycache__/
/src/sage/modular/arithgroup/farey_symbol.h
# List of C and C++ files that are actual source files,
# NOT generated by Cython. The same list appears in src/MANIFEST.in
-!/src/sage/cpython/debugimpl.c
!/src/sage/graphs/base/boost_interface.cpp
!/src/sage/graphs/cliquer/cl.c
!/src/sage/graphs/graph_decompositions/sage_tdlib.cpp
diff --git a/README.md b/README.md
index f54d7ad34b6..0964e22a5e0 100644
--- a/README.md
+++ b/README.md
@@ -222,7 +222,7 @@ in the Installation Guide.
more details.
- Python 3.4 or later, or Python 2.7, a full installation including
- `urllib`; but ideally version 3.9.x, 3.10.x, 3.11.x, 3.12.x, which
+ `urllib`; but ideally version 3.11.x or later, which
will avoid having to build Sage's own copy of Python 3.
See [build/pkgs/python3/SPKG.rst](build/pkgs/python3/SPKG.rst)
for more details.
@@ -551,11 +551,11 @@ SAGE_ROOT Root directory (create by git clone)
│ │ ├── installed/
│ │ │ Records of installed non-Python packages
│ │ ├── scripts/ Scripts for uninstalling installed packages
-│ │ └── venv-python3.9 (SAGE_VENV)
+│ │ └── venv-python (SAGE_VENV)
│ │ │ Installation hierarchy (virtual environment)
│ │ │ for Python packages
│ │ ├── bin/ Executables and installed scripts
-│ │ ├── lib/python3.9/site-packages/
+│ │ ├── lib/python/site-packages/
│ │ │ Python modules/packages are installed here
│ │ └── var/lib/sage/
│ │ └── wheels/
diff --git a/pyproject.toml b/pyproject.toml
index a1febc07917..117a5006067 100644
--- a/pyproject.toml
+++ b/pyproject.toml
@@ -62,8 +62,6 @@ classifiers = [
"Operating System :: POSIX",
"Operating System :: MacOS :: MacOS X",
"Programming Language :: Python :: 3 :: Only",
- "Programming Language :: Python :: 3.9",
- "Programming Language :: Python :: 3.10",
"Programming Language :: Python :: 3.11",
"Programming Language :: Python :: 3.12",
"Programming Language :: Python :: 3.13",
@@ -71,7 +69,7 @@ classifiers = [
"Topic :: Scientific/Engineering :: Mathematics",
]
urls = {Homepage = "https://www.sagemath.org"}
-requires-python = ">=3.9, <3.14"
+requires-python = ">=3.11, <3.14"
[project.optional-dependencies]
R = [
diff --git a/pyrightconfig.json b/pyrightconfig.json
index 643c56360c9..826c3aabe86 100644
--- a/pyrightconfig.json
+++ b/pyrightconfig.json
@@ -7,7 +7,7 @@
"root": "src"
}
],
- "pythonVersion": "3.9",
+ "pythonVersion": "3.11",
"exclude": ["venv"],
"venvPath": "./venv/",
"venv": "./",
diff --git a/ruff.toml b/ruff.toml
index 15def717a4e..1c21d484455 100644
--- a/ruff.toml
+++ b/ruff.toml
@@ -1,7 +1,7 @@
# https://docs.astral.sh/ruff/configuration/#config-file-discovery
-# Assume Python 3.9
-target-version = "py39"
+# Python 3.11 is the minimum supported version
+target-version = "py311"
lint.select = [
"E", # pycodestyle errors - https://docs.astral.sh/ruff/rules/#error-e
diff --git a/src/MANIFEST.in b/src/MANIFEST.in
index f6231401294..8428dfff314 100644
--- a/src/MANIFEST.in
+++ b/src/MANIFEST.in
@@ -23,7 +23,6 @@ global-exclude *.cpp
# List of C and C++ files that are actual source files,
# NOT generated by Cython. The same list appears in SAGE_ROOT/.gitignore
#
-include sage/cpython/debugimpl.c
include sage/graphs/base/boost_interface.cpp
include sage/graphs/cliquer/cl.c
include sage/libs/eclib/wrap.cpp
diff --git a/src/doc/en/developer/coding_in_python.rst b/src/doc/en/developer/coding_in_python.rst
index 1ea6eebb317..f86ab9a09c3 100644
--- a/src/doc/en/developer/coding_in_python.rst
+++ b/src/doc/en/developer/coding_in_python.rst
@@ -12,17 +12,14 @@ Sage.
Python language standard
========================
-Sage library code needs to be compatible with all versions of Python
-that Sage supports. The information regarding the supported versions
-can be found in the files ``build/pkgs/python3/spkg-configure.m4`` and
-``src/setup.cfg.m4``.
-
-Python 3.9 is the oldest supported version. Hence,
-all language and library features that are available in Python 3.9 can
-be used; but features introduced in Python 3.10 cannot be used. If a
-feature is deprecated in a newer supported version, it must be ensured
-that deprecation warnings issued by Python do not lead to failures in
-doctests.
+Sage follows the time window-based support policy
+`SPEC 0 — Minimum Supported Dependencies `_
+for Python versions.
+The current minimum supported Python version can be found in the
+``pyproject.toml`` file. Accordingly, only language and library features
+available in this version can be used. If a feature is deprecated in a newer
+supported version, it must be ensured that deprecation warnings issued by
+Python do not lead to failures in doctests.
Some key language and library features have been backported to older Python versions
using one of two mechanisms:
@@ -34,21 +31,9 @@ using one of two mechanisms:
of annotations). All Sage library code that uses type annotations
should include this ``__future__`` import and follow PEP 563.
-- Backport packages
-
- - `importlib_metadata <../reference/spkg/importlib_metadata>`_
- (to be used in place of ``importlib.metadata``),
- - `importlib_resources <../reference/spkg/importlib_resources>`_
- (to be used in place of ``importlib.resources``),
- - `typing_extensions <../reference/spkg/typing_extensions>`_
- (to be used in place of ``typing``).
-
- The Sage library declares these packages as dependencies and ensures that
- versions that provide features of Python 3.11 are available.
-
-Meta :issue:`29756` keeps track of newer Python features and serves
-as a starting point for discussions on how to make use of them in the
-Sage library.
+- The `typing_extensions <../reference/spkg/typing_extensions>`_ package
+ is used to backport features from newer versions of the ``typing`` module.
+ The Sage library declares this package as a dependency.
Design
diff --git a/src/doc/en/installation/conda.rst b/src/doc/en/installation/conda.rst
index ae560bb5a38..65f03583af6 100644
--- a/src/doc/en/installation/conda.rst
+++ b/src/doc/en/installation/conda.rst
@@ -50,7 +50,7 @@ Create a new conda environment containing SageMath, either with ``mamba`` or ``c
$ conda create -n sage sage python=X
-where ``X`` is version of Python, e.g. ``3.9``.
+where ``X`` is version of Python, e.g. ``3.12``.
To use Sage from there,
@@ -86,22 +86,22 @@ Here we assume that you are using a git checkout.
.. code-block:: shell
- $ mamba env create --file environment-3.11-linux.yml --name sage-dev
+ $ mamba env create --file environment-3.12-linux.yml --name sage-dev
$ conda activate sage-dev
.. tab:: conda
.. code-block:: shell
- $ conda env create --file environment-3.11-linux.yml --name sage-dev
+ $ conda env create --file environment-3.12-linux.yml --name sage-dev
$ conda activate sage-dev
- Alternatively, you can use ``environment-3.11-linux.yml`` or
- ``environment-optional-3.11-linux.yml``, which will only install standard
+ Alternatively, you can use ``environment-3.12-linux.yml`` or
+ ``environment-optional-3.12-linux.yml``, which will only install standard
(and optional) packages without any additional developer tools.
- A different Python version can be selected by replacing ``3.11`` by ``3.9``
- or ``3.10`` in these commands.
+ A different Python version can be selected by replacing ``3.12`` with the
+ desired version.
- Bootstrap the source tree and install the build prerequisites and the Sage library::
@@ -137,7 +137,7 @@ After editing any Cython files, rebuild the Sage library using::
In order to update the conda environment later, you can run::
- $ mamba env update --file environment-3.11-linux.yml --name sage-dev
+ $ mamba env update --file environment-3.12-linux.yml --name sage-dev
To build the documentation, use::
@@ -156,5 +156,5 @@ To build the documentation, use::
You can update the conda lock files by running
``.github/workflows/conda-lock-update.py`` or by running
- ``conda-lock --platform linux-64 --filename environment-3.11-linux.yml --lockfile environment-3.11-linux.lock``
+ ``conda-lock --platform linux-64 --filename environment-3.12-linux.yml --lockfile environment-3.12-linux.lock``
manually.
diff --git a/src/doc/en/installation/launching.rst b/src/doc/en/installation/launching.rst
index b612a89a9c1..bb99fbcfb00 100644
--- a/src/doc/en/installation/launching.rst
+++ b/src/doc/en/installation/launching.rst
@@ -67,9 +67,8 @@ Sage uses the following environment variables when it runs:
- See
https://docs.python.org/3/using/cmdline.html#environment-variables
- for more variables used by Python (not an exhaustive list). With
- Python 3.11 or later, a brief summary can also be obtained by
- running `python3 --help-env`.
+ for more variables used by Python (not an exhaustive list).
+ A brief summary can also be obtained by running `python3 --help-env`.
Using a Jupyter Notebook remotely
---------------------------------
diff --git a/src/sage/all__sagemath_repl.py b/src/sage/all__sagemath_repl.py
index c830950c26b..13efd115e1c 100644
--- a/src/sage/all__sagemath_repl.py
+++ b/src/sage/all__sagemath_repl.py
@@ -100,12 +100,6 @@
message=r"Pickle, copy, and deepcopy support will be "
r"removed from itertools in Python 3.14.")
-# triggered in Python 3.9 on Redhat-based distributions
-# https://github.com/sagemath/sage/issues/37863
-# https://github.com/networkx/networkx/issues/7101
-warnings.filterwarnings('ignore', category=RuntimeWarning,
- message="networkx backend defined more than once: nx-loopback")
-
from sage.all__sagemath_objects import *
from sage.all__sagemath_environment import *
diff --git a/src/sage/cpython/atexit.pyx b/src/sage/cpython/atexit.pyx
index 8f833ab1437..c74c1d0308a 100644
--- a/src/sage/cpython/atexit.pyx
+++ b/src/sage/cpython/atexit.pyx
@@ -148,8 +148,6 @@ from cpython.ref cimport PyObject
# Implement "_atexit_callbacks()" for each supported python version
cdef extern from *:
"""
- #if PY_VERSION_HEX >= 0x030a0000
- /********** Python 3.10 **********/
#define Py_BUILD_CORE
#undef _PyGC_FINALIZED
#include "internal/pycore_interp.h"
@@ -163,29 +161,6 @@ cdef extern from *:
struct atexit_state state = interp->atexit;
return state.callbacks;
}
- #else
- /********** Python < 3.10 **********/
- /* Internal structures defined in the CPython source in
- * Modules/atexitmodule.c and subject to (but unlikely to) change. Watch
- * https://bugs.python.org/issue32082 for a request to (eventually)
- * re-expose more of the atexit module's internals to Python
- * typedef struct
- */
- typedef struct {
- PyObject *func;
- PyObject *args;
- PyObject *kwargs;
- } atexit_callback;
- typedef struct {
- atexit_callback **atexit_callbacks;
- int ncallbacks;
- int callback_len;
- } atexitmodule_state;
- static atexit_callback ** _atexit_callbacks(PyObject *self) {
- atexitmodule_state *state = PyModule_GetState(self);
- return state->atexit_callbacks;
- }
- #endif
"""
ctypedef struct atexit_callback:
PyObject* func
diff --git a/src/sage/cpython/cython_metaclass.h b/src/sage/cpython/cython_metaclass.h
index ecf7f973c3e..f7b6f345fa3 100644
--- a/src/sage/cpython/cython_metaclass.h
+++ b/src/sage/cpython/cython_metaclass.h
@@ -8,13 +8,6 @@
* http://www.gnu.org/licenses/
*****************************************************************************/
-/* Compatibility for python 3.8, can be removed later */
-#if PY_VERSION_HEX < 0x030900A4 && !defined(Py_SET_TYPE)
-static inline void _Py_SET_TYPE(PyObject *ob, PyTypeObject *type)
-{ ob->ob_type = type; }
-#define Py_SET_TYPE(ob, type) _Py_SET_TYPE((PyObject*)(ob), type)
-#endif
-
/* Tuple (None, None, None), initialized as needed */
static PyObject* NoneNoneNone;
@@ -52,7 +45,6 @@ static CYTHON_INLINE int Sage_PyType_Ready(PyTypeObject* t)
if (r < 0)
return r;
-#if PY_VERSION_HEX >= 0x03050000
// Cython 3 sets Py_TPFLAGS_HEAPTYPE before calling PyType_Ready,
// and resets just after the call. We need to reset it earlier,
// since otherwise the call to metaclass.__init__ below may have
@@ -60,7 +52,6 @@ static CYTHON_INLINE int Sage_PyType_Ready(PyTypeObject* t)
// See also:
// https://github.com/cython/cython/issues/3603
t->tp_flags &= ~Py_TPFLAGS_HEAPTYPE;
-#endif
/* Set or get metaclass (the type of t) */
PyTypeObject* metaclass;
diff --git a/src/sage/cpython/debug.pyx b/src/sage/cpython/debug.pyx
index f4e0a44046f..a11dfc085f3 100644
--- a/src/sage/cpython/debug.pyx
+++ b/src/sage/cpython/debug.pyx
@@ -19,9 +19,6 @@ cdef extern from "Python.h":
# Helper to get a pointer to an object's __dict__ slot, if any
PyObject** _PyObject_GetDictPtr(obj)
-cdef extern from "debugimpl.c":
- void _type_debug(PyTypeObject*)
-
from sage.cpython.getattr cimport AttributeErrorMessage
@@ -303,5 +300,3 @@ def type_debug(cls):
"""
if not isinstance(cls, type):
raise TypeError(f"{cls!r} is not a type")
-
- _type_debug(cls)
diff --git a/src/sage/cpython/debugimpl.c b/src/sage/cpython/debugimpl.c
deleted file mode 100644
index 176e93900c2..00000000000
--- a/src/sage/cpython/debugimpl.c
+++ /dev/null
@@ -1,348 +0,0 @@
-#include
-
-#if PY_MAJOR_VERSION == 3 && PY_MINOR_VERSION >= 9
-
-static void _type_debug(PyTypeObject* tp)
-{
- printf("Not implemented for CPython >= 3.9\n");
-}
-
-#else
-
-#define HAVE_WEAKREFS(tp) (1)
-#define HAVE_CLASS(tp) (1)
-#define HAVE_ITER(tp) (1)
-#define HAVE_RICHCOMPARE(tp) (1)
-#define HAVE_INPLACEOPS(tp) (1)
-#define HAVE_SEQUENCE_IN(tp) (1)
-#define HAVE_GETCHARBUFFER(tp) (1)
-#define HAVE_NEW_DIVISION(tp) (1)
-#define HAVE_INDEX(tp) (1)
-#define HAVE_NEWBUFFER(tp) (1)
-#define HAVE_FINALIZE(tp) (tp->tp_flags & Py_TPFLAGS_HAVE_FINALIZE)
-
-static void print_object(void* pyobj)
-{
- if (pyobj == NULL)
- {
- printf("NULL\n");
- return;
- }
-
- PyObject* obj = (PyObject*)pyobj;
-
- if (PyTuple_Check(obj))
- {
- printf("%s:\n", Py_TYPE(obj)->tp_name);
-
- Py_ssize_t i, n = PyTuple_GET_SIZE(obj);
- for (i = 0; i < n; i++)
- {
- printf(" ");
- PyObject_Print(PyTuple_GET_ITEM(obj, i), stdout, 0);
- printf("\n");
- }
- }
- else if (PyDict_Check(obj))
- {
- printf("%s:\n", Py_TYPE(obj)->tp_name);
-
- Py_ssize_t pos = 0;
- PyObject* key;
- PyObject* value;
- while (PyDict_Next(obj, &pos, &key, &value))
- {
- printf(" ");
- PyObject_Print(key, stdout, 0);
- printf(": ");
- PyObject_Print(value, stdout, 0);
- printf("\n");
- }
- }
- else
- {
- PyObject_Print(obj, stdout, 0);
- printf("\n");
- }
-}
-
-
-#define pointer_check_constant(ptr, val) \
- if (ptr == (void*)(val)) \
- { \
- special = 0; \
- printf(#val "\n"); \
- }
-
-#define subattr_pointer_value(sub, attr) \
- special = 1; \
- pointer_check_constant(tp->attr, NULL) \
- else pointer_check_constant(tp->attr, PyType_GenericAlloc) \
- else pointer_check_constant(tp->attr, PyType_GenericNew) \
- else pointer_check_constant(tp->attr, PyObject_Del) \
- else pointer_check_constant(tp->attr, PyObject_GC_Del) \
- else pointer_check_constant(tp->attr, PyObject_GenericGetAttr) \
- else pointer_check_constant(tp->attr, PyObject_GenericSetAttr) \
- else pointer_check_constant(tp->attr, _Py_HashPointer) \
- else pointer_check_constant(tp->attr, PyObject_HashNotImplemented) \
- else pointer_check_constant(tp->attr, subtype_traverse) \
- else pointer_check_constant(tp->attr, subtype_clear) \
- else pointer_check_constant(tp->attr, subtype_dealloc) \
- else \
- { \
- PyObject* mro = tp->tp_mro; \
- PyTypeObject* subtp; \
- Py_ssize_t i, n = PyTuple_GET_SIZE(mro); \
- for (i = n-1; i >= 0; i--) \
- { \
- subtp = (PyTypeObject*)PyTuple_GET_ITEM(mro, i); \
- if (subtp != tp && PyType_Check(subtp)) \
- { \
- if (subtp->sub && tp->attr == subtp->attr) \
- { \
- special = 0; \
- printf("== %s\n", subtp->tp_name); \
- break; \
- } \
- } \
- } \
- } \
- if (special) printf("%p\n", tp->attr);
-
-#define attr_pointer_value(attr) subattr_pointer_value(tp_name, attr);
-
-#define attr_pointer(attr) \
- printf(" " #attr ": "); \
- attr_pointer_value(attr);
-#define attr_pointer_meth(attr, method) \
- printf(" " #attr " (" method "): "); \
- attr_pointer_value(attr);
-#define subattr_pointer(sub, attr) \
- printf(" " #attr ": "); \
- subattr_pointer_value(sub, sub->attr);
-#define subattr_pointer_meth(sub, attr, method) \
- printf(" " #attr " (" method "): "); \
- subattr_pointer_value(sub, sub->attr);
-
-#define attr_object(attr) \
- printf(" " #attr ": "); \
- print_object(tp->attr);
-#define attr_object_meth(attr, method) \
- printf(" " #attr " (" method "): "); \
- print_object(tp->attr);
-
-#define attr_flag(flag) \
- if (tp->tp_flags & Py_TPFLAGS_ ## flag) \
- printf(" " #flag "\n");
-
-
-static void _type_debug(PyTypeObject* tp)
-{
- int special;
-
- PyObject_Print((PyObject*)tp, stdout, 0);
- printf(" (%p)\n", tp);
- printf(" ob_refcnt: %ld\n", (long)Py_REFCNT(tp));
- printf(" ob_type: "); print_object(Py_TYPE(tp));
- printf(" tp_name: %s\n", tp->tp_name);
- printf(" tp_basicsize: %ld\n", (long)tp->tp_basicsize);
- printf(" tp_itemsize: %ld\n", (long)tp->tp_itemsize);
- printf(" tp_dictoffset: %ld\n", (long)tp->tp_dictoffset);
- if HAVE_WEAKREFS(tp)
- {
- printf(" tp_weaklistoffset: %ld\n", (long)tp->tp_weaklistoffset);
- }
-
- if HAVE_CLASS(tp)
- {
- attr_object_meth(tp_base, "__base__");
- attr_object_meth(tp_bases, "__bases__");
- attr_object_meth(tp_mro, "__mro__");
- attr_object_meth(tp_dict, "__dict__");
- }
-
- attr_pointer(tp_alloc);
- attr_pointer_meth(tp_new, "__new__");
- attr_pointer_meth(tp_init, "__init__");
- attr_pointer_meth(tp_dealloc, "__dealloc__");
- if (tp->tp_flags & Py_TPFLAGS_HEAPTYPE)
- {
- attr_pointer_meth(tp_del, "__del__");
- }
- #if PY_MAJOR_VERSION >= 3
- if HAVE_FINALIZE(tp)
- {
- attr_pointer_meth(tp_finalize, "__del__");
- }
- #endif
- attr_pointer(tp_free);
-
- attr_pointer_meth(tp_repr, "__repr__");
- attr_pointer(tp_print);
- attr_pointer_meth(tp_hash, "__hash__");
- attr_pointer_meth(tp_call, "__call__");
- attr_pointer_meth(tp_str, "__str__");
- #if PY_MAJOR_VERSION <= 2
- attr_pointer_meth(tp_compare, "cmp");
- #endif
- attr_pointer_meth(tp_richcompare, "__richcmp__");
- attr_pointer_meth(tp_getattr, "__getattribute__");
- attr_pointer_meth(tp_setattr, "__setattribute__");
- attr_pointer_meth(tp_getattro, "__getattribute__");
- attr_pointer_meth(tp_setattro, "__setattribute__");
- if HAVE_ITER(tp)
- {
- attr_pointer_meth(tp_iter, "__iter__");
- attr_pointer_meth(tp_iternext, "__next__");
- }
- if HAVE_CLASS(tp)
- {
- attr_pointer_meth(tp_descr_get, "__get__");
- attr_pointer_meth(tp_descr_set, "__set__");
-
- attr_object(tp_cache);
- attr_object(tp_weaklist);
- }
- if HAVE_RICHCOMPARE(tp)
- {
- attr_pointer(tp_traverse);
- attr_pointer(tp_clear);
- }
- if HAVE_CLASS(tp)
- {
- attr_pointer(tp_is_gc);
- }
-
- attr_pointer(tp_as_number);
- if (special)
- {
- subattr_pointer_meth(tp_as_number, nb_add, "__add__");
- subattr_pointer_meth(tp_as_number, nb_subtract, "__sub__");
- subattr_pointer_meth(tp_as_number, nb_multiply, "__mul__");
- #if PY_MAJOR_VERSION <= 2
- subattr_pointer_meth(tp_as_number, nb_divide, "__div__");
- #endif
- if HAVE_NEW_DIVISION(tp)
- {
- subattr_pointer_meth(tp_as_number, nb_floor_divide, "__floordiv__");
- subattr_pointer_meth(tp_as_number, nb_true_divide, "__truediv__");
- }
- subattr_pointer_meth(tp_as_number, nb_remainder, "__mod__");
- subattr_pointer_meth(tp_as_number, nb_divmod, "__divmod__");
- subattr_pointer_meth(tp_as_number, nb_power, "__pow__");
- subattr_pointer_meth(tp_as_number, nb_negative, "__neg__");
- subattr_pointer_meth(tp_as_number, nb_positive, "__pos__");
- subattr_pointer_meth(tp_as_number, nb_absolute, "__abs__");
- subattr_pointer_meth(tp_as_number, nb_bool, "__bool__");
- subattr_pointer_meth(tp_as_number, nb_invert, "__invert__");
- subattr_pointer_meth(tp_as_number, nb_lshift, "__lshift__");
- subattr_pointer_meth(tp_as_number, nb_rshift, "__rshift__");
- subattr_pointer_meth(tp_as_number, nb_and, "__and__");
- subattr_pointer_meth(tp_as_number, nb_or, "__or__");
- subattr_pointer_meth(tp_as_number, nb_xor, "__xor__");
- subattr_pointer_meth(tp_as_number, nb_int, "__int__");
- #if PY_MAJOR_VERSION <= 2
- subattr_pointer_meth(tp_as_number, nb_long, "__long__");
- #endif
- if HAVE_INDEX(tp)
- {
- subattr_pointer_meth(tp_as_number, nb_index, "__index__");
- }
- subattr_pointer_meth(tp_as_number, nb_float, "__float__");
- #if PY_MAJOR_VERSION <= 2
- subattr_pointer_meth(tp_as_number, nb_oct, "__oct__");
- subattr_pointer_meth(tp_as_number, nb_hex, "__hex__");
- subattr_pointer(tp_as_number, nb_coerce);
- #endif
-
- if HAVE_INPLACEOPS(tp)
- {
- subattr_pointer_meth(tp_as_number, nb_inplace_add, "__iadd__");
- subattr_pointer_meth(tp_as_number, nb_inplace_subtract, "__isub__");
- subattr_pointer_meth(tp_as_number, nb_inplace_multiply, "__imul__");
- #if PY_MAJOR_VERSION <= 2
- subattr_pointer_meth(tp_as_number, nb_inplace_divide, "__idiv__");
- #endif
- if HAVE_NEW_DIVISION(tp)
- {
- subattr_pointer_meth(tp_as_number, nb_inplace_floor_divide, "__ifloordiv__");
- subattr_pointer_meth(tp_as_number, nb_inplace_true_divide, "__itruediv__");
- }
- subattr_pointer_meth(tp_as_number, nb_inplace_remainder, "__imod__");
- subattr_pointer_meth(tp_as_number, nb_inplace_power, "__ipow__");
- subattr_pointer_meth(tp_as_number, nb_inplace_lshift, "__ilshift__");
- subattr_pointer_meth(tp_as_number, nb_inplace_rshift, "__irshift__");
- subattr_pointer_meth(tp_as_number, nb_inplace_and, "__iand__");
- subattr_pointer_meth(tp_as_number, nb_inplace_or, "__ior__");
- subattr_pointer_meth(tp_as_number, nb_inplace_xor, "__ixor__");
- }
- }
-
- attr_pointer(tp_as_sequence);
- if (special)
- {
- subattr_pointer_meth(tp_as_sequence, sq_length, "__len__");
- subattr_pointer_meth(tp_as_sequence, sq_concat, "__add__");
- if HAVE_INPLACEOPS(tp)
- {
- subattr_pointer_meth(tp_as_sequence, sq_inplace_concat, "__iadd__");
- }
- subattr_pointer_meth(tp_as_sequence, sq_repeat, "__mul__");
- if HAVE_INPLACEOPS(tp)
- {
- subattr_pointer_meth(tp_as_sequence, sq_inplace_repeat, "__imul__");
- }
- subattr_pointer_meth(tp_as_sequence, sq_item, "__getitem__");
- subattr_pointer_meth(tp_as_sequence, sq_ass_item, "__setitem__");
- if HAVE_SEQUENCE_IN(tp)
- {
- subattr_pointer_meth(tp_as_sequence, sq_contains, "__contains__");
- }
- }
-
- attr_pointer(tp_as_mapping);
- if (special)
- {
- subattr_pointer_meth(tp_as_mapping, mp_length, "__len__");
- subattr_pointer_meth(tp_as_mapping, mp_subscript, "__getitem__");
- subattr_pointer_meth(tp_as_mapping, mp_ass_subscript, "__setitem__");
- }
-
- attr_pointer(tp_as_buffer);
- if (special)
- {
- #if PY_MAJOR_VERSION <= 2
- subattr_pointer(tp_as_buffer, bf_getreadbuffer);
- subattr_pointer(tp_as_buffer, bf_getwritebuffer);
- subattr_pointer(tp_as_buffer, bf_getsegcount);
- if HAVE_GETCHARBUFFER(tp)
- {
- subattr_pointer(tp_as_buffer, bf_getcharbuffer);
- }
- #endif
- if HAVE_NEWBUFFER(tp)
- {
- subattr_pointer_meth(tp_as_buffer, bf_getbuffer, "__getbuffer__");
- subattr_pointer_meth(tp_as_buffer, bf_releasebuffer, "__releasebuffer__");
- }
- }
-
- printf(" tp_flags:\n");
- attr_flag(HEAPTYPE);
- attr_flag(BASETYPE);
- attr_flag(READY);
- attr_flag(READYING);
- attr_flag(HAVE_GC);
- #if PY_MAJOR_VERSION <= 2
- attr_flag(CHECKTYPES);
- #endif
- attr_flag(HAVE_VERSION_TAG);
- attr_flag(VALID_VERSION_TAG);
- attr_flag(IS_ABSTRACT);
- if (tp->tp_flags & Py_TPFLAGS_HAVE_VERSION_TAG)
- {
- printf(" tp_version_tag: %lu\n", (unsigned long)tp->tp_version_tag);
- }
-}
-
-#endif
diff --git a/src/sage/cpython/pycore_long.h b/src/sage/cpython/pycore_long.h
index 99561f1ba96..bbe9d3964bd 100644
--- a/src/sage/cpython/pycore_long.h
+++ b/src/sage/cpython/pycore_long.h
@@ -2,12 +2,14 @@
#include
#if PY_VERSION_HEX >= 0x030C00A5
+// For Python 3.12 compatibility
#define ob_digit(o) (((PyLongObject*)o)->long_value.ob_digit)
#else
#define ob_digit(o) (((PyLongObject*)o)->ob_digit)
#endif
#if PY_VERSION_HEX >= 0x030C00A7
+// For Python 3.12 compatibility
// taken from cpython:Include/internal/pycore_long.h @ 3.12
/* Long value tag bits:
@@ -87,12 +89,7 @@ _PyLong_DigitCount(const PyLongObject *op)
static inline void
_PyLong_SetSignAndDigitCount(PyLongObject *op, int sign, Py_ssize_t size)
{
-#if (PY_MAJOR_VERSION == 3) && (PY_MINOR_VERSION < 9)
-// The function Py_SET_SIZE is defined starting with python 3.9.
- Py_SIZE(op) = size;
-#else
Py_SET_SIZE(op, sign < 0 ? -size : size);
-#endif
}
#endif
diff --git a/src/sage/doctest/forker.py b/src/sage/doctest/forker.py
index f3950cde06b..df55ad9f6a0 100644
--- a/src/sage/doctest/forker.py
+++ b/src/sage/doctest/forker.py
@@ -1097,7 +1097,7 @@ def compile_and_execute(self, example, compiler, globs):
False
sage: doctests, extras = FDS.create_doctests(globs)
sage: ex0 = doctests[0].examples[0]
- sage: flags = 32768 if sys.version_info.minor < 8 else 524288
+ sage: flags = 524288
sage: def compiler(ex):
....: return compile(ex.source, '',
....: 'single', flags, 1)
diff --git a/src/sage/libs/gmp/pylong.pyx b/src/sage/libs/gmp/pylong.pyx
index 41587396120..a6049232443 100644
--- a/src/sage/libs/gmp/pylong.pyx
+++ b/src/sage/libs/gmp/pylong.pyx
@@ -32,14 +32,6 @@ from sage.cpython.pycore_long cimport (ob_digit, _PyLong_IsNegative,
from sage.libs.gmp.mpz cimport *
cdef extern from *:
- """
- /* Compatibility for python 3.8, can be removed later */
- #if PY_VERSION_HEX < 0x030900A4 && !defined(Py_SET_SIZE)
- static inline void _Py_SET_SIZE(PyVarObject *ob, Py_ssize_t size)
- { ob->ob_size = size; }
- #define Py_SET_SIZE(ob, size) _Py_SET_SIZE((PyVarObject*)(ob), size)
- #endif
- """
void Py_SET_SIZE(object, Py_ssize_t)
int hash_bits """
#ifdef _PyHASH_BITS
diff --git a/src/sage/misc/fpickle.pyx b/src/sage/misc/fpickle.pyx
index 1dd438de210..a17a92f0636 100644
--- a/src/sage/misc/fpickle.pyx
+++ b/src/sage/misc/fpickle.pyx
@@ -44,18 +44,13 @@ def reduce_code(co):
raise ValueError("Cannot pickle code objects from closures")
co_args = (co.co_argcount,)
- if sys.version_info.minor >= 8:
- co_args += (co.co_posonlyargcount,)
+ co_args += (co.co_posonlyargcount,)
co_args += (co.co_kwonlyargcount, co.co_nlocals,
co.co_stacksize, co.co_flags, co.co_code,
co.co_consts, co.co_names, co.co_varnames, co.co_filename,
co.co_name)
- if sys.version_info.minor >= 11:
- co_args += (co.co_qualname, co.co_firstlineno,
- co.co_linetable, co.co_exceptiontable)
- else:
- co_args += (co.co_firstlineno, co.co_lnotab)
-
+ co_args += (co.co_qualname, co.co_firstlineno,
+ co.co_linetable, co.co_exceptiontable)
return (code_ctor, co_args)
diff --git a/src/sage/misc/inherit_comparison_impl.c b/src/sage/misc/inherit_comparison_impl.c
index f12dc2a6976..2854beab87c 100644
--- a/src/sage/misc/inherit_comparison_impl.c
+++ b/src/sage/misc/inherit_comparison_impl.c
@@ -8,14 +8,8 @@
static CYTHON_INLINE void inherit_comparison(PyTypeObject* dst, const PyTypeObject* src)
{
/* Do nothing if "dst" already has comparison defined */
-#if (PY_MAJOR_VERSION < 3)
- if (dst->tp_compare) return;
-#endif
if (dst->tp_richcompare) return;
/* Copy comparison method(s) */
-#if (PY_MAJOR_VERSION < 3)
- dst->tp_compare = src->tp_compare;
-#endif
dst->tp_richcompare = src->tp_richcompare;
}
diff --git a/src/sage_docbuild/ext/sage_autodoc.py b/src/sage_docbuild/ext/sage_autodoc.py
index 94e7d076fa9..8b80350585c 100644
--- a/src/sage_docbuild/ext/sage_autodoc.py
+++ b/src/sage_docbuild/ext/sage_autodoc.py
@@ -1969,28 +1969,6 @@ def get_doc(self) -> list[list[str]] | None:
if isinstance(self.object, TypeVar):
if self.object.__doc__ == TypeVar.__doc__:
return []
- # ------------------------------------------------------------------
- # This section is kept for compatibility with python 3.9
- # see https://github.com/sagemath/sage/pull/38549#issuecomment-2327790930
- if sys.version_info[:2] < (3, 10):
- if inspect.isNewType(self.object) or isinstance(self.object, TypeVar):
- parts = self.modname.strip('.').split('.')
- orig_objpath = self.objpath
- for i in range(len(parts)):
- new_modname = '.'.join(parts[:len(parts) - i])
- new_objpath = parts[len(parts) - i:] + orig_objpath
- try:
- analyzer = ModuleAnalyzer.for_module(new_modname)
- analyzer.analyze()
- key = ('', new_objpath[-1])
- comment = list(analyzer.attr_docs.get(key, []))
- if comment:
- self.objpath = new_objpath
- self.modname = new_modname
- return [comment]
- except PycodeError:
- pass
- # ------------------------------------------------------------------
if self.doc_as_attr:
# Don't show the docstring of the class when it is an alias.
if self.get_variable_comment():
diff --git a/src/sage_setup/command/sage_build_cython.py b/src/sage_setup/command/sage_build_cython.py
index 880ce7383e2..2e04bd80f87 100644
--- a/src/sage_setup/command/sage_build_cython.py
+++ b/src/sage_setup/command/sage_build_cython.py
@@ -104,8 +104,7 @@ def finalize_options(self):
('force', 'force')]
# Python 3.5 now has a parallel option as well
- if sys.version_info[:2] >= (3, 5):
- inherit_opts.append(('parallel', 'parallel'))
+ inherit_opts.append(('parallel', 'parallel'))
self.set_undefined_options('build_ext', *inherit_opts)
diff --git a/src/setup.cfg.m4 b/src/setup.cfg.m4
index 3a4ec930b8f..6ad88107ce4 100644
--- a/src/setup.cfg.m4
+++ b/src/setup.cfg.m4
@@ -9,7 +9,7 @@ license_files = LICENSE.txt
include(`setup_cfg_metadata.m4')dnl'
[options]
-python_requires = >=3.9, <3.14
+python_requires = >=3.11, <3.14
install_requires =
SPKG_INSTALL_REQUIRES_six
dnl From build/pkgs/sagelib/dependencies