From 54dae354f378210f7c398bb0219911401c662c94 Mon Sep 17 00:00:00 2001 From: "Hanna Shalamitskaya (EPAM)" Date: Thu, 4 Jul 2024 15:37:18 +0500 Subject: [PATCH 1/2] Switch to the SAMM 2.2.0 --- .github/workflows/push_request_check.yml | 2 +- core/esmf-aspect-meta-model-python/README.md | 4 +- .../base/README.md | 4 +- .../base/__init__.py | 16 +- .../base/characteristics/trait.py | 2 +- .../{contraints => constraints}/__init__.py | 0 .../{contraints => constraints}/constraint.py | 0 .../encoding_constraint.py | 2 +- .../fixed_point_constraint.py | 2 +- .../language_constraint.py | 2 +- .../length_constraint.py | 2 +- .../locale_constraint.py | 2 +- .../range_constraint.py | 2 +- .../regular_expression_constraint.py | 2 +- .../base/namespace.py | 18 ++ .../base/value.py | 24 ++ .../impl/characteristics/default_trait.py | 2 +- .../impl/constraints/default_constraint.py | 2 +- .../default_encoding_constraint.py | 2 +- .../default_fixed_point_constraint.py | 2 +- .../default_language_constraint.py | 2 +- .../constraints/default_length_constraint.py | 2 +- .../constraints/default_locale_constraint.py | 2 +- .../constraints/default_range_constraint.py | 2 +- .../default_regular_expression_constraint.py | 2 +- .../impl/default_namespace.py | 17 ++ .../impl/default_value.py | 35 +++ .../encoding_constraint_instantiator.py | 2 +- .../instantiator/enumeration_instantiator.py | 50 ++-- .../fixed_point_constraint_instantiator.py | 2 +- .../language_constraint_instantiator.py | 2 +- .../length_constraint_instantiator.py | 2 +- .../locale_constraint_instantiator.py | 2 +- .../instantiator/namespace_instantiator.py | 23 ++ .../range_constraint_instantiator.py | 2 +- ...ular_expression_constraint_instantiator.py | 2 +- .../loader/instantiator/trait_instantiator.py | 2 +- .../loader/instantiator/value_instantiator.py | 27 ++ .../loader/samm_graph.py | 8 + .../samm_meta_model.py | 2 +- .../vocabulary/constants.py | 4 + .../pyproject.toml | 5 +- .../scripts/constants.py | 5 +- .../scripts/download_samm_cli.py | 6 +- .../scripts/samm/download_samm_release.py | 2 +- .../java_models/test_loading_aspects.py | 230 ++++++++++-------- .../test_enumeration_instantiator.py | 70 +++++- ...est_fixed_point_constraint_instantiator.py | 2 +- core/esmf-aspect-meta-model-python/tox.ini | 2 +- .../modules/ROOT/pages/index.adoc | 114 +++------ 50 files changed, 461 insertions(+), 259 deletions(-) rename core/esmf-aspect-meta-model-python/esmf_aspect_meta_model_python/base/{contraints => constraints}/__init__.py (100%) rename core/esmf-aspect-meta-model-python/esmf_aspect_meta_model_python/base/{contraints => constraints}/constraint.py (100%) rename core/esmf-aspect-meta-model-python/esmf_aspect_meta_model_python/base/{contraints => constraints}/encoding_constraint.py (89%) rename core/esmf-aspect-meta-model-python/esmf_aspect_meta_model_python/base/{contraints => constraints}/fixed_point_constraint.py (92%) rename core/esmf-aspect-meta-model-python/esmf_aspect_meta_model_python/base/{contraints => constraints}/language_constraint.py (90%) rename core/esmf-aspect-meta-model-python/esmf_aspect_meta_model_python/base/{contraints => constraints}/length_constraint.py (92%) rename core/esmf-aspect-meta-model-python/esmf_aspect_meta_model_python/base/{contraints => constraints}/locale_constraint.py (90%) rename core/esmf-aspect-meta-model-python/esmf_aspect_meta_model_python/base/{contraints => constraints}/range_constraint.py (94%) rename core/esmf-aspect-meta-model-python/esmf_aspect_meta_model_python/base/{contraints => constraints}/regular_expression_constraint.py (90%) create mode 100644 core/esmf-aspect-meta-model-python/esmf_aspect_meta_model_python/base/namespace.py create mode 100644 core/esmf-aspect-meta-model-python/esmf_aspect_meta_model_python/base/value.py create mode 100644 core/esmf-aspect-meta-model-python/esmf_aspect_meta_model_python/impl/default_namespace.py create mode 100644 core/esmf-aspect-meta-model-python/esmf_aspect_meta_model_python/impl/default_value.py create mode 100644 core/esmf-aspect-meta-model-python/esmf_aspect_meta_model_python/loader/instantiator/namespace_instantiator.py create mode 100644 core/esmf-aspect-meta-model-python/esmf_aspect_meta_model_python/loader/instantiator/value_instantiator.py diff --git a/.github/workflows/push_request_check.yml b/.github/workflows/push_request_check.yml index 08a1d72..98c7f26 100644 --- a/.github/workflows/push_request_check.yml +++ b/.github/workflows/push_request_check.yml @@ -37,7 +37,7 @@ jobs: poetry run download-samm-release poetry build - - name: run tests + - name: run test*s run: | cd core/esmf-aspect-meta-model-python poetry run tox -e py310 diff --git a/core/esmf-aspect-meta-model-python/README.md b/core/esmf-aspect-meta-model-python/README.md index 9873d4b..b4ff829 100644 --- a/core/esmf-aspect-meta-model-python/README.md +++ b/core/esmf-aspect-meta-model-python/README.md @@ -116,7 +116,7 @@ SAMMUnitsGraph is a class contains functions for accessing units of measurement. from esmf_aspect_meta_model_python.samm_meta_model import units unit_name = "unit:volt" -units.print_description(units.get_info(unit_name)) +units.print_info(units.get_info(unit_name)) # preferredName: volt # commonCode: VLT # ... @@ -126,7 +126,7 @@ units.print_description(units.get_info(unit_name)) volt_info = units.get_info("unit:volt") # {'preferredName': rdflib.term.Literal('volt', lang='en'), 'commonCode': rdflib.term.Literal('VLT'), ... } -units.print_description(volt_info) +units.print_info(volt_info) # preferredName: volt # commonCode: VLT # ... diff --git a/core/esmf-aspect-meta-model-python/esmf_aspect_meta_model_python/base/README.md b/core/esmf-aspect-meta-model-python/esmf_aspect_meta_model_python/base/README.md index b740916..53b9332 100644 --- a/core/esmf-aspect-meta-model-python/esmf_aspect_meta_model_python/base/README.md +++ b/core/esmf-aspect-meta-model-python/esmf_aspect_meta_model_python/base/README.md @@ -38,11 +38,13 @@ HasUrn │ ├── LocaleConstraint │ ├── RangeConstraint │ └── RegularExpressionConstraint + ├── Namespace ├── Event ├── Operation ├── Property ├── QuantityKind - └── Unit + ├── Unit + └── Value BoundDefiniton ``` \ No newline at end of file diff --git a/core/esmf-aspect-meta-model-python/esmf_aspect_meta_model_python/base/__init__.py b/core/esmf-aspect-meta-model-python/esmf_aspect_meta_model_python/base/__init__.py index 8a0f4ed..1060046 100644 --- a/core/esmf-aspect-meta-model-python/esmf_aspect_meta_model_python/base/__init__.py +++ b/core/esmf-aspect-meta-model-python/esmf_aspect_meta_model_python/base/__init__.py @@ -27,14 +27,14 @@ from .characteristics.state import State from .characteristics.structured_value import StructuredValue from .characteristics.trait import Trait -from .contraints.constraint import Constraint -from .contraints.encoding_constraint import EncodingConstraint -from .contraints.fixed_point_constraint import FixedPointConstraint -from .contraints.language_constraint import LanguageConstraint -from .contraints.length_constraint import LengthConstraint -from .contraints.locale_constraint import LocaleConstraint -from .contraints.range_constraint import RangeConstraint -from .contraints.regular_expression_constraint import RegularExpressionConstraint +from .constraints.constraint import Constraint +from .constraints.encoding_constraint import EncodingConstraint +from .constraints.fixed_point_constraint import FixedPointConstraint +from .constraints.language_constraint import LanguageConstraint +from .constraints.length_constraint import LengthConstraint +from .constraints.locale_constraint import LocaleConstraint +from .constraints.range_constraint import RangeConstraint +from .constraints.regular_expression_constraint import RegularExpressionConstraint from .data_types.abstract_entity import AbstractEntity from .data_types.complex_type import ComplexType from .data_types.data_type import DataType diff --git a/core/esmf-aspect-meta-model-python/esmf_aspect_meta_model_python/base/characteristics/trait.py b/core/esmf-aspect-meta-model-python/esmf_aspect_meta_model_python/base/characteristics/trait.py index 95d54df..10e8657 100644 --- a/core/esmf-aspect-meta-model-python/esmf_aspect_meta_model_python/base/characteristics/trait.py +++ b/core/esmf-aspect-meta-model-python/esmf_aspect_meta_model_python/base/characteristics/trait.py @@ -14,7 +14,7 @@ from esmf_aspect_meta_model_python.base.characteristics.characteristic import Characteristic -from ..contraints import constraint +from ..constraints import constraint class Trait(Characteristic, ABC): diff --git a/core/esmf-aspect-meta-model-python/esmf_aspect_meta_model_python/base/contraints/__init__.py b/core/esmf-aspect-meta-model-python/esmf_aspect_meta_model_python/base/constraints/__init__.py similarity index 100% rename from core/esmf-aspect-meta-model-python/esmf_aspect_meta_model_python/base/contraints/__init__.py rename to core/esmf-aspect-meta-model-python/esmf_aspect_meta_model_python/base/constraints/__init__.py diff --git a/core/esmf-aspect-meta-model-python/esmf_aspect_meta_model_python/base/contraints/constraint.py b/core/esmf-aspect-meta-model-python/esmf_aspect_meta_model_python/base/constraints/constraint.py similarity index 100% rename from core/esmf-aspect-meta-model-python/esmf_aspect_meta_model_python/base/contraints/constraint.py rename to core/esmf-aspect-meta-model-python/esmf_aspect_meta_model_python/base/constraints/constraint.py diff --git a/core/esmf-aspect-meta-model-python/esmf_aspect_meta_model_python/base/contraints/encoding_constraint.py b/core/esmf-aspect-meta-model-python/esmf_aspect_meta_model_python/base/constraints/encoding_constraint.py similarity index 89% rename from core/esmf-aspect-meta-model-python/esmf_aspect_meta_model_python/base/contraints/encoding_constraint.py rename to core/esmf-aspect-meta-model-python/esmf_aspect_meta_model_python/base/constraints/encoding_constraint.py index fb3aeb0..91762de 100644 --- a/core/esmf-aspect-meta-model-python/esmf_aspect_meta_model_python/base/contraints/encoding_constraint.py +++ b/core/esmf-aspect-meta-model-python/esmf_aspect_meta_model_python/base/constraints/encoding_constraint.py @@ -11,7 +11,7 @@ from abc import ABC, abstractmethod -from esmf_aspect_meta_model_python.base.contraints.constraint import Constraint +from esmf_aspect_meta_model_python.base.constraints.constraint import Constraint class EncodingConstraint(Constraint, ABC): diff --git a/core/esmf-aspect-meta-model-python/esmf_aspect_meta_model_python/base/contraints/fixed_point_constraint.py b/core/esmf-aspect-meta-model-python/esmf_aspect_meta_model_python/base/constraints/fixed_point_constraint.py similarity index 92% rename from core/esmf-aspect-meta-model-python/esmf_aspect_meta_model_python/base/contraints/fixed_point_constraint.py rename to core/esmf-aspect-meta-model-python/esmf_aspect_meta_model_python/base/constraints/fixed_point_constraint.py index 6afda97..4ff0d93 100644 --- a/core/esmf-aspect-meta-model-python/esmf_aspect_meta_model_python/base/contraints/fixed_point_constraint.py +++ b/core/esmf-aspect-meta-model-python/esmf_aspect_meta_model_python/base/constraints/fixed_point_constraint.py @@ -11,7 +11,7 @@ from abc import ABC, abstractmethod -from esmf_aspect_meta_model_python.base.contraints.constraint import Constraint +from esmf_aspect_meta_model_python.base.constraints.constraint import Constraint class FixedPointConstraint(Constraint, ABC): diff --git a/core/esmf-aspect-meta-model-python/esmf_aspect_meta_model_python/base/contraints/language_constraint.py b/core/esmf-aspect-meta-model-python/esmf_aspect_meta_model_python/base/constraints/language_constraint.py similarity index 90% rename from core/esmf-aspect-meta-model-python/esmf_aspect_meta_model_python/base/contraints/language_constraint.py rename to core/esmf-aspect-meta-model-python/esmf_aspect_meta_model_python/base/constraints/language_constraint.py index b77a7f5..b343ef0 100644 --- a/core/esmf-aspect-meta-model-python/esmf_aspect_meta_model_python/base/contraints/language_constraint.py +++ b/core/esmf-aspect-meta-model-python/esmf_aspect_meta_model_python/base/constraints/language_constraint.py @@ -11,7 +11,7 @@ from abc import ABC, abstractmethod -from esmf_aspect_meta_model_python.base.contraints.constraint import Constraint +from esmf_aspect_meta_model_python.base.constraints.constraint import Constraint class LanguageConstraint(Constraint, ABC): diff --git a/core/esmf-aspect-meta-model-python/esmf_aspect_meta_model_python/base/contraints/length_constraint.py b/core/esmf-aspect-meta-model-python/esmf_aspect_meta_model_python/base/constraints/length_constraint.py similarity index 92% rename from core/esmf-aspect-meta-model-python/esmf_aspect_meta_model_python/base/contraints/length_constraint.py rename to core/esmf-aspect-meta-model-python/esmf_aspect_meta_model_python/base/constraints/length_constraint.py index d22b010..02146ab 100644 --- a/core/esmf-aspect-meta-model-python/esmf_aspect_meta_model_python/base/contraints/length_constraint.py +++ b/core/esmf-aspect-meta-model-python/esmf_aspect_meta_model_python/base/constraints/length_constraint.py @@ -12,7 +12,7 @@ from abc import ABC, abstractmethod from typing import Optional -from esmf_aspect_meta_model_python.base.contraints.constraint import Constraint +from esmf_aspect_meta_model_python.base.constraints.constraint import Constraint class LengthConstraint(Constraint, ABC): diff --git a/core/esmf-aspect-meta-model-python/esmf_aspect_meta_model_python/base/contraints/locale_constraint.py b/core/esmf-aspect-meta-model-python/esmf_aspect_meta_model_python/base/constraints/locale_constraint.py similarity index 90% rename from core/esmf-aspect-meta-model-python/esmf_aspect_meta_model_python/base/contraints/locale_constraint.py rename to core/esmf-aspect-meta-model-python/esmf_aspect_meta_model_python/base/constraints/locale_constraint.py index a4caec4..15c7408 100644 --- a/core/esmf-aspect-meta-model-python/esmf_aspect_meta_model_python/base/contraints/locale_constraint.py +++ b/core/esmf-aspect-meta-model-python/esmf_aspect_meta_model_python/base/constraints/locale_constraint.py @@ -11,7 +11,7 @@ from abc import ABC, abstractmethod -from esmf_aspect_meta_model_python.base.contraints.constraint import Constraint +from esmf_aspect_meta_model_python.base.constraints.constraint import Constraint class LocaleConstraint(Constraint, ABC): diff --git a/core/esmf-aspect-meta-model-python/esmf_aspect_meta_model_python/base/contraints/range_constraint.py b/core/esmf-aspect-meta-model-python/esmf_aspect_meta_model_python/base/constraints/range_constraint.py similarity index 94% rename from core/esmf-aspect-meta-model-python/esmf_aspect_meta_model_python/base/contraints/range_constraint.py rename to core/esmf-aspect-meta-model-python/esmf_aspect_meta_model_python/base/constraints/range_constraint.py index be9f544..15fa8d1 100644 --- a/core/esmf-aspect-meta-model-python/esmf_aspect_meta_model_python/base/contraints/range_constraint.py +++ b/core/esmf-aspect-meta-model-python/esmf_aspect_meta_model_python/base/constraints/range_constraint.py @@ -13,7 +13,7 @@ from typing import Any, Optional from esmf_aspect_meta_model_python.base.bound_definition import BoundDefinition -from esmf_aspect_meta_model_python.base.contraints.constraint import Constraint +from esmf_aspect_meta_model_python.base.constraints.constraint import Constraint class RangeConstraint(Constraint, ABC): diff --git a/core/esmf-aspect-meta-model-python/esmf_aspect_meta_model_python/base/contraints/regular_expression_constraint.py b/core/esmf-aspect-meta-model-python/esmf_aspect_meta_model_python/base/constraints/regular_expression_constraint.py similarity index 90% rename from core/esmf-aspect-meta-model-python/esmf_aspect_meta_model_python/base/contraints/regular_expression_constraint.py rename to core/esmf-aspect-meta-model-python/esmf_aspect_meta_model_python/base/constraints/regular_expression_constraint.py index 6c0998a..338bde6 100644 --- a/core/esmf-aspect-meta-model-python/esmf_aspect_meta_model_python/base/contraints/regular_expression_constraint.py +++ b/core/esmf-aspect-meta-model-python/esmf_aspect_meta_model_python/base/constraints/regular_expression_constraint.py @@ -11,7 +11,7 @@ from abc import ABC, abstractmethod -from esmf_aspect_meta_model_python.base.contraints.constraint import Constraint +from esmf_aspect_meta_model_python.base.constraints.constraint import Constraint class RegularExpressionConstraint(Constraint, ABC): diff --git a/core/esmf-aspect-meta-model-python/esmf_aspect_meta_model_python/base/namespace.py b/core/esmf-aspect-meta-model-python/esmf_aspect_meta_model_python/base/namespace.py new file mode 100644 index 0000000..3516402 --- /dev/null +++ b/core/esmf-aspect-meta-model-python/esmf_aspect_meta_model_python/base/namespace.py @@ -0,0 +1,18 @@ +# Copyright (c) 2023 Robert Bosch Manufacturing Solutions GmbH +# +# See the AUTHORS file(s) distributed with this work for additional +# information regarding authorship. +# +# This Source Code Form is subject to the terms of the Mozilla Public +# License, v. 2.0. If a copy of the MPL was not distributed with this +# file, You can obtain one at https://mozilla.org/MPL/2.0/. +# +# SPDX-License-Identifier: MPL-2.0 + +from abc import ABC + +from esmf_aspect_meta_model_python.base import Base + + +class Namespace(Base, ABC): + """Namespace interface class.""" diff --git a/core/esmf-aspect-meta-model-python/esmf_aspect_meta_model_python/base/value.py b/core/esmf-aspect-meta-model-python/esmf_aspect_meta_model_python/base/value.py new file mode 100644 index 0000000..b146b07 --- /dev/null +++ b/core/esmf-aspect-meta-model-python/esmf_aspect_meta_model_python/base/value.py @@ -0,0 +1,24 @@ +# Copyright (c) 2023 Robert Bosch Manufacturing Solutions GmbH +# +# See the AUTHORS file(s) distributed with this work for additional +# information regarding authorship. +# +# This Source Code Form is subject to the terms of the Mozilla Public +# License, v. 2.0. If a copy of the MPL was not distributed with this +# file, You can obtain one at https://mozilla.org/MPL/2.0/. +# +# SPDX-License-Identifier: MPL-2.0 + +from abc import ABC, abstractmethod +from typing import Any + +from esmf_aspect_meta_model_python.base import Base + + +class Value(Base, ABC): + """Value interface class.""" + + @property + @abstractmethod + def value(self) -> Any: + """Value.""" diff --git a/core/esmf-aspect-meta-model-python/esmf_aspect_meta_model_python/impl/characteristics/default_trait.py b/core/esmf-aspect-meta-model-python/esmf_aspect_meta_model_python/impl/characteristics/default_trait.py index e3764a4..d0db536 100644 --- a/core/esmf-aspect-meta-model-python/esmf_aspect_meta_model_python/impl/characteristics/default_trait.py +++ b/core/esmf-aspect-meta-model-python/esmf_aspect_meta_model_python/impl/characteristics/default_trait.py @@ -13,7 +13,7 @@ from esmf_aspect_meta_model_python.base.characteristics.characteristic import Characteristic from esmf_aspect_meta_model_python.base.characteristics.trait import Trait -from esmf_aspect_meta_model_python.base.contraints.constraint import Constraint +from esmf_aspect_meta_model_python.base.constraints.constraint import Constraint from esmf_aspect_meta_model_python.impl.characteristics.default_characteristic import DefaultCharacteristic from esmf_aspect_meta_model_python.loader.meta_model_base_attributes import MetaModelBaseAttributes diff --git a/core/esmf-aspect-meta-model-python/esmf_aspect_meta_model_python/impl/constraints/default_constraint.py b/core/esmf-aspect-meta-model-python/esmf_aspect_meta_model_python/impl/constraints/default_constraint.py index d95cb08..40b2fec 100644 --- a/core/esmf-aspect-meta-model-python/esmf_aspect_meta_model_python/impl/constraints/default_constraint.py +++ b/core/esmf-aspect-meta-model-python/esmf_aspect_meta_model_python/impl/constraints/default_constraint.py @@ -11,7 +11,7 @@ import abc -from esmf_aspect_meta_model_python.base.contraints.constraint import Constraint +from esmf_aspect_meta_model_python.base.constraints.constraint import Constraint from esmf_aspect_meta_model_python.impl.base_impl import BaseImpl diff --git a/core/esmf-aspect-meta-model-python/esmf_aspect_meta_model_python/impl/constraints/default_encoding_constraint.py b/core/esmf-aspect-meta-model-python/esmf_aspect_meta_model_python/impl/constraints/default_encoding_constraint.py index 1d62009..b46363e 100644 --- a/core/esmf-aspect-meta-model-python/esmf_aspect_meta_model_python/impl/constraints/default_encoding_constraint.py +++ b/core/esmf-aspect-meta-model-python/esmf_aspect_meta_model_python/impl/constraints/default_encoding_constraint.py @@ -9,7 +9,7 @@ # # SPDX-License-Identifier: MPL-2.0 -from esmf_aspect_meta_model_python.base.contraints.encoding_constraint import EncodingConstraint +from esmf_aspect_meta_model_python.base.constraints.encoding_constraint import EncodingConstraint from esmf_aspect_meta_model_python.impl.constraints.default_constraint import DefaultConstraint from esmf_aspect_meta_model_python.loader.meta_model_base_attributes import MetaModelBaseAttributes diff --git a/core/esmf-aspect-meta-model-python/esmf_aspect_meta_model_python/impl/constraints/default_fixed_point_constraint.py b/core/esmf-aspect-meta-model-python/esmf_aspect_meta_model_python/impl/constraints/default_fixed_point_constraint.py index 819152c..4380ab9 100644 --- a/core/esmf-aspect-meta-model-python/esmf_aspect_meta_model_python/impl/constraints/default_fixed_point_constraint.py +++ b/core/esmf-aspect-meta-model-python/esmf_aspect_meta_model_python/impl/constraints/default_fixed_point_constraint.py @@ -9,7 +9,7 @@ # # SPDX-License-Identifier: MPL-2.0 -from esmf_aspect_meta_model_python.base.contraints.fixed_point_constraint import FixedPointConstraint +from esmf_aspect_meta_model_python.base.constraints.fixed_point_constraint import FixedPointConstraint from esmf_aspect_meta_model_python.impl.constraints.default_constraint import DefaultConstraint from esmf_aspect_meta_model_python.loader.meta_model_base_attributes import MetaModelBaseAttributes diff --git a/core/esmf-aspect-meta-model-python/esmf_aspect_meta_model_python/impl/constraints/default_language_constraint.py b/core/esmf-aspect-meta-model-python/esmf_aspect_meta_model_python/impl/constraints/default_language_constraint.py index c5da1a2..67d98d4 100644 --- a/core/esmf-aspect-meta-model-python/esmf_aspect_meta_model_python/impl/constraints/default_language_constraint.py +++ b/core/esmf-aspect-meta-model-python/esmf_aspect_meta_model_python/impl/constraints/default_language_constraint.py @@ -9,7 +9,7 @@ # # SPDX-License-Identifier: MPL-2.0 -from esmf_aspect_meta_model_python.base.contraints.language_constraint import LanguageConstraint +from esmf_aspect_meta_model_python.base.constraints.language_constraint import LanguageConstraint from esmf_aspect_meta_model_python.impl.constraints.default_constraint import DefaultConstraint from esmf_aspect_meta_model_python.loader.meta_model_base_attributes import MetaModelBaseAttributes diff --git a/core/esmf-aspect-meta-model-python/esmf_aspect_meta_model_python/impl/constraints/default_length_constraint.py b/core/esmf-aspect-meta-model-python/esmf_aspect_meta_model_python/impl/constraints/default_length_constraint.py index 488b62b..eb5b2b8 100644 --- a/core/esmf-aspect-meta-model-python/esmf_aspect_meta_model_python/impl/constraints/default_length_constraint.py +++ b/core/esmf-aspect-meta-model-python/esmf_aspect_meta_model_python/impl/constraints/default_length_constraint.py @@ -11,7 +11,7 @@ from typing import Optional -from esmf_aspect_meta_model_python.base.contraints.length_constraint import LengthConstraint +from esmf_aspect_meta_model_python.base.constraints.length_constraint import LengthConstraint from esmf_aspect_meta_model_python.impl.constraints.default_constraint import DefaultConstraint from esmf_aspect_meta_model_python.loader.meta_model_base_attributes import MetaModelBaseAttributes diff --git a/core/esmf-aspect-meta-model-python/esmf_aspect_meta_model_python/impl/constraints/default_locale_constraint.py b/core/esmf-aspect-meta-model-python/esmf_aspect_meta_model_python/impl/constraints/default_locale_constraint.py index a725a36..b5d7d83 100644 --- a/core/esmf-aspect-meta-model-python/esmf_aspect_meta_model_python/impl/constraints/default_locale_constraint.py +++ b/core/esmf-aspect-meta-model-python/esmf_aspect_meta_model_python/impl/constraints/default_locale_constraint.py @@ -9,7 +9,7 @@ # # SPDX-License-Identifier: MPL-2.0 -from esmf_aspect_meta_model_python.base.contraints.locale_constraint import LocaleConstraint +from esmf_aspect_meta_model_python.base.constraints.locale_constraint import LocaleConstraint from esmf_aspect_meta_model_python.impl.constraints.default_constraint import DefaultConstraint from esmf_aspect_meta_model_python.loader.meta_model_base_attributes import MetaModelBaseAttributes diff --git a/core/esmf-aspect-meta-model-python/esmf_aspect_meta_model_python/impl/constraints/default_range_constraint.py b/core/esmf-aspect-meta-model-python/esmf_aspect_meta_model_python/impl/constraints/default_range_constraint.py index 11226b8..39bcce6 100644 --- a/core/esmf-aspect-meta-model-python/esmf_aspect_meta_model_python/impl/constraints/default_range_constraint.py +++ b/core/esmf-aspect-meta-model-python/esmf_aspect_meta_model_python/impl/constraints/default_range_constraint.py @@ -12,7 +12,7 @@ from typing import Any, Optional from esmf_aspect_meta_model_python.base.bound_definition import BoundDefinition -from esmf_aspect_meta_model_python.base.contraints.range_constraint import RangeConstraint +from esmf_aspect_meta_model_python.base.constraints.range_constraint import RangeConstraint from esmf_aspect_meta_model_python.impl.constraints.default_constraint import DefaultConstraint from esmf_aspect_meta_model_python.loader.meta_model_base_attributes import MetaModelBaseAttributes diff --git a/core/esmf-aspect-meta-model-python/esmf_aspect_meta_model_python/impl/constraints/default_regular_expression_constraint.py b/core/esmf-aspect-meta-model-python/esmf_aspect_meta_model_python/impl/constraints/default_regular_expression_constraint.py index 2169acd..37b8278 100644 --- a/core/esmf-aspect-meta-model-python/esmf_aspect_meta_model_python/impl/constraints/default_regular_expression_constraint.py +++ b/core/esmf-aspect-meta-model-python/esmf_aspect_meta_model_python/impl/constraints/default_regular_expression_constraint.py @@ -9,7 +9,7 @@ # # SPDX-License-Identifier: MPL-2.0 -from esmf_aspect_meta_model_python.base.contraints.regular_expression_constraint import RegularExpressionConstraint +from esmf_aspect_meta_model_python.base.constraints.regular_expression_constraint import RegularExpressionConstraint from esmf_aspect_meta_model_python.impl.constraints.default_constraint import DefaultConstraint from esmf_aspect_meta_model_python.loader.meta_model_base_attributes import MetaModelBaseAttributes diff --git a/core/esmf-aspect-meta-model-python/esmf_aspect_meta_model_python/impl/default_namespace.py b/core/esmf-aspect-meta-model-python/esmf_aspect_meta_model_python/impl/default_namespace.py new file mode 100644 index 0000000..3455f92 --- /dev/null +++ b/core/esmf-aspect-meta-model-python/esmf_aspect_meta_model_python/impl/default_namespace.py @@ -0,0 +1,17 @@ +# Copyright (c) 2023 Robert Bosch Manufacturing Solutions GmbH +# +# See the AUTHORS file(s) distributed with this work for additional +# information regarding authorship. +# +# This Source Code Form is subject to the terms of the Mozilla Public +# License, v. 2.0. If a copy of the MPL was not distributed with this +# file, You can obtain one at https://mozilla.org/MPL/2.0/. +# +# SPDX-License-Identifier: MPL-2.0 + +from esmf_aspect_meta_model_python.base.namespace import Namespace +from esmf_aspect_meta_model_python.impl.base_impl import BaseImpl + + +class DefaultNamespace(BaseImpl, Namespace): + """Default namespace class.""" diff --git a/core/esmf-aspect-meta-model-python/esmf_aspect_meta_model_python/impl/default_value.py b/core/esmf-aspect-meta-model-python/esmf_aspect_meta_model_python/impl/default_value.py new file mode 100644 index 0000000..ab8ffc7 --- /dev/null +++ b/core/esmf-aspect-meta-model-python/esmf_aspect_meta_model_python/impl/default_value.py @@ -0,0 +1,35 @@ +# Copyright (c) 2023 Robert Bosch Manufacturing Solutions GmbH +# +# See the AUTHORS file(s) distributed with this work for additional +# information regarding authorship. +# +# This Source Code Form is subject to the terms of the Mozilla Public +# License, v. 2.0. If a copy of the MPL was not distributed with this +# file, You can obtain one at https://mozilla.org/MPL/2.0/. +# +# SPDX-License-Identifier: MPL-2.0 + +from typing import Any + +from esmf_aspect_meta_model_python.base.value import Value +from esmf_aspect_meta_model_python.impl.base_impl import BaseImpl +from esmf_aspect_meta_model_python.loader.meta_model_base_attributes import MetaModelBaseAttributes + + +class DefaultValue(BaseImpl, Value): + """Default value class.""" + + SCALAR_ATTR_NAMES = BaseImpl.SCALAR_ATTR_NAMES + ["value"] + + def __init__( + self, + meta_model_base_attributes: MetaModelBaseAttributes, + value: Any, + ): + super().__init__(meta_model_base_attributes) + self._value = value + + @property + def value(self) -> Any: + """Value.""" + return self._value diff --git a/core/esmf-aspect-meta-model-python/esmf_aspect_meta_model_python/loader/instantiator/encoding_constraint_instantiator.py b/core/esmf-aspect-meta-model-python/esmf_aspect_meta_model_python/loader/instantiator/encoding_constraint_instantiator.py index a948d42..e61c399 100644 --- a/core/esmf-aspect-meta-model-python/esmf_aspect_meta_model_python/loader/instantiator/encoding_constraint_instantiator.py +++ b/core/esmf-aspect-meta-model-python/esmf_aspect_meta_model_python/loader/instantiator/encoding_constraint_instantiator.py @@ -11,7 +11,7 @@ from rdflib.term import Node -from esmf_aspect_meta_model_python.base.contraints.encoding_constraint import EncodingConstraint +from esmf_aspect_meta_model_python.base.constraints.encoding_constraint import EncodingConstraint from esmf_aspect_meta_model_python.impl.constraints.default_encoding_constraint import DefaultEncodingConstraint from esmf_aspect_meta_model_python.loader.instantiator_base import InstantiatorBase from esmf_aspect_meta_model_python.loader.rdf_helper import RdfHelper diff --git a/core/esmf-aspect-meta-model-python/esmf_aspect_meta_model_python/loader/instantiator/enumeration_instantiator.py b/core/esmf-aspect-meta-model-python/esmf_aspect_meta_model_python/loader/instantiator/enumeration_instantiator.py index e9a283d..bc6576a 100644 --- a/core/esmf-aspect-meta-model-python/esmf_aspect_meta_model_python/loader/instantiator/enumeration_instantiator.py +++ b/core/esmf-aspect-meta-model-python/esmf_aspect_meta_model_python/loader/instantiator/enumeration_instantiator.py @@ -9,7 +9,7 @@ # # SPDX-License-Identifier: MPL-2.0 -import typing +from typing import Any, Dict, List, Optional, Union import rdflib # type: ignore @@ -40,7 +40,7 @@ def _create_instance(self, element_node: Node) -> Enumeration: return DefaultEnumeration(meta_model_base_attributes, data_type, values) - def __to_enum_node_value(self, value_node: Node) -> typing.Dict: + def __to_enum_node_value(self, value_node: Node) -> Union[Dict, str]: """ This method instantiates one possible value of an enumeration. :param value_node: Node of the Graph that represents one enumeration value. @@ -49,38 +49,46 @@ def __to_enum_node_value(self, value_node: Node) -> typing.Dict: - If value_node is a URIRef it will represent a value of a ComplexType :return: the one generated value of the enumeration """ - value = {} + str_value: str = "" + dict_value: Dict = {} - if isinstance(value_node, rdflib.Literal): + if isinstance(value_node, rdflib.Literal) or ( + isinstance(value_node, rdflib.URIRef) and value_node.find("#") == -1 + ): # value represents a simple data type - value = value_node.toPython() + str_value = value_node.toPython() - elif isinstance(value_node, rdflib.URIRef): + elif isinstance(value_node, rdflib.URIRef) or isinstance(value_node, rdflib.term.BNode): # value represents a complex data type - value_node_properties = self._aspect_graph.predicate_objects(value_node) - for property_urn, property_value in value_node_properties: + dict_value = {} + + for property_urn, property_value in self._aspect_graph.predicate_objects(value_node): if property_urn != rdflib.RDF.type and isinstance(property_urn, str): property_name = property_urn.split("#")[1] - actual_value: typing.Optional[typing.Any] + + actual_value: Optional[Any] if self.__is_collection_value(property_urn): actual_value = self.__instantiate_enum_collection(property_value) else: actual_value = self.__to_enum_node_value(property_value) - value[property_name] = actual_value + + if property_name == "see": + dict_value.setdefault(property_name, []).append(actual_value) + else: + dict_value[property_name] = actual_value value_node_name = value_node.split("#")[1] value_key = self._samm.get_urn(SAMM.name).toPython() - value[value_key] = value_node_name # type: ignore + dict_value[value_key] = value_node_name # type: ignore - else: - if not isinstance(value_node, rdflib.term.BNode) or value_node == rdflib.namespace.RDF.nil: - # illegal node type for enumeration value (e.g., Blank Node) - raise TypeError( - f"Every value of an enumeration must either be a Literal (string, int, etc.) or " - f"a URI reference to a ComplexType. Values of type {type(value_node).__name__} are not allowed" - ) + elif value_node == rdflib.namespace.RDF.nil: + # illegal node type for enumeration value (e.g., Blank Node) + raise TypeError( + f"Every value of an enumeration must either be a Literal (string, int, etc.) or " + f"a URI reference to a ComplexType. Values of type {type(value_node).__name__} are not allowed" + ) - return value + return str_value or dict_value def __is_collection_value(self, property_subject: str) -> bool: characteristic = self._aspect_graph.value( # type: ignore @@ -88,13 +96,15 @@ def __is_collection_value(self, property_subject: str) -> bool: predicate=self._samm.get_urn(SAMM.characteristic), ) characteristic_type = self._aspect_graph.value(subject=characteristic, predicate=rdflib.RDF.type) + return characteristic_type in self._sammc.collections_urns() - def __instantiate_enum_collection(self, value_list) -> typing.List[typing.Dict]: + def __instantiate_enum_collection(self, value_list) -> List[Union[Dict, str]]: """creates a collection as a child for enumeration characteristics""" value_node_list = RdfHelper.get_rdf_list_values(value_list, self._aspect_graph) values = [] for value_node in value_node_list: value = self.__to_enum_node_value(value_node) values.append(value) + return values diff --git a/core/esmf-aspect-meta-model-python/esmf_aspect_meta_model_python/loader/instantiator/fixed_point_constraint_instantiator.py b/core/esmf-aspect-meta-model-python/esmf_aspect_meta_model_python/loader/instantiator/fixed_point_constraint_instantiator.py index 749aa45..37b58d4 100644 --- a/core/esmf-aspect-meta-model-python/esmf_aspect_meta_model_python/loader/instantiator/fixed_point_constraint_instantiator.py +++ b/core/esmf-aspect-meta-model-python/esmf_aspect_meta_model_python/loader/instantiator/fixed_point_constraint_instantiator.py @@ -11,7 +11,7 @@ from rdflib.term import Node -from esmf_aspect_meta_model_python.base.contraints.fixed_point_constraint import FixedPointConstraint +from esmf_aspect_meta_model_python.base.constraints.fixed_point_constraint import FixedPointConstraint from esmf_aspect_meta_model_python.impl.constraints.default_fixed_point_constraint import DefaultFixedPointConstraint from esmf_aspect_meta_model_python.loader.instantiator_base import InstantiatorBase from esmf_aspect_meta_model_python.loader.rdf_helper import RdfHelper diff --git a/core/esmf-aspect-meta-model-python/esmf_aspect_meta_model_python/loader/instantiator/language_constraint_instantiator.py b/core/esmf-aspect-meta-model-python/esmf_aspect_meta_model_python/loader/instantiator/language_constraint_instantiator.py index b1f075b..ebcb7a2 100644 --- a/core/esmf-aspect-meta-model-python/esmf_aspect_meta_model_python/loader/instantiator/language_constraint_instantiator.py +++ b/core/esmf-aspect-meta-model-python/esmf_aspect_meta_model_python/loader/instantiator/language_constraint_instantiator.py @@ -11,7 +11,7 @@ from rdflib.term import Node -from esmf_aspect_meta_model_python.base.contraints.language_constraint import LanguageConstraint +from esmf_aspect_meta_model_python.base.constraints.language_constraint import LanguageConstraint from esmf_aspect_meta_model_python.impl.constraints.default_language_constraint import DefaultLanguageConstraint from esmf_aspect_meta_model_python.loader.instantiator_base import InstantiatorBase from esmf_aspect_meta_model_python.loader.rdf_helper import RdfHelper diff --git a/core/esmf-aspect-meta-model-python/esmf_aspect_meta_model_python/loader/instantiator/length_constraint_instantiator.py b/core/esmf-aspect-meta-model-python/esmf_aspect_meta_model_python/loader/instantiator/length_constraint_instantiator.py index 436cd32..4164a8a 100644 --- a/core/esmf-aspect-meta-model-python/esmf_aspect_meta_model_python/loader/instantiator/length_constraint_instantiator.py +++ b/core/esmf-aspect-meta-model-python/esmf_aspect_meta_model_python/loader/instantiator/length_constraint_instantiator.py @@ -11,7 +11,7 @@ from rdflib.term import Node -from esmf_aspect_meta_model_python.base.contraints.length_constraint import LengthConstraint +from esmf_aspect_meta_model_python.base.constraints.length_constraint import LengthConstraint from esmf_aspect_meta_model_python.impl.constraints.default_length_constraint import DefaultLengthConstraint from esmf_aspect_meta_model_python.loader.instantiator_base import InstantiatorBase from esmf_aspect_meta_model_python.loader.rdf_helper import RdfHelper diff --git a/core/esmf-aspect-meta-model-python/esmf_aspect_meta_model_python/loader/instantiator/locale_constraint_instantiator.py b/core/esmf-aspect-meta-model-python/esmf_aspect_meta_model_python/loader/instantiator/locale_constraint_instantiator.py index 5e775ad..b0906e3 100644 --- a/core/esmf-aspect-meta-model-python/esmf_aspect_meta_model_python/loader/instantiator/locale_constraint_instantiator.py +++ b/core/esmf-aspect-meta-model-python/esmf_aspect_meta_model_python/loader/instantiator/locale_constraint_instantiator.py @@ -11,7 +11,7 @@ from rdflib.term import Node -from esmf_aspect_meta_model_python.base.contraints.locale_constraint import LocaleConstraint +from esmf_aspect_meta_model_python.base.constraints.locale_constraint import LocaleConstraint from esmf_aspect_meta_model_python.impl.constraints.default_locale_constraint import DefaultLocaleConstraint from esmf_aspect_meta_model_python.loader.instantiator_base import InstantiatorBase from esmf_aspect_meta_model_python.loader.rdf_helper import RdfHelper diff --git a/core/esmf-aspect-meta-model-python/esmf_aspect_meta_model_python/loader/instantiator/namespace_instantiator.py b/core/esmf-aspect-meta-model-python/esmf_aspect_meta_model_python/loader/instantiator/namespace_instantiator.py new file mode 100644 index 0000000..52867d9 --- /dev/null +++ b/core/esmf-aspect-meta-model-python/esmf_aspect_meta_model_python/loader/instantiator/namespace_instantiator.py @@ -0,0 +1,23 @@ +# Copyright (c) 2023 Robert Bosch Manufacturing Solutions GmbH +# +# See the AUTHORS file(s) distributed with this work for additional +# information regarding authorship. +# +# This Source Code Form is subject to the terms of the Mozilla Public +# License, v. 2.0. If a copy of the MPL was not distributed with this +# file, You can obtain one at https://mozilla.org/MPL/2.0/. +# +# SPDX-License-Identifier: MPL-2.0 + +from rdflib.term import Node + +from esmf_aspect_meta_model_python.base.namespace import Namespace +from esmf_aspect_meta_model_python.impl.default_namespace import DefaultNamespace +from esmf_aspect_meta_model_python.loader.instantiator_base import InstantiatorBase + + +class NamespaceInstantiator(InstantiatorBase[Namespace]): + def _create_instance(self, element_node: Node) -> Namespace: + meta_model_base_attributes = self._get_base_attributes(element_node) + + return DefaultNamespace(meta_model_base_attributes) diff --git a/core/esmf-aspect-meta-model-python/esmf_aspect_meta_model_python/loader/instantiator/range_constraint_instantiator.py b/core/esmf-aspect-meta-model-python/esmf_aspect_meta_model_python/loader/instantiator/range_constraint_instantiator.py index 2c7aada..2d9d469 100644 --- a/core/esmf-aspect-meta-model-python/esmf_aspect_meta_model_python/loader/instantiator/range_constraint_instantiator.py +++ b/core/esmf-aspect-meta-model-python/esmf_aspect_meta_model_python/loader/instantiator/range_constraint_instantiator.py @@ -13,7 +13,7 @@ from rdflib.term import Node from esmf_aspect_meta_model_python.base.bound_definition import BoundDefinition -from esmf_aspect_meta_model_python.base.contraints.range_constraint import RangeConstraint +from esmf_aspect_meta_model_python.base.constraints.range_constraint import RangeConstraint from esmf_aspect_meta_model_python.impl.constraints.default_range_constraint import DefaultRangeConstraint from esmf_aspect_meta_model_python.loader.instantiator_base import InstantiatorBase from esmf_aspect_meta_model_python.vocabulary.sammc import SAMMC diff --git a/core/esmf-aspect-meta-model-python/esmf_aspect_meta_model_python/loader/instantiator/regular_expression_constraint_instantiator.py b/core/esmf-aspect-meta-model-python/esmf_aspect_meta_model_python/loader/instantiator/regular_expression_constraint_instantiator.py index 4705bb0..c58a676 100644 --- a/core/esmf-aspect-meta-model-python/esmf_aspect_meta_model_python/loader/instantiator/regular_expression_constraint_instantiator.py +++ b/core/esmf-aspect-meta-model-python/esmf_aspect_meta_model_python/loader/instantiator/regular_expression_constraint_instantiator.py @@ -11,7 +11,7 @@ from rdflib.term import Node -from esmf_aspect_meta_model_python.base.contraints.regular_expression_constraint import RegularExpressionConstraint +from esmf_aspect_meta_model_python.base.constraints.regular_expression_constraint import RegularExpressionConstraint from esmf_aspect_meta_model_python.impl.constraints.default_regular_expression_constraint import ( DefaultRegularExpressionConstraint, ) diff --git a/core/esmf-aspect-meta-model-python/esmf_aspect_meta_model_python/loader/instantiator/trait_instantiator.py b/core/esmf-aspect-meta-model-python/esmf_aspect_meta_model_python/loader/instantiator/trait_instantiator.py index 15024cd..9eea549 100644 --- a/core/esmf-aspect-meta-model-python/esmf_aspect_meta_model_python/loader/instantiator/trait_instantiator.py +++ b/core/esmf-aspect-meta-model-python/esmf_aspect_meta_model_python/loader/instantiator/trait_instantiator.py @@ -14,7 +14,7 @@ from rdflib.term import Node from esmf_aspect_meta_model_python.base.characteristics.trait import Trait -from esmf_aspect_meta_model_python.base.contraints.constraint import Constraint +from esmf_aspect_meta_model_python.base.constraints.constraint import Constraint from esmf_aspect_meta_model_python.impl.characteristics.default_trait import DefaultTrait from esmf_aspect_meta_model_python.loader.instantiator_base import InstantiatorBase from esmf_aspect_meta_model_python.vocabulary.sammc import SAMMC diff --git a/core/esmf-aspect-meta-model-python/esmf_aspect_meta_model_python/loader/instantiator/value_instantiator.py b/core/esmf-aspect-meta-model-python/esmf_aspect_meta_model_python/loader/instantiator/value_instantiator.py new file mode 100644 index 0000000..92dcf5a --- /dev/null +++ b/core/esmf-aspect-meta-model-python/esmf_aspect_meta_model_python/loader/instantiator/value_instantiator.py @@ -0,0 +1,27 @@ +# Copyright (c) 2023 Robert Bosch Manufacturing Solutions GmbH +# +# See the AUTHORS file(s) distributed with this work for additional +# information regarding authorship. +# +# This Source Code Form is subject to the terms of the Mozilla Public +# License, v. 2.0. If a copy of the MPL was not distributed with this +# file, You can obtain one at https://mozilla.org/MPL/2.0/. +# +# SPDX-License-Identifier: MPL-2.0 + +from typing import Any + +from rdflib.term import Node + +from esmf_aspect_meta_model_python.base.value import Value +from esmf_aspect_meta_model_python.impl.default_value import DefaultValue +from esmf_aspect_meta_model_python.loader.instantiator_base import InstantiatorBase +from esmf_aspect_meta_model_python.vocabulary.samm import SAMM + + +class ValueInstantiator(InstantiatorBase[Value]): + def _create_instance(self, element_node: Node) -> Value: + meta_model_base_attributes = self._get_base_attributes(element_node) + value: Any = self._aspect_graph.value(subject=element_node, predicate=self._samm.get_urn(SAMM.value)) + + return DefaultValue(meta_model_base_attributes, value) diff --git a/core/esmf-aspect-meta-model-python/esmf_aspect_meta_model_python/loader/samm_graph.py b/core/esmf-aspect-meta-model-python/esmf_aspect_meta_model_python/loader/samm_graph.py index 3020bf2..546f2a9 100644 --- a/core/esmf-aspect-meta-model-python/esmf_aspect_meta_model_python/loader/samm_graph.py +++ b/core/esmf-aspect-meta-model-python/esmf_aspect_meta_model_python/loader/samm_graph.py @@ -219,6 +219,13 @@ def load_aspect_model(self) -> Aspect: return self.aspect + def _get_aspect_from_elements(self): + """Geta and save the Aspect element from the model elements.""" + if self.model_elements: + for element in self.model_elements: + if isinstance(element, Aspect): + self.aspect = element + def load_model_elements(self) -> list[BaseImpl]: """Creates a python object(s) to represent the Aspect model graph.""" if self.model_elements is None: @@ -228,6 +235,7 @@ def load_model_elements(self) -> list[BaseImpl]: model_element_factory = ModelElementFactory(self.samm_version, graph, self._cache) self.model_elements = model_element_factory.create_all_graph_elements(model_elements) + self._get_aspect_from_elements() return self.model_elements diff --git a/core/esmf-aspect-meta-model-python/esmf_aspect_meta_model_python/samm_meta_model.py b/core/esmf-aspect-meta-model-python/esmf_aspect_meta_model_python/samm_meta_model.py index e5ab333..9b68599 100644 --- a/core/esmf-aspect-meta-model-python/esmf_aspect_meta_model_python/samm_meta_model.py +++ b/core/esmf-aspect-meta-model-python/esmf_aspect_meta_model_python/samm_meta_model.py @@ -20,7 +20,7 @@ class SammUnitsGraph: """Model units graph.""" - SAMM_VERSION = "2.1.0" + SAMM_VERSION = "2.2.0" UNIT_FILE_PATH = f"samm_aspect_meta_model/samm/unit/{SAMM_VERSION}/units.ttl" QUERY_TEMPLATE = Template("SELECT ?key ?value WHERE {$unit ?key ?value .}") diff --git a/core/esmf-aspect-meta-model-python/esmf_aspect_meta_model_python/vocabulary/constants.py b/core/esmf-aspect-meta-model-python/esmf_aspect_meta_model_python/vocabulary/constants.py index b7cb284..dca16de 100644 --- a/core/esmf-aspect-meta-model-python/esmf_aspect_meta_model_python/vocabulary/constants.py +++ b/core/esmf-aspect-meta-model-python/esmf_aspect_meta_model_python/vocabulary/constants.py @@ -25,6 +25,7 @@ class MetaModelElements: Measurement = "Measurement" MimeType = "MimeType" MultiLanguageText = "MultiLanguageText" + Namespace = "Namespace" Operation = "Operation" Point3d = "Point3d" Property = "Property" @@ -45,6 +46,7 @@ class MetaModelElements: Trait = "Trait" Unit = "Unit" UnitReference = "UnitReference" + Value = "Value" meta_model_elements = ( AbstractEntity, @@ -53,12 +55,14 @@ class MetaModelElements: Constraint, Entity, Event, + Namespace, Operation, Property, Quantifiable, QuantityKind, Trait, Unit, + Value, ) diff --git a/core/esmf-aspect-meta-model-python/pyproject.toml b/core/esmf-aspect-meta-model-python/pyproject.toml index da359d8..cf4c602 100644 --- a/core/esmf-aspect-meta-model-python/pyproject.toml +++ b/core/esmf-aspect-meta-model-python/pyproject.toml @@ -1,6 +1,6 @@ [tool.poetry] name = "esmf-aspect-model-loader" -version = "2.1.5" +version = "2.2.0" description = "Load Aspect Models based on the Semantic Aspect Meta Model" authors = [ "Eclipse Semantic Modeling Framework", @@ -32,7 +32,7 @@ tox = "^4.5.2" zipfile37 = "^0.1.3" rdflib = "^7.1.3" -[tool.poetry.dev-dependencies] +[tool.poetry.group.dev.dependencies] black = "^23.3.0" coverage = "^7.2.5" flake8 = "^6.0.0" @@ -43,7 +43,6 @@ pytest-cov = "^4.0.0" pytest-sugar = "^0.9.7" types-requests = "^2.30.0.0" - [tool.pytest.ini_options] cache_dir = ".pytest_cache" diff --git a/core/esmf-aspect-meta-model-python/scripts/constants.py b/core/esmf-aspect-meta-model-python/scripts/constants.py index 7039582..a722cc6 100644 --- a/core/esmf-aspect-meta-model-python/scripts/constants.py +++ b/core/esmf-aspect-meta-model-python/scripts/constants.py @@ -13,8 +13,8 @@ from string import Template -SAMM_VERSION = "2.1.0" -JAVA_CLI_VERSION = "2.7.0" +SAMM_VERSION = "2.2.0" +JAVA_CLI_VERSION = "2.10.2" class SAMMCliConstants: @@ -27,6 +27,7 @@ class SAMMCliConstants: class TestModelConstants: FOLDER_TO_EXTRACT = "valid" + TEST_MODELS_FOLDER = "org.eclipse.esmf.test" JAVA_CLI_VERSION = JAVA_CLI_VERSION MAVEN_URL = Template( "https://repo1.maven.org/maven2/org/eclipse/esmf/esmf-test-aspect-models/$version_number/" diff --git a/core/esmf-aspect-meta-model-python/scripts/download_samm_cli.py b/core/esmf-aspect-meta-model-python/scripts/download_samm_cli.py index 033e4e5..0be4ed2 100644 --- a/core/esmf-aspect-meta-model-python/scripts/download_samm_cli.py +++ b/core/esmf-aspect-meta-model-python/scripts/download_samm_cli.py @@ -19,9 +19,9 @@ def get_samm_cli_file_name(): """Get a SAMM CLI file name for the current platform.""" if platform.system() == "Windows": - file_name = Const.WIN_FILE_NAME.substitute(version_number=Const.VERSION) + file_name = Const.WIN_FILE_NAME.substitute(version_number=Const.JAVA_CLI_VERSION) elif platform.system() == "Linux": - file_name = Const.LINUX_FILE_NAME.substitute(version_number=Const.VERSION) + file_name = Const.LINUX_FILE_NAME.substitute(version_number=Const.JAVA_CLI_VERSION) else: raise NotImplementedError( f"Please download a SAMM CLI manually for your operation system from '{Const.BASE_PATH}'" @@ -62,7 +62,7 @@ def download_samm_cli(): print(error) else: print(f"Start downloading SAMM CLI {samm_cli_file_name}") - url = Const.BASE_PATH.substitute(version_number=Const.VERSION, file_name=samm_cli_file_name) + url = Const.BASE_PATH.substitute(version_number=Const.JAVA_CLI_VERSION, file_name=samm_cli_file_name) dir_path = Path(__file__).resolve().parents[1] archive_file = os.path.join(dir_path, samm_cli_file_name) diff --git a/core/esmf-aspect-meta-model-python/scripts/samm/download_samm_release.py b/core/esmf-aspect-meta-model-python/scripts/samm/download_samm_release.py index 155a475..2f85cbc 100644 --- a/core/esmf-aspect-meta-model-python/scripts/samm/download_samm_release.py +++ b/core/esmf-aspect-meta-model-python/scripts/samm/download_samm_release.py @@ -15,7 +15,7 @@ import requests -SAMM_VERSION_TO_DOWNLOAD = "2.1.0" +SAMM_VERSION_TO_DOWNLOAD = "2.2.0" def main(): diff --git a/core/esmf-aspect-meta-model-python/tests/integration/java_models/test_loading_aspects.py b/core/esmf-aspect-meta-model-python/tests/integration/java_models/test_loading_aspects.py index 5b7d417..c5ddd3c 100644 --- a/core/esmf-aspect-meta-model-python/tests/integration/java_models/test_loading_aspects.py +++ b/core/esmf-aspect-meta-model-python/tests/integration/java_models/test_loading_aspects.py @@ -1,6 +1,7 @@ """Collect statistics about loading test Aspect models.""" -import csv +import os +import shutil from glob import glob from os import listdir @@ -11,6 +12,9 @@ from scripts.constants import TestModelConstants from scripts.download_test_models import download_test_models +# before start tests, download latest aspect test models with the next command +# poetry run download-test-models + def get_resources_folder_path() -> str: """Get a path for storing test models.""" @@ -20,142 +24,154 @@ def get_resources_folder_path() -> str: return models_path -def check_resources_folder(test_models_exists: bool = False): +def check_resources_folder(): """Remove all files to clear test models directory.""" resources_folder = get_resources_folder_path() - if not exists(resources_folder) or len(listdir(resources_folder)) == 0 or not test_models_exists: + if not exists(resources_folder) or len(listdir(resources_folder)) == 0: download_test_models() def get_test_files(): """Get ttl models for testing.""" resources_folder = get_resources_folder_path() - samm_folder_name = f"samm_{TestModelConstants.SAMM_VERSION.replace('.', '_')}" - search_pattern = join(resources_folder, "**", samm_folder_name, "**", "*.ttl") + search_pattern = join( + resources_folder, + TestModelConstants.FOLDER_TO_EXTRACT, + TestModelConstants.TEST_MODELS_FOLDER, + "**", + "*.ttl", + ) test_model_files = glob(search_pattern, recursive=True) return test_model_files -def load_aspect_test_models(): - """Test for loading Aspect models.""" +def get_aspect_test_models(): + """Get files with aspect test models.""" test_files = get_test_files() if not test_files: check_resources_folder() test_files = get_test_files() - result = [] - all_test_files = len(test_files) - i = 0 - step = 10 - print("Loading test Aspect models...") - - for test_file in test_files: - i += 1 - if i % step == 0: - print(f"{i}/{all_test_files}") - - test_file_path = Path(test_file) - data = { - "file_name": test_file_path.name, - "folder_name": join(test_file_path.parents[1].name, test_file_path.parents[0].name), - "status": "initializing", - "error": None, - } + return test_files + + +def get_terminal_width(): + columns, _ = shutil.get_terminal_size(fallback=(120, 20)) + return columns + + +def check_load_aspect_model(test_models): + total_models = len(test_models) + report = {"passed": 0, "failed": 0, "errors": []} + terminal_width = get_terminal_width() + message = " SAMMGraph.load_aspect_model " + fill_num = round((terminal_width - len(message)) / 2) + print("=" * fill_num, message, "=" * (terminal_width - len(message) - fill_num), "\n", sep="") + + for i, model_path in enumerate(test_models): + model_name = os.path.splitext(os.path.basename(model_path))[0] + + if model_name.lower().startswith("aspect"): + try: + samm_graph = SAMMGraph() + samm_graph.parse(model_path) + aspect = samm_graph.load_aspect_model() + + assert aspect + assert samm_graph.aspect + except Exception as error: + status = "\033[91mFAILED\033[0m" + report["failed"] += 1 + report["errors"].append( + { + "model_name": model_name, + "error": error, + } + ) + else: + status = "\033[92mSUCCESS\033[0m" + report["passed"] += 1 + + output_line = f"{model_name}: {status}" + percentage = (i + 1) / total_models * 100 + right_data = f"[{percentage:6.2f}% ]" + total_length = len(output_line) + len(right_data) + spaces = terminal_width - total_length + if spaces > 0: + print(f"{output_line}{' ' * spaces}{right_data}") + else: + print(f"{output_line} {right_data}") + + print(f"\nResults:\n\033[92m{report['passed']:7.0f} passed\033[0m\n\033[91m{report['failed']:7.0f} failed\033[0m") + for record in report["errors"]: + print(f"{record['model_name']}: FAILED", {record["error"]}) + + assert report["failed"] == 0, "Some models failed to load aspect model" + + +def check_load_model_elements(test_models): + total_models = len(test_models) + report = {"passed": 0, "failed": 0, "errors": []} + terminal_width = get_terminal_width() + message = " SAMMGraph.load_model_elements " + fill_num = round((terminal_width - len(message)) / 2) + print("=" * fill_num, message, "=" * (terminal_width - len(message) - fill_num), "\n", sep="") + + for i, model_path in enumerate(test_models): + model_name = os.path.splitext(os.path.basename(model_path))[0] try: samm_graph = SAMMGraph() - samm_graph.parse(test_file_path) - aspect = samm_graph.load_aspect_model() - if not aspect: - raise Exception("Aspect has not been loaded") - except Exception as error: - data["error"] = str(error) - data["status"] = "exception" - else: - data["status"] = "success" - - result.append(data) - - print(f"{i}/{all_test_files}") - - return result - - -def run_aspect_load_test(): - """Run loading of all test Aspect models.""" - report = load_aspect_test_models() - - base_path = Path(__file__).parent.absolute() - with open(join(base_path, "test_java_models_aspect_load_report.csv"), "w", newline="") as csvfile: - fieldnames = ["folder_name", "file_name", "status", "error"] - writer = csv.DictWriter(csvfile, fieldnames=fieldnames) - - writer.writeheader() - for row in report: - writer.writerow(row) - - -def load_model_elements_test_models(): - """Test for loading Aspect models.""" - test_files = get_test_files() - if not test_files: - check_resources_folder() - test_files = get_test_files() - - result = [] - all_test_files = len(test_files) - i = 0 - step = 10 - print("Loading test Aspect models...") - - for test_file in test_files: - i += 1 - if i % step == 0: - print(f"{i}/{all_test_files}") - - test_file_path = Path(test_file) - data = { - "file_name": test_file_path.name, - "folder_name": join(test_file_path.parents[1].name, test_file_path.parents[0].name), - "status": "initializing", - "error": None, - } - - try: - samm_graph = SAMMGraph() - samm_graph.parse(test_file_path) + samm_graph.parse(model_path) elements = samm_graph.load_model_elements() - if not elements: - raise Exception("Aspect model elements has not been loaded") + + assert elements + assert samm_graph.model_elements + if model_name.lower().startswith("aspect"): + assert samm_graph.aspect except Exception as error: - data["error"] = str(error) - data["status"] = "exception" + status = "\033[91mFAILED\033[0m" + report["failed"] += 1 + report["errors"].append( + { + "model_name": model_name, + "error": error, + } + ) else: - data["status"] = "success" - - result.append(data) + status = "\033[92mSUCCESS\033[0m" + report["passed"] += 1 + + output_line = f"{model_name}: {status}" + percentage = (i + 1) / total_models * 100 + right_data = f"[{percentage:6.2f}% ]" + total_length = len(output_line) + len(right_data) + spaces = terminal_width - total_length + if spaces > 0: + print(f"{output_line}{' ' * spaces}{right_data}") + else: + print(f"{output_line} {right_data}") - print(f"{i}/{all_test_files}") + print(f"\nResults:\n\033[92m{report['passed']:7.0f} passed\033[0m\n\033[91m{report['failed']:7.0f} failed\033[0m") + for record in report["errors"]: + print(f"{record['model_name']}: FAILED", {record["error"]}) - return result + assert report["failed"] == 0, "Some models failed to load model elements" -def run_model_elements_load_test(): - """Run loading of all test Aspect models.""" - report = load_model_elements_test_models() +def test_load_aspect_model(): + test_models = get_aspect_test_models() + assert test_models - base_path = Path(__file__).parent.absolute() - with open(join(base_path, "test_java_models_elements_load_report.csv"), "w", newline="") as csvfile: - fieldnames = ["folder_name", "file_name", "status", "error"] - writer = csv.DictWriter(csvfile, fieldnames=fieldnames) + print("\nSubtests for checking aspect loading") + check_load_aspect_model(test_models) - writer.writeheader() - for row in report: - writer.writerow(row) +def test_load_model_elements(): + test_models = get_aspect_test_models() + assert test_models -def test_loading_aspects(): - run_aspect_load_test() - run_model_elements_load_test() + print("\nSubtests for checking model element loading") + check_load_model_elements(test_models) diff --git a/core/esmf-aspect-meta-model-python/tests/unit/loader/instantiators/test_enumeration_instantiator.py b/core/esmf-aspect-meta-model-python/tests/unit/loader/instantiators/test_enumeration_instantiator.py index 041618d..311f3bf 100644 --- a/core/esmf-aspect-meta-model-python/tests/unit/loader/instantiators/test_enumeration_instantiator.py +++ b/core/esmf-aspect-meta-model-python/tests/unit/loader/instantiators/test_enumeration_instantiator.py @@ -62,9 +62,21 @@ def test_to_enum_node_value_node_is_literal(self, isinstance_mock): assert result == "node_value" value_node_mock.toPython.assert_called_once() + @mock.patch("esmf_aspect_meta_model_python.loader.instantiator.enumeration_instantiator.isinstance") + def test_to_enum_node_value_node_is_ref(self, isinstance_mock): + isinstance_mock.side_effect = (False, True) + base_class_mock = mock.MagicMock(name="EnumerationInstantiator_class") + value_node_mock = mock.MagicMock(name="value_node") + value_node_mock.find.return_value = -1 + value_node_mock.toPython.return_value = "node_value" + result = EnumerationInstantiator._EnumerationInstantiator__to_enum_node_value(base_class_mock, value_node_mock) + + assert result == "node_value" + value_node_mock.toPython.assert_called_once() + @mock.patch("esmf_aspect_meta_model_python.loader.instantiator.enumeration_instantiator.isinstance") def test_to_enum_node_value_node_is_URIRef_collection_value(self, isinstance_mock): - isinstance_mock.side_effect = (False, True, True) + isinstance_mock.side_effect = (False, True, True, True) base_class_mock = mock.MagicMock(name="EnumerationInstantiator_class") base_class_mock._EnumerationInstantiator__is_collection_value.return_value = True base_class_mock._EnumerationInstantiator__instantiate_enum_collection.return_value = "actual_value" @@ -99,8 +111,51 @@ def test_to_enum_node_value_node_is_URIRef_collection_value(self, isinstance_moc value_mock.toPython.assert_called_once() @mock.patch("esmf_aspect_meta_model_python.loader.instantiator.enumeration_instantiator.isinstance") - def test_to_enum_node_value_node_is_URIRef_not_collection_value(self, isinstance_mock): - isinstance_mock.side_effect = (False, True, True) + def test_to_enum_node_value_with_see_property(self, isinstance_mock): + isinstance_mock.side_effect = (False, True, True, True, True) + base_class_mock = mock.MagicMock(name="EnumerationInstantiator_class") + base_class_mock._EnumerationInstantiator__is_collection_value.side_effect = (False, False) + base_class_mock._EnumerationInstantiator__to_enum_node_value.side_effect = ("actual_value_1", "actual_value_2") + aspect_graph_mock = mock.MagicMock(name="aspect_graph") + aspect_graph_mock.predicate_objects.return_value = [ + ("property_urn#see", "property_value_1"), + ("property_urn#see", "property_value_2"), + ] + base_class_mock._aspect_graph = aspect_graph_mock + samm_mock = mock.MagicMock(name="SAMM") + value_mock = mock.MagicMock(name="value") + value_mock.toPython.return_value = "value_key" + samm_mock.get_urn.return_value = value_mock + base_class_mock._samm = samm_mock + result = EnumerationInstantiator._EnumerationInstantiator__to_enum_node_value( + base_class_mock, + "value_node#value_node_name", + ) + + assert len(result) == 2 + assert "see" in result + assert sorted(result["see"]) == ["actual_value_1", "actual_value_2"] + assert "value_key" in result + assert result["value_key"] == "value_node_name" + aspect_graph_mock.predicate_objects.assert_called_once_with("value_node#value_node_name") + base_class_mock._EnumerationInstantiator__is_collection_value.assert_has_calls( + [ + mock.call("property_urn#see"), + mock.call("property_urn#see"), + ] + ) + base_class_mock._EnumerationInstantiator__to_enum_node_value.assert_has_calls( + [ + mock.call("property_value_1"), + mock.call("property_value_2"), + ] + ) + samm_mock.get_urn.assert_called_once_with(SAMM.name) + value_mock.toPython.assert_called_once() + + @mock.patch("esmf_aspect_meta_model_python.loader.instantiator.enumeration_instantiator.isinstance") + def test_to_enum_node_value_node_is_BNode(self, isinstance_mock): + isinstance_mock.side_effect = (False, False, True, True, True) base_class_mock = mock.MagicMock(name="EnumerationInstantiator_class") base_class_mock._EnumerationInstantiator__is_collection_value.return_value = False base_class_mock._EnumerationInstantiator__to_enum_node_value.return_value = "actual_value" @@ -136,14 +191,17 @@ def test_to_enum_node_value_node_is_URIRef_not_collection_value(self, isinstance @mock.patch("esmf_aspect_meta_model_python.loader.instantiator.enumeration_instantiator.isinstance") def test_to_enum_node_value_node_is_URIRef_raise_exception(self, isinstance_mock): - isinstance_mock.side_effect = (False, False, False) + isinstance_mock.side_effect = (False, False, False, False) base_class_mock = mock.MagicMock(name="EnumerationInstantiator_class") with pytest.raises(TypeError) as error: - EnumerationInstantiator._EnumerationInstantiator__to_enum_node_value(base_class_mock, "value_node") + EnumerationInstantiator._EnumerationInstantiator__to_enum_node_value( + base_class_mock, + rdflib.namespace.RDF.nil, + ) assert str(error.value) == ( "Every value of an enumeration must either be a Literal (string, int, etc.) or " - "a URI reference to a ComplexType. Values of type str are not allowed" + "a URI reference to a ComplexType. Values of type URIRef are not allowed" ) def test_is_collection_value(self): diff --git a/core/esmf-aspect-meta-model-python/tests/unit/loader/instantiators/test_fixed_point_constraint_instantiator.py b/core/esmf-aspect-meta-model-python/tests/unit/loader/instantiators/test_fixed_point_constraint_instantiator.py index f2565a5..d9b234e 100644 --- a/core/esmf-aspect-meta-model-python/tests/unit/loader/instantiators/test_fixed_point_constraint_instantiator.py +++ b/core/esmf-aspect-meta-model-python/tests/unit/loader/instantiators/test_fixed_point_constraint_instantiator.py @@ -12,7 +12,7 @@ class TestFixedPointConstraintInstantiator: """FixedPointConstraintInstantiator unit tests class.""" @mock.patch( - "esmf_aspect_meta_model_python.loader.instantiator.fixed_point_constraint_instantiator." "RdfHelper.to_python" + "esmf_aspect_meta_model_python.loader.instantiator.fixed_point_constraint_instantiator.RdfHelper.to_python" ) @mock.patch( "esmf_aspect_meta_model_python.loader.instantiator.fixed_point_constraint_instantiator." diff --git a/core/esmf-aspect-meta-model-python/tox.ini b/core/esmf-aspect-meta-model-python/tox.ini index 95e6b15..6aed071 100644 --- a/core/esmf-aspect-meta-model-python/tox.ini +++ b/core/esmf-aspect-meta-model-python/tox.ini @@ -11,7 +11,7 @@ description = Run the tests commands_pre = poetry install commands = poetry run pytest {posargs: \ - -vv \ + -s -vv \ --cov=esmf_aspect_meta_model_python/ \ --cov-fail-under=85 \ tests/ \ diff --git a/documentation/python-sdk-guide/modules/ROOT/pages/index.adoc b/documentation/python-sdk-guide/modules/ROOT/pages/index.adoc index 3fe5857..bf6239c 100644 --- a/documentation/python-sdk-guide/modules/ROOT/pages/index.adoc +++ b/documentation/python-sdk-guide/modules/ROOT/pages/index.adoc @@ -46,8 +46,8 @@ poetry --version === Introduction Aspect Models are stored as RDF Graphs in `.ttl` (RDF Turtle) files. -The Aspect Model Loader for Python reads one or more Turtle file and parses the Aspect Model. -The result is a Python object representing the root Aspect of the Aspect Model. +The Aspect Model Loader for Python offers a SAMMGraph class that provides two main methods: `load_aspect_model` and `load_model_elements`. +Theese methods allows to read a Turtle file and parses the Aspect Model and return either a root Aspect node or a list of all elements from the Aspect Model. The Aspect has references to all of its children (e.g., Properties and Operations). === Installation @@ -58,7 +58,21 @@ If you want to work with Aspect Models in your Python solution you should instal === PyPI -Currently not available +To install the esmf-aspect-model-loader from PyPI, you can use the following command: + +[source,bash] +---- +poetry add esmf-aspect-model-loader +---- + +You can specify the version of the package by adding the version number after the package name. +For example, to install version 2.2.0 of the package, you can use the following command: +[source,bash] +---- +poetry add esmf-aspect-model-loader==2.2.0 +---- + +For more detailed information how to add a library via poetry please read https://python-poetry.org/docs/cli/#add[Poetry add guide]. === GitHub Releases @@ -67,7 +81,7 @@ To use GitHub release as dependency using Poetry, you need to add it like this: [source,toml] ---- [tool.poetry.dependencies] -esmf-aspect-meta-model-python = { git = "https://github.com/eclipse-esmf/esmf-sdk-py-aspect-model-loader.git", tag = "1.0.0" } +esmf-aspect-model-loader = { git = "https://github.com/eclipse-esmf/esmf-sdk-py-aspect-model-loader.git", tag = "v2.2.0", subdirectory = "core/esmf-aspect-meta-model-python" }` ---- for more information on depend on a library located in a git: @@ -82,7 +96,7 @@ If you are working with Poetry, you can easily import that package by adding the [source,toml] ---- [tool.poetry.dependencies] -esmf-aspect-meta-model-python = { path = "path/to/esmf-aspect-meta-model-python-x.y.z.tar.gz" } +esmf-aspect-model-loader = { path = "path/to/esmf-aspect-meta-model-python-x.y.z.tar.gz" } ---- To make Poetry recognize your changes, run @@ -99,65 +113,35 @@ https://github.com/eclipse-esmf/esmf-aspect-model-editor/blob/main/core/apps/ame Aspect model. -==== Loading an Aspect Model from one *.ttl file - -Import the Aspect Model Loader in your Python module -[source,python] - ----- -from esmf_aspect_meta_model_python.loader.aspect_loader import AspectLoader ----- - -Then create an instance of the AspectLoader and run the method `load_aspect_model()` from the `AspectLoader` with +==== Loading an Aspect Model [source,python] ----- -from esmf_aspect_meta_model_python.loader.aspect_loader import AspectLoader -loader = AspectLoader() -aspect = loader.load_aspect_model(PATH_TO_TURTLE_FILE) ---- +# import a SAMMGraph class to your Python module +from esmf_aspect_meta_model_python import SAMMGraph -where the input argument `PATH_TO_TURTLE_FILE` can either be a `Path` object or a string representing a path to the ttl file. - -Both, relative paths and absolute paths are allowed. - -The return value of `load_aspect_model()` is an instance of the class `DefaultAspect` which is declared in the project. - -==== Loading an Aspect Model from multiple files - -If the Aspect Model is separated into multiple `.ttl` files you can load the Aspect Model by calling the method `load_aspect_model_from_multiple_files` -with a list of file paths. - -[source,python] ----- -from esmf_aspect_meta_model_python.loader.aspect_loader import AspectLoader +# Define the path to local Turtle file +model_path = "PATH_TO_TURTLE_FILE" -loader = AspectLoader() -aspect = loader.load_aspect_model_from_multiple_files([ - "file1.ttl", - "file2.ttl", - "file3.ttl", -]) ----- +# Create an instance of SAMMGraph +samm_graph = SAMMGraph() -It may happen that the multiple files contain multiple aspect definitions and not only one. -In this case it is possible to pass the URN of the Aspect as a hint, so the Loader knows which Aspect to load. +# Parse the Turtle file to load the graph +samm_graph.parse(model_path) -[source,python] ----- -from esmf_aspect_meta_model_python.loader.aspect_loader import AspectLoader +# Load the aspect model from the graph +aspect = samm_graph.load_aspect_model() +print(aspect) -loader = AspectLoader() -aspect_urn = "urn:samm:org.eclipse.esmf.samm:test:1.0.0#myAspect" -aspect = loader.load_aspect_model_from_multiple_files( - ["file1.ttl", "file2.ttl", "file3.ttl"], - aspect_urn, -) +# or load all model elements +elements = samm_graph.load_model_elements() +for element in elements: + print(element) ---- -The urn can either be a string or an instance of rdflib.URIRef. -If no urn is passed and the `.ttl` files contain multiple Aspects, the Aspect Loader will load the first one that is found. +where the input argument `PATH_TO_TURTLE_FILE` can either be a `Path` object or a string representing a path to the ttl file. +Both, relative paths and absolute paths are allowed. === Traversing the Aspect Model @@ -351,27 +335,3 @@ It is set up to extract the RDF Turtle files from the released SAMM artifact or If you are not sure whether you need the SAMM Aspect Meta Model as a dependency you probably don't need it because it does not contain any Python functionality. It is only intended for working with Aspect Models on RDF level. - -=== Installation - -The package is released on PyPI under the name `esmf-samm-aspect-meta-model`. -The package can be imported to a Python project by adding the package as a dependency. - -If you are using Poetry as a dependency manager you can execute the following commands: - -[source,bash] ----- -poetry add samm-aspect-meta-model -poetry install ----- - -The `pyproject.toml` file of your project should then include the following: -[source,toml] - ----- -[tool.poetry.dependencies] -samm-aspect-meta-model = "^x.y.z" ----- - -In the future it is planned to publish all packages of the Python SDK on public repositories. -The authentication will then not be required anymore. From 931759aa7b1cb07f8dc48cb78bf468fe59f83027 Mon Sep 17 00:00:00 2001 From: "Hanna Shalamitskaya (EPAM)" Date: Fri, 4 Apr 2025 14:33:48 +0500 Subject: [PATCH 2/2] Fix collecting values for enumeration --- .github/workflows/push_request_check.yml | 2 +- .../impl/__init__.py | 1 + .../instantiator/enumeration_instantiator.py | 6 +- .../loader/instantiator/state_instantiator.py | 6 +- .../loader/meta_model_base_attributes.py | 17 +- .../tests/unit/base/test_aspect.py | 59 ++++++ .../tests/unit/base/test_property.py | 90 +++++++++ .../tests/unit/base/test_property_func.py | 71 +++++++ .../characteristics/test_characteristic.py | 8 + .../tests/unit/impl/test_value.py | 18 ++ .../instantiators/test_state_instantiator.py | 183 ++++++++++++++++++ .../loader/test_meta_model_base_attributes.py | 136 +++++++++++++ 12 files changed, 582 insertions(+), 15 deletions(-) create mode 100644 core/esmf-aspect-meta-model-python/tests/unit/base/test_aspect.py create mode 100644 core/esmf-aspect-meta-model-python/tests/unit/base/test_property.py create mode 100644 core/esmf-aspect-meta-model-python/tests/unit/base/test_property_func.py create mode 100644 core/esmf-aspect-meta-model-python/tests/unit/impl/test_value.py create mode 100644 core/esmf-aspect-meta-model-python/tests/unit/loader/instantiators/test_state_instantiator.py create mode 100644 core/esmf-aspect-meta-model-python/tests/unit/loader/test_meta_model_base_attributes.py diff --git a/.github/workflows/push_request_check.yml b/.github/workflows/push_request_check.yml index 98c7f26..08a1d72 100644 --- a/.github/workflows/push_request_check.yml +++ b/.github/workflows/push_request_check.yml @@ -37,7 +37,7 @@ jobs: poetry run download-samm-release poetry build - - name: run test*s + - name: run tests run: | cd core/esmf-aspect-meta-model-python poetry run tox -e py310 diff --git a/core/esmf-aspect-meta-model-python/esmf_aspect_meta_model_python/impl/__init__.py b/core/esmf-aspect-meta-model-python/esmf_aspect_meta_model_python/impl/__init__.py index dc01586..729fb70 100644 --- a/core/esmf-aspect-meta-model-python/esmf_aspect_meta_model_python/impl/__init__.py +++ b/core/esmf-aspect-meta-model-python/esmf_aspect_meta_model_python/impl/__init__.py @@ -45,3 +45,4 @@ from .default_property import DefaultBlankProperty, DefaultProperty, DefaultPropertyWithExtends from .default_quantity_kind import DefaultQuantityKind from .default_unit import DefaultUnit +from .default_value import DefaultValue diff --git a/core/esmf-aspect-meta-model-python/esmf_aspect_meta_model_python/loader/instantiator/enumeration_instantiator.py b/core/esmf-aspect-meta-model-python/esmf_aspect_meta_model_python/loader/instantiator/enumeration_instantiator.py index bc6576a..b4aeaad 100644 --- a/core/esmf-aspect-meta-model-python/esmf_aspect_meta_model_python/loader/instantiator/enumeration_instantiator.py +++ b/core/esmf-aspect-meta-model-python/esmf_aspect_meta_model_python/loader/instantiator/enumeration_instantiator.py @@ -49,8 +49,8 @@ def __to_enum_node_value(self, value_node: Node) -> Union[Dict, str]: - If value_node is a URIRef it will represent a value of a ComplexType :return: the one generated value of the enumeration """ - str_value: str = "" - dict_value: Dict = {} + str_value: Optional[str] = None + dict_value: Optional[Dict] = None if isinstance(value_node, rdflib.Literal) or ( isinstance(value_node, rdflib.URIRef) and value_node.find("#") == -1 @@ -88,7 +88,7 @@ def __to_enum_node_value(self, value_node: Node) -> Union[Dict, str]: f"a URI reference to a ComplexType. Values of type {type(value_node).__name__} are not allowed" ) - return str_value or dict_value + return str_value if str_value is not None else dict_value if dict_value is not None else "" def __is_collection_value(self, property_subject: str) -> bool: characteristic = self._aspect_graph.value( # type: ignore diff --git a/core/esmf-aspect-meta-model-python/esmf_aspect_meta_model_python/loader/instantiator/state_instantiator.py b/core/esmf-aspect-meta-model-python/esmf_aspect_meta_model_python/loader/instantiator/state_instantiator.py index 0413b27..71bbd20 100644 --- a/core/esmf-aspect-meta-model-python/esmf_aspect_meta_model_python/loader/instantiator/state_instantiator.py +++ b/core/esmf-aspect-meta-model-python/esmf_aspect_meta_model_python/loader/instantiator/state_instantiator.py @@ -67,8 +67,10 @@ def __to_state_node_value(self, value_node: Optional[Node]) -> Dict: if property_urn != rdflib.RDF.type and isinstance(property_urn, str): property_name = property_urn.split("#")[1] actual_value: Optional[Any] - if self.__is_collection_value(property_urn): - actual_value = self.__instantiate_enum_collection(property_value) + if self._EnumerationInstantiator__is_collection_value(property_urn): # type: ignore + actual_value = self._EnumerationInstantiator__instantiate_enum_collection( # type: ignore + property_value + ) else: actual_value = self.__to_state_node_value(property_value) value[property_name] = actual_value diff --git a/core/esmf-aspect-meta-model-python/esmf_aspect_meta_model_python/loader/meta_model_base_attributes.py b/core/esmf-aspect-meta-model-python/esmf_aspect_meta_model_python/loader/meta_model_base_attributes.py index 6fec2f8..3e2ad18 100644 --- a/core/esmf-aspect-meta-model-python/esmf_aspect_meta_model_python/loader/meta_model_base_attributes.py +++ b/core/esmf-aspect-meta-model-python/esmf_aspect_meta_model_python/loader/meta_model_base_attributes.py @@ -94,10 +94,7 @@ def from_meta_model_element( return MetaModelBaseAttributes(meta_model_version, urn, name, preferred_names, descriptions, see) - raise TypeError( - "Unexpected type. Get MetaModelBaseAttributes.from_meta_model_element \ - can't handle this type." - ) + raise TypeError("Unexpected type. Get MetaModelBaseAttributes.from_meta_model_element can't handle this type.") @staticmethod def __create_default_name(meta_model_element: rdflib.BNode, aspect_graph, samm) -> str: @@ -129,12 +126,14 @@ def __get_name_from_urn(urn: str) -> str: urn:samm:org.eclipse.esmf.examples:TestAspect:1.0.0 -> TestAspect """ split_urn = urn.split("#") + if len(split_urn) == 2: - # urn:samm:org.eclipse.esmf.examples#testProperty - return split_urn[1] - # urn:samm:org.eclipse.esmf.examples:TestAspect:1.0.0 - split_urn = urn.split(":") - return split_urn[-2] + name = split_urn[1] + else: + split_urn = urn.split(":") + name = split_urn[-2] + + return name @staticmethod def __get_language_strings( diff --git a/core/esmf-aspect-meta-model-python/tests/unit/base/test_aspect.py b/core/esmf-aspect-meta-model-python/tests/unit/base/test_aspect.py new file mode 100644 index 0000000..29cadb9 --- /dev/null +++ b/core/esmf-aspect-meta-model-python/tests/unit/base/test_aspect.py @@ -0,0 +1,59 @@ +"""Aspect interface test suite.""" + +from esmf_aspect_meta_model_python.base.aspect import Aspect + + +class AspectInterface(Aspect): + """Aspect interface class for testing.""" + + def __init__(self, name): + self._name = name + + def urn(self): + pass + + def meta_model_version(self): + pass + + @property + def name(self): + return self._name + + def preferred_names(self): + pass + + def descriptions(self): + pass + + def see(self): + pass + + def events(self): + pass + + def operations(self): + pass + + def properties(self): + pass + + @property + def parent_elements(self): + return None + + @parent_elements.setter + def parent_elements(self, elements): + pass + + def append_parent_element(self, element): + pass + + +class TestAspect: + """Aspect interface test suite.""" + + def test_is_collection_aspect(self): + aspect = AspectInterface("name") + result = aspect.is_collection_aspect + + assert result is False diff --git a/core/esmf-aspect-meta-model-python/tests/unit/base/test_property.py b/core/esmf-aspect-meta-model-python/tests/unit/base/test_property.py new file mode 100644 index 0000000..666aa3a --- /dev/null +++ b/core/esmf-aspect-meta-model-python/tests/unit/base/test_property.py @@ -0,0 +1,90 @@ +"""Property interface test suite.""" + +from unittest import mock + +from esmf_aspect_meta_model_python.base.characteristics.trait import Trait +from esmf_aspect_meta_model_python.base.property import Property + + +class PropertyInterface(Property): + """Property interface class for testing.""" + + def __init__(self, name, characteristic=None): + self.name = name + self.characteristic = characteristic + + def characteristic(self): + pass + + def example_value(self): + pass + + def is_abstract(self): + pass + + def extends(self): + pass + + def is_optional(self): + pass + + def is_not_in_payload(self): + pass + + def payload_name(self): + pass + + @property + def parent_elements(self): + return None + + @parent_elements.setter + def parent_elements(self, elements): + pass + + def append_parent_element(self, element): + pass + + def name(self): + return self.name + + def preferred_names(self): + pass + + def descriptions(self): + pass + + def see(self): + pass + + def urn(self): + pass + + def meta_model_version(self): + pass + + +class TestProperty: + """Property interface test suite.""" + + def test_effective_characteristic_empty(self): + interface = PropertyInterface("name") + result = interface.effective_characteristic + + assert result is None + + @mock.patch("esmf_aspect_meta_model_python.base.property.isinstance") + def test_effective_characteristic(self, isinstance_mock): + characteristic_mock = mock.MagicMock(name="characteristic") + characteristic_mock.base_characteristic = "base_characteristic" + isinstance_mock.side_effect = (True, False) + interface = PropertyInterface("name", characteristic_mock) + result = interface.effective_characteristic + + assert result == "base_characteristic" + isinstance_mock.assert_has_calls( + [ + mock.call(characteristic_mock, Trait), + mock.call("base_characteristic", Trait), + ] + ) diff --git a/core/esmf-aspect-meta-model-python/tests/unit/base/test_property_func.py b/core/esmf-aspect-meta-model-python/tests/unit/base/test_property_func.py new file mode 100644 index 0000000..0f80391 --- /dev/null +++ b/core/esmf-aspect-meta-model-python/tests/unit/base/test_property_func.py @@ -0,0 +1,71 @@ +"""Property Func interface test suite.""" + +from unittest import mock + +import pytest + +from esmf_aspect_meta_model_python.base.property_func import PropertyFunc + + +class TestPropertyFunc: + """Property Func interface test suite.""" + + def test_fget_name(self): + callable_property_mock = mock.MagicMock(name="callable_property") + callable_property_mock.fget.__name__ = "test_name" + result = PropertyFunc.fget_name(callable_property_mock) + + assert result == "test_name" + + def test_fget_name_raises_attribute_error(self): + with pytest.raises(AttributeError) as error: + PropertyFunc.fget_name(None) + + assert str(error.value) == "Unable to execute fget.__name__ for this argument." + + def test_has_properties(self): + class TestClass: + def __init__(self, a, b): + self._a = a + self._b = b + + @property + def a(self): + return self._a + + @property + def b(self): + return self._b + + obj = TestClass("value_1", "value_2") + result = PropertyFunc.has_properties(obj, TestClass.a, TestClass.b) + + assert result is True + + def test_has_properties_missing_property(self): + class BaseTestClass: + def __init__(self, a, b): + self._a = a + self._b = b + + @property + def a(self): + return self._a + + @property + def b(self): + return self._b + + class TestClass: + def __init__(self, a, b): + self._a = a + self._b = b + + @property + def a(self): + return self._a + + obj = TestClass("value_1", "value_2") + result = PropertyFunc.has_properties(obj, BaseTestClass.a, BaseTestClass.b) + + assert result is False diff --git a/core/esmf-aspect-meta-model-python/tests/unit/impl/characteristics/test_characteristic.py b/core/esmf-aspect-meta-model-python/tests/unit/impl/characteristics/test_characteristic.py index 9012b73..e2e9021 100644 --- a/core/esmf-aspect-meta-model-python/tests/unit/impl/characteristics/test_characteristic.py +++ b/core/esmf-aspect-meta-model-python/tests/unit/impl/characteristics/test_characteristic.py @@ -2,6 +2,8 @@ from unittest import mock +import pytest + from esmf_aspect_meta_model_python.impl import DefaultCharacteristic @@ -21,6 +23,12 @@ def test_init(self, super_mock, isinstance_mock): assert result._data_type == self.data_type_mock self.data_type_mock.append_parent_element.assert_called_once_with(result) + def test_init_raise_exception(self): + with pytest.raises(ValueError) as error: + DefaultCharacteristic(self.meta_model_mock, None) + + assert str(error.value) == "Attribute 'data_type' is required for Characteristic class." + @mock.patch("esmf_aspect_meta_model_python.impl.characteristics.default_characteristic.BaseImpl.__init__") def test_data_type(self, _): characteristic = DefaultCharacteristic(self.meta_model_mock, self.data_type_mock) diff --git a/core/esmf-aspect-meta-model-python/tests/unit/impl/test_value.py b/core/esmf-aspect-meta-model-python/tests/unit/impl/test_value.py new file mode 100644 index 0000000..fa49590 --- /dev/null +++ b/core/esmf-aspect-meta-model-python/tests/unit/impl/test_value.py @@ -0,0 +1,18 @@ +"""DefaultValue class unit tests suit.""" + +from unittest import mock + +from esmf_aspect_meta_model_python.impl import DefaultValue + + +class TestDefaultValue: + """DefaultValue unit tests class.""" + + meta_model_mock = mock.MagicMock(name="meta_model_base_attributes") + + @mock.patch("esmf_aspect_meta_model_python.impl.default_unit.BaseImpl.__init__") + def test_init(self, super_mock): + result = DefaultValue(self.meta_model_mock, "value") + + super_mock.assert_called_once_with(self.meta_model_mock) + assert result.value == "value" diff --git a/core/esmf-aspect-meta-model-python/tests/unit/loader/instantiators/test_state_instantiator.py b/core/esmf-aspect-meta-model-python/tests/unit/loader/instantiators/test_state_instantiator.py new file mode 100644 index 0000000..e555752 --- /dev/null +++ b/core/esmf-aspect-meta-model-python/tests/unit/loader/instantiators/test_state_instantiator.py @@ -0,0 +1,183 @@ +"""StructuredValueInstantiator class unit tests suit.""" + +from unittest import mock + +import pytest + +from esmf_aspect_meta_model_python.loader.instantiator.constants import DATA_TYPE_ERROR_MSG +from esmf_aspect_meta_model_python.loader.instantiator.state_instantiator import StateInstantiator +from esmf_aspect_meta_model_python.vocabulary.samm import SAMM +from esmf_aspect_meta_model_python.vocabulary.sammc import SAMMC + + +class TestStateInstantiator: + """StateInstantiator unit tests class.""" + + @mock.patch("esmf_aspect_meta_model_python.loader.instantiator.state_instantiator.DefaultState") + @mock.patch( + "esmf_aspect_meta_model_python.loader.instantiator.state_instantiator.StateInstantiator." + "_StateInstantiator__to_state_node_value" + ) + @mock.patch("esmf_aspect_meta_model_python.loader.instantiator.state_instantiator.RdfHelper.get_rdf_list_values") + @mock.patch( + "esmf_aspect_meta_model_python.loader.instantiator.state_instantiator.StateInstantiator._get_base_attributes" + ) + @mock.patch("esmf_aspect_meta_model_python.loader.instantiator.state_instantiator.StateInstantiator._get_data_type") + def test_create_instance( + self, + get_data_type_mock, + get_base_attributes_mock, + get_rdf_list_values_mock, + to_state_node_value_mock, + default_state_mock, + ): + get_data_type_mock.return_value = "data_type" + get_base_attributes_mock.return_value = "meta_model_base_attributes" + to_state_node_value_mock.side_effect = ("value", "default") + aspect_graph_mock = mock.MagicMock(name="aspect_graph") + aspect_graph_mock.value.side_effect = ("value_collection_node", "defaultValue") + sammc_mock = mock.MagicMock(name="SAMMC") + sammc_mock.get_urn.side_effect = ("predicate_1", "predicate_2") + get_rdf_list_values_mock.return_value = ["element_node"] + model_elements_mock = mock.MagicMock(name="model_elements") + instantiator = StateInstantiator(model_elements_mock) + instantiator._aspect_graph = aspect_graph_mock + instantiator._sammc = sammc_mock + element_node_mock = mock.MagicMock(name="element_node") + default_state_mock.return_value = "instance" + result = instantiator._create_instance(element_node_mock) + + assert result == "instance" + get_data_type_mock.assert_called_once_with(element_node_mock) + get_base_attributes_mock.assert_called_once_with(element_node_mock) + sammc_mock.get_urn.assert_has_calls( + [ + mock.call(SAMMC.values), + mock.call(SAMMC.default_value), + ] + ) + aspect_graph_mock.value.assert_has_calls( + [ + mock.call(subject=element_node_mock, predicate="predicate_1"), + mock.call(subject=element_node_mock, predicate="predicate_2"), + ] + ) + assert aspect_graph_mock.value.call_count == 2 + get_rdf_list_values_mock.assert_called_once_with("value_collection_node", aspect_graph_mock) + to_state_node_value_mock.assert_has_calls( + [ + mock.call("element_node"), + mock.call("defaultValue"), + ] + ) + default_state_mock.assert_called_once_with( + "meta_model_base_attributes", + "data_type", + ["value"], + "default", + ) + + def test_create_instance_raise_exception(self): + base_class_mock = mock.MagicMock(name="StateInstantiator_class") + base_class_mock._get_data_type.return_value = None + with pytest.raises(TypeError) as error: + StateInstantiator._create_instance(base_class_mock, "element_node") + + assert str(error.value) == DATA_TYPE_ERROR_MSG + + @mock.patch("esmf_aspect_meta_model_python.loader.instantiator.state_instantiator.isinstance") + def test_to_state_node_value_rdflib_literal(self, isinstance_mock): + isinstance_mock.return_value = True + element_node_mock = mock.MagicMock(name="element_node") + element_node_mock.toPython.return_value = "element_node_value" + result = StateInstantiator._StateInstantiator__to_state_node_value( + "base_class", + element_node_mock, + ) + + assert result == "element_node_value" + element_node_mock.toPython.assert_called_once() + + @mock.patch( + "esmf_aspect_meta_model_python.loader.instantiator.state_instantiator.StateInstantiator." + "_EnumerationInstantiator__is_collection_value" + ) + @mock.patch("esmf_aspect_meta_model_python.loader.instantiator.state_instantiator.isinstance") + def test_to_state_node_value_rdflib_uriref_state_value(self, isinstance_mock, is_collection_value_mock): + isinstance_mock.side_effect = (False, True, True, True) + aspect_graph_mock = mock.MagicMock(name="aspect_graph") + property_value_mock = mock.MagicMock(name="property_value") + property_value_mock.toPython.return_value = "actual_value" + aspect_graph_mock.predicate_objects.return_value = [("property_urn#property_name", property_value_mock)] + is_collection_value_mock.return_value = False + name_urn_mock = mock.MagicMock(name="name_urn") + name_urn_mock.toPython.return_value = "value_key" + samm_mock = mock.MagicMock(name="samm") + samm_mock.get_urn.return_value = name_urn_mock + model_elements_mock = mock.MagicMock(name="model_elements") + instantiator = StateInstantiator(model_elements_mock) + instantiator._aspect_graph = aspect_graph_mock + instantiator._samm = samm_mock + result = instantiator._StateInstantiator__to_state_node_value("value_node#value_node_name") + + assert "property_name" in result + assert result["property_name"] == "actual_value" + assert "value_key" in result + assert result["value_key"] == "value_node_name" + aspect_graph_mock.predicate_objects.assert_called_once_with("value_node#value_node_name") + is_collection_value_mock.assert_called_once_with("property_urn#property_name") + samm_mock.get_urn.assert_called_once_with(SAMM.name) + name_urn_mock.toPython.assert_called_once() + + @mock.patch( + "esmf_aspect_meta_model_python.loader.instantiator.state_instantiator.StateInstantiator." + "_EnumerationInstantiator__instantiate_enum_collection" + ) + @mock.patch( + "esmf_aspect_meta_model_python.loader.instantiator.state_instantiator.StateInstantiator." + "_EnumerationInstantiator__is_collection_value" + ) + @mock.patch("esmf_aspect_meta_model_python.loader.instantiator.state_instantiator.isinstance") + def test_to_state_node_value_rdflib_uriref_collection_value( + self, + isinstance_mock, + is_collection_value_mock, + instantiate_enum_collection_mock, + ): + isinstance_mock.side_effect = (False, True, True) + aspect_graph_mock = mock.MagicMock(name="aspect_graph") + aspect_graph_mock.predicate_objects.return_value = [("property_urn#property_name", "property_value")] + is_collection_value_mock.return_value = True + instantiate_enum_collection_mock.return_value = "actual_value" + name_urn_mock = mock.MagicMock(name="name_urn") + name_urn_mock.toPython.return_value = "value_key" + samm_mock = mock.MagicMock(name="samm") + samm_mock.get_urn.return_value = name_urn_mock + model_elements_mock = mock.MagicMock(name="model_elements") + instantiator = StateInstantiator(model_elements_mock) + instantiator._aspect_graph = aspect_graph_mock + instantiator._samm = samm_mock + result = instantiator._StateInstantiator__to_state_node_value("value_node#value_node_name") + + assert "property_name" in result + assert result["property_name"] == "actual_value" + assert "value_key" in result + assert result["value_key"] == "value_node_name" + aspect_graph_mock.predicate_objects.assert_called_once_with("value_node#value_node_name") + is_collection_value_mock.assert_called_once_with("property_urn#property_name") + instantiate_enum_collection_mock.assert_called_once_with("property_value") + samm_mock.get_urn.assert_called_once_with(SAMM.name) + name_urn_mock.toPython.assert_called_once() + + @mock.patch("esmf_aspect_meta_model_python.loader.instantiator.state_instantiator.isinstance") + def test_to_state_node_value_raise_exception(self, isinstance_mock): + isinstance_mock.side_effect = (False, False) + model_elements_mock = mock.MagicMock(name="model_elements") + instantiator = StateInstantiator(model_elements_mock) + with pytest.raises(TypeError) as error: + instantiator._StateInstantiator__to_state_node_value("value_node#value_node_name") + + assert str(error.value) == ( + "Every value of an state must either be a Literal (string, int, etc.) or a URI reference to a ComplexType. " + "Values of type str are not allowed" + ) diff --git a/core/esmf-aspect-meta-model-python/tests/unit/loader/test_meta_model_base_attributes.py b/core/esmf-aspect-meta-model-python/tests/unit/loader/test_meta_model_base_attributes.py new file mode 100644 index 0000000..1565a60 --- /dev/null +++ b/core/esmf-aspect-meta-model-python/tests/unit/loader/test_meta_model_base_attributes.py @@ -0,0 +1,136 @@ +"""Meta Model Base Attributes test suite.""" + +from unittest import mock + +import pytest + +from esmf_aspect_meta_model_python.loader.meta_model_base_attributes import MetaModelBaseAttributes +from esmf_aspect_meta_model_python.vocabulary.samm import SAMM + + +class TestMetaModelBaseAttributes: + """MetaModelBaseAttributes test suite.""" + + def test_init(self): + result = MetaModelBaseAttributes( + "meta_model_version", + "urn", + "name", + {"language": "preferred_name"}, + {"language": "descriptions"}, + ["see"], + ) + + assert result.meta_model_version == "meta_model_version" + assert result.urn == "urn" + assert result.name == "name" + assert result.preferred_names == {"language": "preferred_name"} + assert result.descriptions == {"language": "descriptions"} + assert result.see == ["see"] + + @mock.patch( + "esmf_aspect_meta_model_python.loader.meta_model_base_attributes.MetaModelBaseAttributes." + "_MetaModelBaseAttributes__get_name_from_urn" + ) + @mock.patch("esmf_aspect_meta_model_python.loader.meta_model_base_attributes.isinstance") + @mock.patch("esmf_aspect_meta_model_python.loader.meta_model_base_attributes.RdfHelper.to_python") + @mock.patch( + "esmf_aspect_meta_model_python.loader.meta_model_base_attributes.MetaModelBaseAttributes." + "_MetaModelBaseAttributes__get_attribute_value_list" + ) + @mock.patch( + "esmf_aspect_meta_model_python.loader.meta_model_base_attributes.MetaModelBaseAttributes." + "_MetaModelBaseAttributes__get_language_strings" + ) + def test_from_meta_model_element( + self, + get_language_strings_mock, + get_attribute_value_list_mock, + rdf_helper_to_python_mock, + isinstance_mock, + get_name_from_urn_mock, + ): + get_language_strings_mock.side_effect = ({"language": "preferred_name"}, {"language": "descriptions"}) + get_attribute_value_list_mock.return_value = ["see"] + aspect_graph_mock = mock.MagicMock(name="aspect_graph") + aspect_graph_mock.value.return_value = "name_result" + samm_mock = mock.MagicMock(name="SAMM") + samm_mock.get_urn.side_effect = ("preferred_name_urn", "description_urn", "see_urn", "name") + rdf_helper_to_python_mock.return_value = "name" + isinstance_mock.return_value = True + node_mock = mock.MagicMock(name="meta_model_element_node") + node_mock.toPython.return_value = "urn" + get_name_from_urn_mock.return_value = "urn_name" + result = MetaModelBaseAttributes.from_meta_model_element(node_mock, aspect_graph_mock, samm_mock, "1.0.0") + + assert result.meta_model_version == "1.0.0" + assert result.urn == "urn" + assert result.name == "urn_name" + assert result.preferred_names == {"language": "preferred_name"} + assert result.descriptions == {"language": "descriptions"} + assert result.see == ["see"] + samm_mock.get_urn.assert_has_calls( + [ + mock.call(SAMM.preferred_name), + mock.call(SAMM.description), + mock.call(SAMM.see), + mock.call(SAMM.name), + ] + ) + get_language_strings_mock.assert_has_calls( + [ + mock.call(node_mock, aspect_graph_mock, "preferred_name_urn"), + mock.call(node_mock, aspect_graph_mock, "description_urn"), + ] + ) + get_attribute_value_list_mock.assert_called_once_with(node_mock, aspect_graph_mock, "see_urn") + aspect_graph_mock.value.assert_called_once_with(subject=node_mock, predicate="name") + rdf_helper_to_python_mock.assert_called_once_with("name_result") + node_mock.toPython.assert_called_once() + get_name_from_urn_mock.assert_called_once_with("urn") + + @mock.patch("esmf_aspect_meta_model_python.loader.meta_model_base_attributes.isinstance") + @mock.patch( + "esmf_aspect_meta_model_python.loader.meta_model_base_attributes.MetaModelBaseAttributes." + "_MetaModelBaseAttributes__get_attribute_value_list" + ) + @mock.patch( + "esmf_aspect_meta_model_python.loader.meta_model_base_attributes.MetaModelBaseAttributes." + "_MetaModelBaseAttributes__get_language_strings" + ) + def test_from_meta_model_element_raise_exception( + self, + get_language_strings_mock, + get_attribute_value_list_mock, + isinstance_mock, + ): + get_language_strings_mock.side_effect = ({"language": "preferred_name"}, {"language": "descriptions"}) + get_attribute_value_list_mock.return_value = ["see"] + aspect_graph_mock = mock.MagicMock(name="aspect_graph") + aspect_graph_mock.value.return_value = "name_result" + samm_mock = mock.MagicMock(name="SAMM") + samm_mock.get_urn.side_effect = ("preferred_name_urn", "description_urn", "see_urn") + isinstance_mock.side_effect = (False, False) + with pytest.raises(TypeError) as error: + MetaModelBaseAttributes.from_meta_model_element( + mock.MagicMock(name="node"), + aspect_graph_mock, + samm_mock, + "1.2.3", + ) + + assert str(error.value) == ( + "Unexpected type. Get MetaModelBaseAttributes.from_meta_model_element can't handle this type." + ) + + def test_get_name_from_urn_prefix_with_3_parts(self): + urn = "urn:samm:org.eclipse.esmf.examples#testProperty" + result = MetaModelBaseAttributes._MetaModelBaseAttributes__get_name_from_urn(urn) + + assert result == "testProperty" + + def test_get_name_from_urn_prefix_with_4_parts(self): + urn = "urn:samm:org.eclipse.esmf.examples:TestAspect:1.2.3" + result = MetaModelBaseAttributes._MetaModelBaseAttributes__get_name_from_urn(urn) + + assert result == "TestAspect"