Source code for kelvin.config.common
from __future__ import annotations
import json
import os
from enum import Enum
from pathlib import Path
from typing import Any, List, Literal, Optional
from pydantic import BaseModel, StringConstraints
from typing_extensions import Annotated, override
NameDNS = Annotated[str, StringConstraints(pattern="^[a-z0-9]([-a-z0-9]*[a-z0-9])?$")]
VersionStr = Annotated[
str,
StringConstraints(
pattern="^([0-9]+)\\.([0-9]+)\\.([0-9]+)(?:-([0-9A-Za-z-]+(?:\\.[0-9A-Za-z-]+)*))?(?:\\+[0-9A-Za-z-]+)?$"
),
]
CustomActionTypeStr = Annotated[str, StringConstraints(pattern="^[a-zA-Z0-9]([-_ .a-zA-Z0-9]*[a-zA-Z0-9])?$")]
[docs]
class ConfigError(Exception):
pass
[docs]
class ConfigBaseModel(BaseModel):
model_config = {"populate_by_name": True}
[docs]
@override
def model_dump( # type: ignore[override]
self,
mode: Literal["json", "python"] | str = "json",
by_alias: bool = True,
exclude_unset: bool = True,
exclude_defaults: bool = False,
exclude_none: bool = True,
serialize_as_any: bool = False,
**kwargs: Any,
) -> dict[str, Any]:
return super().model_dump(
mode=mode,
by_alias=by_alias,
exclude_unset=exclude_unset,
exclude_defaults=exclude_defaults,
exclude_none=exclude_none,
serialize_as_any=serialize_as_any,
**kwargs,
)
[docs]
class AppTypes(str, Enum):
importer = "importer"
exporter = "exporter"
app = "app"
docker = "docker"
# legacy - deprecated
kelvin_app = "kelvin"
bridge = "bridge"
legacy_docker = "legacy_docker"
[docs]
class PrimitiveTypes(str, Enum):
number = "number"
string = "string"
boolean = "boolean"
object = "object"
[docs]
class CustomActionDef(ConfigBaseModel):
type: CustomActionTypeStr
[docs]
class CustomActionsIO(ConfigBaseModel):
inputs: List[CustomActionDef] = []
outputs: List[CustomActionDef] = []
[docs]
class AppBaseConfig(ConfigBaseModel):
name: NameDNS
title: str
description: str
type: AppTypes
version: VersionStr
category: Optional[str] = None
[docs]
def read_schema_file(file_path: Path) -> dict:
if not os.path.exists(file_path):
raise ConfigError(f"Schema file {file_path} does not exist.")
try:
with open(file_path) as file:
content = file.read()
if not content.strip():
return {}
return json.loads(content)
except json.JSONDecodeError:
raise ConfigError(f"Schema file {file_path} contains invalid JSON.")