Skip to content

Commit

Permalink
Add "is_a_datatype_class" and "is_datatype_attribute" (stereotype == …
Browse files Browse the repository at this point in the history
…"CIMDatatype"), use these instead of "is_a_float_class" and "is_primitive_float_attribute"

There are now 4 disjoint class types:
- is_a_datatype_class (= float)
- is_an_enum_class
- is_a_primitive_class (Integer, Boolean, Float/Decimal = float, String/Date/DateTime/MonthDay = string)
- all others are normal classes

and 5 disjoint attribute types:
- is_class_attribute
- is_enum_attribute
- is_datatype_attribute
- is_list_attribute
- is_primitive_attribute

Signed-off-by: Thomas Günther <[email protected]>
  • Loading branch information
tom-hg57 committed Nov 15, 2024
1 parent 997988e commit 0fc5750
Show file tree
Hide file tree
Showing 8 changed files with 51 additions and 58 deletions.
45 changes: 9 additions & 36 deletions cimgen/cimgen.py
Original file line number Diff line number Diff line change
Expand Up @@ -246,41 +246,12 @@ def subClasses(self):
def setSubClasses(self, classes):
self.subclasses = classes

@staticmethod
def _simple_float_attribute(attr):
if "dataType" in attr:
return attr["label"] == "value" and attr["dataType"] == "#Float"
return False

def is_a_float_class(self):
if self.about in ("Float", "Decimal"):
return True
simple_float = False
for attr in self.attribute_list:
if CIMComponentDefinition._simple_float_attribute(attr):
simple_float = True
for attr in self.attribute_list:
if not CIMComponentDefinition._simple_float_attribute(attr):
simple_float = False
if simple_float:
return True

candidate_array = {"value": False, "unit": False, "multiplier": False}
optional_attributes = ["denominatorUnit", "denominatorMultiplier"]
for attr in self.attribute_list:
key = attr["label"]
if key in candidate_array:
candidate_array[key] = True
elif key not in optional_attributes:
return False
for key in candidate_array:
if not candidate_array[key]:
return False
return True

def is_a_primitive_class(self):
return self.stereotype == "Primitive"

def is_a_datatype_class(self):
return self.stereotype == "CIMDatatype"


def wrap_and_clean(txt: str, width: int = 120, initial_indent="", subsequent_indent=" ") -> str:
"""
Expand Down Expand Up @@ -460,8 +431,8 @@ def _write_python_files(elem_dict, lang_pack, output_path, version):
"class_origin": elem_dict[class_name].origins(),
"enum_instances": elem_dict[class_name].enum_instances(),
"is_an_enum_class": elem_dict[class_name].is_an_enum_class(),
"is_a_float_class": elem_dict[class_name].is_a_float_class(),
"is_a_primitive_class": elem_dict[class_name].is_a_primitive_class(),
"is_a_datatype_class": elem_dict[class_name].is_a_datatype_class(),
"langPack": lang_pack,
"sub_class_of": elem_dict[class_name].superClass(),
"sub_classes": elem_dict[class_name].subClasses(),
Expand Down Expand Up @@ -494,7 +465,7 @@ def _write_python_files(elem_dict, lang_pack, output_path, version):
attribute["is_enum_attribute"] = _get_bool_string(attribute_type == "enum")
attribute["is_list_attribute"] = _get_bool_string(attribute_type == "list")
attribute["is_primitive_attribute"] = _get_bool_string(attribute_type == "primitive")
attribute["is_primitive_float_attribute"] = _get_bool_string(elem_dict[attribute_class].is_a_float_class())
attribute["is_datatype_attribute"] = _get_bool_string(attribute_type == "datatype")
attribute["attribute_class"] = attribute_class

class_details["attributes"].sort(key=lambda d: d["label"])
Expand Down Expand Up @@ -760,14 +731,16 @@ def _get_attribute_class(attribute: dict) -> str:


def _get_attribute_type(attribute: dict, class_infos: CIMComponentDefinition) -> str:
"""Get the type of an attribute: "class", "enum", "list", or "primitive".
"""Get the type of an attribute: "class", "datatype", "enum", "list", or "primitive".
:param attribute: Dictionary with information about an attribute of a class.
:param class_infos: Information about the attribute class.
:return: Type of the attribute.
"""
attribute_type = "class"
if class_infos.is_a_primitive_class() or class_infos.is_a_float_class():
if class_infos.is_a_datatype_class():
attribute_type = "datatype"
elif class_infos.is_a_primitive_class():
attribute_type = "primitive"
elif class_infos.is_an_enum_class():
attribute_type = "enum"
Expand Down
26 changes: 17 additions & 9 deletions cimgen/languages/cpp/lang_pack.py
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,7 @@ def get_class_location(class_name, class_map, version): # NOSONAR
# This is the function that runs the template.
def run_template(output_path, class_details):

