fmu-manipulation-toolbox 1.9.2b1__tar.gz → 1.9.2b3__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 (90) hide show
  1. {fmu_manipulation_toolbox-1.9.2b1 → fmu_manipulation_toolbox-1.9.2b3}/LICENSE.txt +1 -1
  2. fmu_manipulation_toolbox-1.9.2b3/PKG-INFO +42 -0
  3. {fmu_manipulation_toolbox-1.9.2b1 → fmu_manipulation_toolbox-1.9.2b3}/README.md +27 -23
  4. {fmu_manipulation_toolbox-1.9.2b1 → fmu_manipulation_toolbox-1.9.2b3}/fmu_manipulation_toolbox/__main__.py +2 -2
  5. fmu_manipulation_toolbox-1.9.2b3/fmu_manipulation_toolbox/__version__.py +1 -0
  6. {fmu_manipulation_toolbox-1.9.2b1 → fmu_manipulation_toolbox-1.9.2b3}/fmu_manipulation_toolbox/assembly.py +12 -8
  7. {fmu_manipulation_toolbox-1.9.2b1 → fmu_manipulation_toolbox-1.9.2b3}/fmu_manipulation_toolbox/checker.py +4 -2
  8. fmu_manipulation_toolbox-1.9.2b3/fmu_manipulation_toolbox/cli/datalog2pcap.py +143 -0
  9. {fmu_manipulation_toolbox-1.9.2b1 → fmu_manipulation_toolbox-1.9.2b3}/fmu_manipulation_toolbox/cli/fmucontainer.py +27 -19
  10. {fmu_manipulation_toolbox-1.9.2b1 → fmu_manipulation_toolbox-1.9.2b3}/fmu_manipulation_toolbox/cli/fmusplit.py +5 -2
  11. {fmu_manipulation_toolbox-1.9.2b1 → fmu_manipulation_toolbox-1.9.2b3}/fmu_manipulation_toolbox/cli/fmutool.py +8 -3
  12. {fmu_manipulation_toolbox-1.9.2b1 → fmu_manipulation_toolbox-1.9.2b3}/fmu_manipulation_toolbox/cli/utils.py +11 -1
  13. {fmu_manipulation_toolbox-1.9.2b1 → fmu_manipulation_toolbox-1.9.2b3}/fmu_manipulation_toolbox/container.py +33 -6
  14. {fmu_manipulation_toolbox-1.9.2b1 → fmu_manipulation_toolbox-1.9.2b3}/fmu_manipulation_toolbox/operations.py +4 -3
  15. fmu_manipulation_toolbox-1.9.2b3/fmu_manipulation_toolbox/resources/darwin64/container.dylib +0 -0
  16. fmu_manipulation_toolbox-1.9.2b3/fmu_manipulation_toolbox/resources/linux32/client_sm.so +0 -0
  17. fmu_manipulation_toolbox-1.9.2b3/fmu_manipulation_toolbox/resources/linux64/client_sm.so +0 -0
  18. fmu_manipulation_toolbox-1.9.2b3/fmu_manipulation_toolbox/resources/linux64/container.so +0 -0
  19. fmu_manipulation_toolbox-1.9.2b3/fmu_manipulation_toolbox/resources/win32/client_sm.dll +0 -0
  20. {fmu_manipulation_toolbox-1.9.2b1 → fmu_manipulation_toolbox-1.9.2b3}/fmu_manipulation_toolbox/resources/win32/server_sm.exe +0 -0
  21. fmu_manipulation_toolbox-1.9.2b3/fmu_manipulation_toolbox/resources/win64/client_sm.dll +0 -0
  22. fmu_manipulation_toolbox-1.9.2b3/fmu_manipulation_toolbox/resources/win64/container.dll +0 -0
  23. {fmu_manipulation_toolbox-1.9.2b1 → fmu_manipulation_toolbox-1.9.2b3}/fmu_manipulation_toolbox/resources/win64/server_sm.exe +0 -0
  24. {fmu_manipulation_toolbox-1.9.2b1 → fmu_manipulation_toolbox-1.9.2b3}/fmu_manipulation_toolbox/split.py +10 -1
  25. {fmu_manipulation_toolbox-1.9.2b1 → fmu_manipulation_toolbox-1.9.2b3}/fmu_manipulation_toolbox/version.py +1 -1
  26. fmu_manipulation_toolbox-1.9.2b3/fmu_manipulation_toolbox.egg-info/PKG-INFO +42 -0
  27. {fmu_manipulation_toolbox-1.9.2b1 → fmu_manipulation_toolbox-1.9.2b3}/fmu_manipulation_toolbox.egg-info/SOURCES.txt +1 -2
  28. {fmu_manipulation_toolbox-1.9.2b1 → fmu_manipulation_toolbox-1.9.2b3}/fmu_manipulation_toolbox.egg-info/entry_points.txt +2 -1
  29. {fmu_manipulation_toolbox-1.9.2b1 → fmu_manipulation_toolbox-1.9.2b3}/setup.py +22 -10
  30. {fmu_manipulation_toolbox-1.9.2b1 → fmu_manipulation_toolbox-1.9.2b3}/tests/test_suite.py +109 -42
  31. fmu_manipulation_toolbox-1.9.2b1/PKG-INFO +0 -30
  32. fmu_manipulation_toolbox-1.9.2b1/fmu_manipulation_toolbox/__version__.py +0 -1
  33. fmu_manipulation_toolbox-1.9.2b1/fmu_manipulation_toolbox/gui.py +0 -749
  34. fmu_manipulation_toolbox-1.9.2b1/fmu_manipulation_toolbox/gui_style.py +0 -252
  35. fmu_manipulation_toolbox-1.9.2b1/fmu_manipulation_toolbox/resources/darwin64/container.dylib +0 -0
  36. fmu_manipulation_toolbox-1.9.2b1/fmu_manipulation_toolbox/resources/linux32/client_sm.so +0 -0
  37. fmu_manipulation_toolbox-1.9.2b1/fmu_manipulation_toolbox/resources/linux64/client_sm.so +0 -0
  38. fmu_manipulation_toolbox-1.9.2b1/fmu_manipulation_toolbox/resources/linux64/container.so +0 -0
  39. fmu_manipulation_toolbox-1.9.2b1/fmu_manipulation_toolbox/resources/win32/client_sm.dll +0 -0
  40. fmu_manipulation_toolbox-1.9.2b1/fmu_manipulation_toolbox/resources/win64/client_sm.dll +0 -0
  41. fmu_manipulation_toolbox-1.9.2b1/fmu_manipulation_toolbox/resources/win64/container.dll +0 -0
  42. fmu_manipulation_toolbox-1.9.2b1/fmu_manipulation_toolbox.egg-info/PKG-INFO +0 -30
  43. {fmu_manipulation_toolbox-1.9.2b1 → fmu_manipulation_toolbox-1.9.2b3}/fmu_manipulation_toolbox/__init__.py +0 -0
  44. {fmu_manipulation_toolbox-1.9.2b1 → fmu_manipulation_toolbox-1.9.2b3}/fmu_manipulation_toolbox/cli/__init__.py +0 -0
  45. {fmu_manipulation_toolbox-1.9.2b1 → fmu_manipulation_toolbox-1.9.2b3}/fmu_manipulation_toolbox/help.py +0 -0
  46. {fmu_manipulation_toolbox-1.9.2b1 → fmu_manipulation_toolbox-1.9.2b3}/fmu_manipulation_toolbox/ls.py +0 -0
  47. {fmu_manipulation_toolbox-1.9.2b1 → fmu_manipulation_toolbox-1.9.2b3}/fmu_manipulation_toolbox/remoting.py +0 -0
  48. {fmu_manipulation_toolbox-1.9.2b1 → fmu_manipulation_toolbox-1.9.2b3}/fmu_manipulation_toolbox/resources/checkbox-checked-disabled.png +0 -0
  49. {fmu_manipulation_toolbox-1.9.2b1 → fmu_manipulation_toolbox-1.9.2b3}/fmu_manipulation_toolbox/resources/checkbox-checked-hover.png +0 -0
  50. {fmu_manipulation_toolbox-1.9.2b1 → fmu_manipulation_toolbox-1.9.2b3}/fmu_manipulation_toolbox/resources/checkbox-checked.png +0 -0
  51. {fmu_manipulation_toolbox-1.9.2b1 → fmu_manipulation_toolbox-1.9.2b3}/fmu_manipulation_toolbox/resources/checkbox-unchecked-disabled.png +0 -0
  52. {fmu_manipulation_toolbox-1.9.2b1 → fmu_manipulation_toolbox-1.9.2b3}/fmu_manipulation_toolbox/resources/checkbox-unchecked-hover.png +0 -0
  53. {fmu_manipulation_toolbox-1.9.2b1 → fmu_manipulation_toolbox-1.9.2b3}/fmu_manipulation_toolbox/resources/checkbox-unchecked.png +0 -0
  54. {fmu_manipulation_toolbox-1.9.2b1 → fmu_manipulation_toolbox-1.9.2b3}/fmu_manipulation_toolbox/resources/container.png +0 -0
  55. {fmu_manipulation_toolbox-1.9.2b1 → fmu_manipulation_toolbox-1.9.2b3}/fmu_manipulation_toolbox/resources/drop_fmu.png +0 -0
  56. {fmu_manipulation_toolbox-1.9.2b1 → fmu_manipulation_toolbox-1.9.2b3}/fmu_manipulation_toolbox/resources/fmi-2.0/fmi2Annotation.xsd +0 -0
  57. {fmu_manipulation_toolbox-1.9.2b1 → fmu_manipulation_toolbox-1.9.2b3}/fmu_manipulation_toolbox/resources/fmi-2.0/fmi2AttributeGroups.xsd +0 -0
  58. {fmu_manipulation_toolbox-1.9.2b1 → fmu_manipulation_toolbox-1.9.2b3}/fmu_manipulation_toolbox/resources/fmi-2.0/fmi2ModelDescription.xsd +0 -0
  59. {fmu_manipulation_toolbox-1.9.2b1 → fmu_manipulation_toolbox-1.9.2b3}/fmu_manipulation_toolbox/resources/fmi-2.0/fmi2ScalarVariable.xsd +0 -0
  60. {fmu_manipulation_toolbox-1.9.2b1 → fmu_manipulation_toolbox-1.9.2b3}/fmu_manipulation_toolbox/resources/fmi-2.0/fmi2Type.xsd +0 -0
  61. {fmu_manipulation_toolbox-1.9.2b1 → fmu_manipulation_toolbox-1.9.2b3}/fmu_manipulation_toolbox/resources/fmi-2.0/fmi2Unit.xsd +0 -0
  62. {fmu_manipulation_toolbox-1.9.2b1 → fmu_manipulation_toolbox-1.9.2b3}/fmu_manipulation_toolbox/resources/fmi-2.0/fmi2VariableDependency.xsd +0 -0
  63. {fmu_manipulation_toolbox-1.9.2b1 → fmu_manipulation_toolbox-1.9.2b3}/fmu_manipulation_toolbox/resources/fmi-3.0/fmi3Annotation.xsd +0 -0
  64. {fmu_manipulation_toolbox-1.9.2b1 → fmu_manipulation_toolbox-1.9.2b3}/fmu_manipulation_toolbox/resources/fmi-3.0/fmi3AttributeGroups.xsd +0 -0
  65. {fmu_manipulation_toolbox-1.9.2b1 → fmu_manipulation_toolbox-1.9.2b3}/fmu_manipulation_toolbox/resources/fmi-3.0/fmi3BuildDescription.xsd +0 -0
  66. {fmu_manipulation_toolbox-1.9.2b1 → fmu_manipulation_toolbox-1.9.2b3}/fmu_manipulation_toolbox/resources/fmi-3.0/fmi3InterfaceType.xsd +0 -0
  67. {fmu_manipulation_toolbox-1.9.2b1 → fmu_manipulation_toolbox-1.9.2b3}/fmu_manipulation_toolbox/resources/fmi-3.0/fmi3LayeredStandardManifest.xsd +0 -0
  68. {fmu_manipulation_toolbox-1.9.2b1 → fmu_manipulation_toolbox-1.9.2b3}/fmu_manipulation_toolbox/resources/fmi-3.0/fmi3ModelDescription.xsd +0 -0
  69. {fmu_manipulation_toolbox-1.9.2b1 → fmu_manipulation_toolbox-1.9.2b3}/fmu_manipulation_toolbox/resources/fmi-3.0/fmi3Terminal.xsd +0 -0
  70. {fmu_manipulation_toolbox-1.9.2b1 → fmu_manipulation_toolbox-1.9.2b3}/fmu_manipulation_toolbox/resources/fmi-3.0/fmi3TerminalsAndIcons.xsd +0 -0
  71. {fmu_manipulation_toolbox-1.9.2b1 → fmu_manipulation_toolbox-1.9.2b3}/fmu_manipulation_toolbox/resources/fmi-3.0/fmi3Type.xsd +0 -0
  72. {fmu_manipulation_toolbox-1.9.2b1 → fmu_manipulation_toolbox-1.9.2b3}/fmu_manipulation_toolbox/resources/fmi-3.0/fmi3Unit.xsd +0 -0
  73. {fmu_manipulation_toolbox-1.9.2b1 → fmu_manipulation_toolbox-1.9.2b3}/fmu_manipulation_toolbox/resources/fmi-3.0/fmi3Variable.xsd +0 -0
  74. {fmu_manipulation_toolbox-1.9.2b1 → fmu_manipulation_toolbox-1.9.2b3}/fmu_manipulation_toolbox/resources/fmi-3.0/fmi3VariableDependency.xsd +0 -0
  75. {fmu_manipulation_toolbox-1.9.2b1 → fmu_manipulation_toolbox-1.9.2b3}/fmu_manipulation_toolbox/resources/fmu.png +0 -0
  76. {fmu_manipulation_toolbox-1.9.2b1 → fmu_manipulation_toolbox-1.9.2b3}/fmu_manipulation_toolbox/resources/fmu_manipulation_toolbox.png +0 -0
  77. {fmu_manipulation_toolbox-1.9.2b1 → fmu_manipulation_toolbox-1.9.2b3}/fmu_manipulation_toolbox/resources/help.png +0 -0
  78. {fmu_manipulation_toolbox-1.9.2b1 → fmu_manipulation_toolbox-1.9.2b3}/fmu_manipulation_toolbox/resources/icon-round.png +0 -0
  79. {fmu_manipulation_toolbox-1.9.2b1 → fmu_manipulation_toolbox-1.9.2b3}/fmu_manipulation_toolbox/resources/icon.png +0 -0
  80. {fmu_manipulation_toolbox-1.9.2b1 → fmu_manipulation_toolbox-1.9.2b3}/fmu_manipulation_toolbox/resources/icon_fmu.png +0 -0
  81. {fmu_manipulation_toolbox-1.9.2b1 → fmu_manipulation_toolbox-1.9.2b3}/fmu_manipulation_toolbox/resources/license.txt +0 -0
  82. {fmu_manipulation_toolbox-1.9.2b1 → fmu_manipulation_toolbox-1.9.2b3}/fmu_manipulation_toolbox/resources/linux32/server_sm +0 -0
  83. {fmu_manipulation_toolbox-1.9.2b1 → fmu_manipulation_toolbox-1.9.2b3}/fmu_manipulation_toolbox/resources/linux64/server_sm +0 -0
  84. {fmu_manipulation_toolbox-1.9.2b1 → fmu_manipulation_toolbox-1.9.2b3}/fmu_manipulation_toolbox/resources/mask.png +0 -0
  85. {fmu_manipulation_toolbox-1.9.2b1 → fmu_manipulation_toolbox-1.9.2b3}/fmu_manipulation_toolbox/resources/model.png +0 -0
  86. {fmu_manipulation_toolbox-1.9.2b1 → fmu_manipulation_toolbox-1.9.2b3}/fmu_manipulation_toolbox/terminals.py +0 -0
  87. {fmu_manipulation_toolbox-1.9.2b1 → fmu_manipulation_toolbox-1.9.2b3}/fmu_manipulation_toolbox.egg-info/dependency_links.txt +0 -0
  88. {fmu_manipulation_toolbox-1.9.2b1 → fmu_manipulation_toolbox-1.9.2b3}/fmu_manipulation_toolbox.egg-info/requires.txt +0 -0
  89. {fmu_manipulation_toolbox-1.9.2b1 → fmu_manipulation_toolbox-1.9.2b3}/fmu_manipulation_toolbox.egg-info/top_level.txt +0 -0
  90. {fmu_manipulation_toolbox-1.9.2b1 → fmu_manipulation_toolbox-1.9.2b3}/setup.cfg +0 -0
