Skip to content

Commit

Permalink
Fix Pydantic warnings. (#388)
Browse files Browse the repository at this point in the history
* Fix Pydantic warnings.

Pydantic has deprecated validator and should be replaced by field_validator.

See https://docs.pydantic.dev/2.8/migration/#validator-and-root_validator-are-deprecated

* Use `partial` for validators

* Replace `__fields__` with `model_fields`.

This was deprecated in v2. This instance of `__fields__` was called within a block that only runs in pydantic v2, so it should be fine to replace the function call.

* Fix the rest of pydantic warnings.

* Bump LIBPATCH on tracing and ingress

---------

Co-authored-by: PietroPasotti <[email protected]>
  • Loading branch information
pedro-avalos and PietroPasotti authored Aug 26, 2024
1 parent 521e00e commit d7139be
Show file tree
Hide file tree
Showing 3 changed files with 37 additions and 18 deletions.
12 changes: 8 additions & 4 deletions lib/charms/tempo_k8s/v2/tracing.py
Original file line number Diff line number Diff line change
Expand Up @@ -107,7 +107,7 @@ def __init__(self, *args):

# Increment this PATCH version before using `charmcraft publish-lib` or reset
# to 0 if you are raising the major API version
LIBPATCH = 7
LIBPATCH = 8

PYDEPS = ["pydantic"]

Expand Down Expand Up @@ -174,7 +174,8 @@ class AmbiguousRelationUsageError(TracingError):
"""Raised when one wrongly assumes that there can only be one relation on an endpoint."""


if int(pydantic.version.VERSION.split(".")[0]) < 2:
PYDANTIC_IS_V1 = int(pydantic.version.VERSION.split(".")[0]) < 2
if PYDANTIC_IS_V1:

class DatabagModel(BaseModel): # type: ignore
"""Base databag model."""
Expand Down Expand Up @@ -312,7 +313,7 @@ def dump(self, databag: Optional[MutableMapping] = None, clear: bool = True):


# todo use models from charm-relation-interfaces
if int(pydantic.version.VERSION.split(".")[0]) < 2:
if PYDANTIC_IS_V1:

class ProtocolType(BaseModel): # type: ignore
"""Protocol Type."""
Expand Down Expand Up @@ -865,7 +866,10 @@ def _on_tracing_relation_changed(self, event):
return

data = TracingProviderAppData.load(relation.data[relation.app])
self.on.endpoint_changed.emit(relation, [i.dict() for i in data.receivers]) # type: ignore
self.on.endpoint_changed.emit(
relation,
[i.dict() if PYDANTIC_IS_V1 else i.model_dump(mode="json") for i in data.receivers],
)

def _on_tracing_relation_broken(self, event: RelationBrokenEvent):
"""Notify the providers that the endpoint is broken."""
Expand Down
27 changes: 18 additions & 9 deletions lib/charms/traefik_k8s/v2/ingress.py
Original file line number Diff line number Diff line change
Expand Up @@ -56,13 +56,14 @@ def _on_ingress_revoked(self, event: IngressPerAppRevokedEvent):
import socket
import typing
from dataclasses import dataclass
from functools import partial
from typing import Any, Callable, Dict, List, MutableMapping, Optional, Sequence, Tuple, Union

import pydantic
from ops.charm import CharmBase, RelationBrokenEvent, RelationEvent
from ops.framework import EventSource, Object, ObjectEvents, StoredState
from ops.model import ModelError, Relation, Unit
from pydantic import AnyHttpUrl, BaseModel, Field, validator
from pydantic import AnyHttpUrl, BaseModel, Field

# The unique Charmhub library identifier, never change it
LIBID = "e6de2a5cd5b34422a204668f3b8f90d2"
Expand All @@ -72,7 +73,7 @@ def _on_ingress_revoked(self, event: IngressPerAppRevokedEvent):

# Increment this PATCH version before using `charmcraft publish-lib` or reset
# to 0 if you are raising the major API version
LIBPATCH = 13
LIBPATCH = 14

PYDEPS = ["pydantic"]

Expand All @@ -84,6 +85,9 @@ def _on_ingress_revoked(self, event: IngressPerAppRevokedEvent):

PYDANTIC_IS_V1 = int(pydantic.version.VERSION.split(".")[0]) < 2
if PYDANTIC_IS_V1:
from pydantic import validator

input_validator = partial(validator, pre=True)

class DatabagModel(BaseModel): # type: ignore
"""Base databag model."""
Expand Down Expand Up @@ -143,7 +147,9 @@ def dump(self, databag: Optional[MutableMapping] = None, clear: bool = True):
return databag

else:
from pydantic import ConfigDict
from pydantic import ConfigDict, field_validator

input_validator = partial(field_validator, mode="before")

class DatabagModel(BaseModel):
"""Base databag model."""
Expand Down Expand Up @@ -171,7 +177,7 @@ def load(cls, databag: MutableMapping):
k: json.loads(v)
for k, v in databag.items()
# Don't attempt to parse model-external values
if k in {(f.alias or n) for n, f in cls.__fields__.items()} # type: ignore
if k in {(f.alias or n) for n, f in cls.model_fields.items()} # type: ignore
}
except json.JSONDecodeError as e:
msg = f"invalid databag contents: expecting json. {databag}"
Expand Down Expand Up @@ -252,14 +258,14 @@ class IngressRequirerAppData(DatabagModel):
default="http", description="What scheme to use in the generated ingress url"
)