if class_details["is_a_float_class"]:
if class_details["is_a_datatype_class"] or class_details["class_name"] in ("Float", "Decimal"):
templates = float_template_files
elif class_details["is_an_enum_class"]:
templates = enum_template_files
Expand Down Expand Up @@ -110,7 +110,7 @@ def label(text, render):
def insert_assign_fn(text, render):
attribute_txt = render(text)
attribute_json = eval(attribute_txt)
if not (attribute_json["is_primitive_attribute"] or attribute_json["is_enum_attribute"]):
if not _attribute_is_primitive_or_datatype_or_enum(attribute_json):
return ""
label = attribute_json["label"]
class_name = attribute_json["domain"]
Expand All @@ -130,7 +130,7 @@ def insert_assign_fn(text, render):
def insert_class_assign_fn(text, render):
attribute_txt = render(text)
attribute_json = eval(attribute_txt)
if attribute_json["is_primitive_attribute"] or attribute_json["is_enum_attribute"]:
if _attribute_is_primitive_or_datatype_or_enum(attribute_json):
return ""
label = attribute_json["label"]
class_name = attribute_json["domain"]
Expand Down Expand Up @@ -171,7 +171,7 @@ def create_class_assign(text, render):
attribute_json = eval(attribute_txt)
assign = ""
attribute_class = attribute_json["attribute_class"]
if attribute_json["is_primitive_attribute"] or attribute_json["is_enum_attribute"]:
if _attribute_is_primitive_or_datatype_or_enum(attribute_json):
return ""
if attribute_json["is_list_attribute"]:
if "inverseRole" in attribute_json:
Expand Down Expand Up @@ -277,16 +277,16 @@ def create_assign(text, render):
attribute_json = eval(attribute_txt)
assign = ""
_class = attribute_json["attribute_class"]
if not (attribute_json["is_primitive_attribute"] or attribute_json["is_enum_attribute"]):
if not _attribute_is_primitive_or_datatype_or_enum(attribute_json):
return ""
label_without_keyword = attribute_json["label"]
if label_without_keyword == "switch":
label_without_keyword = "_switch"