@@ -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
@@ -0,0 +1,42 @@
1
+ Metadata-Version: 2.4
2
+ Name: fmu_manipulation_toolbox
3
+ Version: 1.9.2b3
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)](https://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,31 +1,36 @@
1
1
  ![](fmu_manipulation_toolbox/resources/fmu_manipulation_toolbox.png)
2
2
 
3
- FMU Manipulation Toolbox is a python package which help to analyse, modify or combine
4
- [Functional Mock-up Units (FMUs)](http://fmi-standard.org/) without recompilation. It is highly customizable as it comes with
3
+ ![](https://raw.githubusercontent.com/grouperenault/fmu_manipulation_toolbox/refs/heads/badges/.github/badges/python-version.svg)
4
+ ![](https://raw.githubusercontent.com/grouperenault/fmu_manipulation_toolbox/refs/heads/badges/.github/badges/fmi-version.svg)
5
+ ![](https://raw.githubusercontent.com/grouperenault/fmu_manipulation_toolbox/refs/heads/badges/.github/badges/coverage.svg)
6
+
7
+ # 👀 Overview
8
+
9
+ FMU Manipulation Toolbox is a python package which helps to analyze, modify or combine
10
+ [Functional Mock-up Units (FMUs)](http://fmi-standard.org/) without recompilation. It is highly customizable and comes with
5
11
  a Python API.
6
12
 
7
- FMU Manipulation Toolbox can be used in different ways :
8
- - Using a Graphical User Interface: suitable for end user
9
- - Using a Command Line Interface: useful in
10
- - Using a python API: the most efficient for automation (CI/CD, transformation scripts, ...)
13
+ FMU Manipulation Toolbox can be used in different ways:
14
+ - Using a Graphical User Interface: suitable for end users
15
+ - Using a Command Line Interface: useful for scripting and automation
16
+ - Using a Python API: the most efficient option for automation (CI/CD, transformation scripts, ...))
11
17
 
12
18
  Major features:
13
- - Analyse FMU content: list ports and their attributes, check compliance of `ModelDescription.xml` with XSD, ...
14
- - Alter FMU by modifying its `modelDescription.xml` file. NOTE: manipulating this file can be a dangerous
15
- thing! Communicating with the FMU-developer and adapting the way the FMU is generated is preferable when
16
- possible.
17
- - Add binary interface. Typical use case is porting a 32bits FMUs to 64bits (or vice et versa).
18
- - Nest FMUs in a [FMU Container](doc/container.md)
19
+ - Analyze FMU content: list ports and their attributes, check compliance of `ModelDescription.xml` with XSD, etc.
20
+ - Alter FMU by modifying its `modelDescription.xml` file. NOTE: manipulating this file can be a risky.
21
+ When possible, it is preferable to communicate with the FMU developer and adapt the FMU generation process.
22
+ - Add binary interfaces. Typical use case is porting a 32-bit FMUs to 64-bit systems (or vice et versa).
23
+ - Combine FMUs into [FMU Containers](doc/container.md) and allow your favourite FMI tool to orchestrate complex assembly of FMUs.
19
24
 
20
25
  FMI versions 2.0 and 3.0 are supported.
21
26
 
22
- ## Installation
27
+ # ⚙️ Installation
23
28
 
24
29
  Two options available to install FMU Manipulation Toolbox:
25
30
 
26
31
  - (*Easiest option*) Install with from PyPI: `pip install fmu-manipulation-toolbox`. This will install the latest
27
32
  version of FMU Manipulation Toolbox and all its dependencies. See [PyPI page](https://pypi.org/project/fmu-manipulation-toolbox/).
28
- - Compile and install from [github repository](https://github.com/grouperenault/fmu_manipulation_toolbox). You will need
33
+ - Compile and install from [GitHub repository](https://github.com/grouperenault/fmu_manipulation_toolbox). You will need
29
34
  - Python required packages. See [`requirements.txt`](requirements.txt).
30
35
  - C compiler (C99 or later)
31
36
  - CMake (>= 3.20)
@@ -39,7 +44,7 @@ FMU Manipulation Toolbox is packaged for:
39
44
  - Darwin
40
45
 
41
46
 
42
- ## Graphical User Interface
47
+ # 🖥️ Graphical User Interface
43
48
 
44
49
  FMU Manipulation Toolbox is released with a GUI. You can launch it with the following command `fmutool-gui`
45
50
 
@@ -55,7 +60,7 @@ Button colors descriptions:
55
60
  **Original FMU is never modified**. Use `Save` button to get modified copy of the original FMU.
56
61
 
57
62
 
58
- ## Command Line Interface
63
+ # 🔧 Command Line Interface
59
64
 
60
65
  FMU Manipulation Toolbox comes with 2 commands:
61
66
  - `fmutool`: a versatile analysis and manipulation tool for FMU.
@@ -63,7 +68,7 @@ FMU Manipulation Toolbox comes with 2 commands:
63
68
  - `fmusplit: to extract FMUs from a FMU Container.
64
69
 
65
70
 
66
- ### Analysis and Manipulation tool:
71
+ ## Analysis and Manipulation tool:
67
72
 
68
73
  You can use `fmutool -help` to get usage:
69
74
 
@@ -149,7 +154,7 @@ optional arguments:
149
154
  later issues when using the FMU. (default: None)
150
155
  ```
151
156
 
152
- ### FMU Containers
157
+ ## FMU Containers
153
158
 
154
159
  ```
155
160
  usage: fmucontainer [-h] [-fmu-directory FMU_DIRECTORY] [-fmi FMI_VERSION]
@@ -178,7 +183,7 @@ options:
178
183
  -dump-json Dump a JSON file for each container. (default: False)
179
184
  ```
180
185
 
181
- ## API
186
+ # 🚀 API
182
187
 
183
188
  You can write your own FMU Manipulation scripts. Once you downloaded fmutool module,
184
189
  adding the `import` statement lets you access the API :
@@ -188,7 +193,7 @@ from fmu_manipulation_toolbox.operations import ...
188
193
  ```
189
194
 
190
195
 
191
- ### remove toplevel bus (if any)
196
+ ## remove toplevel bus (if any)
192
197
 
193
198
  Given a FMU with the following I/O structure
194
199
  ```
@@ -230,9 +235,8 @@ The following code will dump all FMU's Scalars names into a CSV:
230
235
  from fmu_manipulation_toolbox.operations import FMU, OperationSaveNamesToCSV
231
236
 
232
237
  fmu = FMU(r"bouncing_ball.fmu")
233
- operation = OperationSaveNamesToCSV()
238
+ operation = OperationSaveNamesToCSV(r"bouncing_ball.csv")
234
239
  fmu.apply_operation(operation)
235
- operation.write_csv(r"bouncing_ball.csv")
236
240
  ```
237
241
 
238
242
  The produced CSV contains 2 columns in order to be reused in the next transformation.
@@ -249,7 +253,7 @@ e;e;5;parameter;tunable
249
253
  ```
250
254
 
251
255
 
252
- ### Read CSV and rename FMU ports
256
+ ## Read CSV and rename FMU ports
253
257
 
254
258
  CSV file should contain 2 columns:
255
259
  1. the current name
@@ -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():
@@ -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
@@ -0,0 +1,143 @@
1
+ import argparse
2
+ import csv
3
+ import logging
4
+ import sys
5
+
6
+ from pathlib import Path
7
+ from typing import *
8
+
9
+ from .utils import setup_logger, close_logger, make_wide
10
+ from ..version import __version__ as version
11
+
12
+ logger = setup_logger()
13
+
14
+ class DatalogConverter:
15
+ def __init__(self, cvs_filename: Union[Path, str]):
16
+ self.csv_filename = Path(cvs_filename)
17
+ self.pcap_filename = self.csv_filename.with_suffix(".pcap")
18
+
19
+ def open_pcap(self):
20
+ logger.info(f"Creating PCAP file '{self.pcap_filename}'...")
21
+ file = open(self.pcap_filename, "wb")
22
+ file.write(int(0xA1B2C3D4).to_bytes(4, byteorder="big")) # Magic number
23
+ # meaning the timestamp are in min seconds and microseconds
24
+
25
+ file.write(int(2).to_bytes(2, byteorder="big")) # Major Version of fileformat
26
+ file.write(int(4).to_bytes(2, byteorder="big")) # Minor Version
27
+ file.write(int(0).to_bytes(4, byteorder="big")) # Reserved. SHOULD BE 0.
28
+ file.write(int(0).to_bytes(4, byteorder="big")) # Reserved. SHOULD BE 0.
29
+
30
+ file.write(int(0xFFFF).to_bytes(4, byteorder="big")) # snaplen indicating the maximum number of octets
31
+ # captured from each packet.
32
+
33
+ file.write(int(227).to_bytes(4, byteorder="big")) # link type. his field is defined in the Section
34
+ # # 8.1 IANA registry.
35
+ return file
36
+
37
+ def open_csv(self):
38
+ logger.debug(f"Loading '{self.csv_filename}'")
39
+ file = open(self.csv_filename, "rt")
40
+ return file
41
+
42
+ def decode_hexstring(self, hex_string: bytes, time_s, time_us):
43
+ opcode = int.from_bytes(hex_string[0:4], byteorder="little")
44
+ length = int.from_bytes(hex_string[4:8], byteorder="little")
45
+ can_id = int.from_bytes(hex_string[8:12], byteorder="little")
46
+ if opcode == 0x10: # TRANSMIT
47
+ rtr = int.from_bytes(hex_string[13:14], byteorder="little")
48
+ ide = int.from_bytes(hex_string[12:13], byteorder="little")
49
+ data_length = int.from_bytes(hex_string[14:16], byteorder="little")
50
+ raw_data = hex_string[16:]
51
+
52
+ logger.debug(f"time={time_s}.{time_us:06d} OP=0x{opcode:04X} len={length} {data_length} id={can_id}"
53
+ f" ide={ide} rtr={rtr} len={data_length} {raw_data}")
54
+
55
+ # TimeStamp
56
+ self.pcapfile.write(time_s.to_bytes(4, byteorder="big"))
57
+ self.pcapfile.write(time_us.to_bytes(4, byteorder="big"))
58
+
59
+ # Packet length
60
+ packet_length = data_length + 8
61
+ self.pcapfile.write(packet_length.to_bytes(4, byteorder="big"))
62
+ self.pcapfile.write(packet_length.to_bytes(4, byteorder="big"))
63
+
64
+ # Control and flags
65
+ control = (can_id & 0x1FFFFFFF) | ((rtr & 0b1) << 30) | ((ide & 0b1) << 31)
66
+ self.pcapfile.write(control.to_bytes(4, byteorder="big"))
67
+
68
+ # Frame Length
69
+ self.pcapfile.write(data_length.to_bytes(1, byteorder="big"))
70
+
71
+ # Reserved
72
+ self.pcapfile.write(int(0).to_bytes(2, byteorder="big"))
73
+
74
+ # DLC
75
+ dlc = int(data_length) # Classic CAN
76
+ self.pcapfile.write(dlc.to_bytes(1, byteorder="big"))
77
+
78
+ # PAYLOAD
79
+ self.pcapfile.write(raw_data)
80
+
81
+ def convert(self):
82
+ with self.open_csv() as self.csvfile, self.open_pcap() as self.pcapfile:
83
+ csv_reader = csv.DictReader(self.csvfile)
84
+
85
+ data_column_names = [ name for name in csv_reader.fieldnames if "_Data" in name ]
86
+ clock_column_names = {}
87
+
88
+ for column_name in data_column_names:
89
+ splitted_name = column_name.split(".")
90
+ splitted_name[-1] = splitted_name[-1].replace("_Data", "_Clock")
91
+ clock_column_name = ".".join(splitted_name)
92
+
93
+ if clock_column_name in csv_reader.fieldnames:
94
+ logger.debug(f"{column_name} is clocked by {clock_column_name}")
95
+ clock_column_names[column_name] = clock_column_name
96
+
97
+ for row in csv_reader:
98
+ time_s, time_us = divmod(float(row["time"]), 1)
99
+ time_s = int(time_s)
100
+ time_us = int(time_us * 1000000)
101
+
102
+ for names in data_column_names:
103
+ hex_data = row[names]
104
+ if hex_data:
105
+ try:
106
+ clock = row[clock_column_names[names]] == "1"
107
+ except KeyError:
108
+ clock = True
109
+ if clock:
110
+ self.decode_hexstring(bytes.fromhex(hex_data), time_s, time_us)
111
+
112
+
113
+ def datalog2pcap():
114
+ logger.info(f"FMUContainer version {version}")
115
+ logger.warning(f"Datalog2PCAP is still experimental.")
116
+
117
+ parser = argparse.ArgumentParser(prog="datalog2pcap", description="Convert datalog from container to PCAP file.",
118
+ formatter_class=make_wide(argparse.ArgumentDefaultsHelpFormatter),
119
+ add_help=False,
120
+ epilog="see: https://github.com/grouperenault/fmu_manipulation_toolbox/blob/main/"
121
+ "doc/datalog.md")
122
+
123
+ parser.add_argument('-h', '-help', action="help")
124
+
125
+ parser.add_argument("-can", action="store", dest="can_filename", default=None,
126
+ metavar="can-datalog.csv", required=True,
127
+ help="Datalog with CAN data and clocks.")
128
+
129
+ parser.add_argument("-debug", action="store_true", dest="debug",
130
+ help="Add lot of useful log during the process.")
131
+
132
+ config = parser.parse_args(sys.argv[1:])
133
+
134
+ if config.debug:
135
+ logger.setLevel(logging.DEBUG)
136
+
137
+ DatalogConverter(config.can_filename).convert()
138
+
139
+ close_logger(logger)
140
+
141
+
142
+ if __name__ == "__main__":
143
+ datalog2pcap()
@@ -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: