Skip to content

Commit

Permalink
use enum for <cims:stereotype rdf:resource="http://iec.ch/TC57/NonSta…
Browse files Browse the repository at this point in the history
…ndard/UML#enumeration"/>

Signed-off-by: Federico M. Facca <[email protected]>
  • Loading branch information
chicco785 committed Oct 11, 2023
1 parent 988d130 commit f76e320
Show file tree
Hide file tree
Showing 3 changed files with 88 additions and 9 deletions.
42 changes: 35 additions & 7 deletions CIMgen.py
Original file line number Diff line number Diff line change
Expand Up @@ -638,18 +638,42 @@ def _merge_classes(profiles_dict):
class_dict[class_key].addAttribute(attr)
return class_dict

def recursivelyAddSubClasses(class_dict, class_name):
def recursively_add_sub_classes(class_dict, class_name):
newSubClasses = []
theClass = class_dict[class_name]
for name in theClass.subClasses():
newSubClasses.append(name)
newNewSubClasses = recursivelyAddSubClasses(class_dict, name)
newNewSubClasses = recursively_add_sub_classes(class_dict, name)
newSubClasses = newSubClasses + newNewSubClasses
return newSubClasses

def addSubClassesOfSubClasses(class_dict):
for className in class_dict:
class_dict[className].setSubClasses(recursivelyAddSubClasses(class_dict, className))
def add_sub_classes_of_sub_classes(class_dict):
for class_name in class_dict:
class_dict[class_name].setSubClasses(recursively_add_sub_classes(class_dict, class_name))

def add_sub_classes_of_sub_classes_clean(class_dict, source):
temp = {}
for class_name in class_dict:
for name in class_dict[class_name].subClasses():
if name not in class_dict:
temp[name] = source[name]
add_sub_classes_of_sub_classes_clean(temp, source)
class_dict.update(temp)

# Order classes based on dependency order

def generate_clean_sub_classes(class_dict_with_origins, clean_class_dict):
for class_name in class_dict_with_origins:
super_class_name = class_dict_with_origins[class_name].superClass()
if super_class_name == None and class_dict_with_origins[class_name].has_instances():
clean_class_dict[class_name] = class_dict_with_origins[class_name]

for class_name in class_dict_with_origins:
super_class_name = class_dict_with_origins[class_name].superClass()
if super_class_name == None and not class_dict_with_origins[class_name].has_instances():
clean_class_dict[class_name] = class_dict_with_origins[class_name]

add_sub_classes_of_sub_classes_clean(clean_class_dict, class_dict_with_origins)

def cim_generate(directory, outputPath, version, langPack):
"""Generates cgmes python classes from cgmes ontology
Expand Down Expand Up @@ -691,6 +715,8 @@ def cim_generate(directory, outputPath, version, langPack):
# merge classes from different profiles into one class and track origin of the classes and their attributes
class_dict_with_origins = _merge_classes(profiles_dict)

clean_class_dict = {}

# work out the subclasses for each class by noting the reverse relationship
for className in class_dict_with_origins:
superClassName = class_dict_with_origins[className].superClass()
Expand All @@ -702,10 +728,12 @@ def cim_generate(directory, outputPath, version, langPack):
print("No match for superClass in dict: :", superClassName)

# recursively add the subclasses of subclasses
addSubClassesOfSubClasses(class_dict_with_origins)
add_sub_classes_of_sub_classes(class_dict_with_origins)

generate_clean_sub_classes(class_dict_with_origins, clean_class_dict)

# get information for writing python files and write python files
_write_python_files(class_dict_with_origins, langPack, outputPath, version)
_write_python_files(clean_class_dict, langPack, outputPath, version)

if "modernpython" in langPack.__name__:
langPack.resolve_headers(outputPath, version)
Expand Down
44 changes: 42 additions & 2 deletions modernpython/langPack.py
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ def location(version):
base = {"base_class": "Base", "class_location": location}

template_files = [{"filename": "cimpy_class_template.mustache", "ext": ".py"}]

enum_template_files = [{"filename": "pydantic_enum_template.mustache", "ext": ".py"}]

def get_class_location(class_name, class_map, version):
# Check if the current class has a parent class
Expand All @@ -55,6 +55,24 @@ def _set_type(text, render):
return _get_type_and_default(text, render)[0]


# 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:
instance = eval(render(text))
except SyntaxError as se:
rendered = render(text)
rendered = rendered.replace("&quot;", '"')
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 _get_type_and_default(text, renderer) -> tuple[str, str]:
result = renderer(text)
# the field {{dataType}} either contains the multiplicity of an attribute if it is a reference or otherwise the
Expand Down Expand Up @@ -89,7 +107,29 @@ def set_float_classes(new_float_classes):


def run_template(version_path, class_details):
for template_info in template_files:
if class_details["has_instances"] == True:
run_template_enum(version_path, class_details, enum_template_files)
else:
run_template_schema(version_path, class_details, template_files)

def run_template_enum(version_path, class_details, templates):
for template_info in templates:
class_file = os.path.join(version_path, class_details["class_name"] + template_info["ext"])
if not os.path.exists(class_file):
with open(class_file, "w", encoding="utf-8") as file:
template_path = os.path.join(os.getcwd(), "modernpython/templates", template_info["filename"])
class_details["setInstances"] = _set_instances
with open(template_path, encoding="utf-8") as f:
args = {
"data": class_details,
"template": f,
"partials_dict": partials,
}
output = chevron.render(**args)
file.write(output)

def run_template_schema(version_path, class_details, templates):
for template_info in templates:
class_file = os.path.join(version_path, class_details["class_name"] + template_info["ext"])
if not os.path.exists(class_file):
with open(class_file, "w", encoding="utf-8") as file:
Expand Down
11 changes: 11 additions & 0 deletions modernpython/templates/pydantic_enum_template.mustache
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
from enum import Enum

class {{class_name}}(str,Enum):

'''
{{{class_comment}}}
'''

{{#instances}}
{{#setInstances}}{{.}}{{/setInstances}}
{{/instances}}

0 comments on commit f76e320

Please sign in to comment.