Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Make minimum Python version 3.9 again #64

Merged
merged 2 commits into from
Oct 22, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions .github/workflows/tests.yml
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,8 @@ jobs:
strategy:
matrix:
python:
- "3.9"
- "3.10"
- "3.11"
- "3.12"
- "3.13"
Expand Down
10 changes: 9 additions & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,13 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0

## [Unreleased]

## [0.0.13]

### Changed

- The minimum Python version required has been brought back to `3.9`
([#64](https://github.com/trailofbits/pypi-attestations/pull/64)).

### Fixed

- `python -m pypi_attestations verify` now handles inputs like `dist/*`
Expand Down Expand Up @@ -139,7 +146,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0

- Initial implementation

[Unreleased]: https://github.com/trailofbits/pypi-attestation-models/compare/v0.0.12...HEAD
[Unreleased]: https://github.com/trailofbits/pypi-attestation-models/compare/v0.0.13...HEAD
[0.0.13]: https://github.com/trailofbits/pypi-attestation-models/compare/v0.0.12...v0.0.13
[0.0.12]: https://github.com/trailofbits/pypi-attestation-models/compare/v0.0.11...v0.0.12
[0.0.11]: https://github.com/trailofbits/pypi-attestation-models/compare/v0.0.10...v0.0.11
[0.0.10]: https://github.com/trailofbits/pypi-attestation-models/compare/v0.0.9...v0.0.10
Expand Down
8 changes: 6 additions & 2 deletions pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ dependencies = [
"sigstore~=3.4",
"sigstore-protobuf-specs",
]
requires-python = ">=3.11"
requires-python = ">=3.9"

[tool.setuptools.dynamic]
version = { attr = "pypi_attestations.__version__" }
Expand Down Expand Up @@ -57,6 +57,7 @@ omit = ["src/pypi_attestations/_cli.py", "src/pypi_attestations/__main__.py"]
mypy_path = "src"
packages = "pypi_attestations"
plugins = ["pydantic.mypy"]
python_version = "3.9"
allow_redefinition = true
check_untyped_defs = true
disallow_incomplete_defs = true
Expand All @@ -75,7 +76,7 @@ warn_unused_ignores = true

[tool.ruff]
line-length = 100
target-version = "py311"
target-version = "py39"

[tool.ruff.lint]
select = ["E", "F", "I", "W", "UP", "ANN", "D", "COM", "ISC", "TCH", "SLF"]
Expand All @@ -84,6 +85,9 @@ select = ["E", "F", "I", "W", "UP", "ANN", "D", "COM", "ISC", "TCH", "SLF"]
# COM812 and ISC001 can cause conflicts when using ruff as a formatter.
# See https://docs.astral.sh/ruff/formatter/#conflicting-lint-rules.
ignore = ["ANN101", "ANN102", "D203", "D213", "COM812", "ISC001"]
# Needed since Pydantic relies on runtime type annotations, and we target Python versions
# < 3.10. See https://docs.astral.sh/ruff/rules/non-pep604-annotation/#why-is-this-bad
pyupgrade.keep-runtime-typing = true

[tool.ruff.lint.per-file-ignores]

Expand Down
2 changes: 1 addition & 1 deletion src/pypi_attestations/__init__.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
"""The `pypi-attestations` APIs."""

__version__ = "0.0.12"
__version__ = "0.0.13"

from ._impl import (
Attestation,
Expand Down
15 changes: 8 additions & 7 deletions src/pypi_attestations/_impl.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@

import base64
from enum import Enum
from typing import TYPE_CHECKING, Annotated, Any, Literal, NewType
from typing import TYPE_CHECKING, Annotated, Any, Literal, NewType, Optional, Union, get_args

import sigstore.errors
from annotated_types import MinLen # noqa: TCH002
Expand Down Expand Up @@ -187,7 +187,7 @@ def verify(
dist: Distribution,
*,
staging: bool = False,
) -> tuple[str, dict[str, Any] | None]:
) -> tuple[str, Optional[dict[str, Any]]]:
"""Verify against an existing Python distribution.

The `identity` can be an object confirming to
Expand All @@ -203,7 +203,8 @@ def verify(
# NOTE: Can't do `isinstance` with `Publisher` since it's
# a `_GenericAlias`; instead we punch through to the inner
# `_Publisher` union.
if isinstance(identity, _Publisher):
# Use of typing.get_args is needed for Python < 3.10
if isinstance(identity, get_args(_Publisher)):
policy = identity._as_policy() # noqa: SLF001
else:
policy = identity
Expand Down Expand Up @@ -387,7 +388,7 @@ class _PublisherBase(BaseModel):
model_config = ConfigDict(alias_generator=to_snake)

kind: str
claims: dict[str, Any] | None = None
claims: Optional[dict[str, Any]] = None

def _as_policy(self) -> VerificationPolicy:
"""Return an appropriate `sigstore.policy.VerificationPolicy` for this publisher."""
Expand Down Expand Up @@ -483,7 +484,7 @@ class GitHubPublisher(_PublisherBase):
action.
"""

environment: str | None = None
environment: Optional[str] = None
"""
The optional name GitHub Actions environment that the publishing
action was performed from.
Expand All @@ -505,7 +506,7 @@ class GitLabPublisher(_PublisherBase):
`bar` owned by group `foo` and subgroup `baz`.
"""

environment: str | None = None
environment: Optional[str] = None
"""
The optional environment that the publishing action was performed from.
"""
Expand All @@ -531,7 +532,7 @@ def _as_policy(self) -> VerificationPolicy:
return policy.AllOf(policies)


_Publisher = GitHubPublisher | GitLabPublisher
_Publisher = Union[GitHubPublisher, GitLabPublisher]
Publisher = Annotated[_Publisher, Field(discriminator="kind")]


Expand Down
9 changes: 5 additions & 4 deletions test/test_impl.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
import os
from hashlib import sha256
from pathlib import Path
from typing import Any
from typing import Any, Optional

import pretend
import pytest
Expand Down Expand Up @@ -133,7 +133,7 @@ def test_verify_github_attested(self) -> None:
assert predicate == {}

@pytest.mark.parametrize("claims", (None, {}, {"ref": "refs/tags/v0.0.4a2"}))
def test_verify_from_github_publisher(self, claims: dict | None) -> None:
def test_verify_from_github_publisher(self, claims: Optional[dict]) -> None:
publisher = impl.GitHubPublisher(
repository="trailofbits/pypi-attestation-models",
workflow="release.yml",
Expand Down Expand Up @@ -556,7 +556,7 @@ def test_as_policy(self) -> None:
assert len(pol._children) == 3

@pytest.mark.parametrize("claims", [None, {}, {"something": "unrelated"}, {"ref": None}])
def test_as_policy_invalid(self, claims: dict | None) -> None:
def test_as_policy_invalid(self, claims: Optional[dict]) -> None:
publisher = impl.GitLabPublisher(repository="fake/fake", claims=claims)

with pytest.raises(impl.VerificationError, match="refusing to build a policy"):
Expand Down Expand Up @@ -600,7 +600,8 @@ class TestBase64Bytes:
def test_decoding(self) -> None:
# This raises when using our custom type. When using Pydantic's Base64Bytes,
# this succeeds
with pytest.raises(ValueError, match="Only base64 data is allowed"):
# The exception message is different in Python 3.9 vs >=3.10
with pytest.raises(ValueError, match="Non-base64 digit found|Only base64 data is allowed"):
DummyModel(base64_bytes=b"a\n\naaa")

def test_encoding(self) -> None:
Expand Down