From ed8045ceea02aa044f08b0f05250de24bd5645a2 Mon Sep 17 00:00:00 2001 From: Adam Turner <9087854+AA-Turner@users.noreply.github.com> Date: Fri, 18 Oct 2024 01:22:37 +0100 Subject: [PATCH] Test on Python 3.14 (#12978) --- .github/workflows/main.yml | 4 ++-- pyproject.toml | 1 + sphinx/util/inspect.py | 4 ++++ sphinx/util/typing.py | 3 +++ tests/test_extensions/test_ext_autodoc.py | 8 ++++++++ tests/test_extensions/test_ext_autodoc_configs.py | 7 +++++++ tox.ini | 4 ++-- 7 files changed, 27 insertions(+), 4 deletions(-) diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index a6c0c56458..804bdc46fb 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -70,7 +70,6 @@ jobs: PYTHONWARNINGS: "error" # treat all warnings as errors deadsnakes: - if: false runs-on: ubuntu-latest name: Python ${{ matrix.python }} (Docutils ${{ matrix.docutils }}) strategy: @@ -95,6 +94,7 @@ jobs: - name: Install dependencies run: | python -m pip install --upgrade pip + sed -i 's/flit_core>=3.7/flit_core @ git+https:\/\/github.com\/pypa\/flit.git#subdirectory=flit_core/' pyproject.toml python -m pip install .[test] - name: Install Docutils ${{ matrix.docutils }} run: python -m pip install --upgrade "docutils~=${{ matrix.docutils }}.0" @@ -104,7 +104,6 @@ jobs: PYTHONWARNINGS: "error" # treat all warnings as errors deadsnakes-free-threraded: - if: false runs-on: ubuntu-latest name: Python ${{ matrix.python }} (Docutils ${{ matrix.docutils }}; free-threaded) strategy: @@ -130,6 +129,7 @@ jobs: - name: Install dependencies run: | python -m pip install --upgrade pip + sed -i 's/flit_core>=3.7/flit_core @ git+https:\/\/github.com\/pypa\/flit.git#subdirectory=flit_core/' pyproject.toml python -m pip install .[test] - name: Install Docutils ${{ matrix.docutils }} run: python -m pip install --upgrade "docutils~=${{ matrix.docutils }}.0" diff --git a/pyproject.toml b/pyproject.toml index 19e493cef2..d0fe005005 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -34,6 +34,7 @@ classifiers = [ "Programming Language :: Python :: 3.11", "Programming Language :: Python :: 3.12", "Programming Language :: Python :: 3.13", + "Programming Language :: Python :: 3.14", "Programming Language :: Python :: Implementation :: CPython", "Programming Language :: Python :: Implementation :: PyPy", "Framework :: Sphinx", diff --git a/sphinx/util/inspect.py b/sphinx/util/inspect.py index 15f98f544a..0b1b28e2d5 100644 --- a/sphinx/util/inspect.py +++ b/sphinx/util/inspect.py @@ -727,6 +727,10 @@ def _evaluate_forwardref( localns: dict[str, Any] | None, ) -> Any: """Evaluate a forward reference.""" + if sys.version_info[:2] >= (3, 14): + # https://docs.python.org/dev/library/annotationlib.html#annotationlib.ForwardRef.evaluate + # https://docs.python.org/dev/library/typing.html#typing.evaluate_forward_ref + return typing.evaluate_forward_ref(ref, globals=globalns, locals=localns) if sys.version_info >= (3, 12, 4): # ``type_params`` were added in 3.13 and the signature of _evaluate() # is not backward-compatible (it was backported to 3.12.4, so anything diff --git a/sphinx/util/typing.py b/sphinx/util/typing.py index 8f2a6ed835..337bad412c 100644 --- a/sphinx/util/typing.py +++ b/sphinx/util/typing.py @@ -425,6 +425,9 @@ def stringify_annotation( annotation_module: str = getattr(annotation, '__module__', '') annotation_name: str = getattr(annotation, '__name__', '') annotation_module_is_typing = annotation_module == 'typing' + if sys.version_info[:2] >= (3, 14) and isinstance(annotation, ForwardRef): + # ForwardRef moved from `typing` to `annotationlib` in Python 3.14. + annotation_module_is_typing = True # Extract the annotation's base type by considering formattable cases if isinstance(annotation, TypeVar) and not _is_unpack_form(annotation): diff --git a/tests/test_extensions/test_ext_autodoc.py b/tests/test_extensions/test_ext_autodoc.py index f2387a29d0..5990ea0166 100644 --- a/tests/test_extensions/test_ext_autodoc.py +++ b/tests/test_extensions/test_ext_autodoc.py @@ -1588,6 +1588,14 @@ class _EnumFormatter: * Look an enum member (valid only if the enum has members) * Create a new enum class (functional API) """ + if sys.version_info[:2] >= (3, 14): + if functional_constructor: + return ( + '(new_class_name, /, names, *, module=None, ' + 'qualname=None, type=None, start=1, boundary=None)' + ) + else: + return '(*values)' if sys.version_info[:2] >= (3, 13) or sys.version_info[:3] >= (3, 12, 3): if functional_constructor: return ( diff --git a/tests/test_extensions/test_ext_autodoc_configs.py b/tests/test_extensions/test_ext_autodoc_configs.py index 0298cdd3b5..58e90eba42 100644 --- a/tests/test_extensions/test_ext_autodoc_configs.py +++ b/tests/test_extensions/test_ext_autodoc_configs.py @@ -10,6 +10,11 @@ from sphinx.testing import restructuredtext from tests.test_extensions.autodoc_util import do_autodoc +skip_py314_segfault = pytest.mark.skipif( + sys.version_info[:2] >= (3, 14), + reason='Segmentation fault: https://github.com/python/cpython/issues/125017', +) + IS_PYPY = platform.python_implementation() == 'PyPy' @@ -182,6 +187,7 @@ def test_autodoc_class_signature_separated_init(app): ] +@skip_py314_segfault @pytest.mark.sphinx('html', testroot='ext-autodoc') def test_autodoc_class_signature_separated_new(app): app.config.autodoc_class_signature = 'separated' @@ -365,6 +371,7 @@ def test_autodoc_inherit_docstrings_for_inherited_members(app): ] +@skip_py314_segfault @pytest.mark.sphinx('html', testroot='ext-autodoc') def test_autodoc_docstring_signature(app): options = {'members': None, 'special-members': '__init__, __new__'} diff --git a/tox.ini b/tox.ini index 6fd6e18ce9..572647c119 100644 --- a/tox.ini +++ b/tox.ini @@ -1,6 +1,6 @@ [tox] minversion = 4.2.0 -envlist = py{311,312,313} +envlist = py{311,312,313,314} [testenv] usedevelop = True @@ -19,7 +19,7 @@ passenv = BUILDER READTHEDOCS description = - py{311,312,313}: Run unit tests against {envname}. + py{311,312,313,314}: Run unit tests against {envname}. extras = test setenv =