From bc813467ed5ff0596809dad6e6d01f93747e8dd8 Mon Sep 17 00:00:00 2001 From: HUG0-D Date: Fri, 15 Nov 2024 14:27:44 +0100 Subject: [PATCH 01/20] Added identification of CIMDatatypes and Primitive classes Signed-off-by: HUG0-D --- .gitignore | 1 + 1 file changed, 1 insertion(+) diff --git a/.gitignore b/.gitignore index d8c0846c..56dba38b 100644 --- a/.gitignore +++ b/.gitignore @@ -9,3 +9,4 @@ __pycache__/ .vscode/* */.DS_Store .DS_Store +tests/ From 6db0aadf0ece3173c7a4c062947e376f6bab4626 Mon Sep 17 00:00:00 2001 From: HUG0-D Date: Fri, 15 Nov 2024 14:41:15 +0100 Subject: [PATCH 02/20] Decomposition of the run_template function, template files are now defined as dict Signed-off-by: HUG0-D --- cimgen/languages/modernpython/lang_pack.py | 51 ++++++++++++---------- 1 file changed, 27 insertions(+), 24 deletions(-) diff --git a/cimgen/languages/modernpython/lang_pack.py b/cimgen/languages/modernpython/lang_pack.py index 99685bf8..00d51655 100644 --- a/cimgen/languages/modernpython/lang_pack.py +++ b/cimgen/languages/modernpython/lang_pack.py @@ -35,9 +35,9 @@ def location(version): # NOSONAR base = {"base_class": "Base", "class_location": location} # These are the files that are used to generate the python files. -template_files = [{"filename": "cimpy_class_template.mustache", "ext": ".py"}] -constants_template_files = [{"filename": "cimpy_constants_template.mustache", "ext": ".py"}] -profile_template_files = [{"filename": "cimpy_cgmesProfile_template.mustache", "ext": ".py"}] +template_files = {"filename": "cimpy_class_template.mustache", "ext": ".py"} +constants_template_files = {"filename": "cimpy_constants_template.mustache", "ext": ".py"} +profile_template_files = {"filename": "cimpy_cgmesProfile_template.mustache", "ext": ".py"} def get_class_location(class_name, class_map, version): # NOSONAR @@ -79,20 +79,25 @@ def _get_type_and_default(text, render) -> tuple[str, str]: def run_template(output_path, class_details): if class_details["is_a_primitive_class"] or class_details["is_a_datatype_class"]: return - for template_info in template_files: - resource_file = Path( - os.path.join( - output_path, - "resources", - class_details["class_name"] + template_info["ext"], - ) + template = template_files + class_details["setDefault"] = _set_default + class_details["setType"] = _set_type + resource_file = _create_file(output_path, class_details, template) + _write_templated_file(resource_file, class_details, template["filename"]) + + +def _create_file(output_path, class_details, template) -> str: + resource_file = Path( + os.path.join( + output_path, + "resources", + class_details["class_name"] + template["ext"], ) - if not resource_file.exists(): - if not (parent := resource_file.parent).exists(): - parent.mkdir() - class_details["setDefault"] = _set_default - class_details["setType"] = _set_type - _write_templated_file(resource_file, class_details, template_info["filename"]) + ) + if not resource_file.exists(): + if not (parent := resource_file.parent).exists(): + parent.mkdir() + return resource_file def _write_templated_file(class_file, class_details, template_filename): @@ -109,17 +114,15 @@ def _write_templated_file(class_file, class_details, template_filename): def _create_constants(output_path: str, cim_namespace: str): - for template_info in constants_template_files: - class_file = os.path.join(output_path, "utils", "constants" + template_info["ext"]) - class_details = {"cim_namespace": cim_namespace} - _write_templated_file(class_file, class_details, template_info["filename"]) + class_file = os.path.join(output_path, "utils", "constants" + constants_template_files["ext"]) + class_details = {"cim_namespace": cim_namespace} + _write_templated_file(class_file, class_details, constants_template_files["filename"]) def _create_cgmes_profile(output_path: str, profile_details: list): - for template_info in profile_template_files: - class_file = os.path.join(output_path, "utils", "profile" + template_info["ext"]) - class_details = {"profiles": profile_details} - _write_templated_file(class_file, class_details, template_info["filename"]) + class_file = os.path.join(output_path, "utils", "profile" + profile_template_files["ext"]) + class_details = {"profiles": profile_details} + _write_templated_file(class_file, class_details, profile_template_files["filename"]) def resolve_headers(path: str, version: str): From 57137231338c1f218103f37a92f3dfc9dd4cded7 Mon Sep 17 00:00:00 2001 From: HUG0-D Date: Fri, 15 Nov 2024 14:53:10 +0100 Subject: [PATCH 03/20] Added Primitive class and template Signed-off-by: HUG0-D --- cimgen/languages/modernpython/lang_pack.py | 40 +++++++++++++++++-- .../templates/primitive_template.mustache | 19 +++++++++ .../languages/modernpython/utils/datatypes.py | 26 ++++++++++++ 3 files changed, 81 insertions(+), 4 deletions(-) create mode 100644 cimgen/languages/modernpython/templates/primitive_template.mustache create mode 100644 cimgen/languages/modernpython/utils/datatypes.py diff --git a/cimgen/languages/modernpython/lang_pack.py b/cimgen/languages/modernpython/lang_pack.py index 00d51655..2e578074 100644 --- a/cimgen/languages/modernpython/lang_pack.py +++ b/cimgen/languages/modernpython/lang_pack.py @@ -38,6 +38,7 @@ def location(version): # NOSONAR template_files = {"filename": "cimpy_class_template.mustache", "ext": ".py"} constants_template_files = {"filename": "cimpy_constants_template.mustache", "ext": ".py"} profile_template_files = {"filename": "cimpy_cgmesProfile_template.mustache", "ext": ".py"} +primitive_template_files = {"filename": "primitive_template.mustache", "ext": ".py"} def get_class_location(class_name, class_map, version): # NOSONAR @@ -76,12 +77,43 @@ def _get_type_and_default(text, render) -> tuple[str, str]: return ("str", 'default=""') +def _primitive_to_data_type(datatype): + if datatype.lower() == "integer": + return "int" + if datatype.lower() == "boolean": + return "bool" + if datatype.lower() == "string": + return "str" + if datatype.lower() == "datetime": + return "datetime" + if datatype.lower() == "monthday": + return "str" # TO BE FIXED? I could not find a datatype in python that holds only month and day. + if datatype.lower() == "date": + return "date" + # as of today no CIM model is using only time. + if datatype.lower() == "time": + return "time" + if datatype.lower() == "float": + return "float" + if datatype.lower() == "string": + return "str" + else: + # this actually never happens + return "float" + + def run_template(output_path, class_details): - if class_details["is_a_primitive_class"] or class_details["is_a_datatype_class"]: + if class_details["is_a_primitive_class"]: + # Primitives are never used in the in memory representation but only for + # the schema + template = primitive_template_files + class_details["python_type"] = _primitive_to_data_type(class_details["class_name"]) + elif class_details["is_a_datatype_class"]: return - template = template_files - class_details["setDefault"] = _set_default - class_details["setType"] = _set_type + else: + template = template_files + class_details["setDefault"] = _set_default + class_details["setType"] = _set_type resource_file = _create_file(output_path, class_details, template) _write_templated_file(resource_file, class_details, template["filename"]) diff --git a/cimgen/languages/modernpython/templates/primitive_template.mustache b/cimgen/languages/modernpython/templates/primitive_template.mustache new file mode 100644 index 00000000..be44ab00 --- /dev/null +++ b/cimgen/languages/modernpython/templates/primitive_template.mustache @@ -0,0 +1,19 @@ +""" +Generated from the CGMES files via cimgen: https://github.com/sogno-platform/cimgen +""" + +from datetime import date, datetime, time +from ..utils.datatypes import Primitive +from ..utils.profile import Profile + +{{class_name}} = Primitive( + name="{{class_name}}", + type={{python_type}}, + profiles=[{{#class_origin}} + Profile.{{origin}},{{/class_origin}} + ], +) + +""" +{{{wrapped_class_comment}}} +""" diff --git a/cimgen/languages/modernpython/utils/datatypes.py b/cimgen/languages/modernpython/utils/datatypes.py new file mode 100644 index 00000000..d073b1ff --- /dev/null +++ b/cimgen/languages/modernpython/utils/datatypes.py @@ -0,0 +1,26 @@ +from pydantic import Field +from typing import List + +from .constants import NAMESPACES +from pydantic.dataclasses import dataclass + +from .dataclassconfig import DataclassConfig +from .profile import BaseProfile +from ..resources.UnitMultiplier import UnitMultiplier +from ..resources.UnitSymbol import UnitSymbol + + +@dataclass(config=DataclassConfig) +class Primitive: + + name: str = Field(frozen=True) + type: object = Field(frozen=True) + namespace: str = Field(frozen=True, default=NAMESPACES["cim"]) + profiles: List[BaseProfile] = Field(frozen=True) + + +@dataclass(config=DataclassConfig) +class CIMDatatype(Primitive): + + multiplier: UnitMultiplier = Field(frozen=True) + symbol: UnitSymbol = Field(frozen=True) From e2cba25d7a3f61c10cd3fe7047c6b1677ea59c13 Mon Sep 17 00:00:00 2001 From: HUG0-D Date: Fri, 15 Nov 2024 14:59:53 +0100 Subject: [PATCH 04/20] Adding CIMDatatype classes and template Signed-off-by: HUG0-D --- cimgen/languages/modernpython/lang_pack.py | 32 ++++++++++++++++++- .../templates/cimdatatype_template.mustache | 22 +++++++++++++ 2 files changed, 53 insertions(+), 1 deletion(-) create mode 100644 cimgen/languages/modernpython/templates/cimdatatype_template.mustache diff --git a/cimgen/languages/modernpython/lang_pack.py b/cimgen/languages/modernpython/lang_pack.py index 2e578074..4665b483 100644 --- a/cimgen/languages/modernpython/lang_pack.py +++ b/cimgen/languages/modernpython/lang_pack.py @@ -39,6 +39,7 @@ def location(version): # NOSONAR constants_template_files = {"filename": "cimpy_constants_template.mustache", "ext": ".py"} profile_template_files = {"filename": "cimpy_cgmesProfile_template.mustache", "ext": ".py"} primitive_template_files = {"filename": "primitive_template.mustache", "ext": ".py"} +cimdatatype_template_files = {"filename": "cimdatatype_template.mustache", "ext": ".py"} def get_class_location(class_name, class_map, version): # NOSONAR @@ -102,6 +103,32 @@ def _primitive_to_data_type(datatype): return "float" +def _compute_cim_data_type(attributes) -> dict: + cim_attributes = {} + cim_attributes["python_type"] = "None" + cim_attributes["unit"] = "UnitSymbol.none" + cim_attributes["multiplier"] = "UnitMultiplier.none" + + for attribute in attributes: + if ( + "about" in attribute + and attribute["about"] + and "value" in attribute["about"] + and "attribute_class" in attribute + ): + cim_attributes["python_type"] = _primitive_to_data_type(attribute["attribute_class"]) + if ( + "about" in attribute + and attribute["about"] + and "multiplier" in attribute["about"] + and "isFixed" in attribute + ): + cim_attributes["multiplier"] = "UnitMultiplier." + attribute["isFixed"] + if "about" in attribute and attribute["about"] and "unit" in attribute["about"] and "isFixed" in attribute: + cim_attributes["unit"] = "UnitSymbol." + attribute["isFixed"] + return cim_attributes + + def run_template(output_path, class_details): if class_details["is_a_primitive_class"]: # Primitives are never used in the in memory representation but only for @@ -109,7 +136,10 @@ def run_template(output_path, class_details): template = primitive_template_files class_details["python_type"] = _primitive_to_data_type(class_details["class_name"]) elif class_details["is_a_datatype_class"]: - return + # Datatypes based on primitives are never used in the in memory + # representation but only for the schema + template = cimdatatype_template_files + class_details.update(_compute_cim_data_type(class_details["attributes"])) else: template = template_files class_details["setDefault"] = _set_default diff --git a/cimgen/languages/modernpython/templates/cimdatatype_template.mustache b/cimgen/languages/modernpython/templates/cimdatatype_template.mustache new file mode 100644 index 00000000..2fcc02a7 --- /dev/null +++ b/cimgen/languages/modernpython/templates/cimdatatype_template.mustache @@ -0,0 +1,22 @@ +""" +Generated from the CGMES files via cimgen: https://github.com/sogno-platform/cimgen +""" + +from ..utils.datatypes import CIMDatatype +from ..utils.profile import Profile +from .UnitMultiplier import UnitMultiplier +from .UnitSymbol import UnitSymbol + +{{class_name}} = CIMDatatype( + name="{{class_name}}", + type={{python_type}}, + symbol={{unit}}, + multiplier={{multiplier}}, + profiles=[{{#class_origin}} + Profile.{{origin}},{{/class_origin}} + ], +) + +""" +{{{wrapped_class_comment}}} +""" From 7ab6fe77ca264a76631a864ef90a9596285570d2 Mon Sep 17 00:00:00 2001 From: HUG0-D Date: Fri, 15 Nov 2024 15:20:43 +0100 Subject: [PATCH 05/20] Adding attribute dataclass in json_extra Signed-off-by: HUG0-D --- cimgen/languages/modernpython/lang_pack.py | 22 +++++++++++++++++++ .../templates/cimpy_class_template.mustache | 5 +++-- 2 files changed, 25 insertions(+), 2 deletions(-) diff --git a/cimgen/languages/modernpython/lang_pack.py b/cimgen/languages/modernpython/lang_pack.py index 4665b483..08e634c2 100644 --- a/cimgen/languages/modernpython/lang_pack.py +++ b/cimgen/languages/modernpython/lang_pack.py @@ -103,6 +103,18 @@ def _primitive_to_data_type(datatype): return "float" +def _set_imports(attributes): + classes = set() + for attribute in attributes: + if attribute["is_cim_datatype"] or attribute["is_primitive_attribute"]: + classes.add(attribute["attribute_class"]) + + result = "" + for val in classes: + result += "from ." + val + " import " + val + "\n" + return result + "\n" + + def _compute_cim_data_type(attributes) -> dict: cim_attributes = {} cim_attributes["python_type"] = "None" @@ -129,6 +141,14 @@ def _compute_cim_data_type(attributes) -> dict: return cim_attributes +def _set_cim_data_type(text, render) -> str: + attribute = eval(render(text)) + cim_data_type = "" + if attribute["is_cim_datatype"] or attribute["is_primitive_attribute"]: + cim_data_type = """"cim_data_type": """ + attribute["attribute_class"] + ",\n\t\t" + return cim_data_type + + def run_template(output_path, class_details): if class_details["is_a_primitive_class"]: # Primitives are never used in the in memory representation but only for @@ -144,6 +164,8 @@ def run_template(output_path, class_details): template = template_files class_details["setDefault"] = _set_default class_details["setType"] = _set_type + class_details["setCimDataType"] = _set_cim_data_type + class_details["setImports"] = _set_imports(class_details["attributes"]) resource_file = _create_file(output_path, class_details, template) _write_templated_file(resource_file, class_details, template["filename"]) diff --git a/cimgen/languages/modernpython/templates/cimpy_class_template.mustache b/cimgen/languages/modernpython/templates/cimpy_class_template.mustache index 58ba391d..a757c6e4 100644 --- a/cimgen/languages/modernpython/templates/cimpy_class_template.mustache +++ b/cimgen/languages/modernpython/templates/cimpy_class_template.mustache @@ -10,7 +10,7 @@ from pydantic.dataclasses import dataclass from ..utils.profile import BaseProfile, Profile from {{class_location}} import {{sub_class_of}} - +{{setImports}} @dataclass class {{class_name}}({{sub_class_of}}): @@ -37,7 +37,8 @@ class {{class_name}}({{sub_class_of}}): "is_enum_attribute": {{#is_enum_attribute}}True{{/is_enum_attribute}}{{^is_enum_attribute}}False{{/is_enum_attribute}}, "is_list_attribute": {{#is_list_attribute}}True{{/is_list_attribute}}{{^is_list_attribute}}False{{/is_list_attribute}}, "is_primitive_attribute": {{#is_primitive_attribute}}True{{/is_primitive_attribute}}{{^is_primitive_attribute}}False{{/is_primitive_attribute}}, - }, + "is_cim_datatype": {{#is_cim_datatype}}True{{/is_cim_datatype}}{{^is_cim_datatype}}False{{/is_cim_datatype}}, + {{#setCimDataType}}{{.}}{{/setCimDataType}}}, ) {{/attributes}} From e13cdc8f2638fa0408dc4d8d849f25ae879647d8 Mon Sep 17 00:00:00 2001 From: HUG0-D Date: Fri, 15 Nov 2024 15:29:56 +0100 Subject: [PATCH 06/20] Adding Enum classes Signed-off-by: HUG0-D --- cimgen/languages/modernpython/lang_pack.py | 26 +++++++++++++++++++ .../templates/enum_class_template.mustache | 15 +++++++++++ .../languages/modernpython/utils/datatypes.py | 6 ++--- 3 files changed, 44 insertions(+), 3 deletions(-) create mode 100644 cimgen/languages/modernpython/templates/enum_class_template.mustache diff --git a/cimgen/languages/modernpython/lang_pack.py b/cimgen/languages/modernpython/lang_pack.py index 08e634c2..f7623490 100644 --- a/cimgen/languages/modernpython/lang_pack.py +++ b/cimgen/languages/modernpython/lang_pack.py @@ -1,6 +1,7 @@ import logging import os import re +import ast from distutils.dir_util import copy_tree from pathlib import Path from importlib.resources import files @@ -38,6 +39,7 @@ def location(version): # NOSONAR template_files = {"filename": "cimpy_class_template.mustache", "ext": ".py"} constants_template_files = {"filename": "cimpy_constants_template.mustache", "ext": ".py"} profile_template_files = {"filename": "cimpy_cgmesProfile_template.mustache", "ext": ".py"} +enum_template_files = {"filename": "enum_class_template.mustache", "ext": ".py"} primitive_template_files = {"filename": "primitive_template.mustache", "ext": ".py"} cimdatatype_template_files = {"filename": "cimdatatype_template.mustache", "ext": ".py"} @@ -149,6 +151,27 @@ def _set_cim_data_type(text, render) -> str: return cim_data_type +# called by chevron, text contains the label {{dataType}}, which is evaluated by the renderer (see class template) +def _set_instances(text, render): + instance = None + try: + # render(text) returns a python dict. + # Some fields might be quoted by '"' instead of '"', making the first eval fail. + instance = ast.literal_eval(render(text)) + except SyntaxError as se: + rendered = render(text) + rendered = rendered.replace(""", '"') + instance = eval(rendered) + logger.warning("Exception in evaluating %s : %s . Handled replacing quotes", rendered, se.msg) + if "label" in instance: + value = instance["label"] + ' = "' + instance["label"] + '"' + if "comment" in instance: + value += " # " + instance["comment"] + return value + else: + return "" + + def run_template(output_path, class_details): if class_details["is_a_primitive_class"]: # Primitives are never used in the in memory representation but only for @@ -160,6 +183,9 @@ def run_template(output_path, class_details): # representation but only for the schema template = cimdatatype_template_files class_details.update(_compute_cim_data_type(class_details["attributes"])) + elif class_details["is_an_enum_class"]: + template = enum_template_files + class_details["setInstances"] = _set_instances else: template = template_files class_details["setDefault"] = _set_default diff --git a/cimgen/languages/modernpython/templates/enum_class_template.mustache b/cimgen/languages/modernpython/templates/enum_class_template.mustache new file mode 100644 index 00000000..273e42c8 --- /dev/null +++ b/cimgen/languages/modernpython/templates/enum_class_template.mustache @@ -0,0 +1,15 @@ +""" +Generated from the CGMES 3 files via cimgen: https://github.com/sogno-platform/cimgen +""" + +from enum import Enum + + +class {{class_name}}(str, Enum): + """ + {{{class_comment}}} + """ + + {{#enum_instances}} + {{#setInstances}}{{.}}{{/setInstances}} + {{/enum_instances}} diff --git a/cimgen/languages/modernpython/utils/datatypes.py b/cimgen/languages/modernpython/utils/datatypes.py index d073b1ff..38583efc 100644 --- a/cimgen/languages/modernpython/utils/datatypes.py +++ b/cimgen/languages/modernpython/utils/datatypes.py @@ -4,13 +4,13 @@ from .constants import NAMESPACES from pydantic.dataclasses import dataclass -from .dataclassconfig import DataclassConfig +from .config import cgmes_resource_config from .profile import BaseProfile from ..resources.UnitMultiplier import UnitMultiplier from ..resources.UnitSymbol import UnitSymbol -@dataclass(config=DataclassConfig) +@dataclass(config=cgmes_resource_config) class Primitive: name: str = Field(frozen=True) @@ -19,7 +19,7 @@ class Primitive: profiles: List[BaseProfile] = Field(frozen=True) -@dataclass(config=DataclassConfig) +@dataclass(config=cgmes_resource_config) class CIMDatatype(Primitive): multiplier: UnitMultiplier = Field(frozen=True) From a0a362438b1e15648d76c6cdf84835bd9ca5e48d Mon Sep 17 00:00:00 2001 From: HUG0-D Date: Fri, 15 Nov 2024 15:44:49 +0100 Subject: [PATCH 07/20] Fixing template formating Signed-off-by: HUG0-D --- .../modernpython/templates/cimpy_class_template.mustache | 1 - 1 file changed, 1 deletion(-) diff --git a/cimgen/languages/modernpython/templates/cimpy_class_template.mustache b/cimgen/languages/modernpython/templates/cimpy_class_template.mustache index a757c6e4..3d73d772 100644 --- a/cimgen/languages/modernpython/templates/cimpy_class_template.mustache +++ b/cimgen/languages/modernpython/templates/cimpy_class_template.mustache @@ -11,7 +11,6 @@ from pydantic.dataclasses import dataclass from ..utils.profile import BaseProfile, Profile from {{class_location}} import {{sub_class_of}} {{setImports}} - @dataclass class {{class_name}}({{sub_class_of}}): """ From d5469adbefd50882c9461dc80795626cbc5e1c72 Mon Sep 17 00:00:00 2001 From: HUG0-D Date: Fri, 15 Nov 2024 15:54:58 +0100 Subject: [PATCH 08/20] Fixing template formating Signed-off-by: HUG0-D --- cimgen/languages/modernpython/lang_pack.py | 3 ++- .../modernpython/templates/cimpy_class_template.mustache | 4 ++-- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/cimgen/languages/modernpython/lang_pack.py b/cimgen/languages/modernpython/lang_pack.py index f7623490..f31de145 100644 --- a/cimgen/languages/modernpython/lang_pack.py +++ b/cimgen/languages/modernpython/lang_pack.py @@ -147,7 +147,8 @@ def _set_cim_data_type(text, render) -> str: attribute = eval(render(text)) cim_data_type = "" if attribute["is_cim_datatype"] or attribute["is_primitive_attribute"]: - cim_data_type = """"cim_data_type": """ + attribute["attribute_class"] + ",\n\t\t" + cim_data_type += "\n " + cim_data_type += """"cim_data_type": """ + attribute["attribute_class"] + "," return cim_data_type diff --git a/cimgen/languages/modernpython/templates/cimpy_class_template.mustache b/cimgen/languages/modernpython/templates/cimpy_class_template.mustache index 3d73d772..bb91f643 100644 --- a/cimgen/languages/modernpython/templates/cimpy_class_template.mustache +++ b/cimgen/languages/modernpython/templates/cimpy_class_template.mustache @@ -36,8 +36,8 @@ class {{class_name}}({{sub_class_of}}): "is_enum_attribute": {{#is_enum_attribute}}True{{/is_enum_attribute}}{{^is_enum_attribute}}False{{/is_enum_attribute}}, "is_list_attribute": {{#is_list_attribute}}True{{/is_list_attribute}}{{^is_list_attribute}}False{{/is_list_attribute}}, "is_primitive_attribute": {{#is_primitive_attribute}}True{{/is_primitive_attribute}}{{^is_primitive_attribute}}False{{/is_primitive_attribute}}, - "is_cim_datatype": {{#is_cim_datatype}}True{{/is_cim_datatype}}{{^is_cim_datatype}}False{{/is_cim_datatype}}, - {{#setCimDataType}}{{.}}{{/setCimDataType}}}, + "is_cim_datatype": {{#is_cim_datatype}}True{{/is_cim_datatype}}{{^is_cim_datatype}}False{{/is_cim_datatype}},{{#setCimDataType}}{{.}}{{/setCimDataType}} + }, ) {{/attributes}} From 5d675a3e36eed60fa5ae3b61f9da0017b4a103b2 Mon Sep 17 00:00:00 2001 From: HUG0-D Date: Mon, 18 Nov 2024 09:20:04 +0100 Subject: [PATCH 09/20] Corrected header in template (unspecifying the CGMES version) Signed-off-by: HUG0-D --- .../modernpython/templates/enum_class_template.mustache | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cimgen/languages/modernpython/templates/enum_class_template.mustache b/cimgen/languages/modernpython/templates/enum_class_template.mustache index 273e42c8..0622b9b4 100644 --- a/cimgen/languages/modernpython/templates/enum_class_template.mustache +++ b/cimgen/languages/modernpython/templates/enum_class_template.mustache @@ -1,5 +1,5 @@ """ -Generated from the CGMES 3 files via cimgen: https://github.com/sogno-platform/cimgen +Generated from the CGMES files via cimgen: https://github.com/sogno-platform/cimgen """ from enum import Enum From 900cdd907e9ad1d228c84e0e9a890acdb982e393 Mon Sep 17 00:00:00 2001 From: HUG0-D Date: Mon, 18 Nov 2024 10:49:11 +0100 Subject: [PATCH 10/20] Simplified _set_instance by replacing text before exception and added line-length ignore comment Signed-off-by: HUG0-D --- cimgen/languages/modernpython/lang_pack.py | 12 ++---------- 1 file changed, 2 insertions(+), 10 deletions(-) diff --git a/cimgen/languages/modernpython/lang_pack.py b/cimgen/languages/modernpython/lang_pack.py index f31de145..1fd29a5e 100644 --- a/cimgen/languages/modernpython/lang_pack.py +++ b/cimgen/languages/modernpython/lang_pack.py @@ -155,19 +155,11 @@ def _set_cim_data_type(text, render) -> str: # called by chevron, text contains the label {{dataType}}, which is evaluated by the renderer (see class template) def _set_instances(text, render): instance = None - try: - # render(text) returns a python dict. - # Some fields might be quoted by '"' instead of '"', making the first eval fail. - instance = ast.literal_eval(render(text)) - except SyntaxError as se: - rendered = render(text) - rendered = rendered.replace(""", '"') - instance = eval(rendered) - logger.warning("Exception in evaluating %s : %s . Handled replacing quotes", rendered, se.msg) + instance = ast.literal_eval(render(text).replace(""", '"')) if "label" in instance: value = instance["label"] + ' = "' + instance["label"] + '"' if "comment" in instance: - value += " # " + instance["comment"] + value += " # " + instance["comment"] + " noqa: E501" return value else: return "" From 1ca6bb178de3f19a58dc8e82774de2bb219edf7f Mon Sep 17 00:00:00 2001 From: HUG0-D Date: Mon, 18 Nov 2024 10:52:28 +0100 Subject: [PATCH 11/20] Imports sorted by alphabetical order Signed-off-by: HUG0-D --- cimgen/languages/modernpython/lang_pack.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cimgen/languages/modernpython/lang_pack.py b/cimgen/languages/modernpython/lang_pack.py index 1fd29a5e..2f742080 100644 --- a/cimgen/languages/modernpython/lang_pack.py +++ b/cimgen/languages/modernpython/lang_pack.py @@ -112,7 +112,7 @@ def _set_imports(attributes): classes.add(attribute["attribute_class"]) result = "" - for val in classes: + for val in sorted(classes): result += "from ." + val + " import " + val + "\n" return result + "\n" From 08834d9b44cd861be328bcdcf838df538ff4abc5 Mon Sep 17 00:00:00 2001 From: HUG0-D Date: Mon, 18 Nov 2024 12:16:00 +0100 Subject: [PATCH 12/20] Rename class and attribute property "is_a_primitive"-->"is_a_primitive_class", "is_a_cim_datatype" --> "is_a_datatype_class", "is_cim_datatype" --> "is_datatype_attribute" Signed-off-by: HUG0-D --- cimgen/languages/modernpython/lang_pack.py | 4 ++-- .../modernpython/templates/cimpy_class_template.mustache | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/cimgen/languages/modernpython/lang_pack.py b/cimgen/languages/modernpython/lang_pack.py index 2f742080..ed10ed9c 100644 --- a/cimgen/languages/modernpython/lang_pack.py +++ b/cimgen/languages/modernpython/lang_pack.py @@ -108,7 +108,7 @@ def _primitive_to_data_type(datatype): def _set_imports(attributes): classes = set() for attribute in attributes: - if attribute["is_cim_datatype"] or attribute["is_primitive_attribute"]: + if attribute["is_datatype_attribute"] or attribute["is_primitive_attribute"]: classes.add(attribute["attribute_class"]) result = "" @@ -146,7 +146,7 @@ def _compute_cim_data_type(attributes) -> dict: def _set_cim_data_type(text, render) -> str: attribute = eval(render(text)) cim_data_type = "" - if attribute["is_cim_datatype"] or attribute["is_primitive_attribute"]: + if attribute["is_datatype_attribute"] or attribute["is_primitive_attribute"]: cim_data_type += "\n " cim_data_type += """"cim_data_type": """ + attribute["attribute_class"] + "," return cim_data_type diff --git a/cimgen/languages/modernpython/templates/cimpy_class_template.mustache b/cimgen/languages/modernpython/templates/cimpy_class_template.mustache index bb91f643..66cc3875 100644 --- a/cimgen/languages/modernpython/templates/cimpy_class_template.mustache +++ b/cimgen/languages/modernpython/templates/cimpy_class_template.mustache @@ -36,7 +36,7 @@ class {{class_name}}({{sub_class_of}}): "is_enum_attribute": {{#is_enum_attribute}}True{{/is_enum_attribute}}{{^is_enum_attribute}}False{{/is_enum_attribute}}, "is_list_attribute": {{#is_list_attribute}}True{{/is_list_attribute}}{{^is_list_attribute}}False{{/is_list_attribute}}, "is_primitive_attribute": {{#is_primitive_attribute}}True{{/is_primitive_attribute}}{{^is_primitive_attribute}}False{{/is_primitive_attribute}}, - "is_cim_datatype": {{#is_cim_datatype}}True{{/is_cim_datatype}}{{^is_cim_datatype}}False{{/is_cim_datatype}},{{#setCimDataType}}{{.}}{{/setCimDataType}} + "is_datatype_attribute": {{#is_datatype_attribute}}True{{/is_datatype_attribute}}{{^is_datatype_attribute}}False{{/is_datatype_attribute}},{{#setCimDataType}}{{.}}{{/setCimDataType}} }, ) From 2c3d74c1f8b5a9ae09bae76c2bb659fc2aa3a8a6 Mon Sep 17 00:00:00 2001 From: HUG0-D Date: Mon, 18 Nov 2024 14:37:24 +0100 Subject: [PATCH 13/20] Adapted terminology of variable and function name: cim_data_type as datatype and attribute class Signed-off-by: HUG0-D --- cimgen/languages/modernpython/lang_pack.py | 37 +++++++++---------- .../templates/cimpy_class_template.mustache | 3 +- 2 files changed, 18 insertions(+), 22 deletions(-) diff --git a/cimgen/languages/modernpython/lang_pack.py b/cimgen/languages/modernpython/lang_pack.py index ed10ed9c..14e5357d 100644 --- a/cimgen/languages/modernpython/lang_pack.py +++ b/cimgen/languages/modernpython/lang_pack.py @@ -83,21 +83,18 @@ def _get_type_and_default(text, render) -> tuple[str, str]: def _primitive_to_data_type(datatype): if datatype.lower() == "integer": return "int" + if datatype.lower() == "float": + return "float" if datatype.lower() == "boolean": return "bool" - if datatype.lower() == "string": - return "str" if datatype.lower() == "datetime": return "datetime" - if datatype.lower() == "monthday": - return "str" # TO BE FIXED? I could not find a datatype in python that holds only month and day. if datatype.lower() == "date": return "date" - # as of today no CIM model is using only time. if datatype.lower() == "time": return "time" - if datatype.lower() == "float": - return "float" + if datatype.lower() == "monthday": + return "str" # TO BE FIXED? I could not find a datatype in python that holds only month and day. if datatype.lower() == "string": return "str" else: @@ -117,11 +114,11 @@ def _set_imports(attributes): return result + "\n" -def _compute_cim_data_type(attributes) -> dict: - cim_attributes = {} - cim_attributes["python_type"] = "None" - cim_attributes["unit"] = "UnitSymbol.none" - cim_attributes["multiplier"] = "UnitMultiplier.none" +def _set_datatype_attributes(attributes) -> dict: + datatype_attributes = {} + datatype_attributes["python_type"] = "None" + datatype_attributes["unit"] = "UnitSymbol.none" + datatype_attributes["multiplier"] = "UnitMultiplier.none" for attribute in attributes: if ( @@ -130,25 +127,25 @@ def _compute_cim_data_type(attributes) -> dict: and "value" in attribute["about"] and "attribute_class" in attribute ): - cim_attributes["python_type"] = _primitive_to_data_type(attribute["attribute_class"]) + datatype_attributes["python_type"] = _primitive_to_data_type(attribute["attribute_class"]) if ( "about" in attribute and attribute["about"] and "multiplier" in attribute["about"] and "isFixed" in attribute ): - cim_attributes["multiplier"] = "UnitMultiplier." + attribute["isFixed"] + datatype_attributes["multiplier"] = "UnitMultiplier." + attribute["isFixed"] if "about" in attribute and attribute["about"] and "unit" in attribute["about"] and "isFixed" in attribute: - cim_attributes["unit"] = "UnitSymbol." + attribute["isFixed"] - return cim_attributes + datatype_attributes["unit"] = "UnitSymbol." + attribute["isFixed"] + return datatype_attributes -def _set_cim_data_type(text, render) -> str: +def _set_attribute_class(text, render) -> str: attribute = eval(render(text)) cim_data_type = "" if attribute["is_datatype_attribute"] or attribute["is_primitive_attribute"]: cim_data_type += "\n " - cim_data_type += """"cim_data_type": """ + attribute["attribute_class"] + "," + cim_data_type += """"attribute_class": """ + attribute["attribute_class"] + "," return cim_data_type @@ -175,7 +172,7 @@ def run_template(output_path, class_details): # Datatypes based on primitives are never used in the in memory # representation but only for the schema template = cimdatatype_template_files - class_details.update(_compute_cim_data_type(class_details["attributes"])) + class_details.update(_set_datatype_attributes(class_details["attributes"])) elif class_details["is_an_enum_class"]: template = enum_template_files class_details["setInstances"] = _set_instances @@ -183,7 +180,7 @@ def run_template(output_path, class_details): template = template_files class_details["setDefault"] = _set_default class_details["setType"] = _set_type - class_details["setCimDataType"] = _set_cim_data_type + class_details["setAttributeClass"] = _set_attribute_class class_details["setImports"] = _set_imports(class_details["attributes"]) resource_file = _create_file(output_path, class_details, template) _write_templated_file(resource_file, class_details, template["filename"]) diff --git a/cimgen/languages/modernpython/templates/cimpy_class_template.mustache b/cimgen/languages/modernpython/templates/cimpy_class_template.mustache index 66cc3875..f818dc3b 100644 --- a/cimgen/languages/modernpython/templates/cimpy_class_template.mustache +++ b/cimgen/languages/modernpython/templates/cimpy_class_template.mustache @@ -35,8 +35,7 @@ class {{class_name}}({{sub_class_of}}): "is_datatype_attribute": {{#is_datatype_attribute}}True{{/is_datatype_attribute}}{{^is_datatype_attribute}}False{{/is_datatype_attribute}}, "is_enum_attribute": {{#is_enum_attribute}}True{{/is_enum_attribute}}{{^is_enum_attribute}}False{{/is_enum_attribute}}, "is_list_attribute": {{#is_list_attribute}}True{{/is_list_attribute}}{{^is_list_attribute}}False{{/is_list_attribute}}, - "is_primitive_attribute": {{#is_primitive_attribute}}True{{/is_primitive_attribute}}{{^is_primitive_attribute}}False{{/is_primitive_attribute}}, - "is_datatype_attribute": {{#is_datatype_attribute}}True{{/is_datatype_attribute}}{{^is_datatype_attribute}}False{{/is_datatype_attribute}},{{#setCimDataType}}{{.}}{{/setCimDataType}} + "is_primitive_attribute": {{#is_primitive_attribute}}True{{/is_primitive_attribute}}{{^is_primitive_attribute}}False{{/is_primitive_attribute}},{{#setAttributeClass}}{{.}}{{/setAttributeClass}} }, ) From b9f262c643eb34f7f6e7cebdcc348c8a7f49bebe Mon Sep 17 00:00:00 2001 From: HUG0-D Date: Mon, 18 Nov 2024 14:53:02 +0100 Subject: [PATCH 14/20] Adapted terminology of variable and function name: cim_data_type as attribute class Signed-off-by: HUG0-D --- cimgen/languages/modernpython/lang_pack.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/cimgen/languages/modernpython/lang_pack.py b/cimgen/languages/modernpython/lang_pack.py index 14e5357d..05096da3 100644 --- a/cimgen/languages/modernpython/lang_pack.py +++ b/cimgen/languages/modernpython/lang_pack.py @@ -142,11 +142,11 @@ def _set_datatype_attributes(attributes) -> dict: def _set_attribute_class(text, render) -> str: attribute = eval(render(text)) - cim_data_type = "" + attribute_class = "" if attribute["is_datatype_attribute"] or attribute["is_primitive_attribute"]: - cim_data_type += "\n " - cim_data_type += """"attribute_class": """ + attribute["attribute_class"] + "," - return cim_data_type + attribute_class += "\n " + attribute_class += """"attribute_class": """ + attribute["attribute_class"] + "," + return attribute_class # called by chevron, text contains the label {{dataType}}, which is evaluated by the renderer (see class template) From 58e0c21890b216b81dbc005b26dade7b06da5ea5 Mon Sep 17 00:00:00 2001 From: HUG0-D Date: Tue, 19 Nov 2024 09:02:00 +0100 Subject: [PATCH 15/20] Renaming mustache template files and variables to be more consistent Signed-off-by: HUG0-D --- cimgen/languages/modernpython/lang_pack.py | 28 +++++++++---------- ...plate.mustache => class_template.mustache} | 0 ...e.mustache => constants_template.mustache} | 0 ...te.mustache => datatype_template.mustache} | 0 ...mplate.mustache => enum_template.mustache} | 0 ...ate.mustache => profile_template.mustache} | 0 6 files changed, 14 insertions(+), 14 deletions(-) rename cimgen/languages/modernpython/templates/{cimpy_class_template.mustache => class_template.mustache} (100%) rename cimgen/languages/modernpython/templates/{cimpy_constants_template.mustache => constants_template.mustache} (100%) rename cimgen/languages/modernpython/templates/{cimdatatype_template.mustache => datatype_template.mustache} (100%) rename cimgen/languages/modernpython/templates/{enum_class_template.mustache => enum_template.mustache} (100%) rename cimgen/languages/modernpython/templates/{cimpy_cgmesProfile_template.mustache => profile_template.mustache} (100%) diff --git a/cimgen/languages/modernpython/lang_pack.py b/cimgen/languages/modernpython/lang_pack.py index 05096da3..9b368dc1 100644 --- a/cimgen/languages/modernpython/lang_pack.py +++ b/cimgen/languages/modernpython/lang_pack.py @@ -36,12 +36,12 @@ def location(version): # NOSONAR base = {"base_class": "Base", "class_location": location} # These are the files that are used to generate the python files. -template_files = {"filename": "cimpy_class_template.mustache", "ext": ".py"} -constants_template_files = {"filename": "cimpy_constants_template.mustache", "ext": ".py"} -profile_template_files = {"filename": "cimpy_cgmesProfile_template.mustache", "ext": ".py"} -enum_template_files = {"filename": "enum_class_template.mustache", "ext": ".py"} -primitive_template_files = {"filename": "primitive_template.mustache", "ext": ".py"} -cimdatatype_template_files = {"filename": "cimdatatype_template.mustache", "ext": ".py"} +class_template_file = {"filename": "class_template.mustache", "ext": ".py"} +constants_template_file = {"filename": "constants_template.mustache", "ext": ".py"} +profile_template_file = {"filename": "profile_template.mustache", "ext": ".py"} +enum_template_file = {"filename": "enum_template.mustache", "ext": ".py"} +primitive_template_file = {"filename": "primitive_template.mustache", "ext": ".py"} +datatype_template_file = {"filename": "datatype_template.mustache", "ext": ".py"} def get_class_location(class_name, class_map, version): # NOSONAR @@ -166,18 +166,18 @@ def run_template(output_path, class_details): if class_details["is_a_primitive_class"]: # Primitives are never used in the in memory representation but only for # the schema - template = primitive_template_files + template = primitive_template_file class_details["python_type"] = _primitive_to_data_type(class_details["class_name"]) elif class_details["is_a_datatype_class"]: # Datatypes based on primitives are never used in the in memory # representation but only for the schema - template = cimdatatype_template_files + template = datatype_template_file class_details.update(_set_datatype_attributes(class_details["attributes"])) elif class_details["is_an_enum_class"]: - template = enum_template_files + template = enum_template_file class_details["setInstances"] = _set_instances else: - template = template_files + template = class_template_file class_details["setDefault"] = _set_default class_details["setType"] = _set_type class_details["setAttributeClass"] = _set_attribute_class @@ -214,15 +214,15 @@ def _write_templated_file(class_file, class_details, template_filename): def _create_constants(output_path: str, cim_namespace: str): - class_file = os.path.join(output_path, "utils", "constants" + constants_template_files["ext"]) + class_file = os.path.join(output_path, "utils", "constants" + constants_template_file["ext"]) class_details = {"cim_namespace": cim_namespace} - _write_templated_file(class_file, class_details, constants_template_files["filename"]) + _write_templated_file(class_file, class_details, constants_template_file["filename"]) def _create_cgmes_profile(output_path: str, profile_details: list): - class_file = os.path.join(output_path, "utils", "profile" + profile_template_files["ext"]) + class_file = os.path.join(output_path, "utils", "profile" + profile_template_file["ext"]) class_details = {"profiles": profile_details} - _write_templated_file(class_file, class_details, profile_template_files["filename"]) + _write_templated_file(class_file, class_details, profile_template_file["filename"]) def resolve_headers(path: str, version: str): diff --git a/cimgen/languages/modernpython/templates/cimpy_class_template.mustache b/cimgen/languages/modernpython/templates/class_template.mustache similarity index 100% rename from cimgen/languages/modernpython/templates/cimpy_class_template.mustache rename to cimgen/languages/modernpython/templates/class_template.mustache diff --git a/cimgen/languages/modernpython/templates/cimpy_constants_template.mustache b/cimgen/languages/modernpython/templates/constants_template.mustache similarity index 100% rename from cimgen/languages/modernpython/templates/cimpy_constants_template.mustache rename to cimgen/languages/modernpython/templates/constants_template.mustache diff --git a/cimgen/languages/modernpython/templates/cimdatatype_template.mustache b/cimgen/languages/modernpython/templates/datatype_template.mustache similarity index 100% rename from cimgen/languages/modernpython/templates/cimdatatype_template.mustache rename to cimgen/languages/modernpython/templates/datatype_template.mustache diff --git a/cimgen/languages/modernpython/templates/enum_class_template.mustache b/cimgen/languages/modernpython/templates/enum_template.mustache similarity index 100% rename from cimgen/languages/modernpython/templates/enum_class_template.mustache rename to cimgen/languages/modernpython/templates/enum_template.mustache diff --git a/cimgen/languages/modernpython/templates/cimpy_cgmesProfile_template.mustache b/cimgen/languages/modernpython/templates/profile_template.mustache similarity index 100% rename from cimgen/languages/modernpython/templates/cimpy_cgmesProfile_template.mustache rename to cimgen/languages/modernpython/templates/profile_template.mustache From e681a4fa4e272ef33a6cdbac1712a87ed23a0ae8 Mon Sep 17 00:00:00 2001 From: HUG0-D Date: Tue, 19 Nov 2024 10:19:13 +0100 Subject: [PATCH 16/20] Enum class generation using chevron Signed-off-by: HUG0-D --- cimgen/languages/modernpython/lang_pack.py | 15 --------------- .../modernpython/templates/enum_template.mustache | 4 ++-- 2 files changed, 2 insertions(+), 17 deletions(-) diff --git a/cimgen/languages/modernpython/lang_pack.py b/cimgen/languages/modernpython/lang_pack.py index 9b368dc1..710800fb 100644 --- a/cimgen/languages/modernpython/lang_pack.py +++ b/cimgen/languages/modernpython/lang_pack.py @@ -1,7 +1,6 @@ import logging import os import re -import ast from distutils.dir_util import copy_tree from pathlib import Path from importlib.resources import files @@ -149,19 +148,6 @@ def _set_attribute_class(text, render) -> str: return attribute_class -# called by chevron, text contains the label {{dataType}}, which is evaluated by the renderer (see class template) -def _set_instances(text, render): - instance = None - instance = ast.literal_eval(render(text).replace(""", '"')) - if "label" in instance: - value = instance["label"] + ' = "' + instance["label"] + '"' - if "comment" in instance: - value += " # " + instance["comment"] + " noqa: E501" - return value - else: - return "" - - def run_template(output_path, class_details): if class_details["is_a_primitive_class"]: # Primitives are never used in the in memory representation but only for @@ -175,7 +161,6 @@ def run_template(output_path, class_details): class_details.update(_set_datatype_attributes(class_details["attributes"])) elif class_details["is_an_enum_class"]: template = enum_template_file - class_details["setInstances"] = _set_instances else: template = class_template_file class_details["setDefault"] = _set_default diff --git a/cimgen/languages/modernpython/templates/enum_template.mustache b/cimgen/languages/modernpython/templates/enum_template.mustache index 0622b9b4..d0b3826c 100644 --- a/cimgen/languages/modernpython/templates/enum_template.mustache +++ b/cimgen/languages/modernpython/templates/enum_template.mustache @@ -7,9 +7,9 @@ from enum import Enum class {{class_name}}(str, Enum): """ - {{{class_comment}}} + {{{class_comment}}} # noqa: E501 """ {{#enum_instances}} - {{#setInstances}}{{.}}{{/setInstances}} + {{label}} = "{{label}}"{{#comment}} # {{comment}}{{/comment}} # noqa: E501 {{/enum_instances}} From a9314670366c5f981ddde709e59ea9823500b4de Mon Sep 17 00:00:00 2001 From: HUG0-D Date: Tue, 19 Nov 2024 11:19:12 +0100 Subject: [PATCH 17/20] removing pycgmes from base, and chevron_writer imports Signed-off-by: HUG0-D --- .../modernpython/templates/profile_template.mustache | 2 +- cimgen/languages/modernpython/utils/base.py | 4 ++-- cimgen/languages/modernpython/utils/chevron_writer.py | 6 +++--- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/cimgen/languages/modernpython/templates/profile_template.mustache b/cimgen/languages/modernpython/templates/profile_template.mustache index 0c0db152..0ecc6799 100644 --- a/cimgen/languages/modernpython/templates/profile_template.mustache +++ b/cimgen/languages/modernpython/templates/profile_template.mustache @@ -10,7 +10,7 @@ class BaseProfile(str, Enum): """ Profile parent. Use it if you need your own profiles. - All pycgmes objects requiring a Profile are actually asking for a `BaseProfile`. As + All CGMES objects requiring a Profile are actually asking for a `BaseProfile`. As Enum with fields cannot be inherited or composed, just create your own CustomProfile without trying to extend Profile. It will work. """ diff --git a/cimgen/languages/modernpython/utils/base.py b/cimgen/languages/modernpython/utils/base.py index e44b78ba..f6f75703 100644 --- a/cimgen/languages/modernpython/utils/base.py +++ b/cimgen/languages/modernpython/utils/base.py @@ -6,9 +6,9 @@ from pydantic.dataclasses import dataclass -from pycgmes.utils.constants import NAMESPACES +from .constants import NAMESPACES -from ..utils.config import cgmes_resource_config +from .config import cgmes_resource_config from .profile import BaseProfile diff --git a/cimgen/languages/modernpython/utils/chevron_writer.py b/cimgen/languages/modernpython/utils/chevron_writer.py index acd7b48f..103d9175 100644 --- a/cimgen/languages/modernpython/utils/chevron_writer.py +++ b/cimgen/languages/modernpython/utils/chevron_writer.py @@ -3,9 +3,9 @@ import chevron -from pycgmes.utils.base import Base -from pycgmes.utils.constants import NAMESPACES -from pycgmes.utils.profile import BaseProfile, Profile +from .base import Base +from .constants import NAMESPACES +from .profile import BaseProfile, Profile class ChevronWriter: From dd5e0ee84ce382168da852a86cffd12dd0186e3d Mon Sep 17 00:00:00 2001 From: HUG0-D Date: Wed, 20 Nov 2024 09:21:43 +0100 Subject: [PATCH 18/20] Removed need of setAttributeClass by handling attribute_class direclty with chevron Signed-off-by: HUG0-D --- cimgen/languages/modernpython/lang_pack.py | 10 ---------- .../modernpython/templates/class_template.mustache | 8 +++++++- 2 files changed, 7 insertions(+), 11 deletions(-) diff --git a/cimgen/languages/modernpython/lang_pack.py b/cimgen/languages/modernpython/lang_pack.py index 710800fb..4b8fd1d1 100644 --- a/cimgen/languages/modernpython/lang_pack.py +++ b/cimgen/languages/modernpython/lang_pack.py @@ -139,15 +139,6 @@ def _set_datatype_attributes(attributes) -> dict: return datatype_attributes -def _set_attribute_class(text, render) -> str: - attribute = eval(render(text)) - attribute_class = "" - if attribute["is_datatype_attribute"] or attribute["is_primitive_attribute"]: - attribute_class += "\n " - attribute_class += """"attribute_class": """ + attribute["attribute_class"] + "," - return attribute_class - - def run_template(output_path, class_details): if class_details["is_a_primitive_class"]: # Primitives are never used in the in memory representation but only for @@ -165,7 +156,6 @@ def run_template(output_path, class_details): template = class_template_file class_details["setDefault"] = _set_default class_details["setType"] = _set_type - class_details["setAttributeClass"] = _set_attribute_class class_details["setImports"] = _set_imports(class_details["attributes"]) resource_file = _create_file(output_path, class_details, template) _write_templated_file(resource_file, class_details, template["filename"]) diff --git a/cimgen/languages/modernpython/templates/class_template.mustache b/cimgen/languages/modernpython/templates/class_template.mustache index f818dc3b..10fdb5c4 100644 --- a/cimgen/languages/modernpython/templates/class_template.mustache +++ b/cimgen/languages/modernpython/templates/class_template.mustache @@ -35,7 +35,13 @@ class {{class_name}}({{sub_class_of}}): "is_datatype_attribute": {{#is_datatype_attribute}}True{{/is_datatype_attribute}}{{^is_datatype_attribute}}False{{/is_datatype_attribute}}, "is_enum_attribute": {{#is_enum_attribute}}True{{/is_enum_attribute}}{{^is_enum_attribute}}False{{/is_enum_attribute}}, "is_list_attribute": {{#is_list_attribute}}True{{/is_list_attribute}}{{^is_list_attribute}}False{{/is_list_attribute}}, - "is_primitive_attribute": {{#is_primitive_attribute}}True{{/is_primitive_attribute}}{{^is_primitive_attribute}}False{{/is_primitive_attribute}},{{#setAttributeClass}}{{.}}{{/setAttributeClass}} + "is_primitive_attribute": {{#is_primitive_attribute}}True{{/is_primitive_attribute}}{{^is_primitive_attribute}}False{{/is_primitive_attribute}}, +{{#is_datatype_attribute}} + "attribute_class": {{attribute_class}}, +{{/is_datatype_attribute}} +{{#is_primitive_attribute}} + "attribute_class": {{attribute_class}}, +{{/is_primitive_attribute}} }, ) From 6c6c6741ba9e2905ede12c558adfedbb6c3ef709 Mon Sep 17 00:00:00 2001 From: HUG0-D Date: Wed, 20 Nov 2024 09:42:45 +0100 Subject: [PATCH 19/20] Fix sonar issue Signed-off-by: HUG0-D --- cimgen/languages/modernpython/lang_pack.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cimgen/languages/modernpython/lang_pack.py b/cimgen/languages/modernpython/lang_pack.py index 4b8fd1d1..42eb2315 100644 --- a/cimgen/languages/modernpython/lang_pack.py +++ b/cimgen/languages/modernpython/lang_pack.py @@ -172,7 +172,7 @@ def _create_file(output_path, class_details, template) -> str: if not resource_file.exists(): if not (parent := resource_file.parent).exists(): parent.mkdir() - return resource_file + return str(resource_file) def _write_templated_file(class_file, class_details, template_filename): From 29833d0eae6107dda0900c28dcb53828fd28c277 Mon Sep 17 00:00:00 2001 From: HUG0-D Date: Thu, 21 Nov 2024 13:40:50 +0100 Subject: [PATCH 20/20] Fix datatype attributes for cgmes_v2 and simplifed imports Remove need for os library Signed-off-by: HUG0-D --- cimgen/languages/modernpython/lang_pack.py | 62 +++++-------------- .../templates/class_template.mustache | 6 +- .../templates/datatype_template.mustache | 13 ++-- .../languages/modernpython/utils/datatypes.py | 9 ++- 4 files changed, 37 insertions(+), 53 deletions(-) diff --git a/cimgen/languages/modernpython/lang_pack.py b/cimgen/languages/modernpython/lang_pack.py index 42eb2315..64cb4104 100644 --- a/cimgen/languages/modernpython/lang_pack.py +++ b/cimgen/languages/modernpython/lang_pack.py @@ -1,5 +1,4 @@ import logging -import os import re from distutils.dir_util import copy_tree from pathlib import Path @@ -79,11 +78,9 @@ def _get_type_and_default(text, render) -> tuple[str, str]: return ("str", 'default=""') -def _primitive_to_data_type(datatype): +def _get_python_type(datatype): if datatype.lower() == "integer": return "int" - if datatype.lower() == "float": - return "float" if datatype.lower() == "boolean": return "bool" if datatype.lower() == "datetime": @@ -97,45 +94,28 @@ def _primitive_to_data_type(datatype): if datatype.lower() == "string": return "str" else: - # this actually never happens + # everything else should be a float return "float" def _set_imports(attributes): - classes = set() + import_set = set() for attribute in attributes: if attribute["is_datatype_attribute"] or attribute["is_primitive_attribute"]: - classes.add(attribute["attribute_class"]) - - result = "" - for val in sorted(classes): - result += "from ." + val + " import " + val + "\n" - return result + "\n" + import_set.add(attribute["attribute_class"]) + return sorted(import_set) def _set_datatype_attributes(attributes) -> dict: datatype_attributes = {} datatype_attributes["python_type"] = "None" - datatype_attributes["unit"] = "UnitSymbol.none" - datatype_attributes["multiplier"] = "UnitMultiplier.none" - + import_set = set() for attribute in attributes: - if ( - "about" in attribute - and attribute["about"] - and "value" in attribute["about"] - and "attribute_class" in attribute - ): - datatype_attributes["python_type"] = _primitive_to_data_type(attribute["attribute_class"]) - if ( - "about" in attribute - and attribute["about"] - and "multiplier" in attribute["about"] - and "isFixed" in attribute - ): - datatype_attributes["multiplier"] = "UnitMultiplier." + attribute["isFixed"] - if "about" in attribute and attribute["about"] and "unit" in attribute["about"] and "isFixed" in attribute: - datatype_attributes["unit"] = "UnitSymbol." + attribute["isFixed"] + if "value" in attribute.get("about", "") and "attribute_class" in attribute: + datatype_attributes["python_type"] = _get_python_type(attribute["attribute_class"]) + if "isFixed" in attribute: + import_set.add(attribute["attribute_class"]) + datatype_attributes["isFixed_imports"] = sorted(import_set) return datatype_attributes @@ -144,7 +124,7 @@ def run_template(output_path, class_details): # Primitives are never used in the in memory representation but only for # the schema template = primitive_template_file - class_details["python_type"] = _primitive_to_data_type(class_details["class_name"]) + class_details["python_type"] = _get_python_type(class_details["class_name"]) elif class_details["is_a_datatype_class"]: # Datatypes based on primitives are never used in the in memory # representation but only for the schema @@ -156,22 +136,14 @@ def run_template(output_path, class_details): template = class_template_file class_details["setDefault"] = _set_default class_details["setType"] = _set_type - class_details["setImports"] = _set_imports(class_details["attributes"]) + class_details["imports"] = _set_imports(class_details["attributes"]) resource_file = _create_file(output_path, class_details, template) _write_templated_file(resource_file, class_details, template["filename"]) def _create_file(output_path, class_details, template) -> str: - resource_file = Path( - os.path.join( - output_path, - "resources", - class_details["class_name"] + template["ext"], - ) - ) - if not resource_file.exists(): - if not (parent := resource_file.parent).exists(): - parent.mkdir() + resource_file = Path(output_path) / "resources" / (class_details["class_name"] + template["ext"]) + resource_file.parent.mkdir(exist_ok=True) return str(resource_file) @@ -189,13 +161,13 @@ def _write_templated_file(class_file, class_details, template_filename): def _create_constants(output_path: str, cim_namespace: str): - class_file = os.path.join(output_path, "utils", "constants" + constants_template_file["ext"]) + class_file = Path(output_path) / "utils" / ("constants" + constants_template_file["ext"]) class_details = {"cim_namespace": cim_namespace} _write_templated_file(class_file, class_details, constants_template_file["filename"]) def _create_cgmes_profile(output_path: str, profile_details: list): - class_file = os.path.join(output_path, "utils", "profile" + profile_template_file["ext"]) + class_file = Path(output_path) / "utils" / ("profile" + profile_template_file["ext"]) class_details = {"profiles": profile_details} _write_templated_file(class_file, class_details, profile_template_file["filename"]) diff --git a/cimgen/languages/modernpython/templates/class_template.mustache b/cimgen/languages/modernpython/templates/class_template.mustache index 10fdb5c4..59561703 100644 --- a/cimgen/languages/modernpython/templates/class_template.mustache +++ b/cimgen/languages/modernpython/templates/class_template.mustache @@ -10,7 +10,11 @@ from pydantic.dataclasses import dataclass from ..utils.profile import BaseProfile, Profile from {{class_location}} import {{sub_class_of}} -{{setImports}} +{{#imports}} +from .{{.}} import {{.}} +{{/imports}} + + @dataclass class {{class_name}}({{sub_class_of}}): """ diff --git a/cimgen/languages/modernpython/templates/datatype_template.mustache b/cimgen/languages/modernpython/templates/datatype_template.mustache index 2fcc02a7..6d690217 100644 --- a/cimgen/languages/modernpython/templates/datatype_template.mustache +++ b/cimgen/languages/modernpython/templates/datatype_template.mustache @@ -4,14 +4,19 @@ Generated from the CGMES files via cimgen: https://github.com/sogno-platform/cim from ..utils.datatypes import CIMDatatype from ..utils.profile import Profile -from .UnitMultiplier import UnitMultiplier -from .UnitSymbol import UnitSymbol +{{#isFixed_imports}} +from .{{.}} import {{.}} +{{/isFixed_imports}} + {{class_name}} = CIMDatatype( name="{{class_name}}", type={{python_type}}, - symbol={{unit}}, - multiplier={{multiplier}}, +{{#attributes}} +{{#isFixed}} + {{label}}={{attribute_class}}.{{isFixed}}, +{{/isFixed}} +{{/attributes}} profiles=[{{#class_origin}} Profile.{{origin}},{{/class_origin}} ], diff --git a/cimgen/languages/modernpython/utils/datatypes.py b/cimgen/languages/modernpython/utils/datatypes.py index 38583efc..db3d6ba6 100644 --- a/cimgen/languages/modernpython/utils/datatypes.py +++ b/cimgen/languages/modernpython/utils/datatypes.py @@ -1,5 +1,5 @@ from pydantic import Field -from typing import List +from typing import List, Optional, Union from .constants import NAMESPACES from pydantic.dataclasses import dataclass @@ -8,6 +8,7 @@ from .profile import BaseProfile from ..resources.UnitMultiplier import UnitMultiplier from ..resources.UnitSymbol import UnitSymbol +from ..resources.Currency import Currency @dataclass(config=cgmes_resource_config) @@ -22,5 +23,7 @@ class Primitive: @dataclass(config=cgmes_resource_config) class CIMDatatype(Primitive): - multiplier: UnitMultiplier = Field(frozen=True) - symbol: UnitSymbol = Field(frozen=True) + multiplier: Optional[UnitMultiplier] = Field(default=None, frozen=True) + unit: Optional[Union[UnitSymbol, Currency]] = Field(default=None, frozen=True) + denominatorMultiplier: Optional[UnitMultiplier] = Field(default=None, frozen=True) + denominatorUnit: Optional[UnitSymbol] = Field(default=None, frozen=True)