forked from Fediversity/Fediversity
POC: render pydantic schema as module in Python
This commit is contained in:
parent
88674c8efc
commit
b9c12db2ed
2 changed files with 97 additions and 0 deletions
panel/src/panel
53
panel/src/panel/configuration/to_module.py
Normal file
53
panel/src/panel/configuration/to_module.py
Normal 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
|
44
panel/src/panel/tests/test_to_module.py
Normal file
44
panel/src/panel/tests/test_to_module.py
Normal 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)
|
Loading…
Add table
Reference in a new issue