fameio 3.0.0__py3-none-any.whl → 3.1.1__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 +18 -3
- fameio/cli/__init__.py +2 -3
- fameio/cli/options.py +3 -3
- fameio/cli/parser.py +3 -3
- fameio/input/__init__.py +0 -8
- fameio/input/loader/controller.py +5 -6
- fameio/input/metadata.py +4 -7
- fameio/input/scenario/__init__.py +7 -8
- fameio/input/scenario/agent.py +3 -4
- fameio/input/scenario/attribute.py +14 -14
- fameio/input/scenario/contract.py +9 -9
- fameio/input/scenario/exception.py +8 -11
- fameio/input/schema/__init__.py +5 -5
- fameio/input/schema/agenttype.py +8 -9
- fameio/input/schema/attribute.py +95 -74
- fameio/input/validator.py +46 -37
- fameio/input/writer.py +4 -6
- fameio/logs.py +37 -3
- fameio/output/agent_type.py +11 -8
- fameio/output/conversion.py +2 -2
- fameio/output/data_transformer.py +6 -8
- fameio/output/input_dao.py +7 -12
- fameio/output/reader.py +4 -6
- fameio/output/yaml_writer.py +3 -3
- fameio/scripts/convert_results.py +52 -33
- fameio/series.py +22 -23
- fameio/time.py +15 -21
- fameio/tools.py +2 -3
- {fameio-3.0.0.dist-info → fameio-3.1.1.dist-info}/METADATA +37 -29
- fameio-3.1.1.dist-info/RECORD +56 -0
- fameio-3.0.0.dist-info/RECORD +0 -56
- {fameio-3.0.0.dist-info → fameio-3.1.1.dist-info}/LICENSE.txt +0 -0
- {fameio-3.0.0.dist-info → fameio-3.1.1.dist-info}/LICENSES/Apache-2.0.txt +0 -0
- {fameio-3.0.0.dist-info → fameio-3.1.1.dist-info}/LICENSES/CC-BY-4.0.txt +0 -0
- {fameio-3.0.0.dist-info → fameio-3.1.1.dist-info}/LICENSES/CC0-1.0.txt +0 -0
- {fameio-3.0.0.dist-info → fameio-3.1.1.dist-info}/WHEEL +0 -0
- {fameio-3.0.0.dist-info → fameio-3.1.1.dist-info}/entry_points.txt +0 -0
CHANGELOG.md
CHANGED
@@ -1,14 +1,29 @@
|
|
1
|
-
<!-- SPDX-FileCopyrightText:
|
1
|
+
<!-- SPDX-FileCopyrightText: 2025 German Aerospace Center <fame@dlr.de>
|
2
2
|
|
3
3
|
SPDX-License-Identifier: CC0-1.0 -->
|
4
4
|
|
5
|
+
## [3.1.1](https://gitlab.com/fame-framework/fame-io/-/tags/v3.1.1) - 2025-03-21
|
6
|
+
### Added
|
7
|
+
- Add static code analysis to CI pipeline #231 (@dlr-cjs)
|
8
|
+
|
9
|
+
### Fixed
|
10
|
+
- Fixed unused default values for time series attributes #232 (@dlr_fn, @dlr-cjs)
|
11
|
+
- Fixed bugs identified by static code analysis #231 (@dlr-cjs)
|
12
|
+
- Fixed deprecated installation guide-line for testing fameio locally #231 (@dlr_fn)
|
13
|
+
|
14
|
+
## [3.1.0](https://gitlab.com/fame-framework/fame-io/-/tags/v3.1.0) - 2025-01-29
|
15
|
+
### Changed
|
16
|
+
- Speed up of `makeFameRunConfig` for large CSV files #229 (@dlr-cjs, dlr_fn)
|
17
|
+
- Improve testing of `tools.py` #227 (@dlr_fn)
|
18
|
+
- Reorganize badges in tabular representation in `README.md` #226 (@dlr-cjs, dlr_fn)
|
19
|
+
|
5
20
|
# Changelog
|
6
|
-
## [3.0.0](https://gitlab.com/fame-framework/fame-io/-/tags/v3.0.0) - 2024-02
|
21
|
+
## [3.0.0](https://gitlab.com/fame-framework/fame-io/-/tags/v3.0.0) - 2024-12-02
|
7
22
|
### Changed
|
8
23
|
- **Breaking**: Update to fameprotobuf v2.0.2 #208, #215 (@dlr-cjs)
|
9
24
|
- **Breaking**: Remove section `GeneralProperties.Output` in scenarios - any content there will be ignored #208 (@dlr-cjs)
|
10
25
|
- **Breaking**: Set section `JavaPackages` in schema to be mandatory #208 (@dlr-cjs)
|
11
|
-
- **Breaking**: Update header of protobuf files to "fameprotobufstreamfilev002 " - disable reading of old files #208, #214 (@dlr-cjs)
|
26
|
+
- **Breaking**: Update header of protobuf files to `"fameprotobufstreamfilev002 "` - disable reading of old files #208, #214 (@dlr-cjs)
|
12
27
|
- **Breaking**: Replace subparser from command-line argument `--time-merging` with a threefold argument #212 (@dlr-cjs)
|
13
28
|
- **Breaking**: Attribute names "value", "values", and "metadata" are now disallowed as they are reserved for the Metadata implementation #217 (@dlr-cjs)
|
14
29
|
- **Breaking**: Refactor package structure #137 (@dlr_fn, @dlr-cjs)
|
fameio/cli/__init__.py
CHANGED
@@ -1,5 +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
|
-
|
5
|
-
from fameio.cli.parser import update_default_config
|
4
|
+
from fameio.cli.parser import update_default_config # noqa: F401
|
fameio/cli/options.py
CHANGED
@@ -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
|
import argparse
|
@@ -12,8 +12,8 @@ class ParsableEnum(Enum):
|
|
12
12
|
def instantiate(cls, name: str) -> Enum:
|
13
13
|
try:
|
14
14
|
return cls[name]
|
15
|
-
except KeyError:
|
16
|
-
raise argparse.ArgumentTypeError(f"'{name}' is not a valid option")
|
15
|
+
except KeyError as e:
|
16
|
+
raise argparse.ArgumentTypeError(f"'{name}' is not a valid option") from e
|
17
17
|
|
18
18
|
def __str__(self):
|
19
19
|
return self.name
|
fameio/cli/parser.py
CHANGED
@@ -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
|
import copy
|
@@ -63,7 +63,7 @@ def add_output_argument(parser: ArgumentParser, default_value, help_text: str) -
|
|
63
63
|
|
64
64
|
def add_log_level_argument(parser: ArgumentParser, default_value: str) -> None:
|
65
65
|
"""Adds optional argument 'log' to given `parser`"""
|
66
|
-
help_text = "choose logging level (default: {})"
|
66
|
+
help_text = f"choose logging level (default: {default_value})"
|
67
67
|
# noinspection PyTypeChecker
|
68
68
|
parser.add_argument(
|
69
69
|
"-l",
|
@@ -139,7 +139,7 @@ def add_merge_time_argument(parser: ArgumentParser, defaults: Optional[list[int]
|
|
139
139
|
if (
|
140
140
|
not isinstance(defaults, list)
|
141
141
|
or len(defaults) not in [0, 3]
|
142
|
-
or not all(
|
142
|
+
or not all(isinstance(value, int) for value in defaults)
|
143
143
|
):
|
144
144
|
raise ArgumentTypeError(_ERR_INVALID_MERGING_DEFAULT.format(repr(defaults)))
|
145
145
|
|
fameio/input/__init__.py
CHANGED
@@ -6,22 +6,14 @@
|
|
6
6
|
class InputError(Exception):
|
7
7
|
"""An error that occurred while parsing any kind of input"""
|
8
8
|
|
9
|
-
pass
|
10
|
-
|
11
9
|
|
12
10
|
class SchemaError(InputError):
|
13
11
|
"""An error that occurred while parsing a Schema"""
|
14
12
|
|
15
|
-
pass
|
16
|
-
|
17
13
|
|
18
14
|
class ScenarioError(InputError):
|
19
15
|
"""An error that occurred while parsing a Scenario"""
|
20
16
|
|
21
|
-
pass
|
22
|
-
|
23
17
|
|
24
18
|
class YamlLoaderError(InputError):
|
25
19
|
"""An error that occurred while parsing a YAML file"""
|
26
|
-
|
27
|
-
pass
|
@@ -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 fnmatch import fnmatch
|
@@ -10,7 +10,7 @@ import yaml
|
|
10
10
|
from fameio.input import YamlLoaderError
|
11
11
|
from fameio.input.resolver import PathResolver
|
12
12
|
from fameio.input.loader.loader import FameYamlLoader
|
13
|
-
from fameio.logs import log,
|
13
|
+
from fameio.logs import log, log_critical
|
14
14
|
|
15
15
|
|
16
16
|
class LoaderController:
|
@@ -44,7 +44,7 @@ class LoaderController:
|
|
44
44
|
@staticmethod
|
45
45
|
def _spawn_loader_builder() -> Callable[[IO], FameYamlLoader]:
|
46
46
|
"""Returns a new Callable that instantiates a new FameYamlLoader with an IO-stream"""
|
47
|
-
return lambda stream: FameYamlLoader(stream)
|
47
|
+
return lambda stream: FameYamlLoader(stream) # pylint: disable=unnecessary-lambda
|
48
48
|
|
49
49
|
def include(self, loader: FameYamlLoader, include_args: yaml.Node) -> Any:
|
50
50
|
"""Returns content loaded from the specified `include_args`"""
|
@@ -100,7 +100,7 @@ class LoaderController:
|
|
100
100
|
if node:
|
101
101
|
if node not in data.keys():
|
102
102
|
message = LoaderController._ERR_NODE_MISSING.format(file_name, node_address, node)
|
103
|
-
|
103
|
+
raise log_critical(YamlLoaderError(message))
|
104
104
|
data = data[node]
|
105
105
|
log().debug(LoaderController._DEBUG_SEARCH_NODE.format(file_name, node_address))
|
106
106
|
return data
|
@@ -125,5 +125,4 @@ class LoaderController:
|
|
125
125
|
if isinstance(new_data, list) and isinstance(previous_data, list):
|
126
126
|
previous_data.extend(new_data)
|
127
127
|
return previous_data
|
128
|
-
|
129
|
-
log_critical_and_raise(YamlLoaderError(LoaderController._ERR_NOT_LIST))
|
128
|
+
raise log_critical(YamlLoaderError(LoaderController._ERR_NOT_LIST))
|
fameio/input/metadata.py
CHANGED
@@ -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 abc import ABC, abstractmethod
|
@@ -89,8 +89,6 @@ class ValueContainer:
|
|
89
89
|
class ParseError(InputError):
|
90
90
|
"""An error that occurred while parsing content for metadata-annotated simple values"""
|
91
91
|
|
92
|
-
pass
|
93
|
-
|
94
92
|
_ERR_VALUES_ILL_FORMATTED = "Only Lists and Dictionaries are supported here, but was: {}"
|
95
93
|
|
96
94
|
def __init__(self, definition: Union[dict[str, Any], list[Any]] = None) -> None:
|
@@ -102,12 +100,11 @@ class ValueContainer:
|
|
102
100
|
"""Returns value data (and optional metadata) extracted from given `definition`"""
|
103
101
|
if definition is None:
|
104
102
|
return {}
|
105
|
-
|
103
|
+
if isinstance(definition, dict):
|
106
104
|
return {key: MetadataComponent(key_definition) for key, key_definition in definition.items()}
|
107
|
-
|
105
|
+
if isinstance(definition, list):
|
108
106
|
return {key: MetadataComponent() for key in definition}
|
109
|
-
|
110
|
-
raise ValueContainer.ParseError(ValueContainer._ERR_VALUES_ILL_FORMATTED.format(repr(definition)))
|
107
|
+
raise ValueContainer.ParseError(ValueContainer._ERR_VALUES_ILL_FORMATTED.format(repr(definition)))
|
111
108
|
|
112
109
|
@property
|
113
110
|
def values(self) -> dict[str, MetadataComponent]:
|
@@ -1,10 +1,9 @@
|
|
1
|
-
# SPDX-FileCopyrightText:
|
1
|
+
# SPDX-FileCopyrightText: 2025 German Aerospace Center <fame@dlr.de>
|
2
2
|
#
|
3
3
|
# SPDX-License-Identifier: Apache-2.0
|
4
|
-
|
5
|
-
from .
|
6
|
-
from .
|
7
|
-
from .
|
8
|
-
from .
|
9
|
-
from .
|
10
|
-
from .stringset import StringSet
|
4
|
+
from .agent import Agent # noqa: F401
|
5
|
+
from .attribute import Attribute # noqa: F401
|
6
|
+
from .contract import Contract # noqa: F401
|
7
|
+
from .generalproperties import GeneralProperties # noqa: F401
|
8
|
+
from .scenario import Scenario # noqa: F401
|
9
|
+
from .stringset import StringSet # noqa: F401
|
fameio/input/scenario/agent.py
CHANGED
@@ -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
|
@@ -28,7 +28,7 @@ class Agent(Metadata):
|
|
28
28
|
def __init__(self, agent_id: int, type_name: str, metadata: dict = None) -> None:
|
29
29
|
"""Constructs a new Agent"""
|
30
30
|
super().__init__({Agent.KEY_METADATA: metadata} if metadata else None)
|
31
|
-
assert_or_raise(
|
31
|
+
assert_or_raise(isinstance(agent_id, int) and agent_id >= 0, self._ERR_MISSING_ID.format(agent_id))
|
32
32
|
assert_or_raise(bool(type_name and type_name.strip()), self._ERR_MISSING_TYPE)
|
33
33
|
self._id: int = agent_id
|
34
34
|
self._type_name: str = type_name.strip()
|
@@ -79,7 +79,6 @@ class Agent(Metadata):
|
|
79
79
|
|
80
80
|
def _notify_data_changed(self):
|
81
81
|
"""Placeholder method used to signal data changes to derived types"""
|
82
|
-
pass
|
83
82
|
|
84
83
|
@property
|
85
84
|
def id(self) -> int:
|
@@ -89,7 +88,7 @@ class Agent(Metadata):
|
|
89
88
|
@property
|
90
89
|
def display_id(self) -> str:
|
91
90
|
"""Returns the ID of the Agent as a string for display purposes"""
|
92
|
-
return "#{
|
91
|
+
return f"#{self._id}"
|
93
92
|
|
94
93
|
@property
|
95
94
|
def type_name(self) -> str:
|
@@ -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
|
@@ -81,26 +81,25 @@ class Attribute(Metadata):
|
|
81
81
|
if len(definitions) == 0:
|
82
82
|
log_and_raise(Attribute._ERR_LIST_EMPTY.format(name))
|
83
83
|
return Attribute._get_data_type_list(definitions)
|
84
|
-
|
84
|
+
if isinstance(definitions, dict):
|
85
85
|
if len(definitions) == 0:
|
86
86
|
log_and_raise(Attribute._ERR_DICT_EMPTY.format(name))
|
87
87
|
return Attribute._get_data_type_dict(definitions)
|
88
|
-
|
89
|
-
return Attribute.__DefinitionType.VALUE
|
88
|
+
return Attribute.__DefinitionType.VALUE
|
90
89
|
|
91
90
|
@staticmethod
|
92
91
|
def _get_data_type_list(definitions: list[Any]) -> Attribute.__DefinitionType:
|
93
92
|
"""Returns type of data from a given non-empty list `definitions`"""
|
94
|
-
if all(
|
93
|
+
if all(Attribute._is_value_definition(entry) for entry in definitions):
|
95
94
|
return Attribute.__DefinitionType.VALUE_LIST
|
96
|
-
|
95
|
+
if Attribute._is_list_of_dict(definitions):
|
97
96
|
return Attribute.__DefinitionType.NESTED_LIST
|
98
97
|
log_and_raise(Attribute._ERR_MIXED_DATA.format(repr(definitions)))
|
99
98
|
|
100
99
|
@staticmethod
|
101
100
|
def _is_list_of_dict(definitions: list) -> bool:
|
102
101
|
"""Returns True if given `definitions` is a list of (only) dict"""
|
103
|
-
return all(
|
102
|
+
return all(isinstance(entry, dict) for entry in definitions)
|
104
103
|
|
105
104
|
@staticmethod
|
106
105
|
def _get_data_type_dict(definitions: dict[str, Any]) -> Attribute.__DefinitionType:
|
@@ -108,11 +107,11 @@ class Attribute(Metadata):
|
|
108
107
|
low_keys = keys_to_lower(definitions)
|
109
108
|
if Attribute.KEY_VALUE in low_keys.keys():
|
110
109
|
return Attribute.__DefinitionType.VALUE
|
111
|
-
|
110
|
+
if Attribute.KEY_VALUES in low_keys.keys():
|
112
111
|
values = low_keys[Attribute.KEY_VALUES]
|
113
|
-
if all(
|
112
|
+
if all(Attribute._is_value_definition(entry) for entry in values):
|
114
113
|
return Attribute.__DefinitionType.VALUE_LIST
|
115
|
-
|
114
|
+
if Attribute._is_list_of_dict(values):
|
116
115
|
return Attribute.__DefinitionType.NESTED_LIST
|
117
116
|
log_and_raise(Attribute._ERR_MIXED_DATA.format(repr(values)))
|
118
117
|
return Attribute.__DefinitionType.NESTED
|
@@ -158,7 +157,7 @@ class Attribute(Metadata):
|
|
158
157
|
"""Returns value or list of values if available on this Attribute (ignoring any Metadata), else None"""
|
159
158
|
if self._value is not None:
|
160
159
|
return self._value
|
161
|
-
|
160
|
+
if self._value_list is not None:
|
162
161
|
return [item.value for item in self._value_list]
|
163
162
|
return None
|
164
163
|
|
@@ -188,16 +187,17 @@ class Attribute(Metadata):
|
|
188
187
|
def _to_dict(self) -> dict[str, Any]:
|
189
188
|
if self._value is not None:
|
190
189
|
return {self.KEY_VALUE: self._value}
|
191
|
-
|
190
|
+
if self._value_list is not None:
|
192
191
|
return {
|
193
192
|
self.KEY_VALUES: [{self.KEY_VALUE: entry.value, **entry.meta.to_dict()} for entry in self._value_list]
|
194
193
|
}
|
195
|
-
|
194
|
+
if self._nested is not None:
|
196
195
|
return {name: attribute.to_dict() for name, attribute in self.nested.items()}
|
197
|
-
|
196
|
+
if self._nested_list is not None:
|
198
197
|
return {
|
199
198
|
self.KEY_VALUES: [
|
200
199
|
{**{name: attribute.to_dict() for name, attribute in entry.value.items()}, **entry.meta.to_dict()}
|
201
200
|
for entry in self._nested_list
|
202
201
|
]
|
203
202
|
}
|
203
|
+
return {}
|
@@ -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
|
@@ -34,6 +34,7 @@ class Contract(Metadata):
|
|
34
34
|
_ERR_SENDER_IS_RECEIVER = "Contract sender and receiver have the same id: {}"
|
35
35
|
_ERR_DOUBLE_ATTRIBUTE = "Cannot add attribute '{}' to contract because it already exists."
|
36
36
|
|
37
|
+
# pylint: disable=too-many-arguments, too-many-positional-arguments
|
37
38
|
def __init__(
|
38
39
|
self,
|
39
40
|
sender_id: int,
|
@@ -61,7 +62,6 @@ class Contract(Metadata):
|
|
61
62
|
|
62
63
|
def _notify_data_changed(self):
|
63
64
|
"""Placeholder method used to signal data changes to derived types"""
|
64
|
-
pass
|
65
65
|
|
66
66
|
@property
|
67
67
|
def product_name(self) -> str:
|
@@ -76,7 +76,7 @@ class Contract(Metadata):
|
|
76
76
|
@property
|
77
77
|
def display_sender_id(self) -> str:
|
78
78
|
"""Returns the sender ID of the contract as a string for display purposes"""
|
79
|
-
return "#{
|
79
|
+
return f"#{self._sender_id}"
|
80
80
|
|
81
81
|
@property
|
82
82
|
def receiver_id(self) -> int:
|
@@ -86,7 +86,7 @@ class Contract(Metadata):
|
|
86
86
|
@property
|
87
87
|
def display_receiver_id(self) -> str:
|
88
88
|
"""Returns the receiver ID of the contract as a string for display purposes"""
|
89
|
-
return "#{
|
89
|
+
return f"#{self._receiver_id}"
|
90
90
|
|
91
91
|
@property
|
92
92
|
def delivery_interval(self) -> int:
|
@@ -186,13 +186,13 @@ class Contract(Metadata):
|
|
186
186
|
senders = ensure_is_list(get_or_raise(multi_definition, Contract.KEY_SENDER, Contract._ERR_MISSING_KEY))
|
187
187
|
receivers = ensure_is_list(get_or_raise(multi_definition, Contract.KEY_RECEIVER, Contract._ERR_MISSING_KEY))
|
188
188
|
if len(senders) > 1 and len(receivers) == 1:
|
189
|
-
for index in
|
190
|
-
contracts.append(Contract._copy_contract(
|
189
|
+
for index, sender in enumerate(senders):
|
190
|
+
contracts.append(Contract._copy_contract(sender, receivers[0], base_data))
|
191
191
|
elif len(senders) == 1 and len(receivers) > 1:
|
192
|
-
for index in
|
193
|
-
contracts.append(Contract._copy_contract(senders[0],
|
192
|
+
for index, receiver in enumerate(receivers):
|
193
|
+
contracts.append(Contract._copy_contract(senders[0], receiver, base_data))
|
194
194
|
elif len(senders) == len(receivers):
|
195
|
-
for index in range(len(senders)):
|
195
|
+
for index in range(len(senders)): # pylint: disable=consider-using-enumerate
|
196
196
|
contracts.append(Contract._copy_contract(senders[index], receivers[index], base_data))
|
197
197
|
else:
|
198
198
|
log_and_raise(Contract._ERR_MULTI_CONTRACT_CORRUPT.format(senders, receivers))
|
@@ -1,38 +1,35 @@
|
|
1
|
-
# SPDX-FileCopyrightText:
|
1
|
+
# SPDX-FileCopyrightText: 2025 German Aerospace Center <fame@dlr.de>
|
2
2
|
#
|
3
3
|
# SPDX-License-Identifier: Apache-2.0
|
4
|
-
|
5
4
|
from typing import NoReturn, Any, Union
|
6
5
|
|
7
6
|
from fameio.input import ScenarioError
|
8
|
-
from fameio.logs import
|
7
|
+
from fameio.logs import log_error, log
|
9
8
|
|
10
9
|
_DEFAULT_USED = "Using default value '{}' for missing key '{}'"
|
11
10
|
|
12
11
|
|
13
12
|
def log_and_raise(message: str) -> NoReturn:
|
14
13
|
"""Raises ScenarioError with given `message`"""
|
15
|
-
|
14
|
+
raise log_error(ScenarioError(message))
|
16
15
|
|
17
16
|
|
18
17
|
def get_or_raise(dictionary: dict, key: str, message: str) -> Union[Any, NoReturn]:
|
19
18
|
"""Returns value associated with `key` in given `dictionary`, or raises ScenarioException if key is missing"""
|
20
19
|
if key not in dictionary or dictionary[key] is None:
|
21
|
-
|
22
|
-
|
23
|
-
return dictionary[key]
|
20
|
+
raise log_error(ScenarioError(message.format(key)))
|
21
|
+
return dictionary[key]
|
24
22
|
|
25
23
|
|
26
24
|
def assert_or_raise(assertion: bool, msg: str) -> None:
|
27
25
|
"""Raises new ScenarioError with given `msg` if `assertion` is False"""
|
28
26
|
if not assertion:
|
29
|
-
|
27
|
+
raise log_error(ScenarioError(msg))
|
30
28
|
|
31
29
|
|
32
30
|
def get_or_default(dictionary: dict, key: str, default_value) -> Any:
|
33
31
|
"""Returns value associated with `key` in given `dictionary`, or the given `default_value` if key is missing"""
|
34
32
|
if key in dictionary and dictionary[key] is not None:
|
35
33
|
return dictionary[key]
|
36
|
-
|
37
|
-
|
38
|
-
return default_value
|
34
|
+
log().debug(_DEFAULT_USED.format(default_value, key))
|
35
|
+
return default_value
|
fameio/input/schema/__init__.py
CHANGED
@@ -1,8 +1,8 @@
|
|
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
|
|
5
|
-
from .agenttype import AgentType
|
6
|
-
from .attribute import AttributeSpecs, AttributeType
|
7
|
-
from .java_packages import JavaPackages
|
8
|
-
from .schema import Schema
|
5
|
+
from .agenttype import AgentType # noqa: F401
|
6
|
+
from .attribute import AttributeSpecs, AttributeType # noqa: F401
|
7
|
+
from .java_packages import JavaPackages # noqa: F401
|
8
|
+
from .schema import Schema # noqa: F401
|
fameio/input/schema/agenttype.py
CHANGED
@@ -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
|
@@ -7,7 +7,7 @@ from typing import Any, Final
|
|
7
7
|
|
8
8
|
from fameio.input import InputError, SchemaError
|
9
9
|
from fameio.input.metadata import Metadata, MetadataComponent, ValueContainer
|
10
|
-
from fameio.logs import
|
10
|
+
from fameio.logs import log, log_error
|
11
11
|
from fameio.tools import keys_to_lower
|
12
12
|
from .attribute import AttributeSpecs
|
13
13
|
|
@@ -36,7 +36,7 @@ class AgentType(Metadata):
|
|
36
36
|
"""
|
37
37
|
super().__init__()
|
38
38
|
if not name or name.isspace():
|
39
|
-
|
39
|
+
raise log_error(SchemaError(AgentType._ERR_NAME_INVALID.format(name)))
|
40
40
|
self._name = name
|
41
41
|
self._attributes: dict[str, AttributeSpecs] = {}
|
42
42
|
self._products: ValueContainer = ValueContainer()
|
@@ -86,12 +86,11 @@ class AgentType(Metadata):
|
|
86
86
|
"""Returns ValueContainer for `section` of in specifications of `agent_type` extracted from given `values`"""
|
87
87
|
try:
|
88
88
|
data = ValueContainer(values)
|
89
|
-
except InputError:
|
90
|
-
|
91
|
-
|
92
|
-
|
93
|
-
|
94
|
-
return data
|
89
|
+
except InputError as e:
|
90
|
+
raise log_error(SchemaError(AgentType._ERR_UNKNOWN_STRUCTURE.format(section, agent_type, values))) from e
|
91
|
+
if not all(isinstance(item, str) for item in data.as_list()):
|
92
|
+
raise log_error(SchemaError(AgentType._ERR_NO_STRING.format(section, agent_type, data.as_list())))
|
93
|
+
return data
|
95
94
|
|
96
95
|
@property
|
97
96
|
def name(self) -> str:
|