diff --git a/.github/workflows/tests.yaml b/.github/workflows/tests.yaml index 4a755422..759c5d42 100644 --- a/.github/workflows/tests.yaml +++ b/.github/workflows/tests.yaml @@ -28,7 +28,6 @@ jobs: - {python: '3.11'} - {python: '3.10'} - {python: '3.9'} - - {python: '3.8'} - {name: PyPy, python: 'pypy-3.10', tox: pypy310} steps: - uses: actions/checkout@692973e3d937129bcbf40652eb9f2f61becf3332 # v4.1.7 diff --git a/CHANGES.rst b/CHANGES.rst index 38e73c10..9101c486 100644 --- a/CHANGES.rst +++ b/CHANGES.rst @@ -3,7 +3,7 @@ Version 3.0.0 Unreleased -- Drop support for Python 3.7. +- Drop support for Python 3.7 and 3.8. - Use modern packaging metadata with ``pyproject.toml`` instead of ``setup.cfg``. :pr:`348` - Change ``distutils`` imports to ``setuptools``. :pr:`399` diff --git a/pyproject.toml b/pyproject.toml index 7ca3426d..a9e0ea11 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -16,7 +16,7 @@ classifiers = [ "Topic :: Text Processing :: Markup :: HTML", "Typing :: Typed", ] -requires-python = ">=3.8" +requires-python = ">=3.9" [project.urls] Donate = "https://palletsprojects.com/donate" @@ -43,7 +43,7 @@ source = ["markupsafe", "tests"] source = ["src", "*/site-packages"] [tool.mypy] -python_version = "3.8" +python_version = "3.9" files = ["src/markupsafe", "tests"] show_error_codes = true pretty = true @@ -56,7 +56,7 @@ module = [ ignore_missing_imports = true [tool.pyright] -pythonVersion = "3.8" +pythonVersion = "3.9" include = ["src/markupsafe", "tests"] typeCheckingMode = "basic" diff --git a/src/markupsafe/__init__.py b/src/markupsafe/__init__.py index 00cf6b8f..0afddc0c 100644 --- a/src/markupsafe/__init__.py +++ b/src/markupsafe/__init__.py @@ -2,7 +2,6 @@ import collections.abc as cabc import string -import sys import typing as t try: @@ -13,11 +12,13 @@ if t.TYPE_CHECKING: import typing_extensions as te - class HasHTML(te.Protocol): - def __html__(self, /) -> str: ... - class TPEscape(te.Protocol): - def __call__(self, s: t.Any, /) -> Markup: ... +class _HasHTML(t.Protocol): + def __html__(self, /) -> str: ... + + +class _TPEscape(t.Protocol): + def __call__(self, s: t.Any, /) -> Markup: ... def escape(s: t.Any, /) -> Markup: @@ -130,13 +131,13 @@ def __new__( def __html__(self, /) -> te.Self: return self - def __add__(self, value: str | HasHTML, /) -> te.Self: + def __add__(self, value: str | _HasHTML, /) -> te.Self: if isinstance(value, str) or hasattr(value, "__html__"): return self.__class__(super().__add__(self.escape(value))) return NotImplemented - def __radd__(self, value: str | HasHTML, /) -> te.Self: + def __radd__(self, value: str | _HasHTML, /) -> te.Self: if isinstance(value, str) or hasattr(value, "__html__"): return self.escape(value).__add__(self) @@ -164,7 +165,7 @@ def __mod__(self, value: t.Any, /) -> te.Self: def __repr__(self, /) -> str: return f"{self.__class__.__name__}({super().__repr__()})" - def join(self, iterable: cabc.Iterable[str | HasHTML], /) -> te.Self: + def join(self, iterable: cabc.Iterable[str | _HasHTML], /) -> te.Self: return self.__class__(super().join(map(self.escape, iterable))) def split( # type: ignore[override] @@ -291,13 +292,11 @@ def zfill(self, width: t.SupportsIndex, /) -> te.Self: def casefold(self, /) -> te.Self: return self.__class__(super().casefold()) - if sys.version_info >= (3, 9): - - def removeprefix(self, prefix: str, /) -> te.Self: - return self.__class__(super().removeprefix(prefix)) + def removeprefix(self, prefix: str, /) -> te.Self: + return self.__class__(super().removeprefix(prefix)) - def removesuffix(self, suffix: str) -> te.Self: - return self.__class__(super().removesuffix(suffix)) + def removesuffix(self, suffix: str) -> te.Self: + return self.__class__(super().removesuffix(suffix)) def partition(self, sep: str, /) -> tuple[te.Self, te.Self, te.Self]: left, sep, right = super().partition(sep) @@ -331,8 +330,8 @@ def __html_format__(self, format_spec: str, /) -> te.Self: class EscapeFormatter(string.Formatter): __slots__ = ("escape",) - def __init__(self, escape: TPEscape) -> None: - self.escape: TPEscape = escape + def __init__(self, escape: _TPEscape) -> None: + self.escape: _TPEscape = escape super().__init__() def format_field(self, value: t.Any, format_spec: str) -> str: @@ -358,9 +357,9 @@ class _MarkupEscapeHelper: __slots__ = ("obj", "escape") - def __init__(self, obj: t.Any, escape: TPEscape) -> None: + def __init__(self, obj: t.Any, escape: _TPEscape) -> None: self.obj: t.Any = obj - self.escape: TPEscape = escape + self.escape: _TPEscape = escape def __getitem__(self, key: t.Any, /) -> te.Self: return self.__class__(self.obj[key], self.escape) diff --git a/tox.ini b/tox.ini index 1daab3da..cb3c865c 100644 --- a/tox.ini +++ b/tox.ini @@ -1,6 +1,6 @@ [tox] envlist = - py3{13,12,11,10,9,8} + py3{13,12,11,10,9} pypy310 style typing