Skip to content
GitLab
Explore
Sign in
Primary navigation
Search or go to…
Project
Python Unified Device Interface
Manage
Activity
Members
Labels
Plan
Issues
Issue boards
Milestones
Code
Merge requests
Repository
Branches
Commits
Tags
Repository graph
Compare revisions
Snippets
Build
Pipelines
Jobs
Pipeline schedules
Artifacts
Deploy
Releases
Package registry
Container registry
Model registry
Operate
Environments
Terraform modules
Monitor
Incidents
Analyze
Value stream analytics
Contributor analytics
CI/CD analytics
Repository analytics
Model experiments
Help
Help
Support
GitLab documentation
Compare GitLab plans
GitLab community forum
Contribute to GitLab
Provide feedback
Terms and privacy
Keyboard shortcuts
?
Snippets
Groups
Projects
Show more breadcrumbs
WZL-IQS-Public
Sensor Interfacing Language (SOIL)
Python Unified Device Interface
Commits
ecd0e780
Commit
ecd0e780
authored
3 years ago
by
Matthias Stefan Bodenbenner
Browse files
Options
Downloads
Patches
Plain Diff
merged master into develop
parent
db812499
No related branches found
No related tags found
No related merge requests found
Changes
3
Show whitespace changes
Inline
Side-by-side
Showing
3 changed files
requirements.txt
+3
-8
3 additions, 8 deletions
requirements.txt
src/soil/component.py
+83
-24
83 additions, 24 deletions
src/soil/component.py
src/soil/error.py
+5
-0
5 additions, 0 deletions
src/soil/error.py
with
91 additions
and
32 deletions
requirements.txt
+
3
−
8
View file @
ecd0e780
aiohttp
@
file:///D:/bld/aiohttp_1605734736785/work
aiohttp
==3.7.3
async-timeout
==3.0.1
async-timeout
==3.0.1
attrs
@
file:///home/conda/feedstock_root/build_artifacts/attrs_1605083924122/work
attrs
@
file:///home/conda/feedstock_root/build_artifacts/attrs_1605083924122/work
certifi
==2020.11.8
certifi
==2020.11.8
chardet
@
file:///D:/bld/chardet_1602255574834/work
chardet
@
file:///D:/bld/chardet_1602255574834/work
docstring-parser
==0.7.3
docstring-parser
==0.7.3
idna
@
file:///home/conda/feedstock_root/build_artifacts/idna_1593328102638/work
nest-asyncio
==1.4.3
multidict
@
file:///D:/bld/multidict_1602413330828/work
nest-asyncio
@
file:///home/conda/feedstock_root/build_artifacts/nest-asyncio_1605195931949/work
paho-mqtt
==1.5.1
strict-rfc3339
==0.7
strict-rfc3339
==0.7
typing-extensions
@
file:///home/conda/feedstock_root/build_artifacts/typing_extensions_1602702424206/work
wzl-mqtt
==2.3.0
wincertstore
==0.2
wzl-mqtt
==1.3.1
wzl-utilities
==1.2.2
wzl-utilities
==1.2.2
yarl
@
file:///D:/bld/yarl_1605429655746/work
yarl
@
file:///D:/bld/yarl_1605429655746/work
This diff is collapsed.
Click to expand it.
src/soil/component.py
+
83
−
24
View file @
ecd0e780
'''
Provides the Component class being the structuring element of the UDI, i.e. the underlying SOIL Model.
Components are structural elements of a SOIL-model.
A component contains an arbitrary number of children elements such that the overall model has tree-like shape.
Children elements can be components, functions, parameters or measurements.
'''
# from __future__ import annotations
# from __future__ import annotations
import
json
import
json
import
os
import
os
...
@@ -20,7 +28,41 @@ logger = root_logger.get(__name__)
...
@@ -20,7 +28,41 @@ logger = root_logger.get(__name__)
class
Component
(
Element
):
class
Component
(
Element
):
def
__init__
(
self
,
uuid
:
str
,
name
:
str
,
description
:
str
,
functions
:
List
[
Function
],
measurements
:
List
[
Measurement
],
def
__init__
(
self
,
uuid
:
str
,
name
:
str
,
description
:
str
,
functions
:
List
[
Function
],
measurements
:
List
[
Measurement
],
parameters
:
List
[
Parameter
],
components
:
List
[
'
Component
'
],
implementation
:
Dict
,
ontology
:
str
=
None
):
parameters
:
List
[
Parameter
],
components
:
List
[
'
Component
'
],
mapping
:
Dict
,
ontology
:
str
=
None
):
"""
Args:
uuid: Locally unique identifier of the component. Must start with
'
COM-
'
.
For the sake if simplicity, it is suggested to use the name and simply prepend
'
COM-
'
to obtain the UUID:
name: Human readable name of the component.
description: Human readable description of the purpose of the component.
functions: List of all children functions.
measurements: List of all children measurements.
parameters: List of all children parameters.
components: List of all children components. Might contain dynamic-components.
mapping: Dictionary containing a mapping of the underlying device implementation to the HTTP-endpoints.
The mapping of a component looks as follows :
{
'
getter
'
: com_implementation.get,
'
setter
'
: com_implementation.set,
'
MEA-Temperature
'
: com_implementation.get_mea_temperature,
'
PAR-State
'
: {...},
'
FUN-Reset: {...},
'
COM-Part
'
: {...},
}
If the component does not have dynamic children components,
'
getter
'
and
'
setter
'
are set to None.
For all children there is a key-value pair where the UUID of the child is the key and the mapping of the child is the value.
For the structure of the childrens
'
mappings please refer to the respective documentation.
ontology: Optional field containing the reference to a semantic definition of the components name or purpose.
Raises:
ValueError: The UUID does not start with
'
COM
'
.
AmbiguousUUIDException: There are at least two children having the same UUID.
InvalidModelException: One of the lists containing the components
'
children is not a list or contains elements which are not of the correct type.
InvalidMappingException: If something is wrong with the provided mapping.
"""
Element
.
__init__
(
self
,
uuid
,
name
,
description
,
ontology
)
Element
.
__init__
(
self
,
uuid
,
name
,
description
,
ontology
)
if
uuid
[:
3
]
!=
'
COM
'
:
if
uuid
[:
3
]
!=
'
COM
'
:
raise
Exception
(
'
{}: The UUID must start with COM!
'
.
format
(
uuid
))
raise
Exception
(
'
{}: The UUID must start with COM!
'
.
format
(
uuid
))
...
@@ -53,18 +95,35 @@ class Component(Element):
...
@@ -53,18 +95,35 @@ class Component(Element):
self
.
_implementation_remove
=
implementation
[
'
remove
'
]
if
'
remove
'
in
implementation
else
None
self
.
_implementation_remove
=
implementation
[
'
remove
'
]
if
'
remove
'
in
implementation
else
None
def
__getitem__
(
self
,
item
:
Union
[
str
,
List
[
str
]],
method
:
int
=
HTTP_GET
)
->
Any
:
def
__getitem__
(
self
,
item
:
Union
[
str
,
List
[
str
]],
method
:
int
=
HTTP_GET
)
->
Any
:
attribute
=
False
"""
Returns the value of the specified item.
if
isinstance
(
item
,
str
):
attribute
=
hasattr
(
self
,
item
)
Args:
if
item
==
"
functions
"
:
item: Either a string or a list of uuids. Possible values string
values are
'
functions
'
,
'
measurements
'
,
'
parameters
'
,
'
components
'
and
'
children
'
. The returned value is the list of the specified
elements.
If a list of UUIDs is given, the __getitem__ method of the child of
which its UUID is equal to first UUID in the list is called with
item[1:0].
method:
Returns: Either a list of (specific) children or, if a list of UUIDs is
given, the method returns an Element.
Raises
"""
if
item
==
'
functions
'
:
return
self
.
_functions
return
self
.
_functions
if
item
==
"
measurements
"
:
if
item
==
'
measurements
'
:
return
self
.
_measurements
return
self
.
_measurements
if
item
==
"
parameters
"
:
if
item
==
'
parameters
'
:
return
self
.
_measurements
return
self
.
_measurements
if
item
==
"
components
"
:
if
item
==
'
components
'
:
return
self
.
_components
return
self
.
_components
if
item
==
"
children
"
:
if
item
==
'
children
'
:
ret
=
[]
ret
=
[]
everything
=
self
.
_components
+
self
.
_measurements
+
self
.
_parameters
+
self
.
_functions
everything
=
self
.
_components
+
self
.
_measurements
+
self
.
_parameters
+
self
.
_functions
for
o
in
everything
:
for
o
in
everything
:
...
@@ -82,33 +141,33 @@ class Component(Element):
...
@@ -82,33 +141,33 @@ class Component(Element):
if
len
(
item
)
==
1
:
if
len
(
item
)
==
1
:
return
o
return
o
else
:
else
:
return
o
.
__getitem__
(
item
[
1
:],
method
)
return
child
.
__getitem__
(
item
[
1
:],
method
)
raise
Exception
(
"
{
}: Given uuid {} is not the id of a child of the current component!
"
.
format
(
self
.
uuid
,
item
)
)
raise
ChildNotFoundException
(
f
'
{
self
.
uuid
}
: Given uuid
{
item
}
is not the id of a child of the current component!
'
)
return
super
().
__getitem__
(
item
,
method
)
return
super
().
__getitem__
(
item
,
method
)
def
__setitem__
(
self
,
key
:
str
,
value
:
Any
):
def
__setitem__
(
self
,
key
:
str
,
value
:
Any
):
if
key
==
"
functions
"
:
if
key
==
'
functions
'
:
if
not
isinstance
(
value
,
list
):
if
not
isinstance
(
value
,
list
):
raise
Exception
(
'
{}: Given functions are not a list!
'
.
format
(
self
.
uuid
))
raise
Exception
(
'
{}: Given functions are not a list!
'
.
format
(
self
.
uuid
))
for
f
in
value
:
for
f
in
value
:
if
not
isinstance
(
f
,
Function
):
if
not
isinstance
(
f
,
Function
):
raise
Exception
(
'
{}: Given function is not of type Function!
'
.
format
(
self
.
uuid
))
raise
Exception
(
'
{}: Given function is not of type Function!
'
.
format
(
self
.
uuid
))
self
.
_functions
=
value
self
.
_functions
=
value
elif
key
==
"
measurements
"
:
elif
key
==
'
measurements
'
:
if
not
isinstance
(
value
,
list
):
if
not
isinstance
(
value
,
list
):
raise
Exception
(
'
{}: Given measurements are not a list!
'
.
format
(
self
.
uuid
))
raise
Exception
(
'
{}: Given measurements are not a list!
'
.
format
(
self
.
uuid
))
for
v
in
value
:
for
v
in
value
:
if
not
isinstance
(
v
,
Measurement
):
if
not
isinstance
(
v
,
Measurement
):
raise
Exception
(
'
{}: Given measurement is not of type Variable!
'
.
format
(
self
.
uuid
))
raise
Exception
(
'
{}: Given measurement is not of type Variable!
'
.
format
(
self
.
uuid
))
self
.
_measurements
=
value
self
.
_measurements
=
value
elif
key
==
"
parameters
"
:
elif
key
==
'
parameters
'
:
if
not
isinstance
(
value
,
list
):
if
not
isinstance
(
value
,
list
):
raise
Exception
(
'
{}: Given parameters are not a list!
'
.
format
(
self
.
uuid
))
raise
Exception
(
'
{}: Given parameters are not a list!
'
.
format
(
self
.
uuid
))
for
v
in
value
:
for
v
in
value
:
if
not
isinstance
(
v
,
Parameter
):
if
not
isinstance
(
v
,
Parameter
):
raise
Exception
(
'
{}: Given parameter is not of type Parameter!
'
.
format
(
self
.
uuid
))
raise
Exception
(
'
{}: Given parameter is not of type Parameter!
'
.
format
(
self
.
uuid
))
self
.
_measurements
=
value
self
.
_measurements
=
value
elif
key
==
"
components
"
:
elif
key
==
'
components
'
:
if
not
isinstance
(
value
,
list
):
if
not
isinstance
(
value
,
list
):
raise
Exception
(
'
{}: Given components are not a list!
'
.
format
(
self
.
uuid
))
raise
Exception
(
'
{}: Given components are not a list!
'
.
format
(
self
.
uuid
))
for
o
in
value
:
for
o
in
value
:
...
@@ -174,7 +233,7 @@ class Component(Element):
...
@@ -174,7 +233,7 @@ class Component(Element):
component_list
[
idx
][
'
returns
'
]
=
merge_measurements
(
function
[
'
returns
'
],
component_list
[
idx
][
'
returns
'
])
component_list
[
idx
][
'
returns
'
]
=
merge_measurements
(
function
[
'
returns
'
],
component_list
[
idx
][
'
returns
'
])
return
component_list
return
component_list
# merge components, i.e. overwrite fields of
"
static
"
children dictionary with the
"
dynamic
"
fields of the parents dictionary
# merge components, i.e. overwrite fields of
'
static
'
children dictionary with the
'
dynamic
'
fields of the parents dictionary
uuid
=
parent_dict
[
'
uuid
'
]
uuid
=
parent_dict
[
'
uuid
'
]
component_dict
[
'
uuid
'
]
=
uuid
component_dict
[
'
uuid
'
]
=
uuid
if
'
name
'
in
parent_dict
:
if
'
name
'
in
parent_dict
:
...
@@ -228,7 +287,7 @@ class Component(Element):
...
@@ -228,7 +287,7 @@ class Component(Element):
measurements
=
[]
measurements
=
[]
for
var
in
dictionary
[
'
measurements
'
]:
for
var
in
dictionary
[
'
measurements
'
]:
if
mapping
is
not
None
:
if
mapping
is
not
None
:
submapping
=
mapping
[
var
[
"
uuid
"
]]
if
var
[
'
uuid
'
]
in
mapping
else
None
submapping
=
mapping
[
var
[
'
uuid
'
]]
if
var
[
'
uuid
'
]
in
mapping
else
None
measurements
+=
[
Measurement
.
deserialize
(
var
,
submapping
)]
measurements
+=
[
Measurement
.
deserialize
(
var
,
submapping
)]
else
:
else
:
measurements
+=
[
Measurement
.
deserialize
(
var
)]
measurements
+=
[
Measurement
.
deserialize
(
var
)]
...
@@ -238,7 +297,7 @@ class Component(Element):
...
@@ -238,7 +297,7 @@ class Component(Element):
parameters
=
[]
parameters
=
[]
for
par
in
dictionary
[
'
parameters
'
]:
for
par
in
dictionary
[
'
parameters
'
]:
if
mapping
is
not
None
:
if
mapping
is
not
None
:
submapping
=
mapping
[
par
[
"
uuid
"
]]
if
par
[
'
uuid
'
]
in
mapping
else
None
submapping
=
mapping
[
par
[
'
uuid
'
]]
if
par
[
'
uuid
'
]
in
mapping
else
None
parameters
+=
[
Parameter
.
deserialize
(
par
,
submapping
)]
parameters
+=
[
Parameter
.
deserialize
(
par
,
submapping
)]
else
:
else
:
parameters
+=
[
Parameter
.
deserialize
(
par
)]
parameters
+=
[
Parameter
.
deserialize
(
par
)]
...
@@ -248,7 +307,7 @@ class Component(Element):
...
@@ -248,7 +307,7 @@ class Component(Element):
functions
=
[]
functions
=
[]
for
func
in
dictionary
[
'
functions
'
]:
for
func
in
dictionary
[
'
functions
'
]:
if
mapping
is
not
None
:
if
mapping
is
not
None
:
submapping
=
mapping
[
func
[
"
uuid
"
]]
if
func
[
'
uuid
'
]
in
mapping
else
None
submapping
=
mapping
[
func
[
'
uuid
'
]]
if
func
[
'
uuid
'
]
in
mapping
else
None
functions
+=
[
Function
.
deserialize
(
func
,
submapping
)]
functions
+=
[
Function
.
deserialize
(
func
,
submapping
)]
else
:
else
:
functions
+=
[
Function
.
deserialize
(
func
)]
functions
+=
[
Function
.
deserialize
(
func
)]
...
@@ -258,7 +317,7 @@ class Component(Element):
...
@@ -258,7 +317,7 @@ class Component(Element):
components
=
[]
components
=
[]
for
obj
in
dictionary
[
'
components
'
]:
for
obj
in
dictionary
[
'
components
'
]:
if
mapping
is
not
None
:
if
mapping
is
not
None
:
submapping
=
mapping
[
obj
[
"
uuid
"
]]
if
obj
[
'
uuid
'
]
in
mapping
else
None
submapping
=
mapping
[
obj
[
'
uuid
'
]]
if
obj
[
'
uuid
'
]
in
mapping
else
None
components
+=
[
Component
.
deserialize
(
obj
,
submapping
,
filepath
)]
components
+=
[
Component
.
deserialize
(
obj
,
submapping
,
filepath
)]
else
:
else
:
components
+=
[
Component
.
deserialize
(
obj
,
filepath
=
filepath
)]
components
+=
[
Component
.
deserialize
(
obj
,
filepath
=
filepath
)]
...
@@ -272,12 +331,12 @@ class Component(Element):
...
@@ -272,12 +331,12 @@ class Component(Element):
raise
SerialisationException
(
'
{}: The component can not be deserialized. {}
'
.
format
(
uuid
,
e
))
raise
SerialisationException
(
'
{}: The component can not be deserialized. {}
'
.
format
(
uuid
,
e
))
def
write
(
self
,
filename
:
str
):
def
write
(
self
,
filename
:
str
):
if
filename
[
-
5
:]
!=
"
.json
"
:
if
filename
[
-
5
:]
!=
'
.json
'
:
raise
Exception
(
'
{} is not a json file!
'
.
format
(
filename
))
raise
Exception
(
'
{} is not a json file!
'
.
format
(
filename
))
model_dict
=
self
.
serialize
([
'
all
'
])
model_dict
=
self
.
serialize
([
'
all
'
])
f
=
open
(
filename
,
"
w
"
)
f
=
open
(
filename
,
'
w
'
)
f
.
write
(
json
.
dumps
(
model_dict
))
f
.
write
(
json
.
dumps
(
model_dict
))
f
.
close
()
f
.
close
()
...
@@ -289,7 +348,7 @@ class Component(Element):
...
@@ -289,7 +348,7 @@ class Component(Element):
return
return
# self._components.append(element)
# self._components.append(element)
else
:
else
:
raise
Exception
(
"
Wrong type updating element on existing model!
"
)
raise
Exception
(
'
Wrong type updating element on existing model!
'
)
def
add
(
self
,
uuid
:
str
,
class_name
:
str
,
json_file
:
str
,
*
args
,
**
kwargs
):
def
add
(
self
,
uuid
:
str
,
class_name
:
str
,
json_file
:
str
,
*
args
,
**
kwargs
):
if
uuid
[:
3
]
==
'
COM
'
:
if
uuid
[:
3
]
==
'
COM
'
:
...
@@ -325,7 +384,7 @@ class Component(Element):
...
@@ -325,7 +384,7 @@ class Component(Element):
if
isinstance
(
file
,
str
):
if
isinstance
(
file
,
str
):
if
not
os
.
path
.
isfile
(
file
):
if
not
os
.
path
.
isfile
(
file
):
raise
Exception
(
'
There is no file named {}!
'
.
format
(
file
))
raise
Exception
(
'
There is no file named {}!
'
.
format
(
file
))
if
file
[
-
5
:]
!=
"
.json
"
:
if
file
[
-
5
:]
!=
'
.json
'
:
raise
Exception
(
'
{} is not a json file!
'
.
format
(
file
))
raise
Exception
(
'
{} is not a json file!
'
.
format
(
file
))
with
open
(
file
,
'
r
'
)
as
f
:
with
open
(
file
,
'
r
'
)
as
f
:
model_dict
=
json
.
load
(
f
)
model_dict
=
json
.
load
(
f
)
...
...
This diff is collapsed.
Click to expand it.
src/soil/error.py
+
5
−
0
View file @
ecd0e780
...
@@ -18,6 +18,11 @@ class DimensionException(DeviceException):
...
@@ -18,6 +18,11 @@ class DimensionException(DeviceException):
def
__init__
(
self
,
description
):
def
__init__
(
self
,
description
):
BasicException
.
__init__
(
self
,
description
)
BasicException
.
__init__
(
self
,
description
)
class
ChildNotFound
(
UserException
):
def
__init__
(
self
,
description
):
UserException
.
__init__
(
self
,
description
)
class
ChildNotFoundException
(
DeviceException
):
class
ChildNotFoundException
(
DeviceException
):
...
...
This diff is collapsed.
Click to expand it.
Preview
0%
Loading
Try again
or
attach a new file
.
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Save comment
Cancel
Please
register
or
sign in
to comment