Merge pull request 'Classgen: export field type definitions' (#3715) from hsjobeki/clan-core:inventory-services-1 into main
Reviewed-on: https://git.clan.lol/clan/clan-core/pulls/3715
This commit is contained in:
@@ -67,6 +67,9 @@
|
|||||||
"*/bin/clan-app"
|
"*/bin/clan-app"
|
||||||
"*/bin/clan-config"
|
"*/bin/clan-config"
|
||||||
];
|
];
|
||||||
|
treefmt.settings.formatter.ruff-format.excludes = [
|
||||||
|
"*/clan_lib/nix_models/*"
|
||||||
|
];
|
||||||
treefmt.settings.formatter.shellcheck.includes = [
|
treefmt.settings.formatter.shellcheck.includes = [
|
||||||
"scripts/pre-commit"
|
"scripts/pre-commit"
|
||||||
];
|
];
|
||||||
|
|||||||
@@ -1,19 +0,0 @@
|
|||||||
import { QueryClient } from "@tanstack/solid-query";
|
|
||||||
import { ApiEnvelope, callApi } from ".";
|
|
||||||
import { Schema as Inventory } from "@/api/Inventory";
|
|
||||||
|
|
||||||
export async function get_inventory(client: QueryClient, base_path: string) {
|
|
||||||
const data = await client.ensureQueryData({
|
|
||||||
queryKey: [base_path, "inventory"],
|
|
||||||
queryFn: () => {
|
|
||||||
console.log("Refreshing inventory");
|
|
||||||
return callApi("get_inventory", {
|
|
||||||
flake: { identifier: base_path },
|
|
||||||
}) as Promise<ApiEnvelope<Inventory>>;
|
|
||||||
},
|
|
||||||
revalidateIfStale: true,
|
|
||||||
staleTime: 60 * 1000,
|
|
||||||
});
|
|
||||||
|
|
||||||
return data;
|
|
||||||
}
|
|
||||||
@@ -11,6 +11,9 @@ from typing import Any, Literal, NotRequired, TypedDict
|
|||||||
class MachineDeploy(TypedDict):
|
class MachineDeploy(TypedDict):
|
||||||
targetHost: NotRequired[str]
|
targetHost: NotRequired[str]
|
||||||
|
|
||||||
|
MachineDeployTargethostType = NotRequired[str]
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
class Machine(TypedDict):
|
class Machine(TypedDict):
|
||||||
deploy: NotRequired[MachineDeploy]
|
deploy: NotRequired[MachineDeploy]
|
||||||
@@ -20,12 +23,25 @@ class Machine(TypedDict):
|
|||||||
name: NotRequired[str]
|
name: NotRequired[str]
|
||||||
tags: NotRequired[list[str]]
|
tags: NotRequired[list[str]]
|
||||||
|
|
||||||
|
MachineDeployType = NotRequired[MachineDeploy]
|
||||||
|
MachineDescriptionType = NotRequired[str]
|
||||||
|
MachineIconType = NotRequired[str]
|
||||||
|
MachineMachineclassType = NotRequired[Literal["nixos", "darwin"]]
|
||||||
|
MachineNameType = NotRequired[str]
|
||||||
|
MachineTagsType = NotRequired[list[str]]
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
class Meta(TypedDict):
|
class Meta(TypedDict):
|
||||||
name: str
|
name: str
|
||||||
description: NotRequired[str]
|
description: NotRequired[str]
|
||||||
icon: NotRequired[str]
|
icon: NotRequired[str]
|
||||||
|
|
||||||
|
MetaNameType = str
|
||||||
|
MetaDescriptionType = NotRequired[str]
|
||||||
|
MetaIconType = NotRequired[str]
|
||||||
|
|
||||||
|
|
||||||
Service = dict[str, Any]
|
Service = dict[str, Any]
|
||||||
|
|
||||||
|
|
||||||
@@ -35,3 +51,10 @@ class Inventory(TypedDict):
|
|||||||
modules: NotRequired[dict[str, Any]]
|
modules: NotRequired[dict[str, Any]]
|
||||||
services: NotRequired[dict[str, Service]]
|
services: NotRequired[dict[str, Service]]
|
||||||
tags: NotRequired[dict[str, Any]]
|
tags: NotRequired[dict[str, Any]]
|
||||||
|
|
||||||
|
InventoryMachinesType = NotRequired[dict[str, Machine]]
|
||||||
|
InventoryMetaType = NotRequired[Meta]
|
||||||
|
InventoryModulesType = NotRequired[dict[str, Any]]
|
||||||
|
InventoryServicesType = NotRequired[dict[str, Service]]
|
||||||
|
InventoryTagsType = NotRequired[dict[str, Any]]
|
||||||
|
|
||||||
|
|||||||
@@ -65,8 +65,8 @@ def field_def_from_default_type(
|
|||||||
field_name: str,
|
field_name: str,
|
||||||
field_types: set[str],
|
field_types: set[str],
|
||||||
class_name: str,
|
class_name: str,
|
||||||
finalize_field: Callable[..., str],
|
finalize_field: Callable[..., tuple[str, str]],
|
||||||
) -> str | None:
|
) -> tuple[str, str] | None:
|
||||||
if "dict" in str(field_types):
|
if "dict" in str(field_types):
|
||||||
return finalize_field(
|
return finalize_field(
|
||||||
field_types=field_types,
|
field_types=field_types,
|
||||||
@@ -127,8 +127,8 @@ def field_def_from_default_value(
|
|||||||
field_name: str,
|
field_name: str,
|
||||||
field_types: set[str],
|
field_types: set[str],
|
||||||
nested_class_name: str,
|
nested_class_name: str,
|
||||||
finalize_field: Callable[..., str],
|
finalize_field: Callable[..., tuple[str, str]],
|
||||||
) -> str | None:
|
) -> tuple[str, str] | None:
|
||||||
# default_value = prop_info.get("default")
|
# default_value = prop_info.get("default")
|
||||||
if default_value is None:
|
if default_value is None:
|
||||||
return finalize_field(
|
return finalize_field(
|
||||||
@@ -184,7 +184,7 @@ def get_field_def(
|
|||||||
default: str | None = None,
|
default: str | None = None,
|
||||||
default_factory: str | None = None,
|
default_factory: str | None = None,
|
||||||
type_appendix: str = "",
|
type_appendix: str = "",
|
||||||
) -> str:
|
) -> tuple[str, str]:
|
||||||
if "None" in field_types or default or default_factory:
|
if "None" in field_types or default or default_factory:
|
||||||
if "None" in field_types:
|
if "None" in field_types:
|
||||||
field_types.remove("None")
|
field_types.remove("None")
|
||||||
@@ -193,7 +193,7 @@ def get_field_def(
|
|||||||
else:
|
else:
|
||||||
serialised_types = " | ".join(field_types) + type_appendix
|
serialised_types = " | ".join(field_types) + type_appendix
|
||||||
|
|
||||||
return f"{field_name}: {serialised_types}"
|
return (field_name, serialised_types)
|
||||||
|
|
||||||
|
|
||||||
# Recursive function to generate dataclasses from JSON schema
|
# Recursive function to generate dataclasses from JSON schema
|
||||||
@@ -204,8 +204,8 @@ def generate_dataclass(
|
|||||||
) -> str:
|
) -> str:
|
||||||
properties = schema.get("properties", {})
|
properties = schema.get("properties", {})
|
||||||
|
|
||||||
required_fields = []
|
required_fields: list[tuple[str, str]] = []
|
||||||
fields_with_default = []
|
fields_with_default: list[tuple[str, str]] = []
|
||||||
nested_classes: list[str] = []
|
nested_classes: list[str] = []
|
||||||
|
|
||||||
# if We are at the top level, and the attribute name is in shallow
|
# if We are at the top level, and the attribute name is in shallow
|
||||||
@@ -218,7 +218,7 @@ def generate_dataclass(
|
|||||||
field_name = prop.replace("-", "_")
|
field_name = prop.replace("-", "_")
|
||||||
|
|
||||||
if len(attr_path) == 0 and prop not in attrs:
|
if len(attr_path) == 0 and prop not in attrs:
|
||||||
field_def = f"{field_name}: NotRequired[dict[str, Any]]"
|
field_def = field_name, "NotRequired[dict[str, Any]]"
|
||||||
fields_with_default.append(field_def)
|
fields_with_default.append(field_def)
|
||||||
# breakpoint()
|
# breakpoint()
|
||||||
continue
|
continue
|
||||||
@@ -345,9 +345,18 @@ def generate_dataclass(
|
|||||||
)
|
)
|
||||||
required_fields.append(field_def)
|
required_fields.append(field_def)
|
||||||
|
|
||||||
# breakpoint()
|
# Join field name with type to form a complete field declaration
|
||||||
|
# e.g. "name: str"
|
||||||
fields_str = "\n ".join(required_fields + fields_with_default)
|
all_field_declarations = [
|
||||||
|
f"{n}: {t}" for n, t in (required_fields + fields_with_default)
|
||||||
|
]
|
||||||
|
hoisted_types: str = "\n".join(
|
||||||
|
[
|
||||||
|
f"{class_name}{n.capitalize()}Type = {x}"
|
||||||
|
for n, x in (required_fields + fields_with_default)
|
||||||
|
]
|
||||||
|
)
|
||||||
|
fields_str = "\n ".join(all_field_declarations)
|
||||||
nested_classes_str = "\n\n".join(nested_classes)
|
nested_classes_str = "\n\n".join(nested_classes)
|
||||||
|
|
||||||
class_def = f"\nclass {class_name}(TypedDict):\n"
|
class_def = f"\nclass {class_name}(TypedDict):\n"
|
||||||
@@ -356,6 +365,8 @@ def generate_dataclass(
|
|||||||
else:
|
else:
|
||||||
class_def += f" {fields_str}"
|
class_def += f" {fields_str}"
|
||||||
|
|
||||||
|
class_def += f"\n\n{hoisted_types}\n"
|
||||||
|
|
||||||
return f"{nested_classes_str}\n\n{class_def}" if nested_classes_str else class_def
|
return f"{nested_classes_str}\n\n{class_def}" if nested_classes_str else class_def
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user