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.
Files changed (65) hide show
  1. {fameio-3.5.1 → fameio-3.5.2}/CHANGELOG.md +5 -1
  2. {fameio-3.5.1 → fameio-3.5.2}/PKG-INFO +1 -1
  3. {fameio-3.5.1 → fameio-3.5.2}/pyproject.toml +1 -1
  4. {fameio-3.5.1 → fameio-3.5.2}/src/fameio/output/conversion.py +9 -4
  5. {fameio-3.5.1 → fameio-3.5.2}/src/fameio/output/csv_writer.py +12 -4
  6. {fameio-3.5.1 → fameio-3.5.2}/src/fameio/scripts/convert_results.py +5 -4
  7. {fameio-3.5.1 → fameio-3.5.2}/src/fameio/series.py +7 -5
  8. {fameio-3.5.1 → fameio-3.5.2}/LICENSE.txt +0 -0
  9. {fameio-3.5.1 → fameio-3.5.2}/LICENSES/Apache-2.0.txt +0 -0
  10. {fameio-3.5.1 → fameio-3.5.2}/LICENSES/CC-BY-4.0.txt +0 -0
  11. {fameio-3.5.1 → fameio-3.5.2}/LICENSES/CC-BY-ND-4.0.txt +0 -0
  12. {fameio-3.5.1 → fameio-3.5.2}/LICENSES/CC0-1.0.txt +0 -0
  13. {fameio-3.5.1 → fameio-3.5.2}/README.md +0 -0
  14. {fameio-3.5.1 → fameio-3.5.2}/src/fameio/__init__.py +0 -0
  15. {fameio-3.5.1 → fameio-3.5.2}/src/fameio/cli/__init__.py +0 -0
  16. {fameio-3.5.1 → fameio-3.5.2}/src/fameio/cli/convert_results.py +0 -0
  17. {fameio-3.5.1 → fameio-3.5.2}/src/fameio/cli/make_config.py +0 -0
  18. {fameio-3.5.1 → fameio-3.5.2}/src/fameio/cli/options.py +0 -0
  19. {fameio-3.5.1 → fameio-3.5.2}/src/fameio/cli/parser.py +0 -0
  20. {fameio-3.5.1 → fameio-3.5.2}/src/fameio/cli/reformat.py +0 -0
  21. {fameio-3.5.1 → fameio-3.5.2}/src/fameio/input/__init__.py +0 -0
  22. {fameio-3.5.1 → fameio-3.5.2}/src/fameio/input/loader/__init__.py +0 -0
  23. {fameio-3.5.1 → fameio-3.5.2}/src/fameio/input/loader/controller.py +0 -0
  24. {fameio-3.5.1 → fameio-3.5.2}/src/fameio/input/loader/loader.py +0 -0
  25. {fameio-3.5.1 → fameio-3.5.2}/src/fameio/input/metadata.py +0 -0
  26. {fameio-3.5.1 → fameio-3.5.2}/src/fameio/input/resolver.py +0 -0
  27. {fameio-3.5.1 → fameio-3.5.2}/src/fameio/input/scenario/__init__.py +0 -0
  28. {fameio-3.5.1 → fameio-3.5.2}/src/fameio/input/scenario/agent.py +0 -0
  29. {fameio-3.5.1 → fameio-3.5.2}/src/fameio/input/scenario/attribute.py +0 -0
  30. {fameio-3.5.1 → fameio-3.5.2}/src/fameio/input/scenario/contract.py +0 -0
  31. {fameio-3.5.1 → fameio-3.5.2}/src/fameio/input/scenario/exception.py +0 -0
  32. {fameio-3.5.1 → fameio-3.5.2}/src/fameio/input/scenario/fameiofactory.py +0 -0
  33. {fameio-3.5.1 → fameio-3.5.2}/src/fameio/input/scenario/generalproperties.py +0 -0
  34. {fameio-3.5.1 → fameio-3.5.2}/src/fameio/input/scenario/scenario.py +0 -0
  35. {fameio-3.5.1 → fameio-3.5.2}/src/fameio/input/scenario/stringset.py +0 -0
  36. {fameio-3.5.1 → fameio-3.5.2}/src/fameio/input/schema/__init__.py +0 -0
  37. {fameio-3.5.1 → fameio-3.5.2}/src/fameio/input/schema/agenttype.py +0 -0
  38. {fameio-3.5.1 → fameio-3.5.2}/src/fameio/input/schema/attribute.py +0 -0
  39. {fameio-3.5.1 → fameio-3.5.2}/src/fameio/input/schema/java_packages.py +0 -0
  40. {fameio-3.5.1 → fameio-3.5.2}/src/fameio/input/schema/schema.py +0 -0
  41. {fameio-3.5.1 → fameio-3.5.2}/src/fameio/input/validator.py +0 -0
  42. {fameio-3.5.1 → fameio-3.5.2}/src/fameio/input/writer.py +0 -0
  43. {fameio-3.5.1 → fameio-3.5.2}/src/fameio/logs.py +0 -0
  44. {fameio-3.5.1 → fameio-3.5.2}/src/fameio/output/__init__.py +0 -0
  45. {fameio-3.5.1 → fameio-3.5.2}/src/fameio/output/agent_type.py +0 -0
  46. {fameio-3.5.1 → fameio-3.5.2}/src/fameio/output/data_transformer.py +0 -0
  47. {fameio-3.5.1 → fameio-3.5.2}/src/fameio/output/execution_dao.py +0 -0
  48. {fameio-3.5.1 → fameio-3.5.2}/src/fameio/output/files.py +0 -0
  49. {fameio-3.5.1 → fameio-3.5.2}/src/fameio/output/input_dao.py +0 -0
  50. {fameio-3.5.1 → fameio-3.5.2}/src/fameio/output/metadata/__init__.py +0 -0
  51. {fameio-3.5.1 → fameio-3.5.2}/src/fameio/output/metadata/compiler.py +0 -0
  52. {fameio-3.5.1 → fameio-3.5.2}/src/fameio/output/metadata/json_writer.py +0 -0
  53. {fameio-3.5.1 → fameio-3.5.2}/src/fameio/output/metadata/locator.py +0 -0
  54. {fameio-3.5.1 → fameio-3.5.2}/src/fameio/output/metadata/oeo_template.py +0 -0
  55. {fameio-3.5.1 → fameio-3.5.2}/src/fameio/output/metadata/template_reader.py +0 -0
  56. {fameio-3.5.1 → fameio-3.5.2}/src/fameio/output/output_dao.py +0 -0
  57. {fameio-3.5.1 → fameio-3.5.2}/src/fameio/output/reader.py +0 -0
  58. {fameio-3.5.1 → fameio-3.5.2}/src/fameio/output/yaml_writer.py +0 -0
  59. {fameio-3.5.1 → fameio-3.5.2}/src/fameio/scripts/REUSE.toml +0 -0
  60. {fameio-3.5.1 → fameio-3.5.2}/src/fameio/scripts/__init__.py +0 -0
  61. {fameio-3.5.1 → fameio-3.5.2}/src/fameio/scripts/exception.py +0 -0
  62. {fameio-3.5.1 → fameio-3.5.2}/src/fameio/scripts/make_config.py +0 -0
  63. {fameio-3.5.1 → fameio-3.5.2}/src/fameio/scripts/reformat.py +0 -0
  64. {fameio-3.5.1 → fameio-3.5.2}/src/fameio/time.py +0 -0
  65. {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
- ## [3.5.1](https://gitlab.com/fame-framework/fame-io/-/tags/v3.5.1) - 2025-07-25
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)
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.3
2
2
  Name: fameio
