fmu-manipulation-toolbox 1.7.5__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 (46) hide show
  1. fmu_manipulation_toolbox/__init__.py +1 -0
  2. fmu_manipulation_toolbox/__main__.py +25 -0
  3. fmu_manipulation_toolbox/__version__.py +1 -0
  4. fmu_manipulation_toolbox/checker.py +61 -0
  5. fmu_manipulation_toolbox/cli.py +216 -0
  6. fmu_manipulation_toolbox/fmu_container.py +784 -0
  7. fmu_manipulation_toolbox/fmu_operations.py +489 -0
  8. fmu_manipulation_toolbox/gui.py +493 -0
  9. fmu_manipulation_toolbox/help.py +87 -0
  10. fmu_manipulation_toolbox/resources/checkbox-checked-disabled.png +0 -0
  11. fmu_manipulation_toolbox/resources/checkbox-checked-hover.png +0 -0
  12. fmu_manipulation_toolbox/resources/checkbox-checked.png +0 -0
  13. fmu_manipulation_toolbox/resources/checkbox-unchecked-disabled.png +0 -0
  14. fmu_manipulation_toolbox/resources/checkbox-unchecked-hover.png +0 -0
  15. fmu_manipulation_toolbox/resources/checkbox-unchecked.png +0 -0
  16. fmu_manipulation_toolbox/resources/drop_fmu.png +0 -0
  17. fmu_manipulation_toolbox/resources/fmi-2.0/fmi2Annotation.xsd +58 -0
  18. fmu_manipulation_toolbox/resources/fmi-2.0/fmi2AttributeGroups.xsd +78 -0
  19. fmu_manipulation_toolbox/resources/fmi-2.0/fmi2ModelDescription.xsd +345 -0
  20. fmu_manipulation_toolbox/resources/fmi-2.0/fmi2ScalarVariable.xsd +218 -0
  21. fmu_manipulation_toolbox/resources/fmi-2.0/fmi2Type.xsd +89 -0
  22. fmu_manipulation_toolbox/resources/fmi-2.0/fmi2Unit.xsd +116 -0
  23. fmu_manipulation_toolbox/resources/fmi-2.0/fmi2VariableDependency.xsd +92 -0
  24. fmu_manipulation_toolbox/resources/fmu.png +0 -0
  25. fmu_manipulation_toolbox/resources/fmu_manipulation_toolbox.png +0 -0
  26. fmu_manipulation_toolbox/resources/help.png +0 -0
  27. fmu_manipulation_toolbox/resources/icon.png +0 -0
  28. fmu_manipulation_toolbox/resources/license.txt +34 -0
  29. fmu_manipulation_toolbox/resources/linux32/client_sm.so +0 -0
  30. fmu_manipulation_toolbox/resources/linux32/server_sm +0 -0
  31. fmu_manipulation_toolbox/resources/linux64/client_sm.so +0 -0
  32. fmu_manipulation_toolbox/resources/linux64/container.so +0 -0
  33. fmu_manipulation_toolbox/resources/linux64/server_sm +0 -0
  34. fmu_manipulation_toolbox/resources/model.png +0 -0
  35. fmu_manipulation_toolbox/resources/win32/client_sm.dll +0 -0
  36. fmu_manipulation_toolbox/resources/win32/server_sm.exe +0 -0
  37. fmu_manipulation_toolbox/resources/win64/client_sm.dll +0 -0
  38. fmu_manipulation_toolbox/resources/win64/container.dll +0 -0
  39. fmu_manipulation_toolbox/resources/win64/server_sm.exe +0 -0
  40. fmu_manipulation_toolbox/version.py +9 -0
  41. fmu_manipulation_toolbox-1.7.5.dist-info/LICENSE.txt +22 -0
  42. fmu_manipulation_toolbox-1.7.5.dist-info/METADATA +20 -0
  43. fmu_manipulation_toolbox-1.7.5.dist-info/RECORD +46 -0
  44. fmu_manipulation_toolbox-1.7.5.dist-info/WHEEL +5 -0
  45. fmu_manipulation_toolbox-1.7.5.dist-info/entry_points.txt +3 -0
  46. fmu_manipulation_toolbox-1.7.5.dist-info/top_level.txt +1 -0
@@ -0,0 +1 @@
1
+
@@ -0,0 +1,25 @@
1
+ import sys
2
+
3
+
4
+ def gui():
5
+ try:
6
+ from .gui import main
7
+ main()
8
+ except ModuleNotFoundError as e:
9
+ print(f"FATAL ERROR: {e}. No GUI Available.")
10
+
11
+
12
+ def cli():
13
+ from .cli import fmutool
14
+ fmutool()
15
+
16
+
17
+ def main():
18
+ if len(sys.argv) == 1:
19
+ gui()
20
+ else:
21
+ cli()
22
+
23
+
24
+ if __name__ == '__main__':
25
+ main()
@@ -0,0 +1 @@
1
+ 'V1.7.5'
@@ -0,0 +1,61 @@
1
+ import importlib.util
2
+ import inspect
3
+ import os
4
+ import xmlschema
5
+ from xmlschema.validators.exceptions import XMLSchemaValidationError
6
+ from .fmu_operations import OperationAbstract
7
+
8
+
9
+ class OperationGenericCheck(OperationAbstract):
10
+ SUPPORTED_FMI_VERSIONS = ('2.0',)
11
+
12
+ def __init__(self):
13
+ self.compliant_with_version = None
14
+
15
+ def __repr__(self):
16
+ return f"FMU Generic Conformity Checks"
17
+
18
+ def fmi_attrs(self, attrs):
19
+ if attrs['fmiVersion'] not in self.SUPPORTED_FMI_VERSIONS:
20
+ print(f"ERROR: Expected FMI {','.join(self.SUPPORTED_FMI_VERSIONS)} versions.")
21
+ return
22
+
23
+ xsd_filename = os.path.join(os.path.dirname(__file__), "resources", "fmi-" + attrs['fmiVersion'],
24
+ "fmi2ModelDescription.xsd")
25
+ try:
26
+ xmlschema.validate(self.fmu.descriptor_filename, schema=xsd_filename)
27
+ except XMLSchemaValidationError as error:
28
+ print(error.reason, error.msg)
29
+ else:
30
+ self.compliant_with_version = attrs['fmiVersion']
31
+
32
+ def closure(self):
33
+ if self.compliant_with_version:
34
+ print(f"INFO: This FMU seems to be compliant with FMI-{self.compliant_with_version}.")
35
+ else:
36
+ print(f"ERROR: This FMU does not validate with FMI standard.")
37
+
38
+
39
+ checker_list = [OperationGenericCheck]
40
+
41
+
42
+ def add_from_file(checker_filename: str):
43
+ spec = importlib.util.spec_from_file_location(checker_filename, checker_filename)
44
+ if not spec:
45
+ print(f"ERROR: Cannot load {checker_filename}. Is this a python file?")
46
+ return
47
+ try:
48
+ checker_module = importlib.util.module_from_spec(spec)
49
+ try:
50
+ spec.loader.exec_module(checker_module)
51
+ except (ModuleNotFoundError, SyntaxError) as error:
52
+ print(f"ERROR: Cannot load {checker_filename}: {error})")
53
+ return
54
+
55
+ for checker_name, checker_class in inspect.getmembers(checker_module, inspect.isclass):
56
+ if OperationAbstract in checker_class.__bases__:
57
+ checker_list.append(checker_class)
58
+ print(f"Adding checker: {checker_filename}|{checker_name}")
59
+
60
+ except AttributeError:
61
+ print(f"ERROR: {checker_filename} should implement class 'OperationCheck'")
@@ -0,0 +1,216 @@
1
+ import argparse
2
+ import logging
3
+ import sys
4
+ from colorama import Fore, Style, init
5
+
6
+ from .fmu_operations import *
7
+ from .fmu_container import FMUContainerSpecReader, FMUContainerError
8
+ from .checker import checker_list
9
+ from .version import __version__ as version
10
+ from .help import Help
11
+
12
+
13
+ def setup_logger():
14
+ class CustomFormatter(logging.Formatter):
15
+ def format(self, record):
16
+ log_format = "%(levelname)-8s | %(message)s"
17
+ format_per_level = {
18
+ logging.DEBUG: str(Fore.BLUE) + log_format,
19
+ logging.INFO: str(Fore.CYAN) + log_format,
20
+ logging.WARNING: str(Fore.YELLOW) + log_format,
21
+ logging.ERROR: str(Fore.RED) + log_format,
22
+ logging.CRITICAL: str(Fore.RED + Style.BRIGHT) + log_format,
23
+ }
24
+ formatter = logging.Formatter(format_per_level[record.levelno])
25
+ return formatter.format(record)
26
+ init()
27
+ logger = logging.getLogger("fmu_manipulation_toolbox")
28
+ handler = logging.StreamHandler(stream=sys.stdout)
29
+ handler.setFormatter(CustomFormatter())
30
+ logger.addHandler(handler)
31
+ logger.setLevel(logging.INFO)
32
+
33
+ return logger
34
+
35
+
36
+ def make_wide(formatter, w=120, h=36):
37
+ """Return a wider HelpFormatter, if possible."""
38
+ try:
39
+ # https://stackoverflow.com/a/5464440
40
+ # beware: "Only the name of this class is considered a public API."
41
+ kwargs = {'width': w, 'max_help_position': h}
42
+ formatter(None, **kwargs)
43
+ return lambda prog: formatter(prog, **kwargs)
44
+ except TypeError:
45
+ return formatter
46
+
47
+
48
+ def fmutool():
49
+ print(f"FMU Manipulation Toolbox version {version}")
50
+ help_message = Help()
51
+
52
+ parser = argparse.ArgumentParser(prog='fmutool',
53
+ description="Analyse and Manipulate a FMU by modifying its 'modelDescription.xml'",
54
+ formatter_class=make_wide(argparse.HelpFormatter),
55
+ add_help=False,
56
+ epilog="see: https://github.com/grouperenault/fmu_manipulation_toolbox/blob/main/README.md")
57
+
58
+ def add_option(option, *args, **kwargs):
59
+ parser.add_argument(option, *args, help=help_message.usage(option), **kwargs)
60
+
61
+ add_option('-h', '-help', action="help")
62
+
63
+ # I/O
64
+ add_option('-input', action='store', dest='fmu_input', default=None, required=True, metavar='path/to/module.fmu')
65
+ add_option('-output', action='store', dest='fmu_output', default=None, metavar='path/to/module-modified.fmu')
66
+
67
+ # Port name manipulation
68
+ add_option('-remove-toplevel', action='append_const', dest='operations_list', const=OperationStripTopLevel())
69
+ add_option('-merge-toplevel', action='append_const', dest='operations_list', const=OperationMergeTopLevel())
70
+ add_option('-trim-until', action='append', dest='operations_list', type=OperationTrimUntil, metavar='prefix')
71
+ add_option('-remove-regexp', action='append', dest='operations_list', type=OperationRemoveRegexp,
72
+ metavar='regular-expression')
73
+ add_option('-keep-only-regexp', action='append', dest='operations_list', type=OperationKeepOnlyRegexp,
74
+ metavar='regular-expression')
75
+ add_option('-remove-all', action='append_const', dest='operations_list', const=OperationRemoveRegexp('.*'))
76
+
77
+ # Batch Rename
78
+ add_option('-dump-csv', action='append', dest='operations_list', type=OperationSaveNamesToCSV,
79
+ metavar='path/to/list.csv')
80
+ add_option('-rename-from-csv', action='append', dest='operations_list', type=OperationRenameFromCSV,
81
+ metavar='path/to/translation.csv')
82
+
83
+ # Remoting
84
+ add_option('-add-remoting-win32', action='append_const', dest='operations_list', const=OperationAddRemotingWin32())
85
+ add_option('-add-remoting-win64', action='append_const', dest='operations_list', const=OperationAddRemotingWin64())
86
+ add_option('-add-frontend-win32', action='append_const', dest='operations_list', const=OperationAddFrontendWin32())
87
+ add_option('-add-frontend-win64', action='append_const', dest='operations_list', const=OperationAddFrontendWin64())
88
+
89
+ # Extraction / Removal
90
+ add_option('-extract-descriptor', action='store', dest='extract_description',
91
+ metavar='path/to/saved-modelDescriptor.xml')
92
+ add_option('-remove-sources', action='append_const', dest='operations_list',
93
+ const=OperationRemoveSources())
94
+ # Filter
95
+ add_option('-only-parameters', action='append_const', dest='apply_on', const='parameter')
96
+ add_option('-only-inputs', action='append_const', dest='apply_on', const='input')
97
+ add_option('-only-outputs', action='append_const', dest='apply_on', const='output')
98
+ # Checker
99
+ add_option('-summary', action='append_const', dest='operations_list', const=OperationSummary())
100
+ add_option('-check', action='append_const', dest='operations_list', const=[checker() for checker in checker_list])
101
+
102
+ cli_options = parser.parse_args()
103
+ # handle the "no operation" use case
104
+ if not cli_options.operations_list:
105
+ cli_options.operations_list = []
106
+
107
+ if cli_options.fmu_input == cli_options.fmu_output:
108
+ print(f"FATAL ERROR: '-input' and '-output' should point to different files.")
109
+ sys.exit(-3)
110
+
111
+ print(f"READING Input='{cli_options.fmu_input}'")
112
+ try:
113
+ fmu = FMU(cli_options.fmu_input)
114
+ except FMUException as reason:
115
+ print(f"FATAL ERROR: {reason}")
116
+ sys.exit(-4)
117
+
118
+ if cli_options.apply_on:
119
+ print("Applying operation for :")
120
+ for causality in cli_options.apply_on:
121
+ print(f" - causality = {causality}")
122
+
123
+ def flatten(list_of_list: list):
124
+ return [x for xs in list_of_list for x in xs]
125
+
126
+ for operation in flatten(cli_options.operations_list):
127
+ print(f" => {operation}")
128
+ try:
129
+ fmu.apply_operation(operation, cli_options.apply_on)
130
+ except OperationException as reason:
131
+ print(f"ERROR: {reason}")
132
+ sys.exit(-6)
133
+
134
+ if cli_options.extract_description:
135
+ print(f"WRITING ModelDescriptor='{cli_options.extract_description}'")
136
+ fmu.save_descriptor(cli_options.extract_description)
137
+
138
+ if cli_options.fmu_output:
139
+ print(f"WRITING Output='{cli_options.fmu_output}'")
140
+ try:
141
+ fmu.repack(cli_options.fmu_output)
142
+ except FMUException as reason:
143
+ print(f"FATAL ERROR: {reason}")
144
+ sys.exit(-5)
145
+ else:
146
+ print(f"INFO Modified FMU is not saved. If necessary use '-output' option.")
147
+
148
+
149
+ def fmucontainer():
150
+ logger = setup_logger()
151
+
152
+ logger.info(f"FMUContainer version {version}")
153
+ parser = argparse.ArgumentParser(prog="fmucontainer", description="Generate FMU from FMU's",
154
+ formatter_class=make_wide(argparse.ArgumentDefaultsHelpFormatter),
155
+ add_help=False,
156
+ epilog="see: https://github.com/grouperenault/fmu_manipulation_toolbox/blob/main/"
157
+ "container/README.md")
158
+
159
+ parser.add_argument('-h', '-help', action="help")
160
+
161
+ parser.add_argument("-fmu-directory", action="store", dest="fmu_directory", required=True,
162
+ help="Directory containing initial FMU’s and used to generate containers.")
163
+
164
+ parser.add_argument("-container", action="append", dest="container_descriptions_list", default=[],
165
+ metavar="filename.csv:step_size",
166
+ help="Description of the container to create.")
167
+
168
+ parser.add_argument("-debug", action="store_true", dest="debug",
169
+ help="Add lot of useful log during the process.")
170
+
171
+ parser.add_argument("-no-auto-input", action="store_false", dest="auto_input", default=True,
172
+ help="Create ONLY explicit input.")
173
+
174
+ parser.add_argument("-no-auto-output", action="store_false", dest="auto_output", default=True,
175
+ help="Create ONLY explicit output.")
176
+
177
+ parser.add_argument("-no-auto-link", action="store_false", dest="auto_link", default=True,
178
+ help="Create ONLY explicit links.")
179
+
180
+ parser.add_argument("-mt", action="store_true", dest="mt", default=False,
181
+ help="Enable Multi-Threaded mode for the generated container.")
182
+
183
+ parser.add_argument("-profile", action="store_true", dest="profiling", default=False,
184
+ help="Enable Profiling mode for the generated container.")
185
+
186
+ config = parser.parse_args()
187
+
188
+ if config.debug:
189
+ logger.setLevel(logging.DEBUG)
190
+
191
+ for description in config.container_descriptions_list:
192
+ try:
193
+ filename_description, step_size = description.split(":")
194
+ step_size = float(step_size)
195
+ except ValueError:
196
+ step_size = None
197
+ filename_description = description
198
+
199
+ container_filename = Path(filename_description).with_suffix(".fmu")
200
+
201
+ try:
202
+ csv_reader = FMUContainerSpecReader(Path(config.fmu_directory))
203
+ container = csv_reader.read(filename_description)
204
+ container.add_implicit_rule(auto_input=config.auto_input,
205
+ auto_output=config.auto_output,
206
+ auto_link=config.auto_link)
207
+ container.make_fmu(container_filename, step_size=step_size, debug=config.debug, mt=config.mt,
208
+ profiling=config.profiling)
209
+ except (FileNotFoundError, FMUContainerError, FMUException) as e:
210
+ logger.error(f"Cannot build container from '{filename_description}': {e}")
211
+ continue
212
+
213
+
214
+ # for debug purpose
215
+ if __name__ == "__main__":
216
+ fmucontainer()