fmu-manipulation-toolbox 1.9.2b1__py3-none-any.whl → 1.9.2b2__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.
Files changed (30) hide show
  1. fmu_manipulation_toolbox/__main__.py +2 -2
  2. fmu_manipulation_toolbox/__version__.py +1 -1
  3. fmu_manipulation_toolbox/assembly.py +12 -8
  4. fmu_manipulation_toolbox/checker.py +4 -2
  5. fmu_manipulation_toolbox/cli/fmucontainer.py +27 -19
  6. fmu_manipulation_toolbox/cli/fmusplit.py +5 -2
  7. fmu_manipulation_toolbox/cli/fmutool.py +8 -3
  8. fmu_manipulation_toolbox/cli/utils.py +11 -1
  9. fmu_manipulation_toolbox/container.py +29 -6
  10. fmu_manipulation_toolbox/operations.py +2 -1
  11. fmu_manipulation_toolbox/resources/darwin64/container.dylib +0 -0
  12. fmu_manipulation_toolbox/resources/linux32/client_sm.so +0 -0
  13. fmu_manipulation_toolbox/resources/linux64/client_sm.so +0 -0
  14. fmu_manipulation_toolbox/resources/linux64/container.so +0 -0
  15. fmu_manipulation_toolbox/resources/win32/client_sm.dll +0 -0
  16. fmu_manipulation_toolbox/resources/win32/server_sm.exe +0 -0
  17. fmu_manipulation_toolbox/resources/win64/client_sm.dll +0 -0
  18. fmu_manipulation_toolbox/resources/win64/container.dll +0 -0
  19. fmu_manipulation_toolbox/resources/win64/server_sm.exe +0 -0
  20. fmu_manipulation_toolbox/split.py +10 -1
  21. fmu_manipulation_toolbox/version.py +1 -1
  22. fmu_manipulation_toolbox-1.9.2b2.dist-info/METADATA +42 -0
  23. {fmu_manipulation_toolbox-1.9.2b1.dist-info → fmu_manipulation_toolbox-1.9.2b2.dist-info}/RECORD +27 -29
  24. {fmu_manipulation_toolbox-1.9.2b1.dist-info → fmu_manipulation_toolbox-1.9.2b2.dist-info}/entry_points.txt +1 -1
  25. {fmu_manipulation_toolbox-1.9.2b1.dist-info → fmu_manipulation_toolbox-1.9.2b2.dist-info}/licenses/LICENSE.txt +1 -1
  26. fmu_manipulation_toolbox/gui.py +0 -749
  27. fmu_manipulation_toolbox/gui_style.py +0 -252
  28. fmu_manipulation_toolbox-1.9.2b1.dist-info/METADATA +0 -30
  29. {fmu_manipulation_toolbox-1.9.2b1.dist-info → fmu_manipulation_toolbox-1.9.2b2.dist-info}/WHEEL +0 -0
  30. {fmu_manipulation_toolbox-1.9.2b1.dist-info → fmu_manipulation_toolbox-1.9.2b2.dist-info}/top_level.txt +0 -0
@@ -3,7 +3,7 @@ import sys
3
3
 
4
4
  def gui():
5
5
  try:
6
- from .gui import main
6
+ from .gui.gui import main
7
7
  main()
8
8
  except ModuleNotFoundError as e:
9
9
  print(f"FATAL ERROR: {e}. No GUI Available.")
@@ -11,7 +11,7 @@ def gui():
11
11
 
12
12
  def cli():
13
13
  from .cli.fmutool import fmutool
14
- fmutool(sys.argv[1:])
14
+ fmutool()
15
15
 
16
16
 
17
17
  def main():
@@ -1 +1 @@
1
- 'V1.9.2b1'
1
+ 'V1.9.2b2'
@@ -7,7 +7,7 @@ import uuid
7
7
  import xml.parsers.expat
8
8
  import zipfile
9
9
 
10
- from .container import FMUContainer, AutoWired
10
+ from .container import FMUContainer
11
11
 
12
12
  logger = logging.getLogger("fmu_manipulation_toolbox")
13
13
 
@@ -103,7 +103,8 @@ class AssemblyNode:
103
103
  def add_start_value(self, fmu_filename: str, port_name: str, value: str):
104
104
  self.start_values[Port(fmu_filename, port_name)] = value
105
105
 
106
- def make_fmu(self, fmu_directory: Path, debug=False, description_pathname=None, fmi_version=2):
106
+ def make_fmu(self, fmu_directory: Path, debug=False, description_pathname=None, fmi_version=2, datalog=False,
107
+ filename=None):
107
108
  for node in self.children.values():
108
109
  node.make_fmu(fmu_directory, debug=debug, fmi_version=fmi_version)
109
110
 
@@ -142,8 +143,11 @@ class AssemblyNode:
142
143
  for link_rule in wired.rule_link:
143
144
  self.add_link(link_rule[0], link_rule[1], link_rule[2], link_rule[3])
144
145
 
145
- container.make_fmu(self.name, self.step_size, mt=self.mt, profiling=self.profiling, sequential=self.sequential,
146
- debug=debug, ts_multiplier=self.ts_multiplier)
146
+ if filename is None:
147
+ filename = self.name
148
+
149
+ container.make_fmu(filename, self.step_size, mt=self.mt, profiling=self.profiling, sequential=self.sequential,
150
+ debug=debug, ts_multiplier=self.ts_multiplier, datalog=datalog)
147
151
 
