fameio 3.5.1__tar.gz → 3.5.2__tar.gz
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-3.5.1 → fameio-3.5.2}/CHANGELOG.md +5 -1
- {fameio-3.5.1 → fameio-3.5.2}/PKG-INFO +1 -1
- {fameio-3.5.1 → fameio-3.5.2}/pyproject.toml +1 -1
- {fameio-3.5.1 → fameio-3.5.2}/src/fameio/output/conversion.py +9 -4
- {fameio-3.5.1 → fameio-3.5.2}/src/fameio/output/csv_writer.py +12 -4
- {fameio-3.5.1 → fameio-3.5.2}/src/fameio/scripts/convert_results.py +5 -4
- {fameio-3.5.1 → fameio-3.5.2}/src/fameio/series.py +7 -5
- {fameio-3.5.1 → fameio-3.5.2}/LICENSE.txt +0 -0
- {fameio-3.5.1 → fameio-3.5.2}/LICENSES/Apache-2.0.txt +0 -0
- {fameio-3.5.1 → fameio-3.5.2}/LICENSES/CC-BY-4.0.txt +0 -0
- {fameio-3.5.1 → fameio-3.5.2}/LICENSES/CC-BY-ND-4.0.txt +0 -0
- {fameio-3.5.1 → fameio-3.5.2}/LICENSES/CC0-1.0.txt +0 -0
- {fameio-3.5.1 → fameio-3.5.2}/README.md +0 -0
- {fameio-3.5.1 → fameio-3.5.2}/src/fameio/__init__.py +0 -0
- {fameio-3.5.1 → fameio-3.5.2}/src/fameio/cli/__init__.py +0 -0
- {fameio-3.5.1 → fameio-3.5.2}/src/fameio/cli/convert_results.py +0 -0
- {fameio-3.5.1 → fameio-3.5.2}/src/fameio/cli/make_config.py +0 -0
- {fameio-3.5.1 → fameio-3.5.2}/src/fameio/cli/options.py +0 -0
- {fameio-3.5.1 → fameio-3.5.2}/src/fameio/cli/parser.py +0 -0
- {fameio-3.5.1 → fameio-3.5.2}/src/fameio/cli/reformat.py +0 -0
- {fameio-3.5.1 → fameio-3.5.2}/src/fameio/input/__init__.py +0 -0
- {fameio-3.5.1 → fameio-3.5.2}/src/fameio/input/loader/__init__.py +0 -0
- {fameio-3.5.1 → fameio-3.5.2}/src/fameio/input/loader/controller.py +0 -0
- {fameio-3.5.1 → fameio-3.5.2}/src/fameio/input/loader/loader.py +0 -0
- {fameio-3.5.1 → fameio-3.5.2}/src/fameio/input/metadata.py +0 -0
- {fameio-3.5.1 → fameio-3.5.2}/src/fameio/input/resolver.py +0 -0
- {fameio-3.5.1 → fameio-3.5.2}/src/fameio/input/scenario/__init__.py +0 -0
- {fameio-3.5.1 → fameio-3.5.2}/src/fameio/input/scenario/agent.py +0 -0
- {fameio-3.5.1 → fameio-3.5.2}/src/fameio/input/scenario/attribute.py +0 -0
- {fameio-3.5.1 → fameio-3.5.2}/src/fameio/input/scenario/contract.py +0 -0
- {fameio-3.5.1 → fameio-3.5.2}/src/fameio/input/scenario/exception.py +0 -0
- {fameio-3.5.1 → fameio-3.5.2}/src/fameio/input/scenario/fameiofactory.py +0 -0
- {fameio-3.5.1 → fameio-3.5.2}/src/fameio/input/scenario/generalproperties.py +0 -0
- {fameio-3.5.1 → fameio-3.5.2}/src/fameio/input/scenario/scenario.py +0 -0
- {fameio-3.5.1 → fameio-3.5.2}/src/fameio/input/scenario/stringset.py +0 -0
- {fameio-3.5.1 → fameio-3.5.2}/src/fameio/input/schema/__init__.py +0 -0
- {fameio-3.5.1 → fameio-3.5.2}/src/fameio/input/schema/agenttype.py +0 -0
- {fameio-3.5.1 → fameio-3.5.2}/src/fameio/input/schema/attribute.py +0 -0
- {fameio-3.5.1 → fameio-3.5.2}/src/fameio/input/schema/java_packages.py +0 -0
- {fameio-3.5.1 → fameio-3.5.2}/src/fameio/input/schema/schema.py +0 -0
- {fameio-3.5.1 → fameio-3.5.2}/src/fameio/input/validator.py +0 -0
- {fameio-3.5.1 → fameio-3.5.2}/src/fameio/input/writer.py +0 -0
- {fameio-3.5.1 → fameio-3.5.2}/src/fameio/logs.py +0 -0
- {fameio-3.5.1 → fameio-3.5.2}/src/fameio/output/__init__.py +0 -0
- {fameio-3.5.1 → fameio-3.5.2}/src/fameio/output/agent_type.py +0 -0
- {fameio-3.5.1 → fameio-3.5.2}/src/fameio/output/data_transformer.py +0 -0
- {fameio-3.5.1 → fameio-3.5.2}/src/fameio/output/execution_dao.py +0 -0
- {fameio-3.5.1 → fameio-3.5.2}/src/fameio/output/files.py +0 -0
- {fameio-3.5.1 → fameio-3.5.2}/src/fameio/output/input_dao.py +0 -0
- {fameio-3.5.1 → fameio-3.5.2}/src/fameio/output/metadata/__init__.py +0 -0
- {fameio-3.5.1 → fameio-3.5.2}/src/fameio/output/metadata/compiler.py +0 -0
- {fameio-3.5.1 → fameio-3.5.2}/src/fameio/output/metadata/json_writer.py +0 -0
- {fameio-3.5.1 → fameio-3.5.2}/src/fameio/output/metadata/locator.py +0 -0
- {fameio-3.5.1 → fameio-3.5.2}/src/fameio/output/metadata/oeo_template.py +0 -0
- {fameio-3.5.1 → fameio-3.5.2}/src/fameio/output/metadata/template_reader.py +0 -0
- {fameio-3.5.1 → fameio-3.5.2}/src/fameio/output/output_dao.py +0 -0
- {fameio-3.5.1 → fameio-3.5.2}/src/fameio/output/reader.py +0 -0
- {fameio-3.5.1 → fameio-3.5.2}/src/fameio/output/yaml_writer.py +0 -0
- {fameio-3.5.1 → fameio-3.5.2}/src/fameio/scripts/REUSE.toml +0 -0
- {fameio-3.5.1 → fameio-3.5.2}/src/fameio/scripts/__init__.py +0 -0
- {fameio-3.5.1 → fameio-3.5.2}/src/fameio/scripts/exception.py +0 -0
- {fameio-3.5.1 → fameio-3.5.2}/src/fameio/scripts/make_config.py +0 -0
- {fameio-3.5.1 → fameio-3.5.2}/src/fameio/scripts/reformat.py +0 -0
- {fameio-3.5.1 → fameio-3.5.2}/src/fameio/time.py +0 -0
- {fameio-3.5.1 → fameio-3.5.2}/src/fameio/tools.py +0 -0
|
@@ -2,7 +2,11 @@
|
|
|
2
2
|
|
|
3
3
|
SPDX-License-Identifier: Apache-2.0 -->
|
|
4
4
|
# Changelog
|
|
5
|
-
##
|
|
5
|
+
## [3.5.2](https://gitlab.com/fame-framework/fame-io/-/tags/v3.5.2) - 2025-10-14
|
|
6
|
+
### Fixed
|
|
7
|
+
- Fix conversion of time stamps on input recovery based on user specifications #274 (@dlr_fn)
|
|
8
|
+
|
|
9
|
+
## [3.5.1](https://gitlab.com/fame-framework/fame-io/-/tags/v3.5.1) - 2025-07-25
|
|
6
10
|
### Fixed
|
|
7
11
|
- Fix crash on result conversion if agent list is provided #266 (@dlr-cjs, @dlr_jk)
|
|
8
12
|
- Fix missing recovery of scenario StringSets #264 (@dlr-cjs)
|
|
@@ -12,7 +12,10 @@ import pandas as pd
|
|
|
12
12
|
from fameio.cli.options import TimeOptions
|
|
13
13
|
from fameio.logs import log_error, log
|
|
14
14
|
from fameio.output import OutputError
|
|
15
|
-
from fameio.
|
|
15
|
+
from fameio.series import TimeSeriesManager
|
|
16
|
+
from fameio.time import FameTime, ConversionError as TimeConversionError, DATE_FORMAT as DATETIME_FORMAT_FAME
|
|
17
|
+
|
|
18
|
+
DATETIME_FORMAT_UTC = "%Y-%m-%d %H:%M:%S"
|
|
16
19
|
|
|
17
20
|
_ERR_UNIMPLEMENTED = "Time conversion mode '{}' not implemented."
|
|
18
21
|
_ERR_TIME_CONVERSION = "Conversion of timestamps failed."
|
|
@@ -86,9 +89,9 @@ def apply_time_option(data: dict[str | None, pd.DataFrame], mode: TimeOptions) -
|
|
|
86
89
|
if mode == TimeOptions.INT:
|
|
87
90
|
log().debug("No time conversion...")
|
|
88
91
|
elif mode == TimeOptions.UTC:
|
|
89
|
-
_convert_time_index(data,
|
|
92
|
+
_convert_time_index(data, DATETIME_FORMAT_UTC)
|
|
90
93
|
elif mode == TimeOptions.FAME:
|
|
91
|
-
_convert_time_index(data,
|
|
94
|
+
_convert_time_index(data, DATETIME_FORMAT_FAME)
|
|
92
95
|
else:
|
|
93
96
|
raise log_error(ConversionError(_ERR_UNIMPLEMENTED.format(mode)))
|
|
94
97
|
except TimeConversionError as e:
|
|
@@ -111,5 +114,7 @@ def _convert_time_index(data: dict[str | None, pd.DataFrame], datetime_format: s
|
|
|
111
114
|
for _, df in data.items():
|
|
112
115
|
index_columns = df.index.names
|
|
113
116
|
df.reset_index(inplace=True)
|
|
114
|
-
df[
|
|
117
|
+
df[TimeSeriesManager.KEY_ROW_TIME] = df[TimeSeriesManager.KEY_ROW_TIME].apply(
|
|
118
|
+
lambda t: FameTime.convert_fame_time_step_to_datetime(t, datetime_format)
|
|
119
|
+
)
|
|
115
120
|
df.set_index(keys=index_columns, inplace=True)
|
|
@@ -6,11 +6,14 @@
|
|
|
6
6
|
from __future__ import annotations
|
|
7
7
|
|
|
8
8
|
from pathlib import Path
|
|
9
|
+
from typing import Literal
|
|
9
10
|
|
|
10
11
|
import pandas as pd
|
|
11
12
|
|
|
13
|
+
from fameio.cli.options import TimeOptions
|
|
12
14
|
from fameio.logs import log_error
|
|
13
15
|
from fameio.output import OutputError
|
|
16
|
+
from fameio.output.conversion import apply_time_option
|
|
14
17
|
from fameio.output.data_transformer import INDEX
|
|
15
18
|
from fameio.series import TimeSeriesManager
|
|
16
19
|
from fameio.tools import ensure_path_exists
|
|
@@ -59,11 +62,14 @@ class CsvWriter:
|
|
|
59
62
|
identifier = self._get_identifier(agent_name, column_name)
|
|
60
63
|
self._write_data_frame(column_data, identifier)
|
|
61
64
|
|
|
62
|
-
def write_all_time_series_to_disk(
|
|
65
|
+
def write_all_time_series_to_disk(
|
|
66
|
+
self, timeseries_manager: TimeSeriesManager, time_mode: TimeOptions | None = None
|
|
67
|
+
) -> None:
|
|
63
68
|
"""Writes time_series of given `timeseries_manager` to disk.
|
|
64
69
|
|
|
65
70
|
Args:
|
|
66
71
|
timeseries_manager: to provide the time series that are to be written
|
|
72
|
+
time_mode: mode of representing time in series that are to be written
|
|
67
73
|
|
|
68
74
|
Raises:
|
|
69
75
|
CsvWriterError: if data could not be written to disk, logged on level "ERROR"
|
|
@@ -72,6 +78,8 @@ class CsvWriter:
|
|
|
72
78
|
if data is not None:
|
|
73
79
|
target_path = Path(self._output_folder, name)
|
|
74
80
|
ensure_path_exists(target_path.parent)
|
|
81
|
+
if time_mode:
|
|
82
|
+
apply_time_option(data={name: data}, mode=time_mode)
|
|
75
83
|
self.write_single_time_series_to_disk(data, target_path)
|
|
76
84
|
|
|
77
85
|
@staticmethod
|
|
@@ -85,10 +93,10 @@ class CsvWriter:
|
|
|
85
93
|
Raises:
|
|
86
94
|
CsvWriterError: if data could not be written to disk, logged on level "ERROR"
|
|
87
95
|
"""
|
|
88
|
-
CsvWriter._dataframe_to_csv(data, file, header=False, index=
|
|
96
|
+
CsvWriter._dataframe_to_csv(data, file, header=False, index=True, mode="w")
|
|
89
97
|
|
|
90
98
|
@staticmethod
|
|
91
|
-
def _dataframe_to_csv(data: pd.DataFrame, file: Path, header: bool, index: bool, mode:
|
|
99
|
+
def _dataframe_to_csv(data: pd.DataFrame, file: Path, header: bool, index: bool, mode: Literal["a", "w"]) -> None:
|
|
92
100
|
"""Write given data to specified CSV file in UTF8 encoding with specified parameters using semicolon separators.
|
|
93
101
|
|
|
94
102
|
Args:
|
|
@@ -132,7 +140,7 @@ class CsvWriter:
|
|
|
132
140
|
"""
|
|
133
141
|
if self._has_file(identifier):
|
|
134
142
|
outfile_name = self._get_outfile_name(identifier)
|
|
135
|
-
mode = "a"
|
|
143
|
+
mode: Literal["a", "w"] = "a"
|
|
136
144
|
header = False
|
|
137
145
|
else:
|
|
138
146
|
outfile_name = self._create_outfile_name(identifier)
|
|
@@ -9,7 +9,7 @@ import pandas as pd
|
|
|
9
9
|
|
|
10
10
|
from fameio.cli import update_default_config
|
|
11
11
|
from fameio.cli.convert_results import handle_args, CLI_DEFAULTS as DEFAULT_CONFIG
|
|
12
|
-
from fameio.cli.options import Options
|
|
12
|
+
from fameio.cli.options import Options, TimeOptions
|
|
13
13
|
from fameio.input import InputError
|
|
14
14
|
from fameio.logs import fameio_logger, log, log_error, log_critical
|
|
15
15
|
from fameio.output import OutputError
|
|
@@ -99,7 +99,7 @@ def _extract_and_convert_data(config: dict[Options, Any], file_stream: BinaryIO,
|
|
|
99
99
|
output_writer.write_to_files(agent_name, data_frames)
|
|
100
100
|
|
|
101
101
|
if config[Options.INPUT_RECOVERY]:
|
|
102
|
-
_recover_inputs(output_path, input_dao, execution_dao.get_fameio_version())
|
|
102
|
+
_recover_inputs(output_path, input_dao, execution_dao.get_fameio_version(), config[Options.TIME])
|
|
103
103
|
if config[Options.MEMORY_SAVING]:
|
|
104
104
|
_memory_saving_apply_conversions(config, output_writer)
|
|
105
105
|
|
|
@@ -118,13 +118,14 @@ def _extract_and_convert_data(config: dict[Options, Any], file_stream: BinaryIO,
|
|
|
118
118
|
log().info("Data conversion completed.")
|
|
119
119
|
|
|
120
120
|
|
|
121
|
-
def _recover_inputs(output_path: Path, input_dao: InputDao, fameio_version: str) -> None:
|
|
121
|
+
def _recover_inputs(output_path: Path, input_dao: InputDao, fameio_version: str, time_mode: TimeOptions) -> None:
|
|
122
122
|
"""Reads scenario configuration from provided `input_dao`.
|
|
123
123
|
|
|
124
124
|
Args:
|
|
125
125
|
output_path: path to output files
|
|
126
126
|
input_dao: to recover the input data from
|
|
127
127
|
fameio_version: version of fameio that was used to create the input data
|
|
128
|
+
time_mode: mode of representing time in recovered input time series
|
|
128
129
|
|
|
129
130
|
Raises:
|
|
130
131
|
OutputError: if inputs could not be recovered or saved to files, logged with level "ERROR"
|
|
@@ -136,7 +137,7 @@ def _recover_inputs(output_path: Path, input_dao: InputDao, fameio_version: str)
|
|
|
136
137
|
raise log_error(OutputError(_ERR_RECOVER_INPUT.format(fameio_version))) from ex
|
|
137
138
|
|
|
138
139
|
series_writer = CsvWriter(output_folder=Path(output_path, RECOVERED_INPUT_PATH), single_export=False)
|
|
139
|
-
series_writer.write_all_time_series_to_disk(timeseries)
|
|
140
|
+
series_writer.write_all_time_series_to_disk(timeseries, time_mode)
|
|
140
141
|
data_to_yaml_file(scenario.to_dict(), Path(output_path, RECOVERED_SCENARIO_PATH))
|
|
141
142
|
|
|
142
143
|
|
|
@@ -8,7 +8,7 @@ import math
|
|
|
8
8
|
import os
|
|
9
9
|
from enum import Enum, auto
|
|
10
10
|
from pathlib import Path
|
|
11
|
-
from typing import Any
|
|
11
|
+
from typing import Any, Final
|
|
12
12
|
|
|
13
13
|
import pandas as pd
|
|
14
14
|
from fameprotobuf.input_file_pb2 import InputData
|
|
@@ -41,10 +41,11 @@ class Entry(Enum):
|
|
|
41
41
|
class TimeSeriesManager:
|
|
42
42
|
"""Manages matching of timeseries data from files and values to unique ids and vice versa."""
|
|
43
43
|
|
|
44
|
+
KEY_ROW_TIME: Final[str] = "TimeStep"
|
|
45
|
+
KEY_ROW_VALUE: Final[str] = "Value"
|
|
46
|
+
|
|
44
47
|
_TIMESERIES_RECONSTRUCTION_PATH = "./timeseries/"
|
|
45
48
|
_CONSTANT_IDENTIFIER = "Constant value: {}"
|
|
46
|
-
_KEY_ROW_TIME = "timeStep"
|
|
47
|
-
_KEY_ROW_VALUE = "value"
|
|
48
49
|
|
|
49
50
|
_ERR_FILE_NOT_FOUND = "Cannot find Timeseries file '{}'."
|
|
50
51
|
_ERR_NUMERIC_STRING = " Remove quotes to use a constant numeric value instead of a timeseries file."
|
|
@@ -274,7 +275,7 @@ class TimeSeriesManager:
|
|
|
274
275
|
"""Reconstructs and stores time series from given list of `timeseries_dao`."""
|
|
275
276
|
for one_series in timeseries:
|
|
276
277
|
self._id_count += 1
|
|
277
|
-
reconstructed = {Entry.ID: one_series.series_id}
|
|
278
|
+
reconstructed: dict[Entry, int | float | None | str | pd.DataFrame] = {Entry.ID: one_series.series_id}
|
|
278
279
|
if len(one_series.values) == 1 or (
|
|
279
280
|
len(one_series.values) == 2 and one_series.values[0] == one_series.values[1]
|
|
280
281
|
):
|
|
@@ -283,7 +284,8 @@ class TimeSeriesManager:
|
|
|
283
284
|
else:
|
|
284
285
|
reconstructed[Entry.NAME] = self._get_cleaned_file_name(one_series.series_name)
|
|
285
286
|
reconstructed[Entry.DATA] = pd.DataFrame(
|
|
286
|
-
{self.
|
|
287
|
+
data={self.KEY_ROW_VALUE: list(one_series.values)},
|
|
288
|
+
index=pd.Index(data=list(one_series.time_steps), name=self.KEY_ROW_TIME),
|
|
287
289
|
)
|
|
288
290
|
self._series_by_id[one_series.series_id] = reconstructed
|
|
289
291
|
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|