Coverage for src / rendercv / schema / models / design / built_in_design.py: 100%
18 statements
« prev ^ index » next coverage.py v7.13.4, created at 2026-03-25 13:49 +0000
« prev ^ index » next coverage.py v7.13.4, created at 2026-03-25 13:49 +0000
1from functools import reduce
2from operator import or_
3from pathlib import Path
4from typing import Annotated, get_args
6import pydantic
8from ...variant_pydantic_model_generator import create_variant_pydantic_model
9from ...yaml_reader import read_yaml
10from .classic_theme import ClassicTheme
13def discover_other_themes() -> list[type[ClassicTheme]]:
14 """Auto-discover and load theme variant classes from other_themes/ directory.
16 Why:
17 Built-in themes beyond classic are defined as YAML files with field
18 overrides. Dynamic discovery and variant generation keeps theme
19 system extensible without code changes for each theme.
21 Returns:
22 List of dynamically generated theme variant classes.
23 """
24 other_themes_dir = Path(__file__).parent / "other_themes"
25 discovered: list[type[ClassicTheme]] = []
27 for yaml_file in sorted(other_themes_dir.glob("*.yaml")):
28 theme_class = create_variant_pydantic_model(
29 variant_name=yaml_file.stem,
30 defaults=read_yaml(yaml_file)["design"],
31 base_class=ClassicTheme,
32 discriminator_field="theme",
33 class_name_suffix="Theme",
34 module_name="rendercv.schema.models.design",
35 )
36 discovered.append(theme_class)
38 return discovered
41# Build discriminated union dynamically
42type BuiltInDesign = Annotated[
43 reduce(or_, discover_other_themes(), ClassicTheme), # ty: ignore[invalid-type-form]
44 pydantic.Field(discriminator="theme"),
45]
46available_themes: list[str] = [
47 ThemeClass.model_fields["theme"].default
48 for ThemeClass in get_args(get_args(BuiltInDesign.__value__)[0])
49]
50built_in_design_adapter = pydantic.TypeAdapter[BuiltInDesign](BuiltInDesign)