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

Bump pydantic to 2.10.0 and remove Base64 workaround #73

Merged
merged 1 commit into from
Nov 20, 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: 1 addition & 1 deletion pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ dependencies = [
"cryptography",
"packaging",
"pyasn1 ~= 0.6",
"pydantic",
"pydantic >= 2.10.0",
"sigstore~=3.4",
"sigstore-protobuf-specs",
]
Expand Down
26 changes: 1 addition & 25 deletions src/pypi_attestations/_impl.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@
from packaging.utils import parse_sdist_filename, parse_wheel_filename
from pyasn1.codec.der.decoder import decode as der_decode
from pyasn1.type.char import UTF8String
from pydantic import Base64Encoder, BaseModel, ConfigDict, EncodedBytes, Field, field_validator
from pydantic import Base64Bytes, BaseModel, ConfigDict, Field, field_validator
from pydantic.alias_generators import to_snake
from pydantic_core import ValidationError
from sigstore._utils import _sha256_streaming
Expand All @@ -38,30 +38,6 @@
from sigstore.verify.policy import VerificationPolicy


class Base64EncoderSansNewline(Base64Encoder):
r"""A Base64Encoder that doesn't insert newlines when encoding.

Pydantic's Base64Bytes type inserts newlines b'\n' every 76 characters because they
use `base64.encodebytes()` instead of `base64.b64encode()`. Pydantic maintainers
have stated that they won't fix this, and that users should work around it by
defining their own Base64 type with a custom encoder.
See https://github.com/pydantic/pydantic/issues/9072 for more details.
"""

@classmethod
def encode(cls, value: bytes) -> bytes:
"""Encode bytes to base64."""
return base64.b64encode(value)

@classmethod
def decode(cls, value: bytes) -> bytes:
"""Decode base64 bytes."""
return base64.b64decode(value, validate=True)


Base64Bytes = Annotated[bytes, EncodedBytes(encoder=Base64EncoderSansNewline)]


class Distribution(BaseModel):
"""Represents a Python package distribution.

Expand Down
16 changes: 6 additions & 10 deletions test/test_impl.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@
import pretend
import pytest
import sigstore
from pydantic import BaseModel, TypeAdapter, ValidationError
from pydantic import Base64Bytes, BaseModel, TypeAdapter, ValidationError
from sigstore.dsse import DigestSet, StatementBuilder, Subject
from sigstore.models import Bundle
from sigstore.oidc import IdentityToken
Expand Down Expand Up @@ -614,18 +614,14 @@ def test_version(self) -> None:


class DummyModel(BaseModel):
base64_bytes: impl.Base64Bytes
base64_bytes: Base64Bytes


class TestBase64Bytes:
# See the docstrings for `_impl.Base64Bytes` for more details
def test_decoding(self) -> None:
# This raises when using our custom type. When using Pydantic's Base64Bytes,
# this succeeds
# 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")

# Regression test for an issue with pydantic < 2.10.0
# The Base64Bytes Pydantic type should not insert newlines
# when encoding to base64.
# See https://github.com/pydantic/pydantic/issues/9072
def test_encoding(self) -> None:
model = DummyModel(base64_bytes=b"aaaa" * 76)
assert "\\n" not in model.model_dump_json()