Skip to content

Commit 8deaad4

Browse files
WIP: Fix PR comments
1 parent 557c5fd commit 8deaad4

File tree

21 files changed

+601
-341
lines changed

21 files changed

+601
-341
lines changed

AUTHORS.md

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2,10 +2,11 @@
22

33
The following people have contributed to this repository:
44

5-
* [Georg Schmidt-Dumont]([email protected])
6-
* [Nico Makowe](mailto:[email protected])
7-
* [Aghyad Farrouh](mailto:[email protected])
5+
* [Hanna Shalamitskaya](mailto:[email protected])
86
* [Andreas Textor](mailto:[email protected])
7+
* [Georg Schmidt-Dumont](mailto:[email protected])
98
* [Michele Santoro](mailto:[email protected])
9+
* Nico Makowe
10+
* Aghyad Farrouh
1011

1112
Please add yourself to this list, if you contribute to the content.

CONVENTIONS.md

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
# ESMF SDK PY Aspect Model Loader Code Conventions
22

3-
The following document contains a compilation of conventions and guidelines to format, structure and write code for the ESMF SDK PY Aspect Model Loader.
3+
The following document contains a compilation of conventions and guidelines to format,
4+
structure and write code for the ESMF SDK PY Aspect Model Loader.
45

56
## General Conventions
67
Our code conventions are based on the [Google Python Style Guide](https://google.github.io/styleguide/pyguide.html) but
Lines changed: 150 additions & 46 deletions
Original file line numberDiff line numberDiff line change
@@ -1,84 +1,113 @@
11
The Aspect Model Loader as part of the Python SDK provided by the [*Eclipse Semantic Modeling Framework*](
22
https://projects.eclipse.org/projects/dt.esmf).
33

4+
<!-- TOC -->
5+
* [An Aspect of the Meta Model](#an-aspect-of-the-meta-model)
6+
* [Set Up SAMM Aspect Meta Model](#set-up-samm-aspect-meta-model)
7+
* [Install poetry](#install-poetry)
8+
* [Install project dependencies](#install-project-dependencies)
9+
* [Download SAMM files](#download-samm-files)
10+
* [Download SAMM release](#download-samm-release)
11+
* [Download SAMM branch](#download-samm-branch)
12+
* [Aspect Meta Model Loader usage](#aspect-meta-model-loader-usage)
13+
* [Samm Units](#samm-units)
14+
* [SAMM CLI wrapper class](#samm-cli-wrapper-class)
15+
* [Scripts](#scripts)
16+
* [Automation Tasks](#automation-tasks)
17+
* [tox](#tox)
18+
* [GitHub actions](#github-actions)
19+
* [Check New Pull Request](#check-new-pull-request)
20+
* [Build release](#build-release)
21+
<!-- TOC -->
22+
423
# An Aspect of the Meta Model
524

625
The `esmf-aspect-model-loader` package provides the Python implementation for the SAMM Aspect Meta Model, or SAMM.
726
Each Meta Model element and each Characteristic class is represented by an interface with a corresponding
827
implementation.
928

10-
## Usage
29+
## Set Up SAMM Aspect Meta Model
1130

12-
An Aspect of the Meta Model can be created as follows using the provided `AspectInstantiator`.
31+
Before getting started to use the `esmf-aspect-model-loader` library you need to apply some set up actions:
1332

14-
```
15-
aspect_loader = AspectLoader()
16-
model_elements = aspect_loader.load_aspect_model("absolute/path/to/turtle.ttl");
17-
aspect = model_elements[0]
18-
```
33+
Required
34+
- [Install poetry](#install-poetry)
35+
- [Install project dependencies](#install-project-dependencies)
36+
- [Download SAMM files](#download-samm-files)
37+
Optional
38+
- [Download SAMM CLI](#download-samm-cli) (needed to use SAMM CLI functions)
39+
- [Download SAMM test models](#download-test-models) (for running integration tests)
1940

20-
or
41+
### Install poetry
2142

22-
```
23-
aspect_loader = AspectLoader()
24-
aspect_urn = "urn:samm:org.eclipse.esmf.samm:aspect.model:0.0.1#AspectName"
25-
aspect = aspect_loader.load_aspect_model("absolute/path/to/turtle.ttl", aspect_urn);
43+
`Poetry` used as a dependency management for the `esmf-aspect-model-loader`. Follow the next [instruction](https://python-poetry.org/docs/#installation)
44+
to install it.
45+
46+
To check the poetry version run:
47+
```console
48+
poetry --version
2649
```
2750

28-
## Automatic Deployment
51+
### Install project dependencies
2952

30-
A [GitHub action called 'Release'](https://github.com/eclipse-esmf/esmf-sdk-py-aspect-model-loader/actions/workflows/tagged_release.yml)
31-
has been set up for the `esmf-aspect-model-loader`. This action checks the code quality by running tests, the [static type checker MyPy](https://github.com/python/mypy) and
32-
the [code formatter 'Black'](https://github.com/psf/black).
53+
Poetry provides convenient functionality for working with dependencies in the project.
54+
To automatically download and install all the necessary libraries, just run one command:
55+
```console
56+
poetry install
57+
```
58+
It is required to run `poetry install` once in the esmf-aspect-model-loader module.
3359

34-
## Set Up SAMM Aspect Meta Model for development
60+
### Download SAMM files
3561

36-
In order to download the SAMM sources, it is required to run `poetry install` once in the `esmf-aspect-model-loader`
37-
module. There are two possibilities to download the SAMM files and extract the Turtle sources for the Meta Model.
62+
There are two possibilities to download the SAMM files and extract the Turtle sources for the Meta Model:
63+
SAMM release or SAMM branch
3864

39-
### Possibility 1 (downloading a release)
65+
#### Download SAMM release
4066

41-
The `download_samm_release` script may be executed with
67+
This script downloads a release JAR-file from GitHub, extracts them for further usage in the Aspect Model Loader:
4268

43-
```
69+
To run script, execute the next command.
70+
```console
4471
poetry run download-samm-release
45-
```
46-
47-
It downloads a release JAR-file from GitHub and extracts the SAMM Files.
48-
The version is specified in the python script.
49-
50-
Link to all Releases: https://github.com/eclipse-esmf/esmf-semantic-aspect-meta-model/releases
72+
```
73+
The version of the SAMM release is specified in the python script.
5174

52-
### Possibility 2 (downloading from the repository)
75+
Link to all Releases: [SAMM Releases](https://github.com/eclipse-esmf/esmf-semantic-aspect-meta-model/releases)
5376

54-
It may happen that there is no .jar file that is up to date with the changes of the SAMM.
55-
This script is an alternative to the `download_samm_release.py` and extracts the files from the repository
56-
directly instead of using the newest release.
77+
#### Download SAMM branch
5778

58-
The script uses the GitHub API and downloads the files from the `main` branch. If the script is run in a
59-
pipeline, it uses a GitHub token to authorize. If the script is run locally, the API is called without a token.
60-
This may cause problems because unauthorized API calls are limited.
79+
The script uses the GitHub API and downloads the files from the `main` GitHub branch.
6180

62-
This script can be executed with
81+
If the script is run in a pipeline, it uses a GitHub token to authorize. If the script is run locally,
82+
the API is called without a token. This may cause problems because unauthorized API calls are limited.
6383

64-
```
84+
Run the next command to download and start working with the Aspect Model Loader.
85+
```console
6586
poetry run download-samm-branch
6687
```
67-
to download and start working with the Aspect Model Loader.
88+
Link to all branches: [SAMM Releases](https://github.com/eclipse-esmf/esmf-semantic-aspect-meta-model/branches)
6889

69-
## Semantic Aspect Meta Model
90+
## Aspect Meta Model Loader usage
7091

71-
To be able to use SAMM meta model classes you need to download the corresponding files.
72-
Details are described in [Set up SAMM Aspect Meta Model for development](#set-up-samm-aspect-meta-model-for-development).
92+
An Aspect of the Meta Model can be loaded as follows:
93+
```python
94+
from esmf_aspect_meta_model_python import AspectLoader
95+
96+
loader = AspectLoader()
97+
model_elements = loader.load_aspect_model("absolute/path/to/turtle.ttl")
98+
aspect = model_elements[0]
7399

74-
This module contains classes for working with Aspect data.
100+
# or you can provide an Aspect URN
75101

76-
SAMM meta model contains:
77-
- SammUnitsGraph: provide a functionality for working with units([units.ttl](./esmf_aspect_meta_model_python/samm_aspect_meta_model/samm/unit/2.1.0/units.ttl)) data
102+
loader = AspectLoader()
103+
aspect_urn = "urn:samm:org.eclipse.esmf.samm:aspect.model:0.0.1#AspectName"
104+
model_elements = loader.load_aspect_model("absolute/path/to/turtle.ttl", aspect_urn)
105+
aspect = model_elements[0]
106+
```
78107

79-
### SammUnitsGraph
108+
## Samm Units
80109

81-
The class contains functions for accessing units of measurement.
110+
SAMMUnitsGraph is a class contains functions for accessing units of measurement.
82111
```python
83112
from esmf_aspect_meta_model_python.samm_meta_model import SammUnitsGraph
84113

@@ -92,3 +121,78 @@ units_graph.print_description(unit_data)
92121
# ...
93122
# symbol: V
94123
```
124+
125+
## SAMM CLI wrapper class
126+
127+
The SAMM CLI is a command line tool provided number of functions for working with Aspect Models.
128+
129+
More detailed information about SAMM CLI functionality can be found in the
130+
[SAMM CLI documentation](https://eclipse-esmf.github.io/esmf-developer-guide/tooling-guide/samm-cli.html).
131+
132+
Python Aspect Model Loader provide a wrapper class to be able to call SAMM CLI functions from the Python code.
133+
For instance, validation of a model can be done with the following code snippet:
134+
135+
```python
136+
from esmf_aspect_meta_model_python.samm_cli_functions import SammCli
137+
138+
samm_cli = SammCli()
139+
model_path = "Paht_to_the_model/Model.ttl"
140+
samm_cli.validate(model_path)
141+
# Input model is valid
142+
```
143+
144+
List of SAMMCLI functions:
145+
- validate
146+
- to_openapi
147+
- to_schema
148+
- to_json
149+
- to_html
150+
- to_png
151+
- to_svg
152+
153+
# Scripts
154+
155+
The Aspect Model Loader provide scripts for downloading some additional code and data.
156+
Provided scripts:
157+
- download-samm-release
158+
- download-samm-branch
159+
- download-samm-cli
160+
- download-test-models
161+
162+
All scripts run like a poetry command. The poetry is available from the folder where [pyproject.toml](pyproject.toml)
163+
is located.
164+
165+
# Automation Tasks
166+
## tox
167+
168+
`tox` is used for the tests automation purpose. There are two environments with different purposes and tests can
169+
be running with the tox:
170+
- pep8: static code checks (PEP8 style) with MyPy and Black
171+
- py310: unit and integration tests
172+
173+
```console
174+
# run all checks use the next command
175+
poetry run tox
176+
177+
# run only pep8 checks
178+
poetry run tox -e pep8
179+
180+
# run tests
181+
poetry run tox -e py310
182+
```
183+
184+
## GitHub actions
185+
186+
There are two actions on the GitHub repo:
187+
- [Check New Pull Request](../../.github/workflows/push_request_check.yml)
188+
- [Build release](../../.github/workflows/tagged_release.yml)
189+
190+
### Check New Pull Request
191+
This action run after creation or updating a pull request and run all automation tests with tox command.
192+
193+
### Build release
194+
Prepare and publish a new release for the `esmf-aspect-model-loader` to the PyPi:
195+
[esmf-aspect-model-loader](https://pypi.org/project/esmf-aspect-model-loader/.)
196+
197+
A list of the available releases on the GitHub:
198+
[Releases](https://github.com/eclipse-esmf/esmf-sdk-py-aspect-model-loader/releases).

core/esmf-aspect-meta-model-python/esmf_aspect_meta_model_python/loader/aspect_loader.py

Lines changed: 17 additions & 79 deletions
Original file line numberDiff line numberDiff line change
@@ -10,10 +10,8 @@
1010
# SPDX-License-Identifier: MPL-2.0
1111

1212
from pathlib import Path
13-
from typing import Optional, Union
13+
from typing import Union
1414

15-
from esmf_aspect_meta_model_python.base.base import Base
16-
from esmf_aspect_meta_model_python.base.property import Property
1715
from esmf_aspect_meta_model_python.loader.default_element_cache import DefaultElementCache
1816
from esmf_aspect_meta_model_python.loader.samm_graph import SAMMGraph
1917

@@ -26,9 +24,9 @@ class AspectLoader:
2624
The default cache strategy ignores inline defined elements.
2725
"""
2826

29-
def __init__(self, graph: Optional[SAMMGraph] = None, cache: Optional[DefaultElementCache] = None) -> None:
30-
self._cache = cache if cache else DefaultElementCache()
31-
self._graph = graph if graph else SAMMGraph(cache=self._cache)
27+
def __init__(self) -> None:
28+
self._cache = DefaultElementCache()
29+
self._graph = SAMMGraph()
3230

3331
def get_graph(self) -> SAMMGraph:
3432
"""Get SAMM graph.
@@ -50,8 +48,20 @@ def convert_file_path(file_path: Union[str, Path]) -> str:
5048
if isinstance(file_path, Path):
5149
file_path = str(file_path)
5250

51+
tmp_path = Path(file_path)
52+
if not tmp_path.exists():
53+
raise FileNotFoundError(f"Could not found the file {tmp_path}")
54+
5355
return file_path
5456

57+
def _reset_graph(self):
58+
"""Reset graph and cache data."""
59+
if self._graph:
60+
self._graph = SAMMGraph()
61+
62+
if self._cache:
63+
self._cache = DefaultElementCache()
64+
5565
def load_aspect_model(self, file_path: Union[Path, str]):
5666
"""Load aspect model to RDF GRAPH.
5767
@@ -61,80 +71,8 @@ def load_aspect_model(self, file_path: Union[Path, str]):
6171
:return: instance of the aspect
6272
"""
6373
file_path = self.convert_file_path(file_path)
74+
self._reset_graph()
6475
_ = self._graph.parse(file_path)
6576
loaded_aspect_model = self._graph.to_python()
6677

6778
return loaded_aspect_model
68-
69-
def find_by_name(self, element_name: str) -> list[Base]:
70-
"""Find a specific model element by name, and returns the found elements
71-
72-
:param element_name: name or pyload of element
73-
:return: list of found elements
74-
"""
75-
return self._cache.get_by_name(element_name)
76-
77-
def find_by_urn(self, urn: str) -> Optional[Base]:
78-
"""Find a specific model element, and returns it or undefined.
79-
80-
:param urn: urn of the model element
81-
:return: found element or None
82-
"""
83-
return self._cache.get_by_urn(urn)
84-
85-
def determine_access_path(self, base_element_name: str) -> list[list[str]]:
86-
"""Determine the access path.
87-
88-
Search for the element in cache first then call "determine_element_access_path" for every found element
89-
90-
:param base_element_name: name of element
91-
:return: list of paths found to access the respective value.
92-
"""
93-
paths: list[list[str]] = []
94-
base_element_list = self.find_by_name(base_element_name)
95-
for element in base_element_list:
96-
paths.extend(self.determine_element_access_path(element))
97-
98-
return paths
99-
100-
def determine_element_access_path(self, base_element: Base) -> list[list[str]]:
101-
"""Determine the path to access the respective value in the Aspect JSON object.
102-
103-
:param base_element: element for determine the path
104-
:return: list of paths found to access the respective value.
105-
"""
106-
path: list[list[str]] = []
107-
if isinstance(base_element, Property):
108-
if hasattr(base_element, "payload_name") and base_element.payload_name is not None: # type: ignore
109-
path.insert(0, [base_element.payload_name]) # type: ignore
110-
else:
111-
path.insert(0, [base_element.name])
112-
113-
return self.__determine_access_path(base_element, path)
114-
115-
def __determine_access_path(self, base_element: Base, path: list[list[str]]) -> list[list[str]]:
116-
"""Determine access path.
117-
118-
:param base_element: element for determine the path
119-
:return: list of paths found to access the respective value.
120-
"""
121-
if base_element is None or base_element.parent_elements is None or len(base_element.parent_elements) == 0:
122-
return path
123-
124-
# in case of multiple parent get the number of additional parents and
125-
# clone the existing paths
126-
path.extend(path[0] for _ in range(len(base_element.parent_elements) - 1))
127-
128-
for index, parent in enumerate(base_element.parent_elements):
129-
if isinstance(parent, Property):
130-
if hasattr(parent, "payload_name") and parent.payload_name is not None: # type: ignore
131-
path_segment = parent.payload_name # type: ignore
132-
else:
133-
path_segment = parent.name
134-
135-
if (len(path[index]) > 0 and path[index][0] != path_segment) or len(path[0]) == 0:
136-
path[index].insert(0, path_segment)
137-
138-
self.__determine_access_path(parent, path) # type: ignore
139-
140-
return path

core/esmf-aspect-meta-model-python/esmf_aspect_meta_model_python/loader/model_element_factory.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -65,6 +65,7 @@ def create_all_graph_elements(self, create_nodes: list[Node]):
6565
instance = self.create_element(node)
6666
except Exception as error:
6767
print(f"Could nod translate the node {node} to a Python object. Error: {error}")
68+
raise error
6869
else:
6970
all_nodes.append(instance)
7071

0 commit comments

Comments
 (0)