148
152
  for node in self.children.values():
149
153
  logger.info(f"Deleting transient FMU Container '{node.name}'")
@@ -241,7 +245,7 @@ class Assembly:
241
245
  self.transient_dirnames: Set[Path] = set()
242
246
 
243
247
  if not fmu_directory.is_dir():
244
- raise AssemblyError(f"FMU directory is not valid: '{fmu_directory}'")
248
+ raise AssemblyError(f"FMU directory is not valid: '{fmu_directory.resolve()}'")
245
249
 
246
250
  self.input_pathname = fmu_directory / self.filename
247
251
  self.description_pathname = self.input_pathname # For inclusion in FMU
@@ -284,7 +288,7 @@ class Assembly:
284
288
  elif filename.endswith(".json"):
285
289
  return self.write_json(filename)
286
290
  else:
287
- logger.critical(f"Unable to write to '{filename}': format unsupported.")
291
+ raise AssemblyError(f"Unable to write to '{filename}': format unsupported.")
288
292
 
289
293
  def read_csv(self):
290
294
  name = str(self.filename.with_suffix(".fmu"))
@@ -525,9 +529,9 @@ class Assembly:
525
529
  self.root = sdd.parse(self.description_pathname)
526
530
  self.root.name = str(self.filename.with_suffix(".fmu"))
527
531
 
528
- def make_fmu(self, dump_json=False, fmi_version=2):
532
+ def make_fmu(self, dump_json=False, fmi_version=2, datalog=False, filename=None):
529
533
  self.root.make_fmu(self.fmu_directory, debug=self.debug, description_pathname=self.description_pathname,
530
- fmi_version=fmi_version)
534
+ fmi_version=fmi_version, datalog=datalog, filename=filename)
531
535
  if dump_json:
532
536
  dump_file = Path(self.input_pathname.stem + "-dump").with_suffix(".json")
533
537
  logger.info(f"Dump Json '{dump_file}'")
@@ -27,11 +27,11 @@ class OperationGenericCheck(OperationAbstract):
27
27
  return
28
28
 
29
29
  fmi_name = f"fmi{attrs['fmiVersion'][0]}"
30
-
31
30
  xsd_filename = os.path.join(os.path.dirname(__file__), "resources", "fmi-" + attrs['fmiVersion'],
32
31
  f"{fmi_name}ModelDescription.xsd")
32
+ xsd = xmlschema.XMLSchema(xsd_filename)
33
33
  try:
34
- xmlschema.validate(self.fmu.descriptor_filename, schema=xsd_filename)
34
+ xsd.validate(self.fmu.descriptor_filename)
35
35
  except XMLSchemaValidationError as error:
36
36
  logger.error(error.reason, error.msg)
37
37
  else:
@@ -43,8 +43,10 @@ class OperationGenericCheck(OperationAbstract):
43
43
  else:
44
44
  logger.error(f"This FMU does not validate with FMI standard.")
45
45
 
46
+
46
47
  _checkers_list: List[type[OperationAbstract]] = [OperationGenericCheck]
47
48
 
49
+
48
50
  def get_checkers() -> List[type[OperationAbstract]]:
49
51
  if sys.version_info < (3, 10):
50
52
  from importlib_metadata import entry_points
@@ -4,7 +4,7 @@ import sys
4
4
 
5
5
  from pathlib import Path
6
6
 
7
- from .utils import setup_logger, make_wide
7
+ from .utils import setup_logger, close_logger, make_wide
8
8
  from ..assembly import Assembly, AssemblyError
9
9
  from ..container import FMUContainerError
10
10
  from ..version import __version__ as version
@@ -22,36 +22,42 @@ def fmucontainer():
22
22
 
23
23
  parser.add_argument('-h', '-help', action="help")
24
24
 
25
- parser.add_argument("-fmu-directory", action="store", dest="fmu_directory", required=False, default=".",
26
- help="Directory containing initial FMU’s and used to generate containers. "
27
- "If not defined, current directory is used.")
28
-
29
- parser.add_argument("-fmi", action="store", dest="fmi_version", required=False, default="2",
30
- help="Define version of FMI to be used for container interface."
31
- "Only '2' or '3' is supported.")
32
-
33
25
  parser.add_argument("-container", action="append", dest="container_descriptions_list", default=[],
34
26
  metavar="filename.{csv|json|ssp},[:step_size]", required=True,
35
27
  help="Description of the container to create.")
36
28
 
29
+ parser.add_argument("-datalog", action="store_true", dest="datalog", default=False,
30
+ help="Log into log file input, output and local variables of the container")
31
+
37
32
  parser.add_argument("-debug", action="store_true", dest="debug",
38
33
  help="Add lot of useful log during the process.")
39
34
 
35
+ parser.add_argument("-dump-json", action="store_true", dest="dump", default=False,
36
+ help="Dump a JSON file for each container.")
37
+
38
+ parser.add_argument("-fmi", action="store", dest="fmi_version", required=False, default="2",
39
+ help="Define version of FMI to be used for container interface."
40
+ "Only '2' or '3' is supported.")
41
+
42
+ parser.add_argument("-fmu-directory", action="store", dest="fmu_directory", required=False, default=".",
43
+ help="Directory containing initial FMU’s and used to generate containers. "
44
+ "If not defined, current directory is used.")
45
+
40
46
  parser.add_argument("-no-auto-input", action="store_false", dest="auto_input", default=True,
41
47
  help="Create ONLY explicit input.")
