Skip to content

Add a marshmallow module with validation tools #108

@llucax

Description

@llucax

What's needed?

We need to provide an easy way to load configuration for API clients using marshmallow.

Proposed solution

Add the following types:

from typing import Annotated
from marshmallow.fields import String
from marshmallow.validate import URL, Length


class GrpcUrlField(String):
    """A marshmallow field for a gRPC URL."""

    def __init__(self, *_: Any, **kwargs: Any) -> None:
        """Initialize this instance."""
        validators = kwargs.pop("validate", [])
        if not isinstance(validators, list):
            validators = [validators]
        validators.append(URL(schemes=["grpc"], error="Not a valid gRPC URL."))
        super().__init__(validate=validators, **kwargs)


class ApiKeyField(String):
    """A marshmallow field for an API key."""

    def __init__(self, *_: Any, **kwargs: Any) -> None:
        """Initialize this instance."""
        validators = kwargs.pop("validate", [])
        if not isinstance(validators, list):
            validators = [validators]
        validators.append(Length(min=1, error="API key must be non-empty."))
        super().__init__(validate=validators, **kwargs)

GrpcUrl = Annotated[str, GrpcUrlField]
]
"""A marshmallow field for a gRPC URL."""

ApiKey = Annotated[str, ApiKeyField]
"""A marshmallow field for an API key."""

Use cases

Validating environment variables, for example:

from dataclasses import dataclass
from frequenz.sdk.config import load_config

@dataclass(frozen=True, kw_only=True)
class EnvironmentConfig:
    API_URL: GrpcUrl
    DISPATCH_API_KEY: ApiKey | None = None

env_config = load_config(EnvironmentConfig, os.environ, unknown=marshmallow.EXCLUDE)

Alternatives and workarounds

No response

Additional context

No response

Metadata

Metadata

Assignees

No one assigned

    Labels

    part:codeAffects the code in generaltype:enhancementNew feature or enhancement visitble to users

    Type

    No type

    Projects

    No projects

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions