From 14887b6407f730aa7429096a03cf01361fbc44a9 Mon Sep 17 00:00:00 2001 From: Matthias Veit Date: Tue, 24 Sep 2024 11:56:36 +0200 Subject: [PATCH] [core][feat] Add kind description in multi tenant mode (#2204) --- fixcore/fixcore/model/exportable_model.py | 1 - fixcore/fixcore/model/model_handler.py | 2 +- fixlib/fixlib/core/model_export.py | 20 ++++++++++++++------ fixlib/fixlib/graph/__init__.py | 2 +- fixlib/test/core/model_export_test.py | 9 +++++++-- 5 files changed, 23 insertions(+), 11 deletions(-) diff --git a/fixcore/fixcore/model/exportable_model.py b/fixcore/fixcore/model/exportable_model.py index 17d487a748..0d4e2cc447 100644 --- a/fixcore/fixcore/model/exportable_model.py +++ b/fixcore/fixcore/model/exportable_model.py @@ -19,7 +19,6 @@ def json_export_simple_schema( with_properties: bool = True, with_relatives: bool = True, with_metadata: bool = True, - aggregate_roots_only: bool = False, ) -> List[Json]: def export_simple(kind: SimpleKind) -> Json: result = kind.as_json() diff --git a/fixcore/fixcore/model/model_handler.py b/fixcore/fixcore/model/model_handler.py index 312f6d4d7d..8fbce1bd3d 100644 --- a/fixcore/fixcore/model/model_handler.py +++ b/fixcore/fixcore/model/model_handler.py @@ -256,7 +256,7 @@ def code_model() -> Model: The model is only loaded on demand and only once. """ load_plugin_classes() - return Model.from_kinds([from_js(m, Kind) for m in export_model()]) # type: ignore + return Model.from_kinds([from_js(m, Kind) for m in export_model(with_kind_description=True)]) # type: ignore class ModelHandlerFromCodeAndDB(ModelHandlerDB): diff --git a/fixlib/fixlib/core/model_export.py b/fixlib/fixlib/core/model_export.py index 8918ff3798..fe4371fbbf 100644 --- a/fixlib/fixlib/core/model_export.py +++ b/fixlib/fixlib/core/model_export.py @@ -150,7 +150,8 @@ def dataclasses_to_fixcore_model( aggregate_root: Optional[Type[Any]] = None, walk_subclasses: bool = True, use_optional_as_required: bool = False, - with_description: bool = True, + with_kind_description: bool = False, + with_prop_description: bool = False, ) -> List[Json]: """ Analyze all transitive dataclasses and create the model @@ -163,7 +164,8 @@ def dataclasses_to_fixcore_model( :param aggregate_root: if a type is a subtype of this type, it will be considered an aggregate root. :param walk_subclasses: if true, all subclasses of the given classes will be analyzed as well. :param use_optional_as_required: if true, all non-optional fields will be considered required. - :param with_description: if true, include the description for classes and properties. + :param with_kind_description: if true, include the description for classes. + :param with_prop_description: if true, include the description for properties. :return: the model definition in the fixcore json format. """ @@ -176,7 +178,7 @@ def prop(field: Attribute) -> List[Json]: # type: ignore meta = field.metadata.copy() kind = meta.pop("type_hint", model_name(field.type)) desc = meta.pop("description", None) - desc = desc if with_description else None + desc = desc if with_prop_description else None required = meta.pop("required", use_optional_as_required and not is_optional(field.type)) # type: ignore synthetic = meta.pop("synthetic", None) synthetic = synthetic if synthetic else {} @@ -253,7 +255,13 @@ def export_data_class(clazz: type) -> None: metadata["service"] = s if (slc := getattr(clazz, "categories", None)) and callable(slc) and (sl := slc()): metadata["categories"] = sl - if with_description and (s := clazz.__dict__.get("kind_description", None)) and isinstance(s, str): + if ( # only export kind description on aggregate roots + with_kind_description + and (ar := aggregate_root) + and issubclass(clazz, ar) + and (s := clazz.__dict__.get("kind_description", None)) + and isinstance(s, str) + ): metadata["description"] = s model.append( @@ -293,9 +301,9 @@ def literal_name(en: Enum) -> str: # Use this model exporter, if a dynamic object is exported # with given name and properties. def dynamic_object_to_fixcore_model( - name: str, properties: Dict[str, type], aggregate_root: bool = True, traverse_dependant: bool = True + name: str, properties: Dict[str, type], aggregate_root: bool = True, traverse_dependant: bool = True, **kwargs: Any ) -> List[Json]: - dependant = dataclasses_to_fixcore_model(set(properties.values())) if traverse_dependant else [] + dependant = dataclasses_to_fixcore_model(set(properties.values()), **kwargs) if traverse_dependant else [] # append definition for top level object dependant.append( { diff --git a/fixlib/fixlib/graph/__init__.py b/fixlib/fixlib/graph/__init__.py index b2d33fc955..0b14b08e77 100644 --- a/fixlib/fixlib/graph/__init__.py +++ b/fixlib/fixlib/graph/__init__.py @@ -398,7 +398,7 @@ def export_model(graph: Optional[Graph] = None, **kwargs: Any) -> List[Json]: for node in graph.nodes: classes.add(type(node)) - model = resource_classes_to_fixcore_model(classes, aggregate_root=BaseResource, with_description=False, **kwargs) + model = resource_classes_to_fixcore_model(classes, aggregate_root=BaseResource, **kwargs) for resource_model in model: if resource_model.get("fqn") == "resource": resource_model.get("properties", []).append( diff --git a/fixlib/test/core/model_export_test.py b/fixlib/test/core/model_export_test.py index 6ef70c6c42..4bcfabeba3 100644 --- a/fixlib/test/core/model_export_test.py +++ b/fixlib/test/core/model_export_test.py @@ -125,7 +125,7 @@ def test_enum_to_model() -> None: def test_dataclasses_to_fixcore_model() -> None: - result = dataclasses_to_fixcore_model({DataClassExample}) + result = dataclasses_to_fixcore_model({DataClassExample}, with_kind_description=True, with_prop_description=True) assert len(result) == 5 for r in result: props = {p["name"]: p for p in r.get("properties", [])} @@ -187,7 +187,12 @@ class GcpTestConfigConfig: def test_config_export(): # Let's assume a dynamic top level object of name Config # The properties are defined by name and related type. - result = dynamic_object_to_fixcore_model("config", {"aws": AwsTestConfig, "gcp": GcpTestConfigConfig}) + result = dynamic_object_to_fixcore_model( + "config", + {"aws": AwsTestConfig, "gcp": GcpTestConfigConfig}, + with_kind_description=True, + with_prop_description=True, + ) result_dict = {a["fqn"]: a for a in result} assert len(result_dict["gcp_config"]["properties"]) == 1 assert len(result_dict["aws_config"]["properties"]) == 2