42
48
 
49
+ parser.add_argument("-no-auto-link", action="store_false", dest="auto_link", default=True,
50
+ help="Create ONLY explicit links.")
51
+
52
+ parser.add_argument("-auto-local", action="store_true", dest="auto_local", default=False,
53
+ help="Expose local variables of the embedded fmu's.")
54
+
43
55
  parser.add_argument("-no-auto-output", action="store_false", dest="auto_output", default=True,
44
56
  help="Create ONLY explicit output.")
45
57
 
46
58
  parser.add_argument("-auto-parameter", action="store_true", dest="auto_parameter", default=False,
47
59
  help="Expose parameters of the embedded fmu's.")
48
60
 
49
- parser.add_argument("-auto-local", action="store_true", dest="auto_local", default=False,
50
- help="Expose local variables of the embedded fmu's.")
51
-
52
- parser.add_argument("-no-auto-link", action="store_false", dest="auto_link", default=True,
53
- help="Create ONLY explicit links.")
54
-
55
61
  parser.add_argument("-mt", action="store_true", dest="mt", default=False,
56
62
  help="Enable Multi-Threaded mode for the generated container.")
57
63
 
@@ -61,9 +67,6 @@ def fmucontainer():
61
67
  parser.add_argument("-sequential", action="store_true", dest="sequential", default=False,
62
68
  help="Use sequential mode to schedule embedded fmu's.")
63
69
 
64
- parser.add_argument("-dump-json", action="store_true", dest="dump", default=False,
65
- help="Dump a JSON file for each container.")
66
-
67
70
  parser.add_argument("-vr", action="store_true", dest="ts_multiplier", default=False,
68
71
  help="Add TS_MULTIPLIER input port to control step_size")
69
72
 
@@ -92,16 +95,21 @@ def fmucontainer():
92
95
  auto_parameter=config.auto_parameter, ts_multiplier=config.ts_multiplier)
93
96
  except FileNotFoundError as e:
94
97
  logger.fatal(f"Cannot read file: {e}")
98
+ close_logger(logger)
95
99
  sys.exit(-1)
96
100
  except (FMUContainerError, AssemblyError) as e:
97
101
  logger.fatal(f"{filename}: {e}")
102
+ close_logger(logger)
98
103
  sys.exit(-2)
99
104
 
100
105
  try:
101
- assembly.make_fmu(dump_json=config.dump, fmi_version=int(config.fmi_version))
106
+ assembly.make_fmu(dump_json=config.dump, fmi_version=int(config.fmi_version), datalog=config.datalog)
102
107
  except FMUContainerError as e:
103
108
  logger.fatal(f"{filename}: {e}")
109
+ close_logger(logger)
104
110
  sys.exit(-3)
105
111
 
112
+ close_logger(logger)
113
+
106
114
  if __name__ == "__main__":
107
115
  fmucontainer()
@@ -2,8 +2,7 @@ import argparse
2
2
  import logging
3
3
  import sys
4
4
 
5
-
6
- from .utils import setup_logger, make_wide
5
+ from .utils import setup_logger, close_logger, make_wide
7
6
  from ..split import FMUSplitter, FMUSplitterError
8
7
  from ..version import __version__ as version
9
8
 
@@ -37,11 +36,15 @@ def fmusplit():
37
36
  splitter.split_fmu()
38
37
  except FMUSplitterError as e:
39
38
  logger.fatal(f"{fmu_filename}: {e}")
39
+ close_logger(logger)
40
40
  sys.exit(-1)
41
41
  except FileNotFoundError as e:
42
42
  logger.fatal(f"Cannot read file: {e}")
43
+ close_logger(logger)
43
44
  sys.exit(-2)
44
45
 
46
+ close_logger(logger)
47
+
45
48
 
46
49
  if __name__ == "__main__":
47
50
  fmusplit()
@@ -1,9 +1,7 @@
1
1
  import argparse
2
2
  import sys
3
3
 
4
- from typing import *
5
-
6
- from .utils import setup_logger, make_wide
4
+ from .utils import setup_logger, close_logger, make_wide
7
5
  from ..operations import (OperationSummary, OperationError, OperationRemoveRegexp,
8
6
  OperationRemoveSources, OperationTrimUntil, OperationKeepOnlyRegexp, OperationMergeTopLevel,
9
7
  OperationStripTopLevel, OperationRenameFromCSV, OperationSaveNamesToCSV, FMU, FMUError)
@@ -78,6 +76,7 @@ def fmutool():
78
76
 
79
77
  if cli_options.fmu_input == cli_options.fmu_output:
80
78
  logger.fatal(f"'-input' and '-output' should point to different files.")
79
+ close_logger(logger)
81
80
  sys.exit(-3)
82
81
 
83
82
  logger.info(f"READING Input='{cli_options.fmu_input}'")
@@ -85,6 +84,7 @@ def fmutool():
85
84
  fmu = FMU(cli_options.fmu_input)
86
85
  except FMUError as reason:
87
86
  logger.fatal(f"{reason}")
87
+ close_logger(logger)
88
88
  sys.exit(-4)
89
89
 
90
90
  if cli_options.apply_on:
@@ -107,6 +107,7 @@ def fmutool():
107
107
  fmu.apply_operation(operation, cli_options.apply_on)
108
108
  except OperationError as reason:
109
109
  logger.fatal(f"{reason}")
110
+ close_logger(logger)
110
111
  sys.exit(-6)
111
112
 
112
113
  if cli_options.extract_description:
@@ -119,9 +120,13 @@ def fmutool():
119
120
  fmu.repack(cli_options.fmu_output)
120
121
  except FMUError as reason:
121
122
  logger.fatal(f"FATAL ERROR: {reason}")
123
+ close_logger(logger)
122
124
  sys.exit(-5)
123
125
  else:
124
126
  logger.info(f"INFO Modified FMU is not saved. If necessary use '-output' option.")
125
127
 
128
+ close_logger(logger)
129
+
130
+
126
131
  if __name__ == "__main__":
127
132
  fmutool()
@@ -2,7 +2,8 @@ import logging
2
2
  import sys
3
3
  from colorama import Fore, Style, init
4
4
 
5
- def setup_logger():
5
+
6
+ def setup_logger() -> logging.Logger:
6
7
  class CustomFormatter(logging.Formatter):
7
8
  def format(self, record):
8
9
  log_format = "%(levelname)-8s | %(message)s"
@@ -24,6 +25,15 @@ def setup_logger():
24
25
 
25
26
  return logger
26
27
 
28
+
29
+ def close_logger(logger: logging.Logger):
30
+ for handler in logger.handlers:
31
+ logger.removeHandler(handler)
32
+ handler.close()
33
+ logger.setLevel(logging.NOTSET)
34
+ logger.propagate = True
35
+
36
+
27
37
  def make_wide(formatter, w=120, h=36):
28
38
  """Return a wider HelpFormatter, if possible."""
29
39
  try:
@@ -484,7 +484,7 @@ class FMUIOList:
484
484
 
485
485
  def add_start_value(self, cport: ContainerPort, value: str):
486
486
  reset = 1 if cport.port.causality == "input" else 0
487
- self.start_values[cport.port.type_name][cport.fmu.name].append((cport, reset, value))
487
+ self.start_values[cport.port.type_name][cport.fmu.name].append((cport.port.vr, reset, value))
488
488
 
489
489
  def write_txt(self, fmu_name, txt_file):
490
490
  for type_name in EmbeddedFMUPort.ALL_TYPES:
@@ -535,7 +535,7 @@ class ClockList:
535
535
 
536
536
  def write_txt(self, txt_file):
537
537
  print(f"# importer CLOCKS: <FMU_INDEX> <NB> <FMU_VR> <VR> [<FMU_VR> <VR>]", file=txt_file)
538
- nb_total_clocks = 0;
538
+ nb_total_clocks = 0
539
539
  for clocks in self.clocks_per_fmu.values():
540
540
  nb_total_clocks += len(clocks)
541
541
 
@@ -756,11 +756,11 @@ class FMUContainer:
756
756
  cport = ContainerPort(self.get_fmu(fmu_filename), port_name)
757
757
 
758
758
  try:
759
- if cport.port.type_name in ('Real', 'Float64', 'Float32'):
759
+ if cport.port.type_name.startswith('real'):
760
760
  value = float(value)
761
- elif cport.port.type_name in ('Integer', 'Int8', 'UInt8', 'Int16', 'UInt16', 'Int32', 'UInt32', 'Int64', 'UInt64'):
761
+ elif cport.port.type_name.startswith('integer') or cport.port.type_name.startswith('uinteger'):
762
762
  value = int(value)
763
- elif cport.port.type_name == 'Boolean':
763
+ elif cport.port.type_name.startswith('boolean'):
764
764
  value = int(bool(value))
765
765
  elif cport.port.type_name == 'String':
766
766
  value = value
@@ -872,7 +872,7 @@ class FMUContainer:
872
872
  logger.warning(f"{cport} is not connected")
873
873
 
874
874
  def make_fmu(self, fmu_filename: Union[str, Path], step_size: Optional[float] = None, debug=False, mt=False,
875
- profiling=False, sequential=False, ts_multiplier=False):
875
+ profiling=False, sequential=False, ts_multiplier=False, datalog=False):
876
876
  if isinstance(fmu_filename, str):
877
877
  fmu_filename = Path(fmu_filename)
878
878
 
@@ -885,11 +885,16 @@ class FMUContainer:
885
885
 
886
886
  base_directory = self.fmu_directory / fmu_filename.with_suffix('')
887
887
  resources_directory = self.make_fmu_skeleton(base_directory)
888
+
888
889
  with open(base_directory / "modelDescription.xml", "wt") as xml_file:
889
890
  self.make_fmu_xml(xml_file, step_size, profiling, ts_multiplier)
890
891
  with open(resources_directory / "container.txt", "wt") as txt_file:
891
892
  self.make_fmu_txt(txt_file, step_size, mt, profiling, sequential)
892
893
 
894
+ if datalog:
895
+ with open(resources_directory / "datalog.txt", "wt") as datalog_file:
896
+ self.make_datalog(datalog_file)
897
+
893
898
  self.make_fmu_package(base_directory, fmu_filename)
894
899
  if not debug:
895
900
  self.make_fmu_cleanup(base_directory)
@@ -1173,6 +1178,24 @@ class FMUContainer:
1173
1178
  # CLOCKS