@validator("scheme", pre=True)
@input_validator("scheme")
def validate_scheme(cls, scheme): # noqa: N805 # pydantic wants 'cls' as first arg
"""Validate scheme arg."""
if scheme not in {"http", "https", "h2c"}:
raise ValueError("invalid scheme: should be one of `http|https|h2c`")
return scheme

@validator("port", pre=True)
@input_validator("port")
def validate_port(cls, port): # noqa: N805 # pydantic wants 'cls' as first arg
"""Validate port."""
assert isinstance(port, int), type(port)
Expand All @@ -277,13 +283,13 @@ class IngressRequirerUnitData(DatabagModel):
"IP can only be None if the IP information can't be retrieved from juju.",
)

@validator("host", pre=True)
@input_validator("host")
def validate_host(cls, host): # noqa: N805 # pydantic wants 'cls' as first arg
"""Validate host."""
assert isinstance(host, str), type(host)
return host

@validator("ip", pre=True)
@input_validator("ip")
def validate_ip(cls, ip): # noqa: N805 # pydantic wants 'cls' as first arg
"""Validate ip."""
if ip is None:
Expand Down Expand Up @@ -462,7 +468,10 @@ def _handle_relation(self, event):
event.relation,
data.app.name,
data.app.model,
[unit.dict() for unit in data.units],
[
unit.dict() if PYDANTIC_IS_V1 else unit.model_dump(mode="json")
for unit in data.units
],
data.app.strip_prefix or False,
data.app.redirect_https or False,
)
Expand Down
16 changes: 11 additions & 5 deletions src/charm.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
from typing import Any, Dict, List, Optional, Tuple, Union, cast
from urllib.parse import urlparse

import pydantic
import yaml
from charms.certificate_transfer_interface.v0.certificate_transfer import (
CertificateAvailableEvent as CertificateTransferAvailableEvent,
Expand All @@ -32,14 +33,15 @@
ForwardAuthRequirerConfig,
)
from charms.observability_libs.v1.cert_handler import CertHandler
from charms.observability_libs.v1.kubernetes_service_patch import (
KubernetesServicePatch,
)
from charms.observability_libs.v1.kubernetes_service_patch import KubernetesServicePatch
from charms.prometheus_k8s.v0.prometheus_scrape import MetricsEndpointProvider
from charms.tempo_k8s.v1.charm_tracing import trace_charm
from charms.tempo_k8s.v2.tracing import TracingEndpointRequirer
from charms.traefik_k8s.v1.ingress import IngressPerAppProvider as IPAv1
from charms.traefik_k8s.v1.ingress_per_unit import DataValidationError, IngressPerUnitProvider
from charms.traefik_k8s.v1.ingress_per_unit import (
DataValidationError,
IngressPerUnitProvider,
)
from charms.traefik_k8s.v2.ingress import IngressPerAppProvider as IPAv2
from charms.traefik_route_k8s.v0.traefik_route import (
TraefikRouteProvider,
Expand Down Expand Up @@ -88,6 +90,8 @@

_TRAEFIK_CONTAINER_NAME = "traefik"

PYDANTIC_IS_V1 = int(pydantic.version.VERSION.split(".")[0]) < 2


class _IngressRelationType(enum.Enum):
per_app = "per_app"
Expand Down Expand Up @@ -931,7 +935,9 @@ def _get_configs_per_app(self, relation: Relation) -> Dict[str, Any]:
logger.error(f"invalid data shared through {relation}... Error: {e}.")
return {}

prefix = self._get_prefix(data.app.dict(by_alias=True))
prefix = self._get_prefix(
data.app.dict(by_alias=True) if PYDANTIC_IS_V1 else data.app.model_dump(by_alias=True)
)
config = self.traefik.get_per_app_http_config(
prefix=prefix,
scheme=data.app.scheme,
Expand Down

0 comments on commit d7139be

Please sign in to comment.