Skip to content

Commit d8daebf

Browse files
authored
⬆️ Drop Python 3.9 & 3.10, support Python 3.14; Drop sphinx v6 (#250)
In preparation for supporting sphinx v9 and docutils v0.22
1 parent b3d6edd commit d8daebf

File tree

15 files changed

+55
-69
lines changed

15 files changed

+55
-69
lines changed

.github/workflows/ci.yml

Lines changed: 12 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -15,10 +15,10 @@ jobs:
1515

1616
steps:
1717
- uses: actions/checkout@v4
18-
- name: Set up Python 3.9
18+
- name: Set up Python
1919
uses: actions/setup-python@v5
2020
with:
21-
python-version: 3.9
21+
python-version: "3.11"
2222
- uses: pre-commit/action@v3.0.1
2323

2424
tests:
@@ -27,22 +27,18 @@ jobs:
2727
fail-fast: false
2828
matrix:
2929
os: [ubuntu-latest]
30-
python-version: ["3.9", "3.10", "3.11", "3.12"]
31-
sphinx-version: ["~=7.0"]
30+
python-version: ["3.11", "3.12", "3.13", "3.14"]
31+
sphinx-version: ["~=7.0", "~=8.0"]
3232
extras: ["testing"]
3333
include:
34-
- os: ubuntu-latest
35-
python-version: "3.9"
36-
sphinx-version: "~=6.0"
37-
extras: "testing"
38-
- os: ubuntu-latest
39-
python-version: "3.10"
40-
sphinx-version: "~=8.0"
41-
extras: "testing-no-myst" # TODO myst does not yet support Sphinx 8.0
4234
- os: windows-latest
43-
python-version: "3.9"
35+
python-version: "3.11"
4436
sphinx-version: "~=7.0"
4537
extras: "testing"
38+
- os: windows-latest
39+
python-version: "3.14"
40+
sphinx-version: "~=8.0"
41+
extras: "testing"
4642

4743
runs-on: ${{ matrix.os }}
4844

@@ -81,10 +77,10 @@ jobs:
8177

8278
steps:
8379
- uses: actions/checkout@v4
84-
- name: Set up Python 3.9
80+
- name: Set up Python
8581
uses: actions/setup-python@v5
8682
with:
87-
python-version: "3.9"
83+
python-version: "3.11"
8884
cache: pip
8985
- name: Install dependencies
9086
run: |
@@ -123,7 +119,7 @@ jobs:
123119
- name: Set up Python
124120
uses: actions/setup-python@v5
125121
with:
126-
python-version: 3.9
122+
python-version: "3.11"
127123
- name: install flit
128124
run: |
129125
pip install flit~=3.4

.pre-commit-config.yaml

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -11,22 +11,22 @@ exclude: >
1111
repos:
1212

1313
- repo: https://github.com/pre-commit/pre-commit-hooks
14-
rev: v4.6.0
14+
rev: v6.0.0
1515
hooks:
1616
- id: check-json
1717
- id: check-yaml
1818
- id: end-of-file-fixer
1919
- id: trailing-whitespace
2020

2121
- repo: https://github.com/astral-sh/ruff-pre-commit
22-
rev: v0.5.5
22+
rev: v0.14.9
2323
hooks:
2424
- id: ruff
2525
args: [--fix]
2626
- id: ruff-format
2727

2828
- repo: https://github.com/pre-commit/mirrors-mypy
29-
rev: v1.11.1
29+
rev: v1.19.1
3030
hooks:
3131
- id: mypy
3232
additional_dependencies: []

.readthedocs.yml

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ version: 2
33
build:
44
os: ubuntu-22.04
55
tools:
6-
python: "3.10"
6+
python: "3.11"
77

88
python:
99
install:
@@ -13,5 +13,6 @@ python:
1313
- rtd
1414

1515
sphinx:
16+
configuration: docs/conf.py
1617
builder: html
1718
fail_on_warning: true

pyproject.toml

Lines changed: 5 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -15,30 +15,29 @@ classifiers = [
1515
"Intended Audience :: Developers",
1616
"License :: OSI Approved :: MIT License",
1717
"Programming Language :: Python :: 3",
18-
"Programming Language :: Python :: 3.9",
19-
"Programming Language :: Python :: 3.10",
2018
"Programming Language :: Python :: 3.11",
2119
"Programming Language :: Python :: 3.12",
2220
"Programming Language :: Python :: 3.13",
21+
"Programming Language :: Python :: 3.14",
2322
"Programming Language :: Python :: Implementation :: CPython",
2423
"Topic :: Software Development :: Libraries :: Python Modules",
2524
"Topic :: Text Processing :: Markup",
2625
"Topic :: Text Processing :: Markup :: Markdown",
2726
"Topic :: Text Processing :: Markup :: reStructuredText",
2827
]
2928
keywords = ["sphinx", "extension", "material design", "web components"]
30-
requires-python = ">=3.9"
31-
dependencies = ["sphinx>=6,<9"]
29+
requires-python = ">=3.11"
30+
dependencies = ["sphinx>=7,<9"]
3231

3332
[project.urls]
3433
Homepage = "https://github.com/executablebooks/sphinx-design"
3534
Documentation = "https://sphinx-design.readthedocs.io"
3635

3736
[project.optional-dependencies]
3837
code-style = ["pre-commit>=3,<4"]
39-
rtd = ["myst-parser>=2,<4"]
38+
rtd = ["myst-parser>=3,<5"]
4039
testing = [
41-
"myst-parser>=2,<4",
40+
"myst-parser>=3,<5",
4241
"pytest~=8.3",
4342
"pytest-cov",
4443
"pytest-regressions",

sphinx_design/__init__.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@
99

1010

1111
def setup(app: "Sphinx") -> dict:
12-
from .extension import setup_extension
12+
from .extension import setup_extension # noqa: PLC0415
1313

1414
setup_extension(app)
1515
return {

sphinx_design/_compat.py

Lines changed: 2 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,7 @@
11
"""Helpers for cross compatibility across dependency versions."""
22

3-
from collections.abc import Iterable
3+
from collections.abc import Callable, Iterable
44
from importlib import resources
5-
from typing import Callable
65

76
from docutils.nodes import Element
87

@@ -14,8 +13,5 @@ def findall(node: Element) -> Callable[..., Iterable[Element]]:
1413
return getattr(node, "findall", node.traverse)
1514

1615

17-
# TODO: >= Python 3.9, only use `resources.files` and drop `resources.read_text`
1816
def read_text(module: resources.Package, filename: str) -> str:
19-
if hasattr(resources, "files"):
20-
return resources.files(module).joinpath(filename).read_text()
21-
return resources.read_text(module, filename)
17+
return resources.files(module).joinpath(filename).read_text()

sphinx_design/article_info.py

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,3 @@
1-
from typing import Optional
2-
31
from docutils import nodes
42
from docutils.parsers.rst import directives
53
from sphinx.application import Sphinx
@@ -32,7 +30,7 @@ class ArticleInfoDirective(SdDirective):
3230
}
3331

3432
def _parse_text(
35-
self, text: str, icon: Optional[nodes.Node] = None, parse: bool = False
33+
self, text: str, icon: nodes.Node | None = None, parse: bool = False
3634
) -> nodes.Node:
3735
"""Parse the text."""
3836
if not parse:

sphinx_design/badges_buttons.py

Lines changed: 4 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,3 @@
1-
from typing import Optional
2-
31
from docutils import nodes
42
from docutils.parsers.rst import directives
53
from sphinx import addnodes
@@ -45,7 +43,7 @@ def setup_badges_and_buttons(app: Sphinx) -> None:
4543
app.add_directive(DIRECTIVE_NAME_BUTTON_REF, ButtonRefDirective)
4644

4745

48-
def create_bdg_classes(color: Optional[str], outline: bool) -> list[str]:
46+
def create_bdg_classes(color: str | None, outline: bool) -> list[str]:
4947
"""Create the badge classes."""
5048
classes = [
5149
"sd-sphinx-override",
@@ -63,7 +61,7 @@ def create_bdg_classes(color: Optional[str], outline: bool) -> list[str]:
6361
class BadgeRole(SphinxRole):
6462
"""Role to display a badge."""
6563

66-
def __init__(self, color: Optional[str] = None, *, outline: bool = False) -> None:
64+
def __init__(self, color: str | None = None, *, outline: bool = False) -> None:
6765
super().__init__()
6866
self.color = color
6967
self.outline = outline
@@ -82,7 +80,7 @@ def run(self) -> tuple[list[nodes.Node], list[nodes.system_message]]:
8280
class LinkBadgeRole(ReferenceRole):
8381
"""Role to display a badge with an external link."""
8482

85-
def __init__(self, color: Optional[str] = None, *, outline: bool = False) -> None:
83+
def __init__(self, color: str | None = None, *, outline: bool = False) -> None:
8684
super().__init__()
8785
self.color = color
8886
self.outline = outline
@@ -105,7 +103,7 @@ def run(self) -> tuple[list[nodes.Node], list[nodes.system_message]]:
105103
class XRefBadgeRole(ReferenceRole):
106104
"""Role to display a badge with an internal link."""
107105

108-
def __init__(self, color: Optional[str] = None, *, outline: bool = False) -> None:
106+
def __init__(self, color: str | None = None, *, outline: bool = False) -> None:
109107
super().__init__()
110108
self.color = color
111109
self.outline = outline

sphinx_design/cards.py

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import re
2-
from typing import NamedTuple, Optional
2+
from typing import NamedTuple
33

44
from docutils import nodes
55
from docutils.parsers.rst import directives
@@ -42,8 +42,8 @@ class CardContent(NamedTuple):
4242
"""
4343

4444
body: tuple[int, StringList]
45-
header: Optional[tuple[int, StringList]] = None
46-
footer: Optional[tuple[int, StringList]] = None
45+
header: tuple[int, StringList] | None = None
46+
footer: tuple[int, StringList] | None = None
4747

4848

4949
class CardDirective(SdDirective):
@@ -79,13 +79,13 @@ def run_with_defaults(self) -> list[nodes.Node]:
7979

8080
@classmethod
8181
def create_card( # noqa: PLR0915
82-
cls, inst: SphinxDirective, arguments: Optional[list], options: dict
82+
cls, inst: SphinxDirective, arguments: list | None, options: dict
8383
) -> nodes.Node:
8484
"""Run the directive."""
8585
# TODO better degradation for latex
8686
card_classes = ["sd-card", "sd-sphinx-override"]
8787
if "width" in options:
88-
card_classes += [f'sd-w-{options["width"].rstrip("%")}']
88+
card_classes += [f"sd-w-{options['width'].rstrip('%')}"]
8989
card_classes += options.get("margin", ["sd-mb-3"])
9090
card_classes += [f"sd-shadow-{options.get('shadow', 'sm')}"]
9191
if "link" in options:

sphinx_design/grids.py

Lines changed: 6 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,3 @@
1-
from typing import Optional
2-
31
from docutils import nodes
42
from docutils.parsers.rst import directives
53
from sphinx.application import Sphinx
@@ -33,7 +31,7 @@ def setup_grids(app: Sphinx):
3331

3432

3533
def _media_option(
36-
argument: Optional[str],
34+
argument: str | None,
3735
prefix: str,
3836
*,
3937
allow_auto: bool = False,
@@ -66,27 +64,27 @@ def _media_option(
6664
raise ValueError(validate_error_msg)
6765
return [f"{prefix}{values[0]}"] + [
6866
f"{prefix}{size}-{value}"
69-
for size, value in zip(["xs", "sm", "md", "lg"], values)
67+
for size, value in zip(["xs", "sm", "md", "lg"], values, strict=False)
7068
]
7169

7270

73-
def row_columns_option(argument: Optional[str]) -> list[str]:
71+
def row_columns_option(argument: str | None) -> list[str]:
7472
"""Validate the number of columns (out of 12) a grid row will have.
7573
7674
One or four integers (for "xs sm md lg") between 1 and 12 (or 'auto').
7775
"""
7876
return _media_option(argument, "sd-row-cols-", allow_auto=True)
7977

8078

81-
def item_columns_option(argument: Optional[str]) -> list[str]:
79+
def item_columns_option(argument: str | None) -> list[str]:
8280
"""Validate the number of columns (out of 12) a grid-item will take up.
8381
8482
One or four integers (for "xs sm md lg") between 1 and 12 (or 'auto').
8583
"""
8684
return _media_option(argument, "sd-col-", allow_auto=True)
8785

8886

89-
def gutter_option(argument: Optional[str]) -> list[str]:
87+
def gutter_option(argument: str | None) -> list[str]:
9088
"""Validate the gutter size between grid items.
9189
9290
One or four integers (for "xs sm md lg") between 0 and 5.
@@ -191,7 +189,7 @@ def run_with_defaults(self) -> list[nodes.Node]:
191189
+ self.options.get("margin", [])
192190
+ self.options.get("padding", [])
193191
+ (
194-
[f'sd-align-major-{self.options["child-align"]}']
192+
[f"sd-align-major-{self.options['child-align']}"]
195193
if "child-align" in self.options
196194
else []
197195
)

0 commit comments

Comments
 (0)