fameio 2.3.0__py3-none-any.whl → 3.0.0__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- CHANGELOG.md +28 -0
- fameio/__init__.py +4 -1
- fameio/{source/cli → cli}/__init__.py +2 -0
- fameio/{source/cli → cli}/convert_results.py +8 -8
- fameio/{source/cli → cli}/make_config.py +5 -5
- fameio/{source/cli → cli}/options.py +0 -8
- fameio/{source/cli → cli}/parser.py +26 -63
- fameio/input/__init__.py +27 -0
- fameio/input/loader/__init__.py +68 -0
- fameio/input/loader/controller.py +129 -0
- fameio/input/loader/loader.py +109 -0
- fameio/input/metadata.py +149 -0
- fameio/input/resolver.py +44 -0
- fameio/{source → input}/scenario/__init__.py +1 -2
- fameio/{source → input}/scenario/agent.py +24 -38
- fameio/input/scenario/attribute.py +203 -0
- fameio/{source → input}/scenario/contract.py +50 -61
- fameio/{source → input}/scenario/exception.py +8 -13
- fameio/{source → input}/scenario/fameiofactory.py +6 -6
- fameio/{source → input}/scenario/generalproperties.py +22 -47
- fameio/{source → input}/scenario/scenario.py +34 -31
- fameio/input/scenario/stringset.py +48 -0
- fameio/{source → input}/schema/__init__.py +2 -2
- fameio/input/schema/agenttype.py +125 -0
- fameio/input/schema/attribute.py +268 -0
- fameio/{source → input}/schema/java_packages.py +26 -22
- fameio/{source → input}/schema/schema.py +25 -22
- fameio/{source → input}/validator.py +32 -35
- fameio/{source → input}/writer.py +86 -86
- fameio/{source/logs.py → logs.py} +25 -9
- fameio/{source/results → output}/agent_type.py +21 -22
- fameio/{source/results → output}/conversion.py +34 -31
- fameio/{source/results → output}/csv_writer.py +7 -7
- fameio/{source/results → output}/data_transformer.py +24 -24
- fameio/{source/results → output}/input_dao.py +51 -49
- fameio/{source/results → output}/output_dao.py +16 -17
- fameio/{source/results → output}/reader.py +30 -31
- fameio/{source/results → output}/yaml_writer.py +2 -3
- fameio/scripts/__init__.py +2 -2
- fameio/scripts/convert_results.py +16 -15
- fameio/scripts/make_config.py +9 -9
- fameio/{source/series.py → series.py} +28 -26
- fameio/{source/time.py → time.py} +8 -8
- fameio/{source/tools.py → tools.py} +2 -2
- {fameio-2.3.0.dist-info → fameio-3.0.0.dist-info}/METADATA +277 -72
- fameio-3.0.0.dist-info/RECORD +56 -0
- fameio/source/__init__.py +0 -8
- fameio/source/loader.py +0 -181
- fameio/source/metadata.py +0 -32
- fameio/source/path_resolver.py +0 -34
- fameio/source/scenario/attribute.py +0 -130
- fameio/source/scenario/stringset.py +0 -51
- fameio/source/schema/agenttype.py +0 -132
- fameio/source/schema/attribute.py +0 -203
- fameio/source/schema/exception.py +0 -9
- fameio-2.3.0.dist-info/RECORD +0 -55
- /fameio/{source/results → output}/__init__.py +0 -0
- {fameio-2.3.0.dist-info → fameio-3.0.0.dist-info}/LICENSE.txt +0 -0
- {fameio-2.3.0.dist-info → fameio-3.0.0.dist-info}/LICENSES/Apache-2.0.txt +0 -0
- {fameio-2.3.0.dist-info → fameio-3.0.0.dist-info}/LICENSES/CC-BY-4.0.txt +0 -0
- {fameio-2.3.0.dist-info → fameio-3.0.0.dist-info}/LICENSES/CC0-1.0.txt +0 -0
- {fameio-2.3.0.dist-info → fameio-3.0.0.dist-info}/WHEEL +0 -0
- {fameio-2.3.0.dist-info → fameio-3.0.0.dist-info}/entry_points.txt +0 -0
@@ -3,26 +3,26 @@
|
|
3
3
|
# SPDX-License-Identifier: Apache-2.0
|
4
4
|
from __future__ import annotations
|
5
5
|
|
6
|
-
from typing import Any,
|
6
|
+
from typing import Any, Optional, Final
|
7
7
|
|
8
|
-
from fameio.
|
9
|
-
from fameio.
|
10
|
-
from fameio.
|
11
|
-
from fameio.
|
12
|
-
from
|
8
|
+
from fameio.input.metadata import Metadata
|
9
|
+
from fameio.logs import log
|
10
|
+
from fameio.time import FameTime
|
11
|
+
from fameio.tools import ensure_is_list, keys_to_lower
|
12
|
+
from .attribute import Attribute
|
13
|
+
from .exception import get_or_default, get_or_raise, log_and_raise
|
13
14
|
|
14
15
|
|
15
|
-
class Contract:
|
16
|
+
class Contract(Metadata):
|
16
17
|
"""Contract between two Agents of a scenario"""
|
17
18
|
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
_KEY_ATTRIBUTES = "Attributes".lower()
|
19
|
+
KEY_SENDER: Final[str] = "SenderId".lower()
|
20
|
+
KEY_RECEIVER: Final[str] = "ReceiverId".lower()
|
21
|
+
KEY_PRODUCT: Final[str] = "ProductName".lower()
|
22
|
+
KEY_FIRST_DELIVERY: Final[str] = "FirstDeliveryTime".lower()
|
23
|
+
KEY_INTERVAL: Final[str] = "DeliveryIntervalInSteps".lower()
|
24
|
+
KEY_EXPIRE: Final[str] = "ExpirationTime".lower()
|
25
|
+
KEY_ATTRIBUTES: Final[str] = "Attributes".lower()
|
26
26
|
|
27
27
|
_ERR_MISSING_KEY = "Contract requires key '{}' but is missing it."
|
28
28
|
_ERR_MULTI_CONTRACT_CORRUPT = (
|
@@ -42,9 +42,10 @@ class Contract:
|
|
42
42
|
delivery_interval: int,
|
43
43
|
first_delivery_time: int,
|
44
44
|
expiration_time: Optional[int] = None,
|
45
|
-
|
45
|
+
metadata: Optional[dict] = None,
|
46
46
|
) -> None:
|
47
47
|
"""Constructs a new Contract"""
|
48
|
+
super().__init__({self.KEY_METADATA: metadata} if metadata else None)
|
48
49
|
assert product_name != ""
|
49
50
|
if sender_id == receiver_id:
|
50
51
|
log().warning(self._ERR_SENDER_IS_RECEIVER.format(sender_id))
|
@@ -56,7 +57,6 @@ class Contract:
|
|
56
57
|
self._delivery_interval = delivery_interval
|
57
58
|
self._first_delivery_time = first_delivery_time
|
58
59
|
self._expiration_time = expiration_time
|
59
|
-
self._meta_data = meta_data
|
60
60
|
self._attributes = {}
|
61
61
|
|
62
62
|
def _notify_data_changed(self):
|
@@ -104,12 +104,7 @@ class Contract:
|
|
104
104
|
return self._expiration_time
|
105
105
|
|
106
106
|
@property
|
107
|
-
def
|
108
|
-
"""Returns the metadata of the contract if available, None otherwise"""
|
109
|
-
return self._meta_data
|
110
|
-
|
111
|
-
@property
|
112
|
-
def attributes(self) -> Dict[str, Attribute]:
|
107
|
+
def attributes(self) -> dict[str, Attribute]:
|
113
108
|
"""Returns dictionary of all Attributes of the contract"""
|
114
109
|
return self._attributes
|
115
110
|
|
@@ -124,30 +119,30 @@ class Contract:
|
|
124
119
|
def from_dict(cls, definitions: dict) -> Contract:
|
125
120
|
"""Parses Contract from given `definitions`"""
|
126
121
|
definitions = keys_to_lower(definitions)
|
127
|
-
sender_id = get_or_raise(definitions, Contract.
|
128
|
-
receiver_id = get_or_raise(definitions, Contract.
|
129
|
-
product_name = get_or_raise(definitions, Contract.
|
122
|
+
sender_id = get_or_raise(definitions, Contract.KEY_SENDER, Contract._ERR_MISSING_KEY)
|
123
|
+
receiver_id = get_or_raise(definitions, Contract.KEY_RECEIVER, Contract._ERR_MISSING_KEY)
|
124
|
+
product_name = get_or_raise(definitions, Contract.KEY_PRODUCT, Contract._ERR_MISSING_KEY)
|
130
125
|
first_delivery_time = FameTime.convert_string_if_is_datetime(
|
131
|
-
get_or_raise(definitions, Contract.
|
126
|
+
get_or_raise(definitions, Contract.KEY_FIRST_DELIVERY, Contract._ERR_MISSING_KEY)
|
132
127
|
)
|
133
|
-
delivery_interval = get_or_raise(definitions, Contract.
|
134
|
-
expiration_time = get_or_default(definitions, Contract.
|
128
|
+
delivery_interval = get_or_raise(definitions, Contract.KEY_INTERVAL, Contract._ERR_MISSING_KEY)
|
129
|
+
expiration_time = get_or_default(definitions, Contract.KEY_EXPIRE, None)
|
135
130
|
expiration_time = FameTime.convert_string_if_is_datetime(expiration_time) if expiration_time else None
|
136
|
-
|
137
|
-
|
131
|
+
|
132
|
+
contract = cls(
|
138
133
|
sender_id,
|
139
134
|
receiver_id,
|
140
135
|
product_name,
|
141
136
|
delivery_interval,
|
142
137
|
first_delivery_time,
|
143
138
|
expiration_time,
|
144
|
-
meta_data,
|
145
139
|
)
|
146
|
-
|
147
|
-
|
148
|
-
|
140
|
+
contract._extract_metadata(definitions)
|
141
|
+
attribute_definitions = get_or_default(definitions, Contract.KEY_ATTRIBUTES, {})
|
142
|
+
contract._init_attributes_from_dict(attribute_definitions)
|
143
|
+
return contract
|
149
144
|
|
150
|
-
def _init_attributes_from_dict(self, attributes:
|
145
|
+
def _init_attributes_from_dict(self, attributes: dict[str, Any]) -> None:
|
151
146
|
"""Resets Contract `attributes` from dict; Must only be called when creating a new Contract"""
|
152
147
|
assert len(self._attributes) == 0
|
153
148
|
self._attributes = {}
|
@@ -155,47 +150,41 @@ class Contract:
|
|
155
150
|
full_name = f"{type}.{id}{name}"
|
156
151
|
self.add_attribute(name, Attribute(full_name, value))
|
157
152
|
|
158
|
-
def
|
153
|
+
def _to_dict(self) -> dict:
|
159
154
|
"""Serializes the Contract content to a dict"""
|
160
155
|
result = {
|
161
|
-
self.
|
162
|
-
self.
|
163
|
-
self.
|
164
|
-
self.
|
165
|
-
self.
|
156
|
+
self.KEY_SENDER: self.sender_id,
|
157
|
+
self.KEY_RECEIVER: self.receiver_id,
|
158
|
+
self.KEY_PRODUCT: self.product_name,
|
159
|
+
self.KEY_FIRST_DELIVERY: self.first_delivery_time,
|
160
|
+
self.KEY_INTERVAL: self.delivery_interval,
|
166
161
|
}
|
167
162
|
|
168
163
|
if self.expiration_time is not None:
|
169
|
-
result[self.
|
164
|
+
result[self.KEY_EXPIRE] = self.expiration_time
|
170
165
|
|
171
166
|
if len(self.attributes) > 0:
|
172
|
-
|
173
|
-
for attr_name, attr_value in self.attributes.items():
|
174
|
-
attributes_dict[attr_name] = attr_value.generic_content
|
175
|
-
result[self._KEY_ATTRIBUTES] = attributes_dict
|
176
|
-
if self.meta_data:
|
177
|
-
result[self._KEY_METADATA] = self._meta_data
|
178
|
-
|
167
|
+
result[self.KEY_ATTRIBUTES] = {name: value.to_dict() for name, value in self.attributes.items()}
|
179
168
|
return result
|
180
169
|
|
181
170
|
@staticmethod
|
182
|
-
def split_contract_definitions(multi_definition: dict) ->
|
171
|
+
def split_contract_definitions(multi_definition: dict) -> list[dict]:
|
183
172
|
"""Splits given `multi_definition` dictionary into list of individual Contract definitions"""
|
184
173
|
contracts = []
|
185
174
|
base_data = {}
|
186
175
|
multi_definition = keys_to_lower(multi_definition)
|
187
176
|
for key in [
|
188
|
-
Contract.
|
189
|
-
Contract.
|
190
|
-
Contract.
|
191
|
-
Contract.
|
192
|
-
Contract.
|
193
|
-
Contract.
|
177
|
+
Contract.KEY_PRODUCT,
|
178
|
+
Contract.KEY_FIRST_DELIVERY,
|
179
|
+
Contract.KEY_INTERVAL,
|
180
|
+
Contract.KEY_EXPIRE,
|
181
|
+
Contract.KEY_METADATA,
|
182
|
+
Contract.KEY_ATTRIBUTES,
|
194
183
|
]:
|
195
184
|
if key in multi_definition:
|
196
185
|
base_data[key] = multi_definition[key]
|
197
|
-
senders = ensure_is_list(get_or_raise(multi_definition, Contract.
|
198
|
-
receivers = ensure_is_list(get_or_raise(multi_definition, Contract.
|
186
|
+
senders = ensure_is_list(get_or_raise(multi_definition, Contract.KEY_SENDER, Contract._ERR_MISSING_KEY))
|
187
|
+
receivers = ensure_is_list(get_or_raise(multi_definition, Contract.KEY_RECEIVER, Contract._ERR_MISSING_KEY))
|
199
188
|
if len(senders) > 1 and len(receivers) == 1:
|
200
189
|
for index in range(len(senders)):
|
201
190
|
contracts.append(Contract._copy_contract(senders[index], receivers[0], base_data))
|
@@ -213,8 +202,8 @@ class Contract:
|
|
213
202
|
def _copy_contract(sender: int, receiver: int, base_data: dict) -> dict:
|
214
203
|
"""Returns a new contract definition dictionary, with given `sender` and `receiver` and copied `base_data`"""
|
215
204
|
contract = {
|
216
|
-
Contract.
|
217
|
-
Contract.
|
205
|
+
Contract.KEY_SENDER: sender,
|
206
|
+
Contract.KEY_RECEIVER: receiver,
|
218
207
|
}
|
219
208
|
contract.update(base_data)
|
220
209
|
return contract
|
@@ -1,31 +1,32 @@
|
|
1
|
-
# SPDX-FileCopyrightText:
|
1
|
+
# SPDX-FileCopyrightText: 2024 German Aerospace Center <fame@dlr.de>
|
2
2
|
#
|
3
3
|
# SPDX-License-Identifier: Apache-2.0
|
4
4
|
|
5
5
|
from typing import NoReturn, Any, Union
|
6
6
|
|
7
|
-
from fameio.
|
7
|
+
from fameio.input import ScenarioError
|
8
|
+
from fameio.logs import log_error_and_raise, log
|
8
9
|
|
9
10
|
_DEFAULT_USED = "Using default value '{}' for missing key '{}'"
|
10
11
|
|
11
12
|
|
12
13
|
def log_and_raise(message: str) -> NoReturn:
|
13
|
-
"""Raises
|
14
|
-
log_error_and_raise(
|
14
|
+
"""Raises ScenarioError with given `message`"""
|
15
|
+
log_error_and_raise(ScenarioError(message))
|
15
16
|
|
16
17
|
|
17
18
|
def get_or_raise(dictionary: dict, key: str, message: str) -> Union[Any, NoReturn]:
|
18
19
|
"""Returns value associated with `key` in given `dictionary`, or raises ScenarioException if key is missing"""
|
19
20
|
if key not in dictionary or dictionary[key] is None:
|
20
|
-
log_error_and_raise(
|
21
|
+
log_error_and_raise(ScenarioError(message.format(key)))
|
21
22
|
else:
|
22
23
|
return dictionary[key]
|
23
24
|
|
24
25
|
|
25
26
|
def assert_or_raise(assertion: bool, msg: str) -> None:
|
26
|
-
"""Raises new
|
27
|
+
"""Raises new ScenarioError with given `msg` if `assertion` is False"""
|
27
28
|
if not assertion:
|
28
|
-
log_error_and_raise(
|
29
|
+
log_error_and_raise(ScenarioError(msg))
|
29
30
|
|
30
31
|
|
31
32
|
def get_or_default(dictionary: dict, key: str, default_value) -> Any:
|
@@ -35,9 +36,3 @@ def get_or_default(dictionary: dict, key: str, default_value) -> Any:
|
|
35
36
|
else:
|
36
37
|
log().debug(_DEFAULT_USED.format(default_value, key))
|
37
38
|
return default_value
|
38
|
-
|
39
|
-
|
40
|
-
class ScenarioException(Exception):
|
41
|
-
"""Indicates an error while parsing a scenario or one of its components"""
|
42
|
-
|
43
|
-
pass
|
@@ -1,11 +1,11 @@
|
|
1
|
-
# SPDX-FileCopyrightText:
|
1
|
+
# SPDX-FileCopyrightText: 2024 German Aerospace Center <fame@dlr.de>
|
2
2
|
#
|
3
3
|
# SPDX-License-Identifier: Apache-2.0
|
4
|
-
from fameio.
|
5
|
-
from
|
6
|
-
from
|
7
|
-
from
|
8
|
-
from
|
4
|
+
from fameio.input.schema import Schema
|
5
|
+
from .agent import Agent
|
6
|
+
from .contract import Contract
|
7
|
+
from .generalproperties import GeneralProperties
|
8
|
+
from .stringset import StringSet
|
9
9
|
|
10
10
|
|
11
11
|
class FameIOFactory:
|
@@ -3,27 +3,25 @@
|
|
3
3
|
# SPDX-License-Identifier: Apache-2.0
|
4
4
|
from __future__ import annotations
|
5
5
|
|
6
|
-
from
|
7
|
-
|
8
|
-
from fameio.
|
9
|
-
from fameio.
|
6
|
+
from typing import Final
|
7
|
+
|
8
|
+
from fameio.logs import log
|
9
|
+
from fameio.time import FameTime
|
10
|
+
from fameio.tools import keys_to_lower
|
11
|
+
from .exception import get_or_default, get_or_raise
|
10
12
|
|
11
13
|
|
12
14
|
class GeneralProperties:
|
13
15
|
"""Hosts general properties of a scenario"""
|
14
16
|
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
_KEY_OUTPUT = "Output".lower()
|
21
|
-
_KEY_INTERVAL = "Interval".lower()
|
22
|
-
_KEY_PROCESS = "Process".lower()
|
17
|
+
KEY_RUN: Final[str] = "RunId".lower()
|
18
|
+
KEY_SIMULATION = "Simulation".lower()
|
19
|
+
KEY_START = "StartTime".lower()
|
20
|
+
KEY_STOP = "StopTime".lower()
|
21
|
+
KEY_SEED = "RandomSeed".lower()
|
23
22
|
|
24
23
|
_ERR_MISSING_KEY = "General Properties requires key '{}' but it is missing."
|
25
24
|
_ERR_SIMULATION_DURATION = "Simulation starts after its end time - check start and stop times."
|
26
|
-
_WARN_OUTPUT_DEPRECATED = "Deprecation warning: GeneralProperties.Output will be removed with FAME-Io version > 3.0"
|
27
25
|
|
28
26
|
def __init__(
|
29
27
|
self,
|
@@ -31,8 +29,6 @@ class GeneralProperties:
|
|
31
29
|
simulation_start_time: int,
|
32
30
|
simulation_stop_time: int,
|
33
31
|
simulation_random_seed: int,
|
34
|
-
output_interval: int,
|
35
|
-
output_process: int,
|
36
32
|
) -> None:
|
37
33
|
if simulation_stop_time < simulation_start_time:
|
38
34
|
log().warning(GeneralProperties._ERR_SIMULATION_DURATION)
|
@@ -40,57 +36,46 @@ class GeneralProperties:
|
|
40
36
|
self._simulation_start_time = simulation_start_time
|
41
37
|
self._simulation_stop_time = simulation_stop_time
|
42
38
|
self._simulation_random_seed = simulation_random_seed
|
43
|
-
self._output_interval = output_interval
|
44
|
-
self._output_process = output_process
|
45
39
|
|
46
40
|
@classmethod
|
47
41
|
def from_dict(cls, definitions: dict) -> GeneralProperties:
|
48
42
|
"""Parse general properties from provided `definitions`"""
|
49
43
|
definitions = keys_to_lower(definitions)
|
50
|
-
run_id = get_or_default(definitions, GeneralProperties.
|
44
|
+
run_id = get_or_default(definitions, GeneralProperties.KEY_RUN, 1)
|
51
45
|
|
52
46
|
simulation_definition = keys_to_lower(
|
53
47
|
get_or_raise(
|
54
48
|
definitions,
|
55
|
-
GeneralProperties.
|
49
|
+
GeneralProperties.KEY_SIMULATION,
|
56
50
|
GeneralProperties._ERR_MISSING_KEY,
|
57
51
|
)
|
58
52
|
)
|
59
53
|
start_time = FameTime.convert_string_if_is_datetime(
|
60
54
|
get_or_raise(
|
61
55
|
simulation_definition,
|
62
|
-
GeneralProperties.
|
56
|
+
GeneralProperties.KEY_START,
|
63
57
|
GeneralProperties._ERR_MISSING_KEY,
|
64
58
|
)
|
65
59
|
)
|
66
60
|
stop_time = FameTime.convert_string_if_is_datetime(
|
67
61
|
get_or_raise(
|
68
62
|
simulation_definition,
|
69
|
-
GeneralProperties.
|
63
|
+
GeneralProperties.KEY_STOP,
|
70
64
|
GeneralProperties._ERR_MISSING_KEY,
|
71
65
|
)
|
72
66
|
)
|
73
|
-
random_seed = get_or_default(simulation_definition, GeneralProperties.
|
74
|
-
|
75
|
-
output_definitions = keys_to_lower(get_or_default(definitions, GeneralProperties._KEY_OUTPUT, dict()))
|
76
|
-
if len(output_definitions) > 1:
|
77
|
-
log().warning(GeneralProperties._WARN_OUTPUT_DEPRECATED)
|
78
|
-
output_interval = get_or_default(output_definitions, GeneralProperties._KEY_INTERVAL, 100)
|
79
|
-
output_process = get_or_default(output_definitions, GeneralProperties._KEY_PROCESS, 0)
|
80
|
-
|
81
|
-
return cls(run_id, start_time, stop_time, random_seed, output_interval, output_process)
|
67
|
+
random_seed = get_or_default(simulation_definition, GeneralProperties.KEY_SEED, 1)
|
68
|
+
return cls(run_id, start_time, stop_time, random_seed)
|
82
69
|
|
83
70
|
def to_dict(self) -> dict:
|
84
71
|
"""Serializes the general properties to a dict"""
|
85
|
-
result = {self.
|
72
|
+
result = {self.KEY_RUN: self._run_id}
|
86
73
|
simulation_dict = {
|
87
|
-
self.
|
88
|
-
self.
|
89
|
-
self.
|
74
|
+
self.KEY_START: self.simulation_start_time,
|
75
|
+
self.KEY_STOP: self.simulation_stop_time,
|
76
|
+
self.KEY_SEED: self.simulation_random_seed,
|
90
77
|
}
|
91
|
-
result[self.
|
92
|
-
output_dict = {self._KEY_INTERVAL: self.output_interval, self._KEY_PROCESS: self.output_process}
|
93
|
-
result[self._KEY_OUTPUT] = output_dict
|
78
|
+
result[self.KEY_SIMULATION] = simulation_dict
|
94
79
|
return result
|
95
80
|
|
96
81
|
@property
|
@@ -112,13 +97,3 @@ class GeneralProperties:
|
|
112
97
|
def simulation_random_seed(self) -> int:
|
113
98
|
"""Returns the simulation random seed"""
|
114
99
|
return self._simulation_random_seed
|
115
|
-
|
116
|
-
@property
|
117
|
-
def output_interval(self) -> int:
|
118
|
-
"""Returns the output interval"""
|
119
|
-
return self._output_interval
|
120
|
-
|
121
|
-
@property
|
122
|
-
def output_process(self) -> int:
|
123
|
-
"""Returns the output process"""
|
124
|
-
return self._output_process
|
@@ -3,30 +3,32 @@
|
|
3
3
|
# SPDX-License-Identifier: Apache-2.0
|
4
4
|
from __future__ import annotations
|
5
5
|
|
6
|
-
from typing import
|
6
|
+
from typing import Final
|
7
7
|
|
8
|
-
from fameio.
|
9
|
-
from fameio.
|
10
|
-
from fameio.
|
11
|
-
from
|
12
|
-
from
|
13
|
-
from
|
14
|
-
from
|
15
|
-
from
|
8
|
+
from fameio.input.metadata import Metadata
|
9
|
+
from fameio.input.schema import Schema
|
10
|
+
from fameio.tools import keys_to_lower
|
11
|
+
from .agent import Agent
|
12
|
+
from .contract import Contract
|
13
|
+
from .exception import get_or_default, get_or_raise
|
14
|
+
from .fameiofactory import FameIOFactory
|
15
|
+
from .generalproperties import GeneralProperties
|
16
|
+
from .stringset import StringSet
|
16
17
|
|
17
18
|
|
18
|
-
class Scenario:
|
19
|
+
class Scenario(Metadata):
|
19
20
|
"""Definition of a scenario"""
|
20
21
|
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
22
|
+
KEY_SCHEMA: Final[str] = "Schema".lower()
|
23
|
+
KEY_GENERAL: Final[str] = "GeneralProperties".lower()
|
24
|
+
KEY_AGENTS: Final[str] = "Agents".lower()
|
25
|
+
KEY_CONTRACTS: Final[str] = "Contracts".lower()
|
26
|
+
KEY_STRING_SETS: Final[str] = "StringSets".lower()
|
26
27
|
|
27
28
|
_MISSING_KEY = "Scenario definition misses required key '{}'."
|
28
29
|
|
29
30
|
def __init__(self, schema: Schema, general_props: GeneralProperties) -> None:
|
31
|
+
super().__init__()
|
30
32
|
self._schema = schema
|
31
33
|
self._general_props = general_props
|
32
34
|
self._string_sets = {}
|
@@ -38,46 +40,47 @@ class Scenario:
|
|
38
40
|
"""Parse scenario from provided `definitions` using given `factory`"""
|
39
41
|
definitions = keys_to_lower(definitions)
|
40
42
|
|
41
|
-
schema = factory.new_schema_from_dict(get_or_raise(definitions, Scenario.
|
43
|
+
schema = factory.new_schema_from_dict(get_or_raise(definitions, Scenario.KEY_SCHEMA, Scenario._MISSING_KEY))
|
42
44
|
general_props = factory.new_general_properties_from_dict(
|
43
|
-
get_or_raise(definitions, Scenario.
|
45
|
+
get_or_raise(definitions, Scenario.KEY_GENERAL, Scenario._MISSING_KEY)
|
44
46
|
)
|
45
47
|
scenario = cls(schema, general_props)
|
48
|
+
scenario._extract_metadata(definitions)
|
46
49
|
|
47
|
-
for name, string_set_definition in get_or_default(definitions, Scenario.
|
50
|
+
for name, string_set_definition in get_or_default(definitions, Scenario.KEY_STRING_SETS, {}).items():
|
48
51
|
scenario.add_string_set(name, factory.new_string_set_from_dict(string_set_definition))
|
49
52
|
|
50
|
-
for agent_definition in get_or_default(definitions, Scenario.
|
53
|
+
for agent_definition in get_or_default(definitions, Scenario.KEY_AGENTS, []):
|
51
54
|
scenario.add_agent(factory.new_agent_from_dict(agent_definition))
|
52
55
|
|
53
|
-
for multi_contract_definition in get_or_default(definitions, Scenario.
|
56
|
+
for multi_contract_definition in get_or_default(definitions, Scenario.KEY_CONTRACTS, []):
|
54
57
|
for single_contract_definition in Contract.split_contract_definitions(multi_contract_definition):
|
55
58
|
scenario.add_contract(factory.new_contract_from_dict(single_contract_definition))
|
56
59
|
|
57
60
|
return scenario
|
58
61
|
|
59
|
-
def
|
62
|
+
def _to_dict(self) -> dict:
|
60
63
|
"""Serializes the scenario content to a dict"""
|
61
64
|
result = {
|
62
|
-
Scenario.
|
63
|
-
Scenario.
|
65
|
+
Scenario.KEY_GENERAL: self.general_properties.to_dict(),
|
66
|
+
Scenario.KEY_SCHEMA: self.schema.to_dict(),
|
64
67
|
}
|
65
68
|
if self.string_sets:
|
66
|
-
result[Scenario.
|
69
|
+
result[Scenario.KEY_STRING_SETS] = {
|
67
70
|
name: string_set.to_dict() for name, string_set in self.string_sets.items()
|
68
71
|
}
|
69
72
|
if self.agents:
|
70
|
-
result[Scenario.
|
73
|
+
result[Scenario.KEY_AGENTS] = []
|
71
74
|
for agent in self.agents:
|
72
|
-
result[Scenario.
|
75
|
+
result[Scenario.KEY_AGENTS].append(agent.to_dict())
|
73
76
|
if self.contracts:
|
74
|
-
result[Scenario.
|
77
|
+
result[Scenario.KEY_CONTRACTS] = []
|
75
78
|
for contract in self.contracts:
|
76
|
-
result[Scenario.
|
79
|
+
result[Scenario.KEY_CONTRACTS].append(contract.to_dict())
|
77
80
|
return result
|
78
81
|
|
79
82
|
@property
|
80
|
-
def agents(self) ->
|
83
|
+
def agents(self) -> list[Agent]:
|
81
84
|
"""Returns all the agents of this scenario as a list"""
|
82
85
|
return self._agents
|
83
86
|
|
@@ -86,7 +89,7 @@ class Scenario:
|
|
86
89
|
self._agents.append(agent)
|
87
90
|
|
88
91
|
@property
|
89
|
-
def contracts(self) ->
|
92
|
+
def contracts(self) -> list[Contract]:
|
90
93
|
"""Returns all the contracts of this scenario as a list"""
|
91
94
|
return self._contracts
|
92
95
|
|
@@ -105,7 +108,7 @@ class Scenario:
|
|
105
108
|
return self._general_props
|
106
109
|
|
107
110
|
@property
|
108
|
-
def string_sets(self) ->
|
111
|
+
def string_sets(self) -> dict[str, StringSet]:
|
109
112
|
"""Returns StringSets of this scenario"""
|
110
113
|
return self._string_sets
|
111
114
|
|
@@ -0,0 +1,48 @@
|
|
1
|
+
# SPDX-FileCopyrightText: 2024 German Aerospace Center <fame@dlr.de>
|
2
|
+
#
|
3
|
+
# SPDX-License-Identifier: Apache-2.0
|
4
|
+
from __future__ import annotations
|
5
|
+
|
6
|
+
from typing import Union, Final
|
7
|
+
|
8
|
+
from fameio.input.metadata import Metadata, MetadataComponent, ValueContainer
|
9
|
+
from fameio.tools import keys_to_lower
|
10
|
+
from .exception import log_and_raise
|
11
|
+
|
12
|
+
|
13
|
+
class StringSet(Metadata):
|
14
|
+
"""Hosts a StringSet in the given format"""
|
15
|
+
|
16
|
+
KEY_VALUES: Final[str] = "Values".lower()
|
17
|
+
|
18
|
+
ValueType = Union[list[str], dict[str, dict]]
|
19
|
+
StringSetType = dict[str, Union[dict, ValueType]]
|
20
|
+
|
21
|
+
_ERR_KEY_MISSING = "Missing mandatory key '{}' in StringSet definition {}."
|
22
|
+
|
23
|
+
def __init__(self, definitions=None):
|
24
|
+
super().__init__(definitions)
|
25
|
+
self._value_container: ValueContainer = ValueContainer(definitions)
|
26
|
+
|
27
|
+
@classmethod
|
28
|
+
def from_dict(cls, definition: StringSetType) -> StringSet:
|
29
|
+
"""Returns StringSet initialised from `definition`"""
|
30
|
+
string_set = cls(definition)
|
31
|
+
definition = keys_to_lower(definition)
|
32
|
+
if cls.KEY_VALUES in definition:
|
33
|
+
string_set._value_container = ValueContainer(definition[cls.KEY_VALUES])
|
34
|
+
else:
|
35
|
+
log_and_raise(cls._ERR_KEY_MISSING.format(cls.KEY_VALUES, definition))
|
36
|
+
return string_set
|
37
|
+
|
38
|
+
def _to_dict(self) -> dict[str, dict[str, dict[str, dict[str, dict]]]]:
|
39
|
+
return {self.KEY_VALUES: self._value_container.to_dict()}
|
40
|
+
|
41
|
+
@property
|
42
|
+
def values(self) -> dict[str, MetadataComponent]:
|
43
|
+
"""Returns values and their associated MetadataComponent"""
|
44
|
+
return self._value_container.values
|
45
|
+
|
46
|
+
def is_in_set(self, key: str) -> bool:
|
47
|
+
"""Returns True if `key` is a valid name in this StringSet"""
|
48
|
+
return self._value_container.has_value(key)
|
@@ -1,8 +1,8 @@
|
|
1
|
-
# SPDX-FileCopyrightText:
|
1
|
+
# SPDX-FileCopyrightText: 2024 German Aerospace Center <fame@dlr.de>
|
2
2
|
#
|
3
3
|
# SPDX-License-Identifier: Apache-2.0
|
4
4
|
|
5
5
|
from .agenttype import AgentType
|
6
6
|
from .attribute import AttributeSpecs, AttributeType
|
7
|
-
from .
|
7
|
+
from .java_packages import JavaPackages
|
8
8
|
from .schema import Schema
|