Skip to content

Commit 83a25c0

Browse files
committed
Add pydantic to docs/metadata.py
1 parent e7e8c49 commit 83a25c0

File tree

3 files changed

+145
-19
lines changed

3 files changed

+145
-19
lines changed

docs/metadata.py

Lines changed: 19 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,14 @@
11
"""
2-
Support parsing pyinfra plugins and parsing
3-
their metadata to docs generator.
2+
Support parsing pyinfra-metadata.toml
3+
4+
Currently just parses plugins their metadata.
45
"""
56

67
import tomllib
7-
from dataclasses import dataclass
88
from typing import Literal
99

10+
from pydantic import BaseModel, TypeAdapter, field_validator
11+
1012
AllowedTagType = Literal[
1113
"boot",
1214
"containers",
@@ -25,16 +27,17 @@
2527
]
2628

2729

28-
@dataclass(frozen=True)
29-
class Tag:
30+
class Tag(BaseModel):
3031
"""Representation of a plugin tag."""
3132

3233
value: AllowedTagType
3334

34-
def __post_init__(self):
35+
@field_validator("value", mode="before")
36+
def _validate_value(cls, v) -> AllowedTagType:
3537
allowed_tags = set(AllowedTagType.__args__)
36-
if self.value not in allowed_tags:
38+
if v not in allowed_tags:
3739
raise ValueError(f"Invalid tag: {self.value}. Allowed: {allowed_tags}")
40+
return v
3841

3942
@property
4043
def title_case(self) -> str:
@@ -48,11 +51,10 @@ def __eq__(self, other):
4851
return NotImplemented
4952

5053

51-
ALLOWED_TAGS = [Tag(tag) for tag in set(AllowedTagType.__args__)]
54+
ALLOWED_TAGS = [Tag(value=tag) for tag in set(AllowedTagType.__args__)]
5255

5356

54-
@dataclass
55-
class Plugin:
57+
class Plugin(BaseModel):
5658
"""Representation of a pyinfra plugin."""
5759

5860
name: str
@@ -61,18 +63,16 @@ class Plugin:
6163
type: Literal["operation", "fact", "connector", "deploy"]
6264
tags: list[Tag]
6365

66+
@field_validator("tags", mode="before")
67+
def _wrap_tags(cls, v):
68+
return [Tag(value=tag) if not isinstance(tag, Tag) else tag for tag in v]
69+
6470

6571
def parse_plugins(metadata_text: str) -> list[Plugin]:
6672
"""Given the contents of a pyinfra-metadata.toml parse out the plugins."""
6773
pyinfra_metadata = tomllib.loads(metadata_text).get("pyinfra", None)
6874
if not pyinfra_metadata:
6975
raise ValueError("Missing [pyinfra.plugins] section in pyinfra-metadata.toml")
70-
71-
plugins = []
72-
for p in pyinfra_metadata["plugins"]:
73-
data = pyinfra_metadata["plugins"][p]
74-
# ensure Tag types and not strings
75-
data["tags"] = [Tag(t) for t in data["tags"]]
76-
plugin = Plugin(**data)
77-
plugins.append(plugin)
78-
return plugins
76+
return TypeAdapter(list[Plugin]).validate_python(
77+
pyinfra_metadata["plugins"].values()
78+
)

pyproject.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ dependencies = [
2020
"typeguard>=4,<5",
2121
"distro>=1.6,<2",
2222
"packaging>=16.1",
23+
"pydantic>=2.11,<3",
2324
"typing-extensions; python_version < '3.11'", # Backport of typing for Unpack (added 3.11)
2425
]
2526
classifiers = [

0 commit comments

Comments
 (0)