3
- Version: 3.5.1
3
+ Version: 3.5.2
4
4
  Summary: Tools for input preparation and output digestion of FAME models
5
5
  License: Apache-2.0
6
6
  Keywords: FAME,fameio,agent-based modelling,energy systems
@@ -7,7 +7,7 @@ build-backend = "poetry.core.masonry.api"
7
7
 
8
8
  [project]
9
9
  name = "fameio"
10
- version = "3.5.1"
10
+ version = "3.5.2"
11
11
  description = "Tools for input preparation and output digestion of FAME models"
12
12
  license = "Apache-2.0"
13
13
  readme = "README.md"
@@ -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.time import FameTime, ConversionError as TimeConversionError
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, "%Y-%m-%d %H:%M:%S")
92
+ _convert_time_index(data, DATETIME_FORMAT_UTC)
90
93
  elif mode == TimeOptions.FAME:
91
- _convert_time_index(data, "%Y-%m-%d_%H:%M:%S")
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["TimeStep"] = df["TimeStep"].apply(lambda t: FameTime.convert_fame_time_step_to_datetime(t, datetime_format))
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(self, timeseries_manager: TimeSeriesManager) -> None:
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=False, mode="w")
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: str) -> None:
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._KEY_ROW_TIME: list(one_series.time_steps), self._KEY_ROW_VALUE: list(one_series.values)}
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