Skip to content

Commit

Permalink
package_managers: generic: Use a serializer for URL-typed fields
Browse files Browse the repository at this point in the history
Pydantic formats down URL types as "type casts" in the serialized
dictionary [1]. Apparently, that's by design and the docs advises to
use custom serializers for given fields [2].

This patch is necessary, because pydantic 2.10.2 changed their behavior
when it comes to handling URL types [3] and so once we bump the version
we'd hit a test failure requiring us to change the unit test to "cast"
some fields as AnyUrl rather than Url. Since these have no place in
plain dictionaries, this patch fixes the problem in the correct way by
the use of pydantic serializers.

[1] pydantic/pydantic#10998
[2] https://docs.pydantic.dev/latest/api/functional_serializers/#pydantic.functional_serializers.PlainSerializer
[3] https://pydantic.dev/articles/pydantic-v2-10-release#migrate-to-subclassing-instead-of-annotated-approach-for-pydantic-url-types

Signed-off-by: Erik Skultety <[email protected]>
  • Loading branch information
eskultety committed Jan 3, 2025
1 parent 98e99a2 commit 10144e7
Show file tree
Hide file tree
Showing 2 changed files with 13 additions and 8 deletions.
14 changes: 11 additions & 3 deletions cachi2/core/package_managers/generic/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,16 @@
from urllib.parse import urljoin, urlparse

from packageurl import PackageURL
from pydantic import AnyUrl, BaseModel, ConfigDict, field_validator, model_validator
from pydantic import (
AnyUrl,
BaseModel,
ConfigDict,
PlainSerializer,
field_validator,
model_validator,
)
from pydantic_core.core_schema import ValidationInfo
from typing_extensions import Annotated

from cachi2.core.checksum import ChecksumInfo
from cachi2.core.errors import PackageManagerError
Expand Down Expand Up @@ -88,7 +96,7 @@ class LockfileArtifactUrl(LockfileArtifactBase):
:param download_url: The URL to download the artifact from.
"""

download_url: AnyUrl
download_url: Annotated[AnyUrl, PlainSerializer(str, return_type=str)]

def resolve_filename(self) -> str:
"""Resolve the filename of the artifact."""
Expand Down Expand Up @@ -120,7 +128,7 @@ def get_sbom_component(self) -> Component:
class LockfileArtifactMavenAttributes(BaseModel):
"""Attributes for a Maven artifact in the lockfile."""

repository_url: AnyUrl
repository_url: Annotated[AnyUrl, PlainSerializer(str, return_type=str)]
group_id: str
artifact_id: str
version: str
Expand Down
7 changes: 2 additions & 5 deletions tests/unit/package_managers/test_generic.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@
from unittest import mock

import pytest
from pydantic_core import Url

from cachi2.core.errors import Cachi2Error, PackageRejected
from cachi2.core.models.input import GenericPackageInput
Expand Down Expand Up @@ -335,15 +334,13 @@ def test_load_generic_lockfile_valid(rooted_tmp_path: RootedPath) -> None:
"metadata": {"version": "1.0"},
"artifacts": [
{
"download_url": Url("https://example.com/artifact"),
"download_url": "https://example.com/artifact",
"filename": str(rooted_tmp_path.join_within_root("archive.zip")),
"checksum": "md5:3a18656e1cea70504b905836dee14db0",
},
{
"checksum": "md5:32112bed1914cfe3799600f962750b1d",
"download_url": Url(
"https://example.com/more/complex/path/file.tar.gz?foo=bar#fragment"
),
"download_url": "https://example.com/more/complex/path/file.tar.gz?foo=bar#fragment",
"filename": str(rooted_tmp_path.join_within_root("file.tar.gz")),
},
],
Expand Down

0 comments on commit 10144e7

Please sign in to comment.