if (
attribute_json["is_enum_attribute"]
or attribute_json["is_primitive_float_attribute"]
or _class in ("Integer", "Boolean")
or attribute_json["is_datatype_attribute"]
or _class in ("Float", "Decimal", "Integer", "Boolean")
):
assign = (
"""
Expand Down Expand Up @@ -337,7 +337,7 @@ def attribute_decl(text, render):

def _attribute_decl(attribute):
_class = attribute["attribute_class"]
if attribute["is_primitive_attribute"] or attribute["is_enum_attribute"]:
if _attribute_is_primitive_or_datatype_or_enum(attribute):
return "CIMPP::" + _class
if attribute["is_list_attribute"]:
return "std::list<CIMPP::" + _class + "*>"
Expand All @@ -354,7 +354,7 @@ def _create_attribute_includes(text, render):
if jsonStringNoHtmlEsc is not None and jsonStringNoHtmlEsc != "":
attributes = json.loads(jsonStringNoHtmlEsc)
for attribute in attributes:
if attribute["is_primitive_attribute"] or attribute["is_enum_attribute"]:
if _attribute_is_primitive_or_datatype_or_enum(attribute):
unique[attribute["attribute_class"]] = True
for clarse in sorted(unique):
include_string += '#include "' + clarse + '.hpp"\n'
Expand Down Expand Up @@ -404,6 +404,14 @@ def set_default(dataType):
return "nullptr"


def _attribute_is_primitive_or_datatype_or_enum(attribute: dict) -> bool:
return _attribute_is_primitive_or_datatype(attribute) or attribute["is_enum_attribute"]


def _attribute_is_primitive_or_datatype(attribute: dict) -> bool:
return attribute["is_primitive_attribute"] or attribute["is_datatype_attribute"]


# The code below this line is used after the main cim_generate phase to generate
# two include files. They are called CIMClassList.hpp and IEC61970.hpp, and
# contain the list of the class files and the list of define functions that add
Expand Down
14 changes: 9 additions & 5 deletions cimgen/languages/java/lang_pack.py
Original file line number Diff line number Diff line change
Expand Up @@ -47,10 +47,10 @@ def run_template(output_path, class_details):

class_details["primitives"] = []
for attr in class_details["attributes"]:
if attr["is_primitive_attribute"] or attr["is_enum_attribute"]:
if _attribute_is_primitive_or_datatype_or_enum(attr):
class_details["primitives"].append(attr)

if class_details["is_a_float_class"]:
if class_details["is_a_datatype_class"] or class_details["class_name"] in ("Float", "Decimal"):
templates = float_template_files
elif class_details["is_an_enum_class"]:
templates = enum_template_files
Expand Down Expand Up @@ -103,7 +103,7 @@ def create_assign(text, render):
attribute_json = eval(attribute_txt)
assign = ""
_class = attribute_json["attribute_class"]
if not (attribute_json["is_primitive_attribute"] or attribute_json["is_enum_attribute"]):
if not _attribute_is_primitive_or_datatype_or_enum(attribute_json):
return ""
label_without_keyword = attribute_json["label"]
if label_without_keyword == "switch":
Expand Down Expand Up @@ -140,7 +140,7 @@ def attribute_decl(text, render):

def _attribute_decl(attribute):
_class = attribute["attribute_class"]
if attribute["is_primitive_attribute"] or attribute["is_enum_attribute"]:
if _attribute_is_primitive_or_datatype_or_enum(attribute):
return _class
if attribute["is_list_attribute"]:
return "List<" + _class + ">"
Expand All @@ -157,7 +157,7 @@ def _create_attribute_includes(text, render):
if jsonStringNoHtmlEsc is not None and jsonStringNoHtmlEsc != "":
attributes = json.loads(jsonStringNoHtmlEsc)
for attribute in attributes:
if attribute["is_primitive_attribute"] or attribute["is_enum_attribute"]:
if _attribute_is_primitive_or_datatype_or_enum(attribute):
unique[attribute["attribute_class"]] = True
for clarse in unique:
if clarse != "String":
Expand Down Expand Up @@ -206,6 +206,10 @@ def set_default(dataType):
return "nullptr"


def _attribute_is_primitive_or_datatype_or_enum(attribute: dict) -> bool:
return attribute["is_primitive_attribute"] or attribute["is_datatype_attribute"] or attribute["is_enum_attribute"]


# The code below this line is used after the main cim_generate phase to generate
# two include files. They are called CIMClassList.hpp and IEC61970.hpp, and
# contain the list of the class files and the list of define functions that add
Expand Down
10 changes: 4 additions & 6 deletions cimgen/languages/javascript/lang_pack.py
Original file line number Diff line number Diff line change
Expand Up @@ -76,7 +76,9 @@ def get_class_location(class_name, class_map, version): # NOSONAR
def select_primitive_render_function(class_details):
class_name = class_details["class_name"]
render = ""
if class_details["is_a_float_class"]:
if class_details["is_a_datatype_class"]:
render = aggregateRenderer["renderFloat"]
elif class_name in ("Float", "Decimal"):
render = aggregateRenderer["renderFloat"]
elif class_name == "String":
render = aggregateRenderer["renderString"]
Expand All @@ -88,9 +90,6 @@ def select_primitive_render_function(class_details):
elif class_name == "DateTime":
# TODO: Implementation Required!
render = aggregateRenderer["renderString"]
elif class_name == "Decimal":
# TODO: Implementation Required!
render = aggregateRenderer["renderString"]
elif class_name == "Integer":
# TODO: Implementation Required!
render = aggregateRenderer["renderString"]
Expand Down Expand Up @@ -158,8 +157,7 @@ def _create_cgmes_profile(output_path: str, profile_details: list, cim_namespace


def _get_class_type(class_details):
class_name = class_details["class_name"]
if class_details["is_a_float_class"] or class_name in ("String", "Boolean", "Integer"):
if class_details["is_a_primitive_class"] or class_details["is_a_datatype_class"]:
return "primitive"
if class_details["is_an_enum_class"]:
return "enum"
Expand Down
6 changes: 4 additions & 2 deletions cimgen/languages/modernpython/lang_pack.py
Original file line number Diff line number Diff line change
Expand Up @@ -63,7 +63,9 @@ def _get_type_and_default(text, render) -> tuple[str, str]:
return ("Optional[str]", "default=None")
elif attribute_json["is_list_attribute"]:
return ("list", "default_factory=list")
elif attribute_json["is_primitive_float_attribute"]:
elif attribute_json["is_datatype_attribute"]:
return ("float", "default=0.0")
elif attribute_json["attribute_class"] in ("Float", "Decimal"):
return ("float", "default=0.0")
elif attribute_json["attribute_class"] == "Integer":
return ("int", "default=0")
Expand All @@ -75,7 +77,7 @@ 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_float_class"]:
if class_details["is_a_primitive_class"] or class_details["is_a_datatype_class"]:
return
for template_info in template_files:
resource_file = Path(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ class {{class_name}}({{sub_class_of}}):
],
"is_used": {{#is_used}}True{{/is_used}}{{^is_used}}False{{/is_used}},
"is_class_attribute": {{#is_class_attribute}}True{{/is_class_attribute}}{{^is_class_attribute}}False{{/is_class_attribute}},
"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}},
Expand Down
6 changes: 6 additions & 0 deletions cimgen/languages/modernpython/utils/export_template.mustache
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,9 @@
{{#is_class_attribute}}
<cim:{{attr_name}} rdf:resource="#{{value}}" />
{{/is_class_attribute}}
{{#is_datatype_attribute}}
<cim:{{attr_name}}>{{value}}</cim:{{attr_name}}>
{{/is_datatype_attribute}}
{{#is_enum_attribute}}
<cim:{{attr_name}} rdf:resource="{{namespace}}{{value}}" />
{{/is_enum_attribute}}
Expand All @@ -31,6 +34,9 @@
{{#is_class_attribute}}
<cim:{{attr_name}} rdf:resource="#{{value}}" />
{{/is_class_attribute}}
{{#is_datatype_attribute}}
<cim:{{attr_name}}>{{value}}</cim:{{attr_name}}>
{{/is_datatype_attribute}}
{{#is_enum_attribute}}
<cim:{{attr_name}} rdf:resource="{{namespace}}{{value}}" />
{{/is_enum_attribute}}
Expand Down
1 change: 1 addition & 0 deletions cimgen/languages/modernpython/utils/writer.py
Original file line number Diff line number Diff line change
Expand Up @@ -190,6 +190,7 @@ def get_attribute_infos(obj: Base) -> dict[str, dict[str, object]]:
"namespace": extra.get("namespace", obj.namespace),
"value": getattr(obj, attr),
"is_class_attribute": extra.get("is_class_attribute"),
"is_datatype_attribute": extra.get("is_datatype_attribute"),
"is_enum_attribute": extra.get("is_enum_attribute"),
"is_list_attribute": extra.get("is_list_attribute"),
"is_primitive_attribute": extra.get("is_primitive_attribute"),
Expand Down

0 comments on commit 0fc5750

Please sign in to comment.