generated from Luis/nextjs-python-web-template
clan-config: init
- nixos-modules to jsonschema converter - nix unit testing via adisbladis/nix-unit - clan config: configuration CLI for nixos-modules
This commit is contained in:
99
pkgs/clan-cli/clan_cli/config/__init__.py
Normal file
99
pkgs/clan-cli/clan_cli/config/__init__.py
Normal file
@@ -0,0 +1,99 @@
|
||||
# !/usr/bin/env python3
|
||||
import argparse
|
||||
import json
|
||||
from pathlib import Path
|
||||
from typing import Any, Optional, Union
|
||||
|
||||
|
||||
class Kwargs:
|
||||
def __init__(self):
|
||||
self.type = None
|
||||
self.default: Any = None
|
||||
self.required: bool = False
|
||||
self.help: Optional[str] = None
|
||||
self.action: Optional[str] = None
|
||||
self.choices: Optional[list] = None
|
||||
|
||||
|
||||
# takes a (sub)parser and configures it
|
||||
def register_parser(
|
||||
parser: Optional[argparse.ArgumentParser] = None,
|
||||
schema: Union[dict, str, Path] = "./tests/config/example-schema.json",
|
||||
) -> dict:
|
||||
if not isinstance(schema, dict):
|
||||
with open(str(schema)) as f:
|
||||
schema: dict = json.load(f)
|
||||
assert "type" in schema and schema["type"] == "object"
|
||||
|
||||
required_set = set(schema.get("required", []))
|
||||
|
||||
if parser is None:
|
||||
parser = argparse.ArgumentParser(description=schema.get("description"))
|
||||
|
||||
type_map = {
|
||||
"array": list,
|
||||
"boolean": bool,
|
||||
"integer": int,
|
||||
"number": float,
|
||||
"string": str,
|
||||
}
|
||||
|
||||
subparsers = parser.add_subparsers(
|
||||
title="more options",
|
||||
description="Other options to configure",
|
||||
help="the option to configure",
|
||||
required=True,
|
||||
)
|
||||
|
||||
for name, value in schema.get("properties", {}).items():
|
||||
assert isinstance(value, dict)
|
||||
|
||||
# TODO: add support for nested objects
|
||||
if value.get("type") == "object":
|
||||
subparser = subparsers.add_parser(name, help=value.get("description"))
|
||||
register_parser(parser=subparser, schema=value)
|
||||
continue
|
||||
# elif value.get("type") == "array":
|
||||
# subparser = parser.add_subparsers(dest=name)
|
||||
# register_parser(subparser, value)
|
||||
# continue
|
||||
kwargs = Kwargs()
|
||||
kwargs.default = value.get("default")
|
||||
kwargs.help = value.get("description")
|
||||
kwargs.required = name in required_set
|
||||
|
||||
if kwargs.default is not None:
|
||||
kwargs.help = f"{kwargs.help}, [{kwargs.default}] in default"
|
||||
|
||||
if "enum" in value:
|
||||
enum_list = value["enum"]
|
||||
assert len(enum_list) > 0, "Enum List is Empty"
|
||||
arg_type = type(enum_list[0])
|
||||
assert all(
|
||||
arg_type is type(item) for item in enum_list
|
||||
), f"Items in [{enum_list}] with Different Types"
|
||||
|
||||
kwargs.type = arg_type
|
||||
kwargs.choices = enum_list
|
||||
else:
|
||||
kwargs.type = type_map[value.get("type")]
|
||||
del kwargs.choices
|
||||
|
||||
name = f"--{name}"
|
||||
|
||||
if kwargs.type is bool:
|
||||
assert not kwargs.default, "boolean have to be False in default"
|
||||
kwargs.default = False
|
||||
kwargs.action = "store_true"
|
||||
del kwargs.type
|
||||
else:
|
||||
del kwargs.action
|
||||
|
||||
parser.add_argument(name, **vars(kwargs))
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
parser = argparse.ArgumentParser()
|
||||
register_parser(parser)
|
||||
args = parser.parse_args()
|
||||
print(args)
|
||||
Reference in New Issue
Block a user