This commit is contained in:
2025-12-15 00:35:53 -06:00
parent a19fb61343
commit 6bfecd956f
6 changed files with 79 additions and 26 deletions

View File

@@ -1,19 +1,30 @@
from pathlib import Path
from typing import cast from typing import cast
from compose.cfg.entity import CfgData, CfgDataYaml from compose.cfg.entity import CfgData, CfgDataYaml, OrgDataYaml
from compose.cfg.get import cfg_get_orgs from compose.cfg.get import cfg_get_orgs
from compose.src_path.entity import SrcPaths from compose.src_path.entity import SrcPaths
from compose.src_path.get import src_path_get_services, src_path_get_volumes from compose.src_path.get import src_path_get_services, src_path_get_volumes
from compose.util import read_yml from compose.util import read_yml, validate_typed_dict
def cfg_data_yml_factory(file: Path) -> CfgDataYaml:
data = cast(CfgDataYaml, read_yml(file))
validate_typed_dict(CfgDataYaml, data, file)
orgs_key = "orgs"
for org in data[orgs_key]:
validate_typed_dict(OrgDataYaml, org, file, (orgs_key,))
return data
def cfg_data_factory(src_paths: SrcPaths) -> CfgData: def cfg_data_factory(src_paths: SrcPaths) -> CfgData:
data = cast(CfgDataYaml, read_yml(src_paths.cfg_file)) data = cfg_data_yml_factory(src_paths.cfg_file)
vols = frozenset(src_path_get_volumes(src_paths, data)) vols = frozenset(src_path_get_volumes(src_paths, data))
return CfgData( return CfgData(
src_paths, src_paths,
src_paths.cfg_dir.name, src_paths.cfg_dir.name,
frozenset(src_path_get_services(src_paths, data)), frozenset(src_path_get_services(src_paths, data)),
vols if vols else None, vols if vols else None,
frozenset(cfg_get_orgs(data)), frozenset(cfg_get_orgs(data, src_paths.cfg_file)),
) )

View File

@@ -1,29 +1,42 @@
from collections.abc import Iterator from collections.abc import Iterator
from pathlib import Path
from typing import cast from typing import cast
from compose.cfg.entity import CfgData, CfgDataYaml, OrgData from compose.cfg.entity import CfgData, CfgDataYaml, OrgData
from compose.compose.entity import VolYaml from compose.compose.entity import VolYaml
from compose.service.entity import Service, ServiceYaml from compose.service.entity import Service
from compose.service.factory import services_yaml_factory
from compose.util import read_yml from compose.util import read_yml
def cfg_get_orgs(data: CfgDataYaml) -> Iterator[OrgData]: def cfg_get_orgs(data: CfgDataYaml, path: Path) -> Iterator[OrgData]:
# orgs = data.get("orgs") # orgs = data.get("orgs")
# if orgs is None: # if orgs is None:
# yield OrgData( # yield OrgData(
# org_data.get("org"), # org_data.get("org"),
# org_data.get("url"), # org_data.get("url"),
# ) # )
for org_data in data["orgs"]: orgs = "orgs"
try:
orgs = data[orgs]
except KeyError as e:
print(f'key "{orgs}" not in "{path!s}"')
raise KeyError(e)
org = "org"
for org_data in orgs:
try:
yield OrgData( yield OrgData(
org_data["org"], org_data[org],
org_data.get("url"), org_data.get("url"),
) )
except KeyError as e:
print(f'key "{orgs}.{org}" not in "{path!s}"')
raise KeyError(e)
def cfg_get_services(cfg_data: CfgData) -> Iterator[tuple[str, Service]]: def cfg_get_services(cfg_data: CfgData) -> Iterator[tuple[str, Service]]:
for path in cfg_data.services: for path in cfg_data.services:
_dict = cast(ServiceYaml, read_yml(path)) _dict = services_yaml_factory(path)
yield path.stem, Service.from_dict(_dict) yield path.stem, Service.from_dict(_dict)

View File

@@ -24,11 +24,11 @@ class ServiceYamlAbc[T_net: T_NetAbc](TypedDict):
volumes: NotRequired[list[str]] volumes: NotRequired[list[str]]
TCo_ServiceYaml = TypeVar( # TCo_ServiceYaml = TypeVar(
"TCo_ServiceYaml", # "TCo_ServiceYaml",
bound=ServiceYamlAbc[T_NetAbc], # bound=ServiceYamlAbc[T_NetAbc],
covariant=True, # covariant=True,
) # )
class ServiceYaml(ServiceYamlAbc[Literal["proxy", "internal"]]): class ServiceYaml(ServiceYamlAbc[Literal["proxy", "internal"]]):

View File

@@ -1,10 +1,12 @@
# from typing import cast from pathlib import Path
from typing import cast
# from compose.cfg import TRAEFIK_PATH from compose.service.entity import ServiceYaml
# from compose.service.entity import TraefikServiceYaml from compose.util import read_yml, validate_typed_dict
# from compose.util import read_yml
# def get_traefik_service(): def services_yaml_factory(path: Path):
# path = TRAEFIK_PATH.joinpath("service.yml") data = cast(ServiceYaml, read_yml(path))
# return cast(TraefikServiceYaml, read_yml(path)) # data = read_yml(path)
validate_typed_dict(ServiceYaml, data)
return data

View File

@@ -1,7 +1,7 @@
import re import re
from collections.abc import Mapping from collections.abc import Mapping
from pathlib import Path from pathlib import Path
from typing import Any, cast, override from typing import Any, ClassVar, KeysView, Protocol, cast, override
import yaml import yaml
@@ -40,6 +40,7 @@ def read_yml(path: Path) -> T_YamlDict:
with path.open("rt") as f: with path.open("rt") as f:
return cast(T_YamlDict, yaml.safe_load(f)) return cast(T_YamlDict, yaml.safe_load(f))
def to_yaml(data: T_YamlDict) -> str: def to_yaml(data: T_YamlDict) -> str:
_yaml = yaml.dump(data, Dumper=VerboseSafeDumper) _yaml = yaml.dump(data, Dumper=VerboseSafeDumper)
return re.sub(r"(^\s*-)", r" \g<1>", _yaml, flags=re.MULTILINE) return re.sub(r"(^\s*-)", r" \g<1>", _yaml, flags=re.MULTILINE)
@@ -47,3 +48,30 @@ def to_yaml(data: T_YamlDict) -> str:
def get_replace_name(name: str) -> str: def get_replace_name(name: str) -> str:
return f"${{_{name.upper()}}}" return f"${{_{name.upper()}}}"
class T_TypedDict(Protocol):
__required_keys__: ClassVar[frozenset[str]]
def keys(self) -> KeysView[str]: ...
def validate_typed_dict(
typed_dict: type[T_TypedDict],
data: T_TypedDict,
path: Path | None = None,
pre: tuple[str, ...] | None = None,
) -> None:
req = typed_dict.__required_keys__.difference(data.keys())
if not req:
return
if pre is None:
keys = (f'"{key}"' for key in req)
else:
key_pre = ".".join(pre)
keys = (f'"{key_pre}.{key}"' for key in req)
msg = f"key(s) ({', '.join(keys)}) not found"
if path is not None:
msg = f"{msg} in file {path!s}"
print(msg)
raise KeyError

View File

@@ -1 +0,0 @@