1174
1179
  clock_list.write_txt(txt_file)
1175
1180
 
1181
+ def make_datalog(self, datalog_file):
1182
+ print(f"# Datalog filename")
1183
+ print(f"{self.identifier}-datalog.csv", file=datalog_file)
1184
+
1185
+ ports = defaultdict(list)
1186
+ for input_port_name, input_port in self.inputs.items():
1187
+ ports[input_port.type_name].append((input_port.vr, input_port_name))
1188
+ for output_port_name, output_port in self.outputs.items():
1189
+ ports[output_port.port.type_name].append((output_port.vr, output_port_name))
1190
+ for link in self.links.values():
1191
+ ports[link.cport_from.port.type_name].append((link.vr, link.name))
1192
+
1193
+ for type_name in EmbeddedFMUPort.ALL_TYPES:
1194
+ print(f"# {type_name}: <VR> <NAME>" , file=datalog_file)
1195
+ print(f"{len(ports[type_name])}", file=datalog_file)
1196
+ for port in ports[type_name]:
1197
+ print(f"{port[0]} {port[1]}", file=datalog_file)
1198
+
1176
1199
  @staticmethod
1177
1200
  def long_path(path: Union[str, Path]) -> str:
1178
1201
  # https://stackoverflow.com/questions/14075465/copy-a-file-with-a-too-long-path-to-another-directory-in-python
@@ -121,7 +121,8 @@ class Manipulation:
121
121
  TAGS_MODEL_STRUCTURE = ("InitialUnknowns", "Derivatives", "Outputs")
122
122
 
123
123
  def __init__(self, operation, fmu):
124
- self.output_filename = tempfile.mktemp()
124
+ (fd, self.output_filename) = tempfile.mkstemp()
125
+ os.close(fd) # File will be re-opened later
125
126
  self.out = None
126
127
  self.operation = operation
127
128
  self.parser = xml.parsers.expat.ParserCreate()
@@ -6,6 +6,15 @@ import xml.parsers.expat
6
6
  from typing import *
7
7
  from pathlib import Path
8
8
 
9
+ from .container import EmbeddedFMUPort
10
+ import logging
11
+ import zipfile
12
+ import json
13
+ import xml.parsers.expat
14
+
15
+ from typing import *
16
+ from pathlib import Path
17
+
9
18
  from .container import EmbeddedFMUPort
10
19
 
11
20
  logger = logging.getLogger("fmu_manipulation_toolbox")
@@ -191,7 +200,7 @@ class FMUSplitterDescription:
191
200
  self.config["mt"] = flags[0] == "1"
192
201
  self.config["profiling"] = self.get_line(file) == "1"
193
202
  self.config["sequential"] = False
194
- elif len(flags) == 3:
203
+ elif len(flags) >= 3:
195
204
  self.supported_fmi_types = EmbeddedFMUPort.ALL_TYPES
196
205
  self.config["mt"] = flags[0] == "1"
197
206
  self.config["profiling"] = flags[1] == "1"
@@ -4,6 +4,6 @@ except ModuleNotFoundError:
4
4
  __version__ = "0.0.dev0"
5
5
 
6
6
  __author__ = "Nicolas.LAURENT@Renault.com"
7
- __copyright__ = "Copyright 2023-2024, Renault SAS"
7
+ __copyright__ = "Copyright 2023-2026, Renault SAS"
8
8
  __license__ = """This code is released under the 2-Clause BSD license.
9
9
  See https://github.com/grouperenault/fmu_manipulation_toolbox/blob/main/LICENSE.txt"""
@@ -0,0 +1,42 @@
1
+ Metadata-Version: 2.4
2
+ Name: fmu_manipulation_toolbox
3
+ Version: 1.9.2b2
4
+ Summary: FMU Manipulation Toolbox is a python package which helps to analyze, modify or combine Functional Mock-up Units (FMUs) without recompilation.
5
+ Home-page: https://github.com/grouperenault/fmu_manipulation_toolbox/
6
+ Author: Nicolas.LAURENT@Renault.com
7
+ License: BSD-2-Clause
8
+ Requires-Python: >=3.9
9
+ Description-Content-Type: text/markdown
10
+ License-File: LICENSE.txt
11
+ Requires-Dist: PySide6>=6.8.0
12
+ Requires-Dist: xmlschema>=3.3.1
13
+ Requires-Dist: elementpath>=4.4.0
14
+ Requires-Dist: colorama>=0.4.6
15
+ Dynamic: author
16
+ Dynamic: description
17
+ Dynamic: description-content-type
18
+ Dynamic: home-page
19
+ Dynamic: license
20
+ Dynamic: license-file
21
+ Dynamic: requires-dist
22
+ Dynamic: requires-python
23
+ Dynamic: summary
24
+
25
+ FMU Manipulation Toolbox is a python package which helps to analyze, modify or combine
26
+ [Functional Mock-up Units (FMUs)](http://fmi-standard.org/) without recompilation. It is highly customizable and comes with
27
+ a Python API.
28
+
29
+ FMU Manipulation Toolbox can be used in different ways:
30
+ - Using a Graphical User Interface: suitable for end users
31
+ - Using a Command Line Interface: useful for scripting and automation
32
+ - Using a Python API: the most efficient option for automation (CI/CD, transformation scripts, ...))
33
+
34
+ Major features:
35
+ - Analyze FMU content: list ports and their attributes, check compliance of `ModelDescription.xml` with XSD, etc.
36
+ - Alter FMU by modifying its `modelDescription.xml` file. NOTE: manipulating this file can be a risky.
37
+ When possible, it is preferable to communicate with the FMU developer and adapt the FMU generation process.
38
+ - Add binary interfaces. Typical use case is porting a 32-bit FMUs to 64-bit systems (or vice et versa).
39
+ - Combine FMUs into [FMU Containers](doc/container.md) and allow your favourite FMI tool to orchestrate complex assembly of FMUs.
40
+
41
+ FMI versions 2.0 and 3.0 are supported.
42
+
@@ -1,23 +1,21 @@
1
1
  fmu_manipulation_toolbox/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
2
- fmu_manipulation_toolbox/__main__.py,sha256=Ixgo_5YS_khXseMujNPsVzaerkHPugLPYPV7FIi5umo,364
3
- fmu_manipulation_toolbox/__version__.py,sha256=eFoY0dV9P-7aIw41HjOXEMNKuPwNW0s1_trJUzchB-g,11
4
- fmu_manipulation_toolbox/assembly.py,sha256=-i9iQLKiPyjdFZyxHmB1FgL3NYmRPfTWVs9lf3fC5sE,27022
5
- fmu_manipulation_toolbox/checker.py,sha256=RmIYd6s4p2S9wdv-uSILfVm__QTZSUJCiq6hr_G5rxA,3119
6
- fmu_manipulation_toolbox/container.py,sha256=HMi3tuMjdrlgVkbzjp5_48OM-iqNFnqc1OsR8O0e9mE,55634
7
- fmu_manipulation_toolbox/gui.py,sha256=-DyWY2MoECr3FGRYdS60Ltoayhd3O0uOCtkQ4YXE8xc,29201
8
- fmu_manipulation_toolbox/gui_style.py,sha256=s6WdrnNd_lCMWhuBf5LKK8wrfLXCU7pFTLUfvqkJVno,6633
2
+ fmu_manipulation_toolbox/__main__.py,sha256=g0ZhVsMiAs5KnhyVNwTe01N2PQjAg7F9YCnXHZB-HwA,356
3
+ fmu_manipulation_toolbox/__version__.py,sha256=dxTf1L29N2UnXoeZR07PLwi-F5jmAKLCVbVRdBuxS8g,11
4
+ fmu_manipulation_toolbox/assembly.py,sha256=QmFihza_I0hK0Ia6tWbjdZeoREhveLrv3d7ERrBUaDk,27217
5
+ fmu_manipulation_toolbox/checker.py,sha256=Dh47b3blibCWjHCeZ61Y_w9Ug0PWvEuSiemZtp-llQA,3141
6
+ fmu_manipulation_toolbox/container.py,sha256=5LpfqWMSkujZqkw37Y1sI2tM2BKTDOUXvyj9c-jIpqM,56680
9
7
  fmu_manipulation_toolbox/help.py,sha256=j8xmnCrwQpaW-SZ8hSqA1dlTXgaqzQWc4Yr3RH_oqck,6012
10
8
  fmu_manipulation_toolbox/ls.py,sha256=wmyoKrvDLXpL-PFz6cUhLLqxDMD5E9L_P4KswWpQHsk,975
11
- fmu_manipulation_toolbox/operations.py,sha256=rfeZiCHuVr5-M4lC496feYl1nrRBheP_W9AsJHtMm58,21094
9
+ fmu_manipulation_toolbox/operations.py,sha256=8noR84f6Ow2sMY6d0oer5BDZ48WBRSKgwOB-aTKElzg,21154
12
10
  fmu_manipulation_toolbox/remoting.py,sha256=N25MDFkIcEWe9CIT1M4L9kea3j-8E7i2I1VOI6zIAdw,3876
13
- fmu_manipulation_toolbox/split.py,sha256=q6a5rZ4s7E24nf4BiebUuoneBEj9j293f2LiAaSDKnE,16345
11
+ fmu_manipulation_toolbox/split.py,sha256=6D99SAGNu4B3PSaSsliWc6Bb5aSBZMxL8t0v8TJBI3Y,16499
14
12
  fmu_manipulation_toolbox/terminals.py,sha256=mGGS4tdE6cJuz-2zvwc7drpmT0QJ7YPe8ENw2UGlEHA,5062
15
- fmu_manipulation_toolbox/version.py,sha256=OhBLkZ1-nhC77kyvffPNAf6m8OZe1bYTnNf_PWs1NvM,392
13
+ fmu_manipulation_toolbox/version.py,sha256=L26Cc3PH97SOa4G9yiYnafrdolK0G_DCQZZTvv3YXqI,392
16
14
  fmu_manipulation_toolbox/cli/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
17
- fmu_manipulation_toolbox/cli/fmucontainer.py,sha256=oYidLBvXyDApsY7JVGlCL5g35yc1F9Gr8tFjYY7077s,4981
18
- fmu_manipulation_toolbox/cli/fmusplit.py,sha256=EDRrj6aHVnyaj3W_4_DUxo84AyZxnRyNGXIad35eWFo,1668
19
- fmu_manipulation_toolbox/cli/fmutool.py,sha256=KUqhUO3NvRdzgY55aoPg7yF3_3sE1GANR6dx-XQAU1M,6043
20
- fmu_manipulation_toolbox/cli/utils.py,sha256=gNhdlFYSSNSb0fovzS0crnxgmqqKXe0KtoZZFhRKhfg,1375
15
+ fmu_manipulation_toolbox/cli/fmucontainer.py,sha256=ZLoC8QMVBVG2S3cdNthMIQ0gYIU9WUbYj8Aj2vxzyfs,5338
16
+ fmu_manipulation_toolbox/cli/fmusplit.py,sha256=sLzdxiC4R5hJYJo9F2TZOMrJOHcadqCvUo9KoCjUaxE,1773
17
+ fmu_manipulation_toolbox/cli/fmutool.py,sha256=E-CCymksBwGFlS3-zJ7DIDA8xIdp_synsxMDYXst8dc,6186
18
+ fmu_manipulation_toolbox/cli/utils.py,sha256=pvedN6cRiDkZ7RdPO1koBOZaGuydYhgcoO0-_QQpOoI,1601
21
19
  fmu_manipulation_toolbox/resources/checkbox-checked-disabled.png,sha256=FWIuyrXlaNLLePHfXj7j9ca5rT8Hgr14KCe1EqTCZyk,2288
22
20
  fmu_manipulation_toolbox/resources/checkbox-checked-hover.png,sha256=KNlV-d_aJNTTvUVXKGT9DBY30sIs2LwocLJrFKNKv8k,2419
23
21
  fmu_manipulation_toolbox/resources/checkbox-checked.png,sha256=gzyFqvRFsZixVh6ZlV4SMWUKzglY1rSn7SvJUKMVvtk,2411
@@ -35,7 +33,7 @@ fmu_manipulation_toolbox/resources/icon_fmu.png,sha256=EuygB2xcoM2WAfKKdyKG_UvTL
35
33
  fmu_manipulation_toolbox/resources/license.txt,sha256=5ODuU8g8pIkK-NMWXu_rjZ6k7gM7b-N2rmg87-2Kmqw,1583
36
34
  fmu_manipulation_toolbox/resources/mask.png,sha256=px1U4hQGL0AmZ4BQPknOVREpMpTSejbah3ntkpqAzFA,3008
37
35
  fmu_manipulation_toolbox/resources/model.png,sha256=EAf_HnZJe8zYGZygerG1MMt2U-tMMZlifzXPj4_iORA,208788
38
- fmu_manipulation_toolbox/resources/darwin64/container.dylib,sha256=LAXXvAWewT4P21esMyCy8DbkbrnSDggSgnS2NUTsrwc,213632
36
+ fmu_manipulation_toolbox/resources/darwin64/container.dylib,sha256=EpQwj07DRShKXq8lzqjFXiAWLwJXQyRPa3TrLjULZCM,230608
39
37
  fmu_manipulation_toolbox/resources/fmi-2.0/fmi2Annotation.xsd,sha256=OGfyJtaJntKypX5KDpuZ-nV1oYLZ6HV16pkpKOmYox4,2731
40
38
  fmu_manipulation_toolbox/resources/fmi-2.0/fmi2AttributeGroups.xsd,sha256=HwyV7LBse-PQSv4z1xjmtzPU3Hjnv4mluq9YdSBNHMQ,3704
41
39
  fmu_manipulation_toolbox/resources/fmi-2.0/fmi2ModelDescription.xsd,sha256=JM4j_9q-pc40XYHb28jfT3iV3aYM5JLqD5aRjO72K1E,18939
@@ -55,19 +53,19 @@ fmu_manipulation_toolbox/resources/fmi-3.0/fmi3Type.xsd,sha256=TaHRoUBIFtmdEwBKB
55
53
  fmu_manipulation_toolbox/resources/fmi-3.0/fmi3Unit.xsd,sha256=CK_F2t5LfyQ6eSNJ8soTFMVK9DU8vD2WiMi2MQvjB0g,3746
56
54
  fmu_manipulation_toolbox/resources/fmi-3.0/fmi3Variable.xsd,sha256=3YU-3q1-c-namz7sMe5cxnmOVOJsRSmfWR02PKv3xaU,19171
57
55
  fmu_manipulation_toolbox/resources/fmi-3.0/fmi3VariableDependency.xsd,sha256=YQSBwXt4IsDlyegY8bX-qQHGSfE5TipTPfo2g2yqq1c,3082
58
- fmu_manipulation_toolbox/resources/linux32/client_sm.so,sha256=OjdzO-OEU0UW1D1YvDouikjKAMWYv3f-tkLZ_qb80g4,34756
56
+ fmu_manipulation_toolbox/resources/linux32/client_sm.so,sha256=Cd4EwnFamF-6cmA0uNJ-xDIs5wkmhfgdeFVAJLBzumY,34756
59
57
  fmu_manipulation_toolbox/resources/linux32/server_sm,sha256=gzKU0BTeaRkvhTMQtHHj3K8uYFyEdyGGn_mZy_jG9xo,21304
60
- fmu_manipulation_toolbox/resources/linux64/client_sm.so,sha256=UOcyFYhHJyLNmQoLdiBD75nzloBmk77g9i91QjdItL0,32592
61
- fmu_manipulation_toolbox/resources/linux64/container.so,sha256=426lYFuGlXmUGRhwDl-VW9_pFJO1RxrWbg6Wv-Fekdc,177032
58
+ fmu_manipulation_toolbox/resources/linux64/client_sm.so,sha256=4aaTSTwCFk0iigVqw67ZMmt9Udj89W6placdTydzcAo,32592
59
+ fmu_manipulation_toolbox/resources/linux64/container.so,sha256=8SEqRP87xhzmkgIlFbgXyyxcSml4Gl_MKmfH7nHEjd8,189944
62
60
  fmu_manipulation_toolbox/resources/linux64/server_sm,sha256=MZn6vITN2qpBHYt_RaK2VnFFp00hk8fTALBHmXPtLwc,22608
63
- fmu_manipulation_toolbox/resources/win32/client_sm.dll,sha256=fk9hb9RJ9AqGLpw5jUHy743OGyHXlcYbYLSeJCPUQRg,17920
64
- fmu_manipulation_toolbox/resources/win32/server_sm.exe,sha256=LDtvrrmmyVPGBNOx4iljMcNYJuNlSZAf-kl_6hTxKu0,15360
65
- fmu_manipulation_toolbox/resources/win64/client_sm.dll,sha256=koFqnnDq-Oe_tlzfNuEGbSvXpFKz9fjPDt_xwaquQqw,21504
66
- fmu_manipulation_toolbox/resources/win64/container.dll,sha256=8OKu_SQABu-eEDm7YIFbcBmnhZolXoIRpmEaObsTHk8,141824
67
- fmu_manipulation_toolbox/resources/win64/server_sm.exe,sha256=Vq5CG6Ll2Pb06J9IKUpV-5VMHUaoALYizIB4PbVtgdc,18432
68
- fmu_manipulation_toolbox-1.9.2b1.dist-info/licenses/LICENSE.txt,sha256=c_862mzyk6ownO3Gt6cVs0-53IXLi_-ZEQFNDVabESw,1285
69
- fmu_manipulation_toolbox-1.9.2b1.dist-info/METADATA,sha256=tXtq9Rodjl3GQ6FOdB7SeGV_yv4htrFXpsict3ffsvo,1157
70
- fmu_manipulation_toolbox-1.9.2b1.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
71
- fmu_manipulation_toolbox-1.9.2b1.dist-info/entry_points.txt,sha256=HjOZkflbI1IuSY8BpOZre20m24M4GDQGCJfPIa7NrlY,264
72
- fmu_manipulation_toolbox-1.9.2b1.dist-info/top_level.txt,sha256=9D_h-5BMjSqf9z-XFkbJL_bMppR2XNYW3WNuPkXou0k,25
73
- fmu_manipulation_toolbox-1.9.2b1.dist-info/RECORD,,
61
+ fmu_manipulation_toolbox/resources/win32/client_sm.dll,sha256=WPAutfVhZ3wMOwM2nuJYaOQby-Nooz6dwX_Jv14zUgI,17920
62
+ fmu_manipulation_toolbox/resources/win32/server_sm.exe,sha256=b6a25dyuw5E06sJwRWNTHwB8ZHwjTxybOE0H9wCHYac,15360
63
+ fmu_manipulation_toolbox/resources/win64/client_sm.dll,sha256=FDxyTCrsryoSHLKhEIBRbNYDzQfUxYW1B2ICKeskfZo,21504
64
+ fmu_manipulation_toolbox/resources/win64/container.dll,sha256=uV6DVwERwLDcsAl2jzgQhNLte5xjGfaUMCu2gwMIC8s,153088
65
+ fmu_manipulation_toolbox/resources/win64/server_sm.exe,sha256=TCF38KOmVIltgBxw84fa22Zx8ZcJ_lHtAVVZzUm6Ncc,18432
66
+ fmu_manipulation_toolbox-1.9.2b2.dist-info/licenses/LICENSE.txt,sha256=0Q8zhEwTu1K-MDmg8Khay5j56BIz2VLI6RcijIFbU_g,1255
67
+ fmu_manipulation_toolbox-1.9.2b2.dist-info/METADATA,sha256=uHdjOJ_iuBOy-KDuoM-bM2rZu7XrVjzD_HQYeFLE-lI,1898
68
+ fmu_manipulation_toolbox-1.9.2b2.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
69
+ fmu_manipulation_toolbox-1.9.2b2.dist-info/entry_points.txt,sha256=6VNL31b5le8S9zp2H0R9ERWmzCy9WuSzVEDcHbWX_70,268
70
+ fmu_manipulation_toolbox-1.9.2b2.dist-info/top_level.txt,sha256=9D_h-5BMjSqf9z-XFkbJL_bMppR2XNYW3WNuPkXou0k,25
71
+ fmu_manipulation_toolbox-1.9.2b2.dist-info/RECORD,,
@@ -4,4 +4,4 @@ fmusplit = fmu_manipulation_toolbox.cli.fmusplit:fmusplit
4
4
  fmutool = fmu_manipulation_toolbox.cli.fmutool:fmutool
5
5
 
6
6
  [gui_scripts]
7
- fmutool-gui = fmu_manipulation_toolbox.gui:main
7
+ fmutool-gui = fmu_manipulation_toolbox.gui.gui:main
@@ -1,4 +1,4 @@
1
- Copyright (c) 2024 Renault SAS - Nicolas.LAURENT@Renault.com
1
+ Copyright (c) 2024 Renault SAS
2
2
 
3
3
  Redistribution and use in source and binary forms, with or without
4
4
  modification, are permitted provided that the following conditions