diff --git a/.github/workflows/_test.yml b/.github/workflows/_test.yml index 601ad3736b..4fe5c77946 100644 --- a/.github/workflows/_test.yml +++ b/.github/workflows/_test.yml @@ -18,7 +18,7 @@ jobs: - name: Set up Python (oldest supported version) uses: actions/setup-python@83679a892e2d95755f2dac6acb0bfd1e9ac5d548 # v6.1.0 with: - python-version: "3.9" + python-version: "3.10" cache: 'pip' cache-dependency-path: | requirements/*.txt @@ -38,7 +38,7 @@ jobs: needs: lint-test strategy: matrix: - python-version: ["3.9", "3.10", "3.11", "3.12", "3.13"] + python-version: ["3.10", "3.11", "3.12", "3.13", "3.14"] os: [ubuntu-latest] include: - python-version: "3.x" diff --git a/pyproject.toml b/pyproject.toml index d0bed22ce8..cce1fc5487 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -8,7 +8,7 @@ description = "A secure updater framework for Python" readme = "README.md" license = "Apache-2.0 OR MIT" license-files = ["LICENSE", "LICENSE-MIT"] -requires-python = ">=3.8" +requires-python = ">=3.10" authors = [ { email = "theupdateframework@googlegroups.com" }, ] @@ -31,11 +31,11 @@ classifiers = [ "Operating System :: POSIX :: Linux", "Programming Language :: Python", "Programming Language :: Python :: 3", - "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", + "Programming Language :: Python :: 3.14", "Programming Language :: Python :: Implementation :: CPython", "Topic :: Security", "Topic :: Software Development", diff --git a/tests/test_fetcher_ng.py b/tests/test_fetcher_ng.py index d04b09f427..7ef7c11b70 100644 --- a/tests/test_fetcher_ng.py +++ b/tests/test_fetcher_ng.py @@ -170,9 +170,10 @@ def test_download_file_upper_length(self) -> None: # Download a file bigger than expected def test_download_file_length_mismatch(self) -> None: - with self.assertRaises( - exceptions.DownloadLengthMismatchError - ), self.fetcher.download_file(self.url, self.file_length - 4): + with ( + self.assertRaises(exceptions.DownloadLengthMismatchError), + self.fetcher.download_file(self.url, self.file_length - 4), + ): pass # we never get here as download_file() raises diff --git a/tests/test_trusted_metadata_set.py b/tests/test_trusted_metadata_set.py index bd8113eb4a..fd59635ed8 100644 --- a/tests/test_trusted_metadata_set.py +++ b/tests/test_trusted_metadata_set.py @@ -7,7 +7,7 @@ import sys import unittest from datetime import datetime, timezone -from typing import Callable, ClassVar +from typing import TYPE_CHECKING, ClassVar from securesystemslib.signer import Signer @@ -30,6 +30,9 @@ ) from tuf.ngclient.config import EnvelopeType +if TYPE_CHECKING: + from collections.abc import Callable + logger = logging.getLogger(__name__) diff --git a/tests/test_updater_ng.py b/tests/test_updater_ng.py index 50ef5ee3be..5393aa3c21 100644 --- a/tests/test_updater_ng.py +++ b/tests/test_updater_ng.py @@ -12,7 +12,7 @@ import tempfile import unittest from collections.abc import Iterable -from typing import TYPE_CHECKING, Callable, ClassVar +from typing import TYPE_CHECKING, ClassVar from unittest.mock import MagicMock, patch from securesystemslib.signer import Signer @@ -30,7 +30,7 @@ from tuf.ngclient import Updater, UpdaterConfig if TYPE_CHECKING: - from collections.abc import Iterable + from collections.abc import Callable, Iterable logger = logging.getLogger(__name__) diff --git a/tests/utils.py b/tests/utils.py index bbfb07dbaa..f4310d0aec 100644 --- a/tests/utils.py +++ b/tests/utils.py @@ -32,11 +32,11 @@ import time import warnings from contextlib import contextmanager -from typing import IO, TYPE_CHECKING, Any, Callable +from typing import IO, TYPE_CHECKING, Any if TYPE_CHECKING: import unittest - from collections.abc import Iterator + from collections.abc import Callable, Iterator logger = logging.getLogger(__name__) @@ -111,7 +111,7 @@ def wait_for_server( sock.settimeout(remaining_timeout) sock.connect((host, port)) succeeded = True - except socket.timeout: + except TimeoutError: pass except OSError as e: # ECONNREFUSED is expected while the server is not started diff --git a/tuf/api/_payload.py b/tuf/api/_payload.py index 8a8c40ffdb..c4a64bb565 100644 --- a/tuf/api/_payload.py +++ b/tuf/api/_payload.py @@ -396,19 +396,15 @@ def verified(self) -> bool: def signed(self) -> dict[str, Key]: """Dictionary of all signing keys that have signed, from both VerificationResults. - return a union of all signed (in python<3.9 this requires - dict unpacking) """ - return {**self.first.signed, **self.second.signed} + return self.first.signed | self.second.signed @property def unsigned(self) -> dict[str, Key]: """Dictionary of all signing keys that have not signed, from both VerificationResults. - return a union of all unsigned (in python<3.9 this requires - dict unpacking) """ - return {**self.first.unsigned, **self.second.unsigned} + return self.first.unsigned | self.second.unsigned class _DelegatorMixin(metaclass=abc.ABCMeta): @@ -1195,8 +1191,8 @@ def _is_target_in_pathpattern(targetpath: str, pathpattern: str) -> bool: # Every part in the pathpattern could include a glob pattern, that's why # each of the target and pathpattern parts should match. - for target_dir, pattern_dir in zip(target_parts, pattern_parts): - if not fnmatch.fnmatch(target_dir, pattern_dir): + for target, pattern in zip(target_parts, pattern_parts, strict=True): + if not fnmatch.fnmatch(target, pattern): return False return True diff --git a/tuf/ngclient/_internal/trusted_metadata_set.py b/tuf/ngclient/_internal/trusted_metadata_set.py index 179a65ed87..689eef01de 100644 --- a/tuf/ngclient/_internal/trusted_metadata_set.py +++ b/tuf/ngclient/_internal/trusted_metadata_set.py @@ -66,7 +66,7 @@ import datetime import logging from collections import abc -from typing import TYPE_CHECKING, Union, cast +from typing import TYPE_CHECKING, cast from tuf.api import exceptions from tuf.api.dsse import SimpleEnvelope @@ -88,7 +88,7 @@ logger = logging.getLogger(__name__) -Delegator = Union[Root, Targets] +Delegator = Root | Targets class TrustedMetadataSet(abc.Mapping):