POC: render pydantic schema as module in Python

This commit is contained in:
Valentin Gagarin 2025-03-25 00:56:23 +01:00
parent 88674c8efc
commit b9c12db2ed
2 changed files with 97 additions and 0 deletions
panel/src/panel

View file

@ -0,0 +1,53 @@
import json
import textwrap
# TODO(@fricklerhandwerk): mix this in as a method on the Pydantic Schema itself
def generate_module(schema, service_name):
properties = schema.get("properties", {})
required = schema.get("required", [])
options = []
for name, prop in properties.items():
nix_type = {
"string": "types.str",
"integer": "types.int",
"boolean": "types.bool"
}[prop["type"]]
desc = prop.get("description")
default = None
if name not in required and "default" in prop:
to_nix_value = {
"string": lambda v: f'"{v}"',
"boolean": lambda v: str(v).lower(),
"integer": lambda v: str(v),
"number": lambda v: str(v)
}
default = to_nix_value[prop["type"]](prop["default"])
option = textwrap.dedent(f"""
{name} = mkOption {{{f'''
description = "{desc}";''' if desc else ''}
type = {nix_type};{f'''
default = {default};''' if default is not None else ''}
}};
""")
options.append(option.strip())
module = textwrap.dedent(f"""
{{ lib, ... }}:
let
cfg = config.services.{service_name};
inherit (lib) mkOption types;
in
{{
options.services.{service_name} = {{
{textwrap.indent("\n\n".join(options), ' ').strip()}
}};
}}
""")
return module

View file

@ -0,0 +1,44 @@
from django.test import TestCase
from pydantic import BaseModel, Field
import textwrap
from panel.configuration import to_module
class ConvertToModule(TestCase):
def test_minimal_module(self):
class Example(BaseModel):
name: str = Field(..., description="Service name")
port: int = Field(8080)
enable: bool = Field(True, description="Enable service")
expected = textwrap.dedent("""
{ lib, ... }:
let
cfg = config.services.myservice;
inherit (lib) mkOption types;
in
{
options.services.myservice = {
name = mkOption {
description = "Service name";
type = types.str;
};
port = mkOption {
type = types.int;
default = 8080;
};
enable = mkOption {
description = "Enable service";
type = types.bool;
default = true;
};
};
}
""")
actual = to_module.generate_module(Example.schema(), "myservice")
self.assertEqual(actual, expected)