fameio 3.1.1__py3-none-any.whl → 3.3.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.
- fameio/cli/convert_results.py +10 -10
- fameio/cli/make_config.py +9 -9
- fameio/cli/options.py +6 -4
- fameio/cli/parser.py +87 -51
- fameio/cli/reformat.py +58 -0
- fameio/input/__init__.py +4 -4
- fameio/input/loader/__init__.py +13 -13
- fameio/input/loader/controller.py +64 -18
- fameio/input/loader/loader.py +25 -16
- fameio/input/metadata.py +57 -38
- fameio/input/resolver.py +9 -10
- fameio/input/scenario/agent.py +62 -26
- fameio/input/scenario/attribute.py +93 -40
- fameio/input/scenario/contract.py +160 -56
- fameio/input/scenario/exception.py +41 -18
- fameio/input/scenario/fameiofactory.py +57 -6
- fameio/input/scenario/generalproperties.py +22 -12
- fameio/input/scenario/scenario.py +117 -38
- fameio/input/scenario/stringset.py +29 -11
- fameio/input/schema/agenttype.py +27 -10
- fameio/input/schema/attribute.py +108 -45
- fameio/input/schema/java_packages.py +14 -12
- fameio/input/schema/schema.py +39 -15
- fameio/input/validator.py +198 -54
- fameio/input/writer.py +137 -46
- fameio/logs.py +28 -47
- fameio/output/__init__.py +5 -1
- fameio/output/agent_type.py +89 -28
- fameio/output/conversion.py +52 -37
- fameio/output/csv_writer.py +107 -27
- fameio/output/data_transformer.py +17 -24
- fameio/output/execution_dao.py +170 -0
- fameio/output/input_dao.py +71 -33
- fameio/output/output_dao.py +33 -11
- fameio/output/reader.py +64 -21
- fameio/output/yaml_writer.py +16 -8
- fameio/scripts/__init__.py +22 -4
- fameio/scripts/convert_results.py +126 -52
- fameio/scripts/convert_results.py.license +1 -1
- fameio/scripts/exception.py +7 -0
- fameio/scripts/make_config.py +34 -13
- fameio/scripts/make_config.py.license +1 -1
- fameio/scripts/reformat.py +71 -0
- fameio/scripts/reformat.py.license +3 -0
- fameio/series.py +174 -59
- fameio/time.py +79 -25
- fameio/tools.py +48 -8
- {fameio-3.1.1.dist-info → fameio-3.3.0.dist-info}/METADATA +50 -34
- fameio-3.3.0.dist-info/RECORD +60 -0
- {fameio-3.1.1.dist-info → fameio-3.3.0.dist-info}/WHEEL +1 -1
- {fameio-3.1.1.dist-info → fameio-3.3.0.dist-info}/entry_points.txt +1 -0
- CHANGELOG.md +0 -288
- fameio-3.1.1.dist-info/RECORD +0 -56
- {fameio-3.1.1.dist-info → fameio-3.3.0.dist-info}/LICENSE.txt +0 -0
- {fameio-3.1.1.dist-info → fameio-3.3.0.dist-info}/LICENSES/Apache-2.0.txt +0 -0
- {fameio-3.1.1.dist-info → fameio-3.3.0.dist-info}/LICENSES/CC-BY-4.0.txt +0 -0
- {fameio-3.1.1.dist-info → fameio-3.3.0.dist-info}/LICENSES/CC0-1.0.txt +0 -0
@@ -1,35 +1,58 @@
|
|
1
1
|
# SPDX-FileCopyrightText: 2025 German Aerospace Center <fame@dlr.de>
|
2
2
|
#
|
3
3
|
# SPDX-License-Identifier: Apache-2.0
|
4
|
-
from
|
4
|
+
from __future__ import annotations
|
5
|
+
|
6
|
+
from typing import Any
|
5
7
|
|
6
8
|
from fameio.input import ScenarioError
|
7
|
-
from fameio.logs import log_error
|
9
|
+
from fameio.logs import log_error
|
8
10
|
|
9
11
|
_DEFAULT_USED = "Using default value '{}' for missing key '{}'"
|
10
12
|
|
11
13
|
|
12
|
-
def
|
13
|
-
"""
|
14
|
-
|
14
|
+
def log_scenario_error(message: str) -> ScenarioError:
|
15
|
+
"""Creates exception with given `message`, logs it on level "Error" and returns it.
|
16
|
+
|
17
|
+
Args:
|
18
|
+
message: to be logged and included in the exception if key is missing
|
19
|
+
|
20
|
+
Returns:
|
21
|
+
created ScenarioError, logged on level "ERROR"
|
22
|
+
"""
|
23
|
+
error = ScenarioError(message)
|
24
|
+
log_error(error)
|
25
|
+
return error
|
26
|
+
|
15
27
|
|
28
|
+
def get_or_raise(dictionary: dict, key: str, error_message: str) -> Any:
|
29
|
+
"""Returns value associated with `key` in given `dictionary`, or raises exception if key or value is missing.
|
16
30
|
|
17
|
-
|
18
|
-
|
31
|
+
Args:
|
32
|
+
dictionary: to search the key in
|
33
|
+
key: to be searched
|
34
|
+
error_message: to be logged and included in the raised exception if key is missing
|
35
|
+
|
36
|
+
Returns:
|
37
|
+
value associated with given key in given dictionary
|
38
|
+
|
39
|
+
Raises:
|
40
|
+
ScenarioError: if given key is not in given dictionary or value is None, logged on level "ERROR"
|
41
|
+
"""
|
19
42
|
if key not in dictionary or dictionary[key] is None:
|
20
|
-
raise
|
43
|
+
raise log_scenario_error(error_message.format(key))
|
21
44
|
return dictionary[key]
|
22
45
|
|
23
46
|
|
24
|
-
def assert_or_raise(assertion: bool,
|
25
|
-
"""Raises
|
26
|
-
if not assertion:
|
27
|
-
raise log_error(ScenarioError(msg))
|
47
|
+
def assert_or_raise(assertion: bool, error_message: str) -> None:
|
48
|
+
"""Raises exception with given `error_message` if `assertion` is False.
|
28
49
|
|
50
|
+
Args:
|
51
|
+
assertion: expression that must be True, else an exception is raised
|
52
|
+
error_message: to be logged and included in the raised exception if key is missing
|
29
53
|
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
return default_value
|
54
|
+
Raises:
|
55
|
+
ScenarioError: if assertion is False, logged on level "ERROR"
|
56
|
+
"""
|
57
|
+
if not assertion:
|
58
|
+
raise log_scenario_error(error_message)
|
@@ -1,4 +1,4 @@
|
|
1
|
-
# SPDX-FileCopyrightText:
|
1
|
+
# SPDX-FileCopyrightText: 2025 German Aerospace Center <fame@dlr.de>
|
2
2
|
#
|
3
3
|
# SPDX-License-Identifier: Apache-2.0
|
4
4
|
from fameio.input.schema import Schema
|
@@ -10,30 +10,81 @@ from .stringset import StringSet
|
|
10
10
|
|
11
11
|
class FameIOFactory:
|
12
12
|
"""Factory used to instantiate the types defined in a scenario file.
|
13
|
+
|
13
14
|
This allows a client to subclass some types in order to extend what a scenario can contain.
|
14
15
|
"""
|
15
16
|
|
16
17
|
@staticmethod
|
17
18
|
def new_schema_from_dict(definitions: dict) -> Schema:
|
18
|
-
"""
|
19
|
+
"""Loads given dictionary `definitions` into a new schema.
|
20
|
+
|
21
|
+
Args:
|
22
|
+
definitions: dictionary representation of schema
|
23
|
+
|
24
|
+
Returns:
|
25
|
+
new Schema
|
26
|
+
|
27
|
+
Raises:
|
28
|
+
SchemaError: if definitions are incomplete or erroneous, logged on level "ERROR"
|
29
|
+
"""
|
19
30
|
return Schema.from_dict(definitions)
|
20
31
|
|
21
32
|
@staticmethod
|
22
33
|
def new_general_properties_from_dict(definitions: dict) -> GeneralProperties:
|
23
|
-
"""
|
34
|
+
"""Parses general properties from provided `definitions`.
|
35
|
+
|
36
|
+
Args:
|
37
|
+
definitions: dictionary representation of general properties
|
38
|
+
|
39
|
+
Returns:
|
40
|
+
new GeneralProperties
|
41
|
+
|
42
|
+
Raises:
|
43
|
+
ScenarioError: if definitions are incomplete or erroneous, logged on level "ERROR"
|
44
|
+
"""
|
24
45
|
return GeneralProperties.from_dict(definitions)
|
25
46
|
|
26
47
|
@staticmethod
|
27
48
|
def new_agent_from_dict(definitions: dict) -> Agent:
|
28
|
-
"""
|
49
|
+
"""Parses an agent from provided `definitions`.
|
50
|
+
|
51
|
+
Args:
|
52
|
+
definitions: dictionary representation of an agent
|
53
|
+
|
54
|
+
Returns:
|
55
|
+
new agent
|
56
|
+
|
57
|
+
Raises:
|
58
|
+
ScenarioError: if definitions are incomplete or erroneous, logged on level "ERROR"
|
59
|
+
"""
|
29
60
|
return Agent.from_dict(definitions)
|
30
61
|
|
31
62
|
@staticmethod
|
32
63
|
def new_contract_from_dict(definitions: dict) -> Contract:
|
33
|
-
"""
|
64
|
+
"""Parses contract from given `definitions`.
|
65
|
+
|
66
|
+
Args:
|
67
|
+
definitions: dictionary representation of a contract
|
68
|
+
|
69
|
+
Returns:
|
70
|
+
new contract
|
71
|
+
|
72
|
+
Raises:
|
73
|
+
ContractError: if definitions are incomplete or erroneous, logged on level "ERROR"
|
74
|
+
"""
|
34
75
|
return Contract.from_dict(definitions)
|
35
76
|
|
36
77
|
@staticmethod
|
37
78
|
def new_string_set_from_dict(definition: StringSet.StringSetType) -> StringSet:
|
38
|
-
"""
|
79
|
+
"""Returns string set initialised from `definition`.
|
80
|
+
|
81
|
+
Args:
|
82
|
+
definition: dictionary representation of string set
|
83
|
+
|
84
|
+
Returns:
|
85
|
+
new string set
|
86
|
+
|
87
|
+
Raises:
|
88
|
+
StringSetError: if definitions are incomplete or erroneous, logged on level "ERROR"
|
89
|
+
"""
|
39
90
|
return StringSet.from_dict(definition)
|
@@ -1,4 +1,4 @@
|
|
1
|
-
# SPDX-FileCopyrightText:
|
1
|
+
# SPDX-FileCopyrightText: 2025 German Aerospace Center <fame@dlr.de>
|
2
2
|
#
|
3
3
|
# SPDX-License-Identifier: Apache-2.0
|
4
4
|
from __future__ import annotations
|
@@ -8,11 +8,11 @@ from typing import Final
|
|
8
8
|
from fameio.logs import log
|
9
9
|
from fameio.time import FameTime
|
10
10
|
from fameio.tools import keys_to_lower
|
11
|
-
from .exception import
|
11
|
+
from .exception import get_or_raise
|
12
12
|
|
13
13
|
|
14
14
|
class GeneralProperties:
|
15
|
-
"""Hosts general properties of a scenario"""
|
15
|
+
"""Hosts general properties of a scenario."""
|
16
16
|
|
17
17
|
KEY_RUN: Final[str] = "RunId".lower()
|
18
18
|
KEY_SIMULATION = "Simulation".lower()
|
@@ -39,9 +39,19 @@ class GeneralProperties:
|
|
39
39
|
|
40
40
|
@classmethod
|
41
41
|
def from_dict(cls, definitions: dict) -> GeneralProperties:
|
42
|
-
"""
|
42
|
+
"""Parses general properties from provided `definitions`.
|
43
|
+
|
44
|
+
Args:
|
45
|
+
definitions: dictionary representation of general properties
|
46
|
+
|
47
|
+
Returns:
|
48
|
+
new GeneralProperties
|
49
|
+
|
50
|
+
Raises:
|
51
|
+
ScenarioError: if definitions are incomplete or erroneous, logged on level "ERROR"
|
52
|
+
"""
|
43
53
|
definitions = keys_to_lower(definitions)
|
44
|
-
run_id =
|
54
|
+
run_id = definitions.get(GeneralProperties.KEY_RUN, 1)
|
45
55
|
|
46
56
|
simulation_definition = keys_to_lower(
|
47
57
|
get_or_raise(
|
@@ -64,12 +74,12 @@ class GeneralProperties:
|
|
64
74
|
GeneralProperties._ERR_MISSING_KEY,
|
65
75
|
)
|
66
76
|
)
|
67
|
-
random_seed =
|
77
|
+
random_seed = simulation_definition.get(GeneralProperties.KEY_SEED, 1)
|
68
78
|
return cls(run_id, start_time, stop_time, random_seed)
|
69
79
|
|
70
80
|
def to_dict(self) -> dict:
|
71
|
-
"""Serializes the general properties to a dict"""
|
72
|
-
result = {self.KEY_RUN: self._run_id}
|
81
|
+
"""Serializes the general properties to a dict."""
|
82
|
+
result: dict = {self.KEY_RUN: self._run_id}
|
73
83
|
simulation_dict = {
|
74
84
|
self.KEY_START: self.simulation_start_time,
|
75
85
|
self.KEY_STOP: self.simulation_stop_time,
|
@@ -80,20 +90,20 @@ class GeneralProperties:
|
|
80
90
|
|
81
91
|
@property
|
82
92
|
def run_id(self) -> int:
|
83
|
-
"""Returns the run ID"""
|
93
|
+
"""Returns the run ID."""
|
84
94
|
return self._run_id
|
85
95
|
|
86
96
|
@property
|
87
97
|
def simulation_start_time(self) -> int:
|
88
|
-
"""Returns the simulation start time"""
|
98
|
+
"""Returns the simulation start time."""
|
89
99
|
return self._simulation_start_time
|
90
100
|
|
91
101
|
@property
|
92
102
|
def simulation_stop_time(self) -> int:
|
93
|
-
"""Returns the simulation stop time"""
|
103
|
+
"""Returns the simulation stop time."""
|
94
104
|
return self._simulation_stop_time
|
95
105
|
|
96
106
|
@property
|
97
107
|
def simulation_random_seed(self) -> int:
|
98
|
-
"""Returns the simulation random seed"""
|
108
|
+
"""Returns the simulation random seed."""
|
99
109
|
return self._simulation_random_seed
|
@@ -1,23 +1,24 @@
|
|
1
|
-
# SPDX-FileCopyrightText:
|
1
|
+
# SPDX-FileCopyrightText: 2025 German Aerospace Center <fame@dlr.de>
|
2
2
|
#
|
3
3
|
# SPDX-License-Identifier: Apache-2.0
|
4
4
|
from __future__ import annotations
|
5
5
|
|
6
|
-
from typing import Final
|
6
|
+
from typing import Final, Any
|
7
7
|
|
8
|
+
from fameio.input import SchemaError
|
8
9
|
from fameio.input.metadata import Metadata
|
10
|
+
from fameio.input.scenario.agent import Agent
|
11
|
+
from fameio.input.scenario.contract import Contract
|
12
|
+
from fameio.input.scenario.exception import get_or_raise, log_scenario_error
|
13
|
+
from fameio.input.scenario.fameiofactory import FameIOFactory
|
14
|
+
from fameio.input.scenario.generalproperties import GeneralProperties
|
15
|
+
from fameio.input.scenario.stringset import StringSet
|
9
16
|
from fameio.input.schema import Schema
|
10
17
|
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
|
17
18
|
|
18
19
|
|
19
20
|
class Scenario(Metadata):
|
20
|
-
"""Definition of a scenario"""
|
21
|
+
"""Definition of a scenario."""
|
21
22
|
|
22
23
|
KEY_SCHEMA: Final[str] = "Schema".lower()
|
23
24
|
KEY_GENERAL: Final[str] = "GeneralProperties".lower()
|
@@ -26,42 +27,120 @@ class Scenario(Metadata):
|
|
26
27
|
KEY_STRING_SETS: Final[str] = "StringSets".lower()
|
27
28
|
|
28
29
|
_MISSING_KEY = "Scenario definition misses required key '{}'."
|
30
|
+
_ERR_SCHEMA = "Could not create scenario: Definition of Schema has errors."
|
31
|
+
_ERR_STRING_SET = "Could not create scenario: Definition of StringSet '{}' has errors."
|
32
|
+
_ERR_MULTI_CONTRACT = "Could not create scenario: Definition of Contracts has errors: {}"
|
33
|
+
_ERR_CONTRACT = "Could not create scenario: Definition of Contract has errors: {}"
|
29
34
|
|
30
35
|
def __init__(self, schema: Schema, general_props: GeneralProperties) -> None:
|
31
36
|
super().__init__()
|
32
37
|
self._schema = schema
|
33
38
|
self._general_props = general_props
|
34
|
-
self._string_sets = {}
|
35
|
-
self._agents = []
|
36
|
-
self._contracts = []
|
39
|
+
self._string_sets: dict[str, StringSet] = {}
|
40
|
+
self._agents: list[Agent] = []
|
41
|
+
self._contracts: list[Contract] = []
|
37
42
|
|
38
43
|
@classmethod
|
39
|
-
def from_dict(cls, definitions: dict, factory=FameIOFactory()) -> Scenario:
|
40
|
-
"""
|
41
|
-
definitions = keys_to_lower(definitions)
|
44
|
+
def from_dict(cls, definitions: dict, factory: FameIOFactory = FameIOFactory()) -> Scenario:
|
45
|
+
"""Parses scenario from provided `definitions` using given `factory`.
|
42
46
|
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
)
|
47
|
-
scenario = cls(schema, general_props)
|
48
|
-
scenario._extract_metadata(definitions)
|
47
|
+
Args:
|
48
|
+
definitions: dictionary representation of scenario
|
49
|
+
factory: helper class with static helpers to instantiate scenario components
|
49
50
|
|
50
|
-
|
51
|
-
|
51
|
+
Returns:
|
52
|
+
new Scenario
|
52
53
|
|
53
|
-
|
54
|
-
scenario
|
54
|
+
Raises:
|
55
|
+
ScenarioError: if scenario definitions are incomplete or erroneous, logged with level "ERROR"
|
56
|
+
"""
|
57
|
+
definitions = keys_to_lower(definitions)
|
55
58
|
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
+
schema = Scenario._extract_schema(definitions, factory)
|
60
|
+
general_properties_definition = get_or_raise(definitions, Scenario.KEY_GENERAL, Scenario._MISSING_KEY)
|
61
|
+
general_properties = factory.new_general_properties_from_dict(general_properties_definition)
|
62
|
+
scenario = cls(schema, general_properties)
|
63
|
+
scenario._extract_metadata(definitions)
|
59
64
|
|
65
|
+
scenario._string_sets = Scenario._extract_string_sets(definitions, factory)
|
66
|
+
scenario._agents = [
|
67
|
+
factory.new_agent_from_dict(agent_definition)
|
68
|
+
for agent_definition in definitions.get(Scenario.KEY_AGENTS, [])
|
69
|
+
]
|
70
|
+
scenario._contracts = Scenario._extract_contracts(definitions, factory)
|
60
71
|
return scenario
|
61
72
|
|
73
|
+
@staticmethod
|
74
|
+
def _extract_schema(definitions: dict, factory: FameIOFactory) -> Schema:
|
75
|
+
"""Extracts schema from given definitions and creates Schema from it.
|
76
|
+
|
77
|
+
Args:
|
78
|
+
definitions: dictionary representation of scenario
|
79
|
+
factory: helper class with static helpers to instantiate scenario components
|
80
|
+
|
81
|
+
Returns:
|
82
|
+
new schema
|
83
|
+
|
84
|
+
Raises:
|
85
|
+
ScenarioError: if schema definitions are missing, incomplete, or erroneous; logged on level "ERROR"
|
86
|
+
"""
|
87
|
+
schema_definition = get_or_raise(definitions, Scenario.KEY_SCHEMA, Scenario._MISSING_KEY)
|
88
|
+
try:
|
89
|
+
return factory.new_schema_from_dict(schema_definition)
|
90
|
+
except SchemaError as e:
|
91
|
+
raise log_scenario_error(Scenario._ERR_SCHEMA) from e
|
92
|
+
|
93
|
+
@staticmethod
|
94
|
+
def _extract_string_sets(definitions: dict, factory: FameIOFactory) -> dict[str, StringSet]:
|
95
|
+
"""Extracts string sets from given definitions and creates dictionary from it.
|
96
|
+
|
97
|
+
Args:
|
98
|
+
definitions: dictionary representation of scenario
|
99
|
+
factory: helper class with static helpers to instantiate scenario components
|
100
|
+
|
101
|
+
Returns:
|
102
|
+
dictionary of string set names associated with their corresponding string set
|
103
|
+
|
104
|
+
Raises:
|
105
|
+
ScenarioError: if string set definitions are incomplete or erroneous; logged on level "ERROR"
|
106
|
+
"""
|
107
|
+
string_sets = {}
|
108
|
+
for name, string_set_definition in definitions.get(Scenario.KEY_STRING_SETS, {}).items():
|
109
|
+
try:
|
110
|
+
string_sets[name] = factory.new_string_set_from_dict(string_set_definition)
|
111
|
+
except StringSet.StringSetError as e:
|
112
|
+
raise log_scenario_error(Scenario._ERR_STRING_SET.format(name)) from e
|
113
|
+
return string_sets
|
114
|
+
|
115
|
+
@staticmethod
|
116
|
+
def _extract_contracts(definitions: dict, factory: FameIOFactory) -> list[Contract]:
|
117
|
+
"""Extracts contracts from given definitions.
|
118
|
+
|
119
|
+
Args:
|
120
|
+
definitions: dictionary representation of scenario
|
121
|
+
factory: helper class with static helpers to instantiate scenario components
|
122
|
+
|
123
|
+
Returns:
|
124
|
+
list of all created one-to-one contracts
|
125
|
+
|
126
|
+
Raises:
|
127
|
+
ScenarioError: if contract definitions are incomplete or erroneous; logged on level "ERROR"
|
128
|
+
"""
|
129
|
+
contracts = []
|
130
|
+
for multi_contract_definition in definitions.get(Scenario.KEY_CONTRACTS, []):
|
131
|
+
try:
|
132
|
+
for single_contract_definition in Contract.split_contract_definitions(multi_contract_definition):
|
133
|
+
try:
|
134
|
+
contracts.append(factory.new_contract_from_dict(single_contract_definition))
|
135
|
+
except Contract.ContractError as e:
|
136
|
+
raise log_scenario_error(Scenario._ERR_CONTRACT.format(single_contract_definition)) from e
|
137
|
+
except Contract.ContractError as e:
|
138
|
+
raise log_scenario_error(Scenario._ERR_MULTI_CONTRACT.format(multi_contract_definition)) from e
|
139
|
+
return contracts
|
140
|
+
|
62
141
|
def _to_dict(self) -> dict:
|
63
|
-
"""Serializes the scenario content to a dict"""
|
64
|
-
result = {
|
142
|
+
"""Serializes the scenario content to a dict."""
|
143
|
+
result: dict[str, Any] = {
|
65
144
|
Scenario.KEY_GENERAL: self.general_properties.to_dict(),
|
66
145
|
Scenario.KEY_SCHEMA: self.schema.to_dict(),
|
67
146
|
}
|
@@ -81,37 +160,37 @@ class Scenario(Metadata):
|
|
81
160
|
|
82
161
|
@property
|
83
162
|
def agents(self) -> list[Agent]:
|
84
|
-
"""Returns all the agents of this scenario as a list"""
|
163
|
+
"""Returns all the agents of this scenario as a list."""
|
85
164
|
return self._agents
|
86
165
|
|
87
166
|
def add_agent(self, agent: Agent) -> None:
|
88
|
-
"""Adds a new agent to this scenario"""
|
167
|
+
"""Adds a new agent to this scenario."""
|
89
168
|
self._agents.append(agent)
|
90
169
|
|
91
170
|
@property
|
92
171
|
def contracts(self) -> list[Contract]:
|
93
|
-
"""Returns all the contracts of this scenario as a list"""
|
172
|
+
"""Returns all the contracts of this scenario as a list."""
|
94
173
|
return self._contracts
|
95
174
|
|
96
175
|
def add_contract(self, contract: Contract) -> None:
|
97
|
-
"""Adds a new contract to this scenario"""
|
176
|
+
"""Adds a new contract to this scenario."""
|
98
177
|
self._contracts.append(contract)
|
99
178
|
|
100
179
|
@property
|
101
180
|
def schema(self) -> Schema:
|
102
|
-
"""Returns Schema associated with this scenario"""
|
181
|
+
"""Returns Schema associated with this scenario."""
|
103
182
|
return self._schema
|
104
183
|
|
105
184
|
@property
|
106
185
|
def general_properties(self) -> GeneralProperties:
|
107
|
-
"""Returns General properties of this scenario"""
|
186
|
+
"""Returns General properties of this scenario."""
|
108
187
|
return self._general_props
|
109
188
|
|
110
189
|
@property
|
111
190
|
def string_sets(self) -> dict[str, StringSet]:
|
112
|
-
"""Returns StringSets of this scenario"""
|
191
|
+
"""Returns StringSets of this scenario."""
|
113
192
|
return self._string_sets
|
114
193
|
|
115
194
|
def add_string_set(self, name: str, string_set: StringSet) -> None:
|
116
|
-
"""Adds `string_set` with `name
|
195
|
+
"""Adds `string_set` with `name`."""
|
117
196
|
self._string_sets[name] = string_set
|
@@ -1,17 +1,21 @@
|
|
1
|
-
# SPDX-FileCopyrightText:
|
1
|
+
# SPDX-FileCopyrightText: 2025 German Aerospace Center <fame@dlr.de>
|
2
2
|
#
|
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, Any, Union
|
7
7
|
|
8
|
+
from fameio.input import InputError
|
8
9
|
from fameio.input.metadata import Metadata, MetadataComponent, ValueContainer
|
10
|
+
from fameio.logs import log_error
|
9
11
|
from fameio.tools import keys_to_lower
|
10
|
-
from .exception import log_and_raise
|
11
12
|
|
12
13
|
|
13
14
|
class StringSet(Metadata):
|
14
|
-
"""Hosts a StringSet in the given format"""
|
15
|
+
"""Hosts a StringSet in the given format."""
|
16
|
+
|
17
|
+
class StringSetError(InputError):
|
18
|
+
"""An error that occurred while parsing a StringSet definition."""
|
15
19
|
|
16
20
|
KEY_VALUES: Final[str] = "Values".lower()
|
17
21
|
|
@@ -19,20 +23,34 @@ class StringSet(Metadata):
|
|
19
23
|
StringSetType = dict[str, Union[dict, ValueType]]
|
20
24
|
|
21
25
|
_ERR_KEY_MISSING = "Missing mandatory key '{}' in StringSet definition {}."
|
26
|
+
_ERR_VALUE_DEFINITION = "StringSet could not be parsed."
|
22
27
|
|
23
|
-
def __init__(self, definitions=None):
|
28
|
+
def __init__(self, definitions: dict[str, Any] | list[Any] | None = None):
|
24
29
|
super().__init__(definitions)
|
25
30
|
self._value_container: ValueContainer = ValueContainer(definitions)
|
26
31
|
|
27
32
|
@classmethod
|
28
33
|
def from_dict(cls, definition: StringSetType) -> StringSet:
|
29
|
-
"""Returns StringSet initialised from `definition
|
34
|
+
"""Returns StringSet initialised from `definition`.
|
35
|
+
|
36
|
+
Args:
|
37
|
+
definition: dictionary representation of string set
|
38
|
+
|
39
|
+
Returns:
|
40
|
+
new StringSet
|
41
|
+
|
42
|
+
Raises:
|
43
|
+
StringSetError: if definitions are incomplete or erroneous, logged on level "ERROR"
|
44
|
+
"""
|
30
45
|
string_set = cls(definition)
|
31
46
|
definition = keys_to_lower(definition)
|
32
47
|
if cls.KEY_VALUES in definition:
|
33
|
-
|
48
|
+
try:
|
49
|
+
string_set._value_container = ValueContainer(definition[cls.KEY_VALUES])
|
50
|
+
except ValueContainer.ParseError as e:
|
51
|
+
raise log_error(StringSet.StringSetError(StringSet._ERR_VALUE_DEFINITION)) from e
|
34
52
|
else:
|
35
|
-
|
53
|
+
raise log_error(StringSet.StringSetError(cls._ERR_KEY_MISSING.format(cls.KEY_VALUES, definition)))
|
36
54
|
return string_set
|
37
55
|
|
38
56
|
def _to_dict(self) -> dict[str, dict[str, dict[str, dict[str, dict]]]]:
|
@@ -40,9 +58,9 @@ class StringSet(Metadata):
|
|
40
58
|
|
41
59
|
@property
|
42
60
|
def values(self) -> dict[str, MetadataComponent]:
|
43
|
-
"""Returns values and their associated MetadataComponent"""
|
61
|
+
"""Returns values and their associated MetadataComponent."""
|
44
62
|
return self._value_container.values
|
45
63
|
|
46
|
-
def is_in_set(self, key:
|
47
|
-
"""Returns True if `key` is a valid name in this StringSet"""
|
64
|
+
def is_in_set(self, key: Any) -> bool:
|
65
|
+
"""Returns True if `key` is a valid name in this StringSet."""
|
48
66
|
return self._value_container.has_value(key)
|
fameio/input/schema/agenttype.py
CHANGED
@@ -13,7 +13,7 @@ from .attribute import AttributeSpecs
|
|
13
13
|
|
14
14
|
|
15
15
|
class AgentType(Metadata):
|
16
|
-
"""Schema definitions for an Agent type"""
|
16
|
+
"""Schema definitions for an Agent type."""
|
17
17
|
|
18
18
|
KEY_ATTRIBUTES: Final[str] = "Attributes".lower()
|
19
19
|
KEY_PRODUCTS: Final[str] = "Products".lower()
|
@@ -32,7 +32,10 @@ class AgentType(Metadata):
|
|
32
32
|
Initialise a new AgentType
|
33
33
|
|
34
34
|
Args:
|
35
|
-
name: name of the AgenType
|
35
|
+
name: name of the AgenType
|
36
|
+
|
37
|
+
Raises:
|
38
|
+
SchemaError: if name is None, empty, or only whitespaces, logged with level "ERROR"
|
36
39
|
"""
|
37
40
|
super().__init__()
|
38
41
|
if not name or name.isspace():
|
@@ -44,8 +47,7 @@ class AgentType(Metadata):
|
|
44
47
|
|
45
48
|
@classmethod
|
46
49
|
def from_dict(cls, name: str, definitions: dict) -> AgentType:
|
47
|
-
"""
|
48
|
-
Creates AgentType with given `name` from specified dictionary
|
50
|
+
"""Creates AgentType with given `name` from specified dictionary.
|
49
51
|
|
50
52
|
Args:
|
51
53
|
name: of the agent type
|
@@ -53,6 +55,9 @@ class AgentType(Metadata):
|
|
53
55
|
|
54
56
|
Returns:
|
55
57
|
a new instance of AgentType
|
58
|
+
|
59
|
+
Raises:
|
60
|
+
SchemaError: if definitions are invalid, logged with level "ERROR"
|
56
61
|
"""
|
57
62
|
agent_type = cls(name)
|
58
63
|
agent_type._extract_metadata(definitions)
|
@@ -83,7 +88,19 @@ class AgentType(Metadata):
|
|
83
88
|
|
84
89
|
@staticmethod
|
85
90
|
def _read_values(section: str, agent_type: str, values: Any) -> ValueContainer:
|
86
|
-
"""Returns ValueContainer for `section`
|
91
|
+
"""Returns ValueContainer for `section` in specifications of `agent_type` extracted from given `values`.
|
92
|
+
|
93
|
+
Args:
|
94
|
+
section: key of the section that contains the values
|
95
|
+
agent_type: name of the agent type that the values are associated with
|
96
|
+
values: list or dict with value definitions
|
97
|
+
|
98
|
+
Returns:
|
99
|
+
container for all the extracted values
|
100
|
+
|
101
|
+
Raises:
|
102
|
+
SchemaError: if the values are ill-formatted, logged with level "ERROR"
|
103
|
+
"""
|
87
104
|
try:
|
88
105
|
data = ValueContainer(values)
|
89
106
|
except InputError as e:
|
@@ -94,26 +111,26 @@ class AgentType(Metadata):
|
|
94
111
|
|
95
112
|
@property
|
96
113
|
def name(self) -> str:
|
97
|
-
"""Returns the agent type name"""
|
114
|
+
"""Returns the agent type name."""
|
98
115
|
return self._name
|
99
116
|
|
100
117
|
@property
|
101
118
|
def products(self) -> dict[str, MetadataComponent]:
|
102
|
-
"""Returns dict of products or an empty dict if no products are defined"""
|
119
|
+
"""Returns dict of products or an empty dict if no products are defined."""
|
103
120
|
return self._products.values
|
104
121
|
|
105
122
|
def get_product_names(self) -> list[str]:
|
106
|
-
"""Returns list of product names or an empty list if no products are defined"""
|
123
|
+
"""Returns list of product names or an empty list if no products are defined."""
|
107
124
|
return self._products.as_list()
|
108
125
|
|
109
126
|
@property
|
110
127
|
def attributes(self) -> dict[str, AttributeSpecs]:
|
111
|
-
"""Returns list of Attributes of this agent or an empty list if no attributes are defined"""
|
128
|
+
"""Returns list of Attributes of this agent or an empty list if no attributes are defined."""
|
112
129
|
return self._attributes
|
113
130
|
|
114
131
|
@property
|
115
132
|
def outputs(self) -> dict[str, MetadataComponent]:
|
116
|
-
"""Returns list of outputs or an empty list if no outputs are defined"""
|
133
|
+
"""Returns list of outputs or an empty list if no outputs are defined."""
|
117
134
|
return self._outputs.values
|
118
135
|
|
119
136
|
def _to_dict(self) -> dict:
|