fmu-manipulation-toolbox 2.1.dev0__tar.gz → 2.1.dev1__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 (312) hide show
  1. {fmu_manipulation_toolbox-2.1.dev0 → fmu_manipulation_toolbox-2.1.dev1}/CHANGELOG.md +27 -0
  2. {fmu_manipulation_toolbox-2.1.dev0 → fmu_manipulation_toolbox-2.1.dev1}/MANIFEST.in +3 -1
  3. {fmu_manipulation_toolbox-2.1.dev0 → fmu_manipulation_toolbox-2.1.dev1}/PKG-INFO +8 -1
  4. {fmu_manipulation_toolbox-2.1.dev0 → fmu_manipulation_toolbox-2.1.dev1}/README.md +7 -0
  5. {fmu_manipulation_toolbox-2.1.dev0 → fmu_manipulation_toolbox-2.1.dev1}/fmu_manipulation_toolbox/_version.py +3 -3
  6. {fmu_manipulation_toolbox-2.1.dev0 → fmu_manipulation_toolbox-2.1.dev1}/fmu_manipulation_toolbox/assistant/fmutools.py +211 -26
  7. {fmu_manipulation_toolbox-2.1.dev0 → fmu_manipulation_toolbox-2.1.dev1}/fmu_manipulation_toolbox/assistant/headless.py +46 -0
  8. {fmu_manipulation_toolbox-2.1.dev0 → fmu_manipulation_toolbox-2.1.dev1}/fmu_manipulation_toolbox/assistant/knowledge.py +7 -3
  9. {fmu_manipulation_toolbox-2.1.dev0 → fmu_manipulation_toolbox-2.1.dev1}/fmu_manipulation_toolbox/assistant/models.py +9 -46
  10. {fmu_manipulation_toolbox-2.1.dev0 → fmu_manipulation_toolbox-2.1.dev1}/fmu_manipulation_toolbox/assistant/server.py +87 -142
  11. fmu_manipulation_toolbox-2.1.dev1/fmu_manipulation_toolbox/assistant/tools.py +319 -0
  12. {fmu_manipulation_toolbox-2.1.dev0 → fmu_manipulation_toolbox-2.1.dev1}/fmu_manipulation_toolbox/checker.py +2 -11
  13. {fmu_manipulation_toolbox-2.1.dev0 → fmu_manipulation_toolbox-2.1.dev1}/fmu_manipulation_toolbox/cli/fmutool.py +11 -1
  14. fmu_manipulation_toolbox-2.1.dev1/fmu_manipulation_toolbox/cli/fmutool_agent.py +285 -0
  15. {fmu_manipulation_toolbox-2.1.dev0 → fmu_manipulation_toolbox-2.1.dev1}/fmu_manipulation_toolbox/help.py +10 -0
  16. {fmu_manipulation_toolbox-2.1.dev0 → fmu_manipulation_toolbox-2.1.dev1}/fmu_manipulation_toolbox/model_description.py +58 -1
  17. {fmu_manipulation_toolbox-2.1.dev0 → fmu_manipulation_toolbox-2.1.dev1}/fmu_manipulation_toolbox/operations.py +85 -22
  18. {fmu_manipulation_toolbox-2.1.dev0 → fmu_manipulation_toolbox-2.1.dev1}/fmu_manipulation_toolbox.egg-info/PKG-INFO +8 -1
  19. {fmu_manipulation_toolbox-2.1.dev0 → fmu_manipulation_toolbox-2.1.dev1}/fmu_manipulation_toolbox.egg-info/SOURCES.txt +6 -0
  20. {fmu_manipulation_toolbox-2.1.dev0 → fmu_manipulation_toolbox-2.1.dev1}/fmu_manipulation_toolbox.egg-info/entry_points.txt +1 -0
  21. {fmu_manipulation_toolbox-2.1.dev0 → fmu_manipulation_toolbox-2.1.dev1}/fmu_manipulation_toolbox.egg-info/scm_file_list.json +16 -0
  22. fmu_manipulation_toolbox-2.1.dev1/fmu_manipulation_toolbox.egg-info/scm_version.json +8 -0
  23. {fmu_manipulation_toolbox-2.1.dev0 → fmu_manipulation_toolbox-2.1.dev1}/mkdocs.yml +2 -0
  24. {fmu_manipulation_toolbox-2.1.dev0 → fmu_manipulation_toolbox-2.1.dev1}/pyproject.toml +1 -0
  25. {fmu_manipulation_toolbox-2.1.dev0 → fmu_manipulation_toolbox-2.1.dev1}/tests/_helpers/mcp_budget.py +7 -2
  26. {fmu_manipulation_toolbox-2.1.dev0 → fmu_manipulation_toolbox-2.1.dev1}/tests/integration/test_cli.py +11 -0
  27. fmu_manipulation_toolbox-2.1.dev1/tests/unit/test_agent_skills.py +242 -0
  28. {fmu_manipulation_toolbox-2.1.dev0 → fmu_manipulation_toolbox-2.1.dev1}/tests/unit/test_assistant_fmutools.py +175 -5
  29. {fmu_manipulation_toolbox-2.1.dev0 → fmu_manipulation_toolbox-2.1.dev1}/tests/unit/test_assistant_server_contract.py +6 -4
  30. {fmu_manipulation_toolbox-2.1.dev0 → fmu_manipulation_toolbox-2.1.dev1}/tests/unit/test_assistant_server_tools.py +76 -0
  31. fmu_manipulation_toolbox-2.1.dev1/tests/unit/test_fmutool_agent.py +286 -0
  32. fmu_manipulation_toolbox-2.1.dev1/tests/unit/test_operations_scope.py +209 -0
  33. fmu_manipulation_toolbox-2.1.dev1/tools/build_skill_zips.py +56 -0
  34. fmu_manipulation_toolbox-2.1.dev0/fmu_manipulation_toolbox.egg-info/scm_version.json +0 -8
  35. {fmu_manipulation_toolbox-2.1.dev0 → fmu_manipulation_toolbox-2.1.dev1}/.git_archival.txt +0 -0
  36. {fmu_manipulation_toolbox-2.1.dev0 → fmu_manipulation_toolbox-2.1.dev1}/.gitattributes +0 -0
  37. {fmu_manipulation_toolbox-2.1.dev0 → fmu_manipulation_toolbox-2.1.dev1}/.gitignore +0 -0
  38. {fmu_manipulation_toolbox-2.1.dev0 → fmu_manipulation_toolbox-2.1.dev1}/CLAUDE.md +0 -0
  39. {fmu_manipulation_toolbox-2.1.dev0 → fmu_manipulation_toolbox-2.1.dev1}/CONTRIBUTING.md +0 -0
  40. {fmu_manipulation_toolbox-2.1.dev0 → fmu_manipulation_toolbox-2.1.dev1}/LICENSE.txt +0 -0
  41. {fmu_manipulation_toolbox-2.1.dev0 → fmu_manipulation_toolbox-2.1.dev1}/cmake/fmutool.cmake +0 -0
  42. {fmu_manipulation_toolbox-2.1.dev0 → fmu_manipulation_toolbox-2.1.dev1}/cmake/gen_version.cmake +0 -0
  43. {fmu_manipulation_toolbox-2.1.dev0 → fmu_manipulation_toolbox-2.1.dev1}/cmake/pgo.cmake +0 -0
  44. {fmu_manipulation_toolbox-2.1.dev0 → fmu_manipulation_toolbox-2.1.dev1}/cmake/version.h.in +0 -0
  45. {fmu_manipulation_toolbox-2.1.dev0 → fmu_manipulation_toolbox-2.1.dev1}/container/CMakeLists.txt +0 -0
  46. {fmu_manipulation_toolbox-2.1.dev0 → fmu_manipulation_toolbox-2.1.dev1}/container/build.bat +0 -0
  47. {fmu_manipulation_toolbox-2.1.dev0 → fmu_manipulation_toolbox-2.1.dev1}/container/config.c +0 -0
  48. {fmu_manipulation_toolbox-2.1.dev0 → fmu_manipulation_toolbox-2.1.dev1}/container/config.h +0 -0
  49. {fmu_manipulation_toolbox-2.1.dev0 → fmu_manipulation_toolbox-2.1.dev1}/container/container.c +0 -0
  50. {fmu_manipulation_toolbox-2.1.dev0 → fmu_manipulation_toolbox-2.1.dev1}/container/container.h +0 -0
  51. {fmu_manipulation_toolbox-2.1.dev0 → fmu_manipulation_toolbox-2.1.dev1}/container/convert.c +0 -0
  52. {fmu_manipulation_toolbox-2.1.dev0 → fmu_manipulation_toolbox-2.1.dev1}/container/convert.h +0 -0
  53. {fmu_manipulation_toolbox-2.1.dev0 → fmu_manipulation_toolbox-2.1.dev1}/container/datalog.c +0 -0
  54. {fmu_manipulation_toolbox-2.1.dev0 → fmu_manipulation_toolbox-2.1.dev1}/container/datalog.h +0 -0
  55. {fmu_manipulation_toolbox-2.1.dev0 → fmu_manipulation_toolbox-2.1.dev1}/container/fmi2.c +0 -0
  56. {fmu_manipulation_toolbox-2.1.dev0 → fmu_manipulation_toolbox-2.1.dev1}/container/fmi3.c +0 -0
  57. {fmu_manipulation_toolbox-2.1.dev0 → fmu_manipulation_toolbox-2.1.dev1}/container/fmu.c +0 -0
  58. {fmu_manipulation_toolbox-2.1.dev0 → fmu_manipulation_toolbox-2.1.dev1}/container/fmu.h +0 -0
  59. {fmu_manipulation_toolbox-2.1.dev0 → fmu_manipulation_toolbox-2.1.dev1}/container/hash.c +0 -0
  60. {fmu_manipulation_toolbox-2.1.dev0 → fmu_manipulation_toolbox-2.1.dev1}/container/hash.h +0 -0
  61. {fmu_manipulation_toolbox-2.1.dev0 → fmu_manipulation_toolbox-2.1.dev1}/container/library.c +0 -0
  62. {fmu_manipulation_toolbox-2.1.dev0 → fmu_manipulation_toolbox-2.1.dev1}/container/library.h +0 -0
  63. {fmu_manipulation_toolbox-2.1.dev0 → fmu_manipulation_toolbox-2.1.dev1}/container/logger.c +0 -0
  64. {fmu_manipulation_toolbox-2.1.dev0 → fmu_manipulation_toolbox-2.1.dev1}/container/logger.h +0 -0
  65. {fmu_manipulation_toolbox-2.1.dev0 → fmu_manipulation_toolbox-2.1.dev1}/container/profile.c +0 -0
  66. {fmu_manipulation_toolbox-2.1.dev0 → fmu_manipulation_toolbox-2.1.dev1}/container/profile.h +0 -0
  67. {fmu_manipulation_toolbox-2.1.dev0 → fmu_manipulation_toolbox-2.1.dev1}/container/solver.c +0 -0
  68. {fmu_manipulation_toolbox-2.1.dev0 → fmu_manipulation_toolbox-2.1.dev1}/container/solver.h +0 -0
  69. {fmu_manipulation_toolbox-2.1.dev0 → fmu_manipulation_toolbox-2.1.dev1}/container/test_fmi.c +0 -0
  70. {fmu_manipulation_toolbox-2.1.dev0 → fmu_manipulation_toolbox-2.1.dev1}/container/tests/data/empty/container.txt +0 -0
  71. {fmu_manipulation_toolbox-2.1.dev0 → fmu_manipulation_toolbox-2.1.dev1}/container/tests/data/one_fmu/container.txt.in +0 -0
  72. {fmu_manipulation_toolbox-2.1.dev0 → fmu_manipulation_toolbox-2.1.dev1}/container/tests/data/one_fmu/datalog.txt.in +0 -0
  73. {fmu_manipulation_toolbox-2.1.dev0 → fmu_manipulation_toolbox-2.1.dev1}/container/tests/stub_fmu.c +0 -0
  74. {fmu_manipulation_toolbox-2.1.dev0 → fmu_manipulation_toolbox-2.1.dev1}/container/tests/test.h +0 -0
  75. {fmu_manipulation_toolbox-2.1.dev0 → fmu_manipulation_toolbox-2.1.dev1}/container/tests/test_config.c +0 -0
  76. {fmu_manipulation_toolbox-2.1.dev0 → fmu_manipulation_toolbox-2.1.dev1}/container/tests/test_configure.c +0 -0
  77. {fmu_manipulation_toolbox-2.1.dev0 → fmu_manipulation_toolbox-2.1.dev1}/container/tests/test_datalog.c +0 -0
  78. {fmu_manipulation_toolbox-2.1.dev0 → fmu_manipulation_toolbox-2.1.dev1}/container/tests/test_locale.c +0 -0
  79. {fmu_manipulation_toolbox-2.1.dev0 → fmu_manipulation_toolbox-2.1.dev1}/container/tests/test_logger.c +0 -0
  80. {fmu_manipulation_toolbox-2.1.dev0 → fmu_manipulation_toolbox-2.1.dev1}/container/tests/test_main.c +0 -0
  81. {fmu_manipulation_toolbox-2.1.dev0 → fmu_manipulation_toolbox-2.1.dev1}/container/tests/test_malformed.c +0 -0
  82. {fmu_manipulation_toolbox-2.1.dev0 → fmu_manipulation_toolbox-2.1.dev1}/container/tests/test_thread.c +0 -0
  83. {fmu_manipulation_toolbox-2.1.dev0 → fmu_manipulation_toolbox-2.1.dev1}/container/tests/test_threads_lifecycle.c +0 -0
  84. {fmu_manipulation_toolbox-2.1.dev0 → fmu_manipulation_toolbox-2.1.dev1}/container/thread.c +0 -0
  85. {fmu_manipulation_toolbox-2.1.dev0 → fmu_manipulation_toolbox-2.1.dev1}/container/thread.h +0 -0
  86. {fmu_manipulation_toolbox-2.1.dev0 → fmu_manipulation_toolbox-2.1.dev1}/fmu_manipulation_toolbox/__init__.py +0 -0
  87. {fmu_manipulation_toolbox-2.1.dev0 → fmu_manipulation_toolbox-2.1.dev1}/fmu_manipulation_toolbox/__main__.py +0 -0
  88. {fmu_manipulation_toolbox-2.1.dev0 → fmu_manipulation_toolbox-2.1.dev1}/fmu_manipulation_toolbox/assembly.py +0 -0
  89. {fmu_manipulation_toolbox-2.1.dev0 → fmu_manipulation_toolbox-2.1.dev1}/fmu_manipulation_toolbox/assistant/__init__.py +0 -0
  90. {fmu_manipulation_toolbox-2.1.dev0 → fmu_manipulation_toolbox-2.1.dev1}/fmu_manipulation_toolbox/assistant/analysis.py +0 -0
  91. {fmu_manipulation_toolbox-2.1.dev0 → fmu_manipulation_toolbox-2.1.dev1}/fmu_manipulation_toolbox/assistant/auth.py +0 -0
  92. {fmu_manipulation_toolbox-2.1.dev0 → fmu_manipulation_toolbox-2.1.dev1}/fmu_manipulation_toolbox/assistant/bridge.py +0 -0
  93. {fmu_manipulation_toolbox-2.1.dev0 → fmu_manipulation_toolbox-2.1.dev1}/fmu_manipulation_toolbox/assistant/paths.py +0 -0
  94. {fmu_manipulation_toolbox-2.1.dev0 → fmu_manipulation_toolbox-2.1.dev1}/fmu_manipulation_toolbox/assistant/replay.py +0 -0
  95. {fmu_manipulation_toolbox-2.1.dev0 → fmu_manipulation_toolbox-2.1.dev1}/fmu_manipulation_toolbox/cli/__init__.py +0 -0
  96. {fmu_manipulation_toolbox-2.1.dev0 → fmu_manipulation_toolbox-2.1.dev1}/fmu_manipulation_toolbox/cli/datalog2pcap.py +0 -0
  97. {fmu_manipulation_toolbox-2.1.dev0 → fmu_manipulation_toolbox-2.1.dev1}/fmu_manipulation_toolbox/cli/fmucontainer.py +0 -0
  98. {fmu_manipulation_toolbox-2.1.dev0 → fmu_manipulation_toolbox-2.1.dev1}/fmu_manipulation_toolbox/cli/fmusplit.py +0 -0
  99. {fmu_manipulation_toolbox-2.1.dev0 → fmu_manipulation_toolbox-2.1.dev1}/fmu_manipulation_toolbox/cli/fmutool_mcp.py +0 -0
  100. {fmu_manipulation_toolbox-2.1.dev0 → fmu_manipulation_toolbox-2.1.dev1}/fmu_manipulation_toolbox/cli/utils.py +0 -0
  101. {fmu_manipulation_toolbox-2.1.dev0 → fmu_manipulation_toolbox-2.1.dev1}/fmu_manipulation_toolbox/compiler.py +0 -0
  102. {fmu_manipulation_toolbox-2.1.dev0 → fmu_manipulation_toolbox-2.1.dev1}/fmu_manipulation_toolbox/container/__init__.py +0 -0
  103. {fmu_manipulation_toolbox-2.1.dev0 → fmu_manipulation_toolbox-2.1.dev1}/fmu_manipulation_toolbox/container/arrays.py +0 -0
  104. {fmu_manipulation_toolbox-2.1.dev0 → fmu_manipulation_toolbox-2.1.dev1}/fmu_manipulation_toolbox/container/builder.py +0 -0
  105. {fmu_manipulation_toolbox-2.1.dev0 → fmu_manipulation_toolbox-2.1.dev1}/fmu_manipulation_toolbox/container/embedded.py +0 -0
  106. {fmu_manipulation_toolbox-2.1.dev0 → fmu_manipulation_toolbox-2.1.dev1}/fmu_manipulation_toolbox/container/errors.py +0 -0
  107. {fmu_manipulation_toolbox-2.1.dev0 → fmu_manipulation_toolbox-2.1.dev1}/fmu_manipulation_toolbox/container/layout.py +0 -0
  108. {fmu_manipulation_toolbox-2.1.dev0 → fmu_manipulation_toolbox-2.1.dev1}/fmu_manipulation_toolbox/container/rules.py +0 -0
  109. {fmu_manipulation_toolbox-2.1.dev0 → fmu_manipulation_toolbox-2.1.dev1}/fmu_manipulation_toolbox/container/txt.py +0 -0
  110. {fmu_manipulation_toolbox-2.1.dev0 → fmu_manipulation_toolbox-2.1.dev1}/fmu_manipulation_toolbox/container/types.py +0 -0
  111. {fmu_manipulation_toolbox-2.1.dev0 → fmu_manipulation_toolbox-2.1.dev1}/fmu_manipulation_toolbox/gui/__init__.py +0 -0
  112. {fmu_manipulation_toolbox-2.1.dev0 → fmu_manipulation_toolbox-2.1.dev1}/fmu_manipulation_toolbox/gui/__main__.py +0 -0
  113. {fmu_manipulation_toolbox-2.1.dev0 → fmu_manipulation_toolbox-2.1.dev1}/fmu_manipulation_toolbox/gui/fmucontainer/__init__.py +0 -0
  114. {fmu_manipulation_toolbox-2.1.dev0 → fmu_manipulation_toolbox-2.1.dev1}/fmu_manipulation_toolbox/gui/fmucontainer/__main__.py +0 -0
  115. {fmu_manipulation_toolbox-2.1.dev0 → fmu_manipulation_toolbox-2.1.dev1}/fmu_manipulation_toolbox/gui/fmucontainer/assembly_io.py +0 -0
  116. {fmu_manipulation_toolbox-2.1.dev0 → fmu_manipulation_toolbox-2.1.dev1}/fmu_manipulation_toolbox/gui/fmucontainer/details/__init__.py +0 -0
  117. {fmu_manipulation_toolbox-2.1.dev0 → fmu_manipulation_toolbox-2.1.dev1}/fmu_manipulation_toolbox/gui/fmucontainer/details/configuration_detail.py +0 -0
  118. {fmu_manipulation_toolbox-2.1.dev0 → fmu_manipulation_toolbox-2.1.dev1}/fmu_manipulation_toolbox/gui/fmucontainer/details/container_detail.py +0 -0
  119. {fmu_manipulation_toolbox-2.1.dev0 → fmu_manipulation_toolbox-2.1.dev1}/fmu_manipulation_toolbox/gui/fmucontainer/details/fmu_detail.py +0 -0
  120. {fmu_manipulation_toolbox-2.1.dev0 → fmu_manipulation_toolbox-2.1.dev1}/fmu_manipulation_toolbox/gui/fmucontainer/details/link_assistant.py +0 -0
  121. {fmu_manipulation_toolbox-2.1.dev0 → fmu_manipulation_toolbox-2.1.dev1}/fmu_manipulation_toolbox/gui/fmucontainer/details/link_assistant_demo.py +0 -0
  122. {fmu_manipulation_toolbox-2.1.dev0 → fmu_manipulation_toolbox-2.1.dev1}/fmu_manipulation_toolbox/gui/fmucontainer/details/link_matching.py +0 -0
  123. {fmu_manipulation_toolbox-2.1.dev0 → fmu_manipulation_toolbox-2.1.dev1}/fmu_manipulation_toolbox/gui/fmucontainer/details/stack.py +0 -0
  124. {fmu_manipulation_toolbox-2.1.dev0 → fmu_manipulation_toolbox-2.1.dev1}/fmu_manipulation_toolbox/gui/fmucontainer/details/wire_detail.py +0 -0
  125. {fmu_manipulation_toolbox-2.1.dev0 → fmu_manipulation_toolbox-2.1.dev1}/fmu_manipulation_toolbox/gui/fmucontainer/graph/__init__.py +0 -0
  126. {fmu_manipulation_toolbox-2.1.dev0 → fmu_manipulation_toolbox-2.1.dev1}/fmu_manipulation_toolbox/gui/fmucontainer/graph/constants.py +0 -0
  127. {fmu_manipulation_toolbox-2.1.dev0 → fmu_manipulation_toolbox-2.1.dev1}/fmu_manipulation_toolbox/gui/fmucontainer/graph/node.py +0 -0
  128. {fmu_manipulation_toolbox-2.1.dev0 → fmu_manipulation_toolbox-2.1.dev1}/fmu_manipulation_toolbox/gui/fmucontainer/graph/node_info_dialog.py +0 -0
  129. {fmu_manipulation_toolbox-2.1.dev0 → fmu_manipulation_toolbox-2.1.dev1}/fmu_manipulation_toolbox/gui/fmucontainer/graph/scene.py +0 -0
  130. {fmu_manipulation_toolbox-2.1.dev0 → fmu_manipulation_toolbox-2.1.dev1}/fmu_manipulation_toolbox/gui/fmucontainer/graph/view.py +0 -0
  131. {fmu_manipulation_toolbox-2.1.dev0 → fmu_manipulation_toolbox-2.1.dev1}/fmu_manipulation_toolbox/gui/fmucontainer/graph/widget.py +0 -0
  132. {fmu_manipulation_toolbox-2.1.dev0 → fmu_manipulation_toolbox-2.1.dev1}/fmu_manipulation_toolbox/gui/fmucontainer/graph/wire.py +0 -0
  133. {fmu_manipulation_toolbox-2.1.dev0 → fmu_manipulation_toolbox-2.1.dev1}/fmu_manipulation_toolbox/gui/fmucontainer/mcp_bridge.py +0 -0
  134. {fmu_manipulation_toolbox-2.1.dev0 → fmu_manipulation_toolbox-2.1.dev1}/fmu_manipulation_toolbox/gui/fmucontainer/tree/__init__.py +0 -0
  135. {fmu_manipulation_toolbox-2.1.dev0 → fmu_manipulation_toolbox-2.1.dev1}/fmu_manipulation_toolbox/gui/fmucontainer/tree/model.py +0 -0
  136. {fmu_manipulation_toolbox-2.1.dev0 → fmu_manipulation_toolbox-2.1.dev1}/fmu_manipulation_toolbox/gui/fmucontainer/tree/panel.py +0 -0
  137. {fmu_manipulation_toolbox-2.1.dev0 → fmu_manipulation_toolbox-2.1.dev1}/fmu_manipulation_toolbox/gui/fmucontainer/tree/sync.py +0 -0
  138. {fmu_manipulation_toolbox-2.1.dev0 → fmu_manipulation_toolbox-2.1.dev1}/fmu_manipulation_toolbox/gui/fmucontainer/tree/widget.py +0 -0
  139. {fmu_manipulation_toolbox-2.1.dev0 → fmu_manipulation_toolbox-2.1.dev1}/fmu_manipulation_toolbox/gui/fmueditor/__init__.py +0 -0
  140. {fmu_manipulation_toolbox-2.1.dev0 → fmu_manipulation_toolbox-2.1.dev1}/fmu_manipulation_toolbox/gui/fmueditor/__main__.py +0 -0
  141. {fmu_manipulation_toolbox-2.1.dev0 → fmu_manipulation_toolbox-2.1.dev1}/fmu_manipulation_toolbox/gui/fmutool/__init__.py +0 -0
  142. {fmu_manipulation_toolbox-2.1.dev0 → fmu_manipulation_toolbox-2.1.dev1}/fmu_manipulation_toolbox/gui/fmutool/__main__.py +0 -0
  143. {fmu_manipulation_toolbox-2.1.dev0 → fmu_manipulation_toolbox-2.1.dev1}/fmu_manipulation_toolbox/gui/helper.py +0 -0
  144. {fmu_manipulation_toolbox-2.1.dev0 → fmu_manipulation_toolbox-2.1.dev1}/fmu_manipulation_toolbox/gui/log.py +0 -0
  145. {fmu_manipulation_toolbox-2.1.dev0 → fmu_manipulation_toolbox-2.1.dev1}/fmu_manipulation_toolbox/gui/style.py +0 -0
  146. {fmu_manipulation_toolbox-2.1.dev0 → fmu_manipulation_toolbox-2.1.dev1}/fmu_manipulation_toolbox/ls.py +0 -0
  147. {fmu_manipulation_toolbox-2.1.dev0 → fmu_manipulation_toolbox-2.1.dev1}/fmu_manipulation_toolbox/remoting.py +0 -0
  148. {fmu_manipulation_toolbox-2.1.dev0 → fmu_manipulation_toolbox-2.1.dev1}/fmu_manipulation_toolbox/resources/checkbox-checked-disabled.png +0 -0
  149. {fmu_manipulation_toolbox-2.1.dev0 → fmu_manipulation_toolbox-2.1.dev1}/fmu_manipulation_toolbox/resources/checkbox-checked-hover.png +0 -0
  150. {fmu_manipulation_toolbox-2.1.dev0 → fmu_manipulation_toolbox-2.1.dev1}/fmu_manipulation_toolbox/resources/checkbox-checked.png +0 -0
  151. {fmu_manipulation_toolbox-2.1.dev0 → fmu_manipulation_toolbox-2.1.dev1}/fmu_manipulation_toolbox/resources/checkbox-unchecked-disabled.png +0 -0
  152. {fmu_manipulation_toolbox-2.1.dev0 → fmu_manipulation_toolbox-2.1.dev1}/fmu_manipulation_toolbox/resources/checkbox-unchecked-hover.png +0 -0
  153. {fmu_manipulation_toolbox-2.1.dev0 → fmu_manipulation_toolbox-2.1.dev1}/fmu_manipulation_toolbox/resources/checkbox-unchecked.png +0 -0
  154. {fmu_manipulation_toolbox-2.1.dev0 → fmu_manipulation_toolbox-2.1.dev1}/fmu_manipulation_toolbox/resources/container.png +0 -0
  155. {fmu_manipulation_toolbox-2.1.dev0 → fmu_manipulation_toolbox-2.1.dev1}/fmu_manipulation_toolbox/resources/drop_fmu.png +0 -0
  156. {fmu_manipulation_toolbox-2.1.dev0 → fmu_manipulation_toolbox-2.1.dev1}/fmu_manipulation_toolbox/resources/fmi/fmi2FunctionTypes.h +0 -0
  157. {fmu_manipulation_toolbox-2.1.dev0 → fmu_manipulation_toolbox-2.1.dev1}/fmu_manipulation_toolbox/resources/fmi/fmi2Functions.h +0 -0
  158. {fmu_manipulation_toolbox-2.1.dev0 → fmu_manipulation_toolbox-2.1.dev1}/fmu_manipulation_toolbox/resources/fmi/fmi2TypesPlatform.h +0 -0
  159. {fmu_manipulation_toolbox-2.1.dev0 → fmu_manipulation_toolbox-2.1.dev1}/fmu_manipulation_toolbox/resources/fmi/fmi3FunctionTypes.h +0 -0
  160. {fmu_manipulation_toolbox-2.1.dev0 → fmu_manipulation_toolbox-2.1.dev1}/fmu_manipulation_toolbox/resources/fmi/fmi3Functions.h +0 -0
  161. {fmu_manipulation_toolbox-2.1.dev0 → fmu_manipulation_toolbox-2.1.dev1}/fmu_manipulation_toolbox/resources/fmi/fmi3PlatformTypes.h +0 -0
  162. {fmu_manipulation_toolbox-2.1.dev0 → fmu_manipulation_toolbox-2.1.dev1}/fmu_manipulation_toolbox/resources/fmi-2.0/fmi2Annotation.xsd +0 -0
  163. {fmu_manipulation_toolbox-2.1.dev0 → fmu_manipulation_toolbox-2.1.dev1}/fmu_manipulation_toolbox/resources/fmi-2.0/fmi2AttributeGroups.xsd +0 -0
  164. {fmu_manipulation_toolbox-2.1.dev0 → fmu_manipulation_toolbox-2.1.dev1}/fmu_manipulation_toolbox/resources/fmi-2.0/fmi2ModelDescription.xsd +0 -0
  165. {fmu_manipulation_toolbox-2.1.dev0 → fmu_manipulation_toolbox-2.1.dev1}/fmu_manipulation_toolbox/resources/fmi-2.0/fmi2ScalarVariable.xsd +0 -0
  166. {fmu_manipulation_toolbox-2.1.dev0 → fmu_manipulation_toolbox-2.1.dev1}/fmu_manipulation_toolbox/resources/fmi-2.0/fmi2Type.xsd +0 -0
  167. {fmu_manipulation_toolbox-2.1.dev0 → fmu_manipulation_toolbox-2.1.dev1}/fmu_manipulation_toolbox/resources/fmi-2.0/fmi2Unit.xsd +0 -0
  168. {fmu_manipulation_toolbox-2.1.dev0 → fmu_manipulation_toolbox-2.1.dev1}/fmu_manipulation_toolbox/resources/fmi-2.0/fmi2VariableDependency.xsd +0 -0
  169. {fmu_manipulation_toolbox-2.1.dev0 → fmu_manipulation_toolbox-2.1.dev1}/fmu_manipulation_toolbox/resources/fmi-3.0/fmi3Annotation.xsd +0 -0
  170. {fmu_manipulation_toolbox-2.1.dev0 → fmu_manipulation_toolbox-2.1.dev1}/fmu_manipulation_toolbox/resources/fmi-3.0/fmi3AttributeGroups.xsd +0 -0
  171. {fmu_manipulation_toolbox-2.1.dev0 → fmu_manipulation_toolbox-2.1.dev1}/fmu_manipulation_toolbox/resources/fmi-3.0/fmi3BuildDescription.xsd +0 -0
  172. {fmu_manipulation_toolbox-2.1.dev0 → fmu_manipulation_toolbox-2.1.dev1}/fmu_manipulation_toolbox/resources/fmi-3.0/fmi3InterfaceType.xsd +0 -0
  173. {fmu_manipulation_toolbox-2.1.dev0 → fmu_manipulation_toolbox-2.1.dev1}/fmu_manipulation_toolbox/resources/fmi-3.0/fmi3LayeredStandardManifest.xsd +0 -0
  174. {fmu_manipulation_toolbox-2.1.dev0 → fmu_manipulation_toolbox-2.1.dev1}/fmu_manipulation_toolbox/resources/fmi-3.0/fmi3ModelDescription.xsd +0 -0
  175. {fmu_manipulation_toolbox-2.1.dev0 → fmu_manipulation_toolbox-2.1.dev1}/fmu_manipulation_toolbox/resources/fmi-3.0/fmi3Terminal.xsd +0 -0
  176. {fmu_manipulation_toolbox-2.1.dev0 → fmu_manipulation_toolbox-2.1.dev1}/fmu_manipulation_toolbox/resources/fmi-3.0/fmi3TerminalsAndIcons.xsd +0 -0
  177. {fmu_manipulation_toolbox-2.1.dev0 → fmu_manipulation_toolbox-2.1.dev1}/fmu_manipulation_toolbox/resources/fmi-3.0/fmi3Type.xsd +0 -0
  178. {fmu_manipulation_toolbox-2.1.dev0 → fmu_manipulation_toolbox-2.1.dev1}/fmu_manipulation_toolbox/resources/fmi-3.0/fmi3Unit.xsd +0 -0
  179. {fmu_manipulation_toolbox-2.1.dev0 → fmu_manipulation_toolbox-2.1.dev1}/fmu_manipulation_toolbox/resources/fmi-3.0/fmi3Variable.xsd +0 -0
  180. {fmu_manipulation_toolbox-2.1.dev0 → fmu_manipulation_toolbox-2.1.dev1}/fmu_manipulation_toolbox/resources/fmi-3.0/fmi3VariableDependency.xsd +0 -0
  181. {fmu_manipulation_toolbox-2.1.dev0 → fmu_manipulation_toolbox-2.1.dev1}/fmu_manipulation_toolbox/resources/fmu.png +0 -0
  182. {fmu_manipulation_toolbox-2.1.dev0 → fmu_manipulation_toolbox-2.1.dev1}/fmu_manipulation_toolbox/resources/fmu_manipulation_toolbox.png +0 -0
  183. {fmu_manipulation_toolbox-2.1.dev0 → fmu_manipulation_toolbox-2.1.dev1}/fmu_manipulation_toolbox/resources/fmucontainer.png +0 -0
  184. {fmu_manipulation_toolbox-2.1.dev0 → fmu_manipulation_toolbox-2.1.dev1}/fmu_manipulation_toolbox/resources/fmueditor.png +0 -0
  185. {fmu_manipulation_toolbox-2.1.dev0 → fmu_manipulation_toolbox-2.1.dev1}/fmu_manipulation_toolbox/resources/fmutool.png +0 -0
  186. {fmu_manipulation_toolbox-2.1.dev0 → fmu_manipulation_toolbox-2.1.dev1}/fmu_manipulation_toolbox/resources/help.png +0 -0
  187. {fmu_manipulation_toolbox-2.1.dev0 → fmu_manipulation_toolbox-2.1.dev1}/fmu_manipulation_toolbox/resources/icon-round.png +0 -0
  188. {fmu_manipulation_toolbox-2.1.dev0 → fmu_manipulation_toolbox-2.1.dev1}/fmu_manipulation_toolbox/resources/icon.png +0 -0
  189. {fmu_manipulation_toolbox-2.1.dev0 → fmu_manipulation_toolbox-2.1.dev1}/fmu_manipulation_toolbox/resources/icon_fmu.png +0 -0
  190. {fmu_manipulation_toolbox-2.1.dev0 → fmu_manipulation_toolbox-2.1.dev1}/fmu_manipulation_toolbox/resources/license.txt +0 -0
  191. {fmu_manipulation_toolbox-2.1.dev0 → fmu_manipulation_toolbox-2.1.dev1}/fmu_manipulation_toolbox/resources/mask.png +0 -0
  192. {fmu_manipulation_toolbox-2.1.dev0 → fmu_manipulation_toolbox-2.1.dev1}/fmu_manipulation_toolbox/resources/radio-checked-disabled.png +0 -0
  193. {fmu_manipulation_toolbox-2.1.dev0 → fmu_manipulation_toolbox-2.1.dev1}/fmu_manipulation_toolbox/resources/radio-checked-hover.png +0 -0
  194. {fmu_manipulation_toolbox-2.1.dev0 → fmu_manipulation_toolbox-2.1.dev1}/fmu_manipulation_toolbox/resources/radio-checked.png +0 -0
  195. {fmu_manipulation_toolbox-2.1.dev0 → fmu_manipulation_toolbox-2.1.dev1}/fmu_manipulation_toolbox/resources/radio-unchecked-disabled.png +0 -0
  196. {fmu_manipulation_toolbox-2.1.dev0 → fmu_manipulation_toolbox-2.1.dev1}/fmu_manipulation_toolbox/resources/radio-unchecked-hover.png +0 -0
  197. {fmu_manipulation_toolbox-2.1.dev0 → fmu_manipulation_toolbox-2.1.dev1}/fmu_manipulation_toolbox/resources/radio-unchecked.png +0 -0
  198. {fmu_manipulation_toolbox-2.1.dev0 → fmu_manipulation_toolbox-2.1.dev1}/fmu_manipulation_toolbox/split.py +0 -0
  199. {fmu_manipulation_toolbox-2.1.dev0 → fmu_manipulation_toolbox-2.1.dev1}/fmu_manipulation_toolbox/terminals.py +0 -0
  200. {fmu_manipulation_toolbox-2.1.dev0 → fmu_manipulation_toolbox-2.1.dev1}/fmu_manipulation_toolbox/textfiles.py +0 -0
  201. {fmu_manipulation_toolbox-2.1.dev0 → fmu_manipulation_toolbox-2.1.dev1}/fmu_manipulation_toolbox/version.py +0 -0
  202. {fmu_manipulation_toolbox-2.1.dev0 → fmu_manipulation_toolbox-2.1.dev1}/fmu_manipulation_toolbox.egg-info/dependency_links.txt +0 -0
  203. {fmu_manipulation_toolbox-2.1.dev0 → fmu_manipulation_toolbox-2.1.dev1}/fmu_manipulation_toolbox.egg-info/requires.txt +0 -0
  204. {fmu_manipulation_toolbox-2.1.dev0 → fmu_manipulation_toolbox-2.1.dev1}/fmu_manipulation_toolbox.egg-info/top_level.txt +0 -0
  205. {fmu_manipulation_toolbox-2.1.dev0 → fmu_manipulation_toolbox-2.1.dev1}/overrides/main.html +0 -0
  206. {fmu_manipulation_toolbox-2.1.dev0 → fmu_manipulation_toolbox-2.1.dev1}/remoting/CMakeLists.txt +0 -0
  207. {fmu_manipulation_toolbox-2.1.dev0 → fmu_manipulation_toolbox-2.1.dev1}/remoting/build.bat +0 -0
  208. {fmu_manipulation_toolbox-2.1.dev0 → fmu_manipulation_toolbox-2.1.dev1}/remoting/client.c +0 -0
  209. {fmu_manipulation_toolbox-2.1.dev0 → fmu_manipulation_toolbox-2.1.dev1}/remoting/client.h +0 -0
  210. {fmu_manipulation_toolbox-2.1.dev0 → fmu_manipulation_toolbox-2.1.dev1}/remoting/communication.c +0 -0
  211. {fmu_manipulation_toolbox-2.1.dev0 → fmu_manipulation_toolbox-2.1.dev1}/remoting/communication.h +0 -0
  212. {fmu_manipulation_toolbox-2.1.dev0 → fmu_manipulation_toolbox-2.1.dev1}/remoting/config.h.in +0 -0
  213. {fmu_manipulation_toolbox-2.1.dev0 → fmu_manipulation_toolbox-2.1.dev1}/remoting/process.c +0 -0
  214. {fmu_manipulation_toolbox-2.1.dev0 → fmu_manipulation_toolbox-2.1.dev1}/remoting/process.h +0 -0
  215. {fmu_manipulation_toolbox-2.1.dev0 → fmu_manipulation_toolbox-2.1.dev1}/remoting/server.c +0 -0
  216. {fmu_manipulation_toolbox-2.1.dev0 → fmu_manipulation_toolbox-2.1.dev1}/remoting/server.h +0 -0
  217. {fmu_manipulation_toolbox-2.1.dev0 → fmu_manipulation_toolbox-2.1.dev1}/requirements.txt +0 -0
  218. {fmu_manipulation_toolbox-2.1.dev0 → fmu_manipulation_toolbox-2.1.dev1}/setup.cfg +0 -0
  219. {fmu_manipulation_toolbox-2.1.dev0 → fmu_manipulation_toolbox-2.1.dev1}/tests/.coveragerc +0 -0
  220. {fmu_manipulation_toolbox-2.1.dev0 → fmu_manipulation_toolbox-2.1.dev1}/tests/_helpers/__init__.py +0 -0
  221. {fmu_manipulation_toolbox-2.1.dev0 → fmu_manipulation_toolbox-2.1.dev1}/tests/_helpers/archive.py +0 -0
  222. {fmu_manipulation_toolbox-2.1.dev0 → fmu_manipulation_toolbox-2.1.dev1}/tests/_helpers/assertions.py +0 -0
  223. {fmu_manipulation_toolbox-2.1.dev0 → fmu_manipulation_toolbox-2.1.dev1}/tests/_helpers/assistant_bridge.py +0 -0
  224. {fmu_manipulation_toolbox-2.1.dev0 → fmu_manipulation_toolbox-2.1.dev1}/tests/_helpers/simulation.py +0 -0
  225. {fmu_manipulation_toolbox-2.1.dev0 → fmu_manipulation_toolbox-2.1.dev1}/tests/benchmarks/bench_manipulation.py +0 -0
  226. {fmu_manipulation_toolbox-2.1.dev0 → fmu_manipulation_toolbox-2.1.dev1}/tests/conftest.py +0 -0
  227. {fmu_manipulation_toolbox-2.1.dev0 → fmu_manipulation_toolbox-2.1.dev1}/tests/gui/test_assistant_qt_bridge.py +0 -0
  228. {fmu_manipulation_toolbox-2.1.dev0 → fmu_manipulation_toolbox-2.1.dev1}/tests/gui/test_fmucontainer_architecture_wires.py +0 -0
  229. {fmu_manipulation_toolbox-2.1.dev0 → fmu_manipulation_toolbox-2.1.dev1}/tests/gui/test_fmucontainer_instances.py +0 -0
  230. {fmu_manipulation_toolbox-2.1.dev0 → fmu_manipulation_toolbox-2.1.dev1}/tests/gui/test_fmucontainer_open_file.py +0 -0
  231. {fmu_manipulation_toolbox-2.1.dev0 → fmu_manipulation_toolbox-2.1.dev1}/tests/gui/test_fmucontainer_reset_ports.py +0 -0
  232. {fmu_manipulation_toolbox-2.1.dev0 → fmu_manipulation_toolbox-2.1.dev1}/tests/gui/test_fmucontainer_ssp_geometry.py +0 -0
  233. {fmu_manipulation_toolbox-2.1.dev0 → fmu_manipulation_toolbox-2.1.dev1}/tests/gui/test_fmucontainer_step_size.py +0 -0
  234. {fmu_manipulation_toolbox-2.1.dev0 → fmu_manipulation_toolbox-2.1.dev1}/tests/gui/test_gui.py +0 -0
  235. {fmu_manipulation_toolbox-2.1.dev0 → fmu_manipulation_toolbox-2.1.dev1}/tests/gui/test_gui_logging.py +0 -0
  236. {fmu_manipulation_toolbox-2.1.dev0 → fmu_manipulation_toolbox-2.1.dev1}/tests/gui/test_link_assistant.py +0 -0
  237. {fmu_manipulation_toolbox-2.1.dev0 → fmu_manipulation_toolbox-2.1.dev1}/tests/gui/test_link_assistant_wire.py +0 -0
  238. {fmu_manipulation_toolbox-2.1.dev0 → fmu_manipulation_toolbox-2.1.dev1}/tests/integration/test_array.py +0 -0
  239. {fmu_manipulation_toolbox-2.1.dev0 → fmu_manipulation_toolbox-2.1.dev1}/tests/integration/test_assistant_stdio_server.py +0 -0
  240. {fmu_manipulation_toolbox-2.1.dev0 → fmu_manipulation_toolbox-2.1.dev1}/tests/integration/test_cli_errors.py +0 -0
  241. {fmu_manipulation_toolbox-2.1.dev0 → fmu_manipulation_toolbox-2.1.dev1}/tests/integration/test_compile_sources.py +0 -0
  242. {fmu_manipulation_toolbox-2.1.dev0 → fmu_manipulation_toolbox-2.1.dev1}/tests/integration/test_container.py +0 -0
  243. {fmu_manipulation_toolbox-2.1.dev0 → fmu_manipulation_toolbox-2.1.dev1}/tests/integration/test_container_enumeration.py +0 -0
  244. {fmu_manipulation_toolbox-2.1.dev0 → fmu_manipulation_toolbox-2.1.dev1}/tests/integration/test_container_perf.py +0 -0
  245. {fmu_manipulation_toolbox-2.1.dev0 → fmu_manipulation_toolbox-2.1.dev1}/tests/integration/test_container_reset.py +0 -0
  246. {fmu_manipulation_toolbox-2.1.dev0 → fmu_manipulation_toolbox-2.1.dev1}/tests/integration/test_container_txt.py +0 -0
  247. {fmu_manipulation_toolbox-2.1.dev0 → fmu_manipulation_toolbox-2.1.dev1}/tests/integration/test_container_xml.py +0 -0
  248. {fmu_manipulation_toolbox-2.1.dev0 → fmu_manipulation_toolbox-2.1.dev1}/tests/integration/test_datalog.py +0 -0
  249. {fmu_manipulation_toolbox-2.1.dev0 → fmu_manipulation_toolbox-2.1.dev1}/tests/integration/test_lsbus.py +0 -0
  250. {fmu_manipulation_toolbox-2.1.dev0 → fmu_manipulation_toolbox-2.1.dev1}/tests/integration/test_me.py +0 -0
  251. {fmu_manipulation_toolbox-2.1.dev0 → fmu_manipulation_toolbox-2.1.dev1}/tests/integration/test_operations_invariants.py +0 -0
  252. {fmu_manipulation_toolbox-2.1.dev0 → fmu_manipulation_toolbox-2.1.dev1}/tests/integration/test_probe_fmu.py +0 -0
  253. {fmu_manipulation_toolbox-2.1.dev0 → fmu_manipulation_toolbox-2.1.dev1}/tests/integration/test_remoting.py +0 -0
  254. {fmu_manipulation_toolbox-2.1.dev0 → fmu_manipulation_toolbox-2.1.dev1}/tests/integration/test_split.py +0 -0
  255. {fmu_manipulation_toolbox-2.1.dev0 → fmu_manipulation_toolbox-2.1.dev1}/tests/integration/test_ssp.py +0 -0
  256. {fmu_manipulation_toolbox-2.1.dev0 → fmu_manipulation_toolbox-2.1.dev1}/tests/pytest.ini +0 -0
  257. {fmu_manipulation_toolbox-2.1.dev0 → fmu_manipulation_toolbox-2.1.dev1}/tests/unit/test_assembly_errors.py +0 -0
  258. {fmu_manipulation_toolbox-2.1.dev0 → fmu_manipulation_toolbox-2.1.dev1}/tests/unit/test_assembly_instances.py +0 -0
  259. {fmu_manipulation_toolbox-2.1.dev0 → fmu_manipulation_toolbox-2.1.dev1}/tests/unit/test_assembly_parsing.py +0 -0
  260. {fmu_manipulation_toolbox-2.1.dev0 → fmu_manipulation_toolbox-2.1.dev1}/tests/unit/test_assistant_analysis.py +0 -0
  261. {fmu_manipulation_toolbox-2.1.dev0 → fmu_manipulation_toolbox-2.1.dev1}/tests/unit/test_assistant_auth.py +0 -0
  262. {fmu_manipulation_toolbox-2.1.dev0 → fmu_manipulation_toolbox-2.1.dev1}/tests/unit/test_assistant_budget.py +0 -0
  263. {fmu_manipulation_toolbox-2.1.dev0 → fmu_manipulation_toolbox-2.1.dev1}/tests/unit/test_assistant_headless.py +0 -0
  264. {fmu_manipulation_toolbox-2.1.dev0 → fmu_manipulation_toolbox-2.1.dev1}/tests/unit/test_assistant_server_runtime.py +0 -0
  265. {fmu_manipulation_toolbox-2.1.dev0 → fmu_manipulation_toolbox-2.1.dev1}/tests/unit/test_checker.py +0 -0
  266. {fmu_manipulation_toolbox-2.1.dev0 → fmu_manipulation_toolbox-2.1.dev1}/tests/unit/test_checker_loading.py +0 -0
  267. {fmu_manipulation_toolbox-2.1.dev0 → fmu_manipulation_toolbox-2.1.dev1}/tests/unit/test_checker_semantic.py +0 -0
  268. {fmu_manipulation_toolbox-2.1.dev0 → fmu_manipulation_toolbox-2.1.dev1}/tests/unit/test_compiler.py +0 -0
  269. {fmu_manipulation_toolbox-2.1.dev0 → fmu_manipulation_toolbox-2.1.dev1}/tests/unit/test_container_internals.py +0 -0
  270. {fmu_manipulation_toolbox-2.1.dev0 → fmu_manipulation_toolbox-2.1.dev1}/tests/unit/test_fmu_descriptor_cache.py +0 -0
  271. {fmu_manipulation_toolbox-2.1.dev0 → fmu_manipulation_toolbox-2.1.dev1}/tests/unit/test_fmu_lifecycle.py +0 -0
  272. {fmu_manipulation_toolbox-2.1.dev0 → fmu_manipulation_toolbox-2.1.dev1}/tests/unit/test_link_matching.py +0 -0
  273. {fmu_manipulation_toolbox-2.1.dev0 → fmu_manipulation_toolbox-2.1.dev1}/tests/unit/test_model_description.py +0 -0
  274. {fmu_manipulation_toolbox-2.1.dev0 → fmu_manipulation_toolbox-2.1.dev1}/tests/unit/test_model_exchange_sizes.py +0 -0
  275. {fmu_manipulation_toolbox-2.1.dev0 → fmu_manipulation_toolbox-2.1.dev1}/tests/unit/test_operations.py +0 -0
  276. {fmu_manipulation_toolbox-2.1.dev0 → fmu_manipulation_toolbox-2.1.dev1}/tests/unit/test_operations_conformity.py +0 -0
  277. {fmu_manipulation_toolbox-2.1.dev0 → fmu_manipulation_toolbox-2.1.dev1}/tests/unit/test_operations_dependencies.py +0 -0
  278. {fmu_manipulation_toolbox-2.1.dev0 → fmu_manipulation_toolbox-2.1.dev1}/tests/unit/test_operations_errors.py +0 -0
  279. {fmu_manipulation_toolbox-2.1.dev0 → fmu_manipulation_toolbox-2.1.dev1}/tests/unit/test_split_parsing.py +0 -0
  280. {fmu_manipulation_toolbox-2.1.dev0 → fmu_manipulation_toolbox-2.1.dev1}/tests/unit/test_terminals.py +0 -0
  281. {fmu_manipulation_toolbox-2.1.dev0 → fmu_manipulation_toolbox-2.1.dev1}/tests/unit/test_textfiles.py +0 -0
  282. {fmu_manipulation_toolbox-2.1.dev0 → fmu_manipulation_toolbox-2.1.dev1}/tests/unit/test_xml_assertions.py +0 -0
  283. {fmu_manipulation_toolbox-2.1.dev0 → fmu_manipulation_toolbox-2.1.dev1}/tests/unit/test_xml_roundtrip.py +0 -0
  284. {fmu_manipulation_toolbox-2.1.dev0 → fmu_manipulation_toolbox-2.1.dev1}/tools/bench_container.py +0 -0
  285. {fmu_manipulation_toolbox-2.1.dev0 → fmu_manipulation_toolbox-2.1.dev1}/tools/compare_traces.py +0 -0
  286. {fmu_manipulation_toolbox-2.1.dev0 → fmu_manipulation_toolbox-2.1.dev1}/tools/dist_inventory.py +0 -0
  287. {fmu_manipulation_toolbox-2.1.dev0 → fmu_manipulation_toolbox-2.1.dev1}/tools/make_carousel.py +0 -0
  288. {fmu_manipulation_toolbox-2.1.dev0 → fmu_manipulation_toolbox-2.1.dev1}/tools/probe_fmu/Probe10ms.fmu +0 -0
  289. {fmu_manipulation_toolbox-2.1.dev0 → fmu_manipulation_toolbox-2.1.dev1}/tools/probe_fmu/Probe20ms.fmu +0 -0
  290. {fmu_manipulation_toolbox-2.1.dev0 → fmu_manipulation_toolbox-2.1.dev1}/tools/probe_fmu/Probe50ms.fmu +0 -0
  291. {fmu_manipulation_toolbox-2.1.dev0 → fmu_manipulation_toolbox-2.1.dev1}/tools/probe_fmu/README.md +0 -0
  292. {fmu_manipulation_toolbox-2.1.dev0 → fmu_manipulation_toolbox-2.1.dev1}/tools/probe_fmu/make_probe.py +0 -0
  293. {fmu_manipulation_toolbox-2.1.dev0 → fmu_manipulation_toolbox-2.1.dev1}/tools/probe_fmu/probe.c +0 -0
  294. {fmu_manipulation_toolbox-2.1.dev0 → fmu_manipulation_toolbox-2.1.dev1}/tools/probe_fmu/scenarios/README.md +0 -0
  295. {fmu_manipulation_toolbox-2.1.dev0 → fmu_manipulation_toolbox-2.1.dev1}/tools/probe_fmu/scenarios/S1.json +0 -0
  296. {fmu_manipulation_toolbox-2.1.dev0 → fmu_manipulation_toolbox-2.1.dev1}/tools/probe_fmu/scenarios/S2.json +0 -0
  297. {fmu_manipulation_toolbox-2.1.dev0 → fmu_manipulation_toolbox-2.1.dev1}/tools/probe_fmu/scenarios/S3.json +0 -0
  298. {fmu_manipulation_toolbox-2.1.dev0 → fmu_manipulation_toolbox-2.1.dev1}/tools/probe_fmu/scenarios/S4a.json +0 -0
  299. {fmu_manipulation_toolbox-2.1.dev0 → fmu_manipulation_toolbox-2.1.dev1}/tools/probe_fmu/scenarios/S4b.json +0 -0
  300. {fmu_manipulation_toolbox-2.1.dev0 → fmu_manipulation_toolbox-2.1.dev1}/tools/probe_fmu/scenarios/S4c.json +0 -0
  301. {fmu_manipulation_toolbox-2.1.dev0 → fmu_manipulation_toolbox-2.1.dev1}/tools/probe_fmu/scenarios/S4d.json +0 -0
  302. {fmu_manipulation_toolbox-2.1.dev0 → fmu_manipulation_toolbox-2.1.dev1}/tools/probe_fmu/scenarios/S5j.json +0 -0
  303. {fmu_manipulation_toolbox-2.1.dev0 → fmu_manipulation_toolbox-2.1.dev1}/tools/probe_fmu/scenarios/S5r.json +0 -0
  304. {fmu_manipulation_toolbox-2.1.dev0 → fmu_manipulation_toolbox-2.1.dev1}/tools/probe_fmu/scenarios/S5s.json +0 -0
  305. {fmu_manipulation_toolbox-2.1.dev0 → fmu_manipulation_toolbox-2.1.dev1}/tools/probe_fmu/scenarios/S6m.json +0 -0
  306. {fmu_manipulation_toolbox-2.1.dev0 → fmu_manipulation_toolbox-2.1.dev1}/tools/probe_fmu/scenarios/S6s.json +0 -0
  307. {fmu_manipulation_toolbox-2.1.dev0 → fmu_manipulation_toolbox-2.1.dev1}/tools/probe_fmu/scenarios/run_container.py +0 -0
  308. {fmu_manipulation_toolbox-2.1.dev0 → fmu_manipulation_toolbox-2.1.dev1}/tools/probe_fmu/scenarios/simulink/build_scenarios.m +0 -0
  309. {fmu_manipulation_toolbox-2.1.dev0 → fmu_manipulation_toolbox-2.1.dev1}/tools/probe_fmu/scenarios/simulink/probe_scenarios.m +0 -0
  310. {fmu_manipulation_toolbox-2.1.dev0 → fmu_manipulation_toolbox-2.1.dev1}/tools/probe_fmu/scenarios/simulink/probe_simulink_api.m +0 -0
  311. {fmu_manipulation_toolbox-2.1.dev0 → fmu_manipulation_toolbox-2.1.dev1}/tools/probe_fmu/scenarios/simulink/run_scenarios.m +0 -0
  312. {fmu_manipulation_toolbox-2.1.dev0 → fmu_manipulation_toolbox-2.1.dev1}/tools/screenshots.py +0 -0
@@ -18,8 +18,35 @@ Not released yet. Changes since 2.0, with the same legend as 2.0.
18
18
  `source` outside the archive is refused. SSP 2.0 files are read; a component without `source` (SSP 2.0) is
19
19
  ignored with a warning, together with its connections.
20
20
 
21
+ ## AI agents
22
+
23
+ - 🟢 **ADDED** **agent skills**: a Claude Code plugin (the repository is a marketplace:
24
+ `/plugin marketplace add grouperenault/fmutool`) with the skills `fmu-inspect`, `fmu-edit` and
25
+ `fmu-container`, which drive the MCP server, or `fmutool-agent` without it; `tools/build_skill_zips.py` builds
26
+ them for claude.ai. They need the toolbox 2.1.dev1 or later (`compatibility` field), and check it by the tools
27
+ available. See [Agent skills](docs/user-guide/agent-skills.md).
28
+ - 🟢 **ADDED** `fmutool-agent`: the tools of the MCP server as a JSON command line (same arguments, same
29
+ results), for agents that only run commands. It needs neither `fastmcp` nor Pydantic; the assembly is kept
30
+ between calls in the file given by `--state`. `fmutool-agent list-tools` prints the version of the toolbox.
31
+ - 🟢 **ADDED** MCP tool `describe_port`: everything declared about one port (every attribute, FMI 3 dimensions,
32
+ declared type and the attributes inherited from it, aliases, terminals).
33
+ - 🟢 **ADDED** MCP filters `type` and `variability` on `list_fmu_ports`, `inspect_fmu_file` and
34
+ `apply_operation`; on an FMI 3 FMU, an FMI 2 type selects its family (`Real`: `Float32`, `Float64`).
35
+ - 🔴 **BREAKING** MCP tool `rename_ports_from_csv` replaced by `rename_ports`, which takes a `mapping`
36
+ (`{"old": "new"}`) or the `csv`, and reports the names of the mapping absent from the FMU (`unknown`).
37
+ - 🔵 **CHANGED** shorter descriptions of some MCP tools and container options, to make room for the new tools
38
+ in the context of small models.
39
+
21
40
  ## fmutool and the Python API
22
41
 
42
+ - 🟢 **ADDED** `-only-type` and `-only-variability` options of `fmutool`, and the `types` and `variabilities`
43
+ arguments of `FMU.apply_operation`: an operation restricted to some types (an FMI 2 type selects its FMI 3
44
+ family) or variabilities (the default of the standard when a port declares none), combined with the
45
+ causality filters.
46
+ - 🟢 **ADDED** `OperationRename`: renaming, or removal, from a mapping of names; `OperationRenameFromCSV` derives
47
+ from it.
48
+ - 🟢 **ADDED** `ModelVariable.causality` and `ModelVariable.variability`, with the defaults of the standard, and
49
+ `ModelVariable.has_type`.
23
50
  - 🟢 **ADDED** `-debug` option of `fmutool` and `fmutool-gui` (at launch): the `DEBUG` lines are logged, in the log
24
51
  area for `fmutool-gui`, e.g. the command lines of the compiler and of the linker of `-compile-sources`.
25
52
 
@@ -2,13 +2,15 @@
2
2
  # With setuptools-scm, every file tracked by git goes into the sdist by default. Keep the Python package and the C
3
3
  # sources of the native binaries (container/, remoting/, and the FMI headers in
4
4
  # fmu_manipulation_toolbox/resources/fmi/); leave out the test data, the documentation, the CI
5
- # configuration and the prebuilt binaries.
5
+ # configuration, the Claude Code plugin and the prebuilt binaries.
6
6
  #
7
7
  # The wheel needs the prebuilt binaries: build it from the source tree, not from the sdist
8
8
  # (`python -m build --sdist --wheel`).
9
9
  prune tests/data
10
10
  prune docs
11
11
  prune .github
12
+ prune plugins
13
+ prune .claude-plugin
12
14
  recursive-exclude fmu_manipulation_toolbox/resources/win32 *
13
15
  recursive-exclude fmu_manipulation_toolbox/resources/win64 *
14
16
  recursive-exclude fmu_manipulation_toolbox/resources/linux32 *
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: fmu_manipulation_toolbox
3
- Version: 2.1.dev0
3
+ Version: 2.1.dev1
4
4
  Summary: FMU Manipulation Toolbox is a python package which helps to analyze, modify, validate, combine or split Functional Mock-up Units (FMUs) without recompilation, through a GUI, a CLI or a Python API.
5
5
  Author-email: Nicolas LAURENT <Nicolas.LAURENT@Renault.com>
6
6
  License-Expression: BSD-2-Clause
@@ -122,6 +122,13 @@ extra:
122
122
  pip install "fmu-manipulation-toolbox[mcp]"
123
123
  ```
124
124
 
125
+ With Claude Code, the `fmutool` plugin adds skills to inspect FMUs, edit their interface and build containers
126
+ ([Agent skills](docs/user-guide/agent-skills.md)); they need version 2.1.dev1 or later of the toolbox:
127
+
128
+ ```
129
+ /plugin install fmutool --marketplace grouperenault/fmutool
130
+ ```
131
+
125
132
 
126
133
  ### Supported platforms
127
134
 
@@ -72,6 +72,13 @@ extra:
72
72
  pip install "fmu-manipulation-toolbox[mcp]"
73
73
  ```
74
74
 
75
+ With Claude Code, the `fmutool` plugin adds skills to inspect FMUs, edit their interface and build containers
76
+ ([Agent skills](docs/user-guide/agent-skills.md)); they need version 2.1.dev1 or later of the toolbox:
77
+
78
+ ```
79
+ /plugin install fmutool --marketplace grouperenault/fmutool
80
+ ```
81
+
75
82
 
76
83
  ### Supported platforms
77
84
 
@@ -18,7 +18,7 @@ version_tuple: tuple[int | str, ...]
18
18
  commit_id: str | None
19
19
  __commit_id__: str | None
20
20
 
21
- __version__ = version = '2.1.dev0'
22
- __version_tuple__ = version_tuple = (2, 1, 'dev0')
21
+ __version__ = version = '2.1.dev1'
22
+ __version_tuple__ = version_tuple = (2, 1, 'dev1')
23
23
 
24
- __commit_id__ = commit_id = 'g1144bc002'
24
+ __commit_id__ = commit_id = 'g3d2800ab9'
@@ -16,6 +16,7 @@ Two design points are worth stating, because they shape the whole module:
16
16
  the read-only tools here never call it.
17
17
  """
18
18
 
19
+ import difflib
19
20
  import logging
20
21
  import re
21
22
  from contextlib import contextmanager
@@ -23,9 +24,11 @@ from pathlib import Path
23
24
  from typing import Any
24
25
 
25
26
  from ..checker import get_checkers
27
+ from ..model_description import ModelDescription, ModelVariable, default_variability, matches_type
28
+ from ..terminals import Terminals
26
29
  from ..operations import (
27
30
  FMU, OperationKeepOnlyRegexp, OperationMergeTopLevel, OperationRemoveRegexp,
28
- OperationRemoveSources, OperationRenameFromCSV, OperationSaveNamesToCSV,
31
+ OperationRemoveSources, OperationRename, OperationRenameFromCSV, OperationSaveNamesToCSV,
29
32
  OperationStripTopLevel, OperationSummary, OperationTrimUntil,
30
33
  )
31
34
 
@@ -47,6 +50,51 @@ OPERATIONS = {
47
50
  #: Causalities an operation can be restricted to.
48
51
  CAUSALITIES = ("input", "output", "parameter", "local")
49
52
 
53
+ #: Types a port filter accepts: the FMI 2.0 names (which also select their FMI 3.0 family) and the FMI 3.0 ones.
54
+ TYPES = tuple(dict.fromkeys(ModelDescription.FMI2_VARIABLE_TYPES + ModelDescription.FMI3_VARIABLE_TYPES))
55
+
56
+ #: Variabilities a port filter accepts.
57
+ VARIABILITIES = ModelDescription.VARIABILITIES
58
+
59
+
60
+ def check_port_filters(causality: list[str] | None = None, types: list[str] | None = None,
61
+ variabilities: list[str] | None = None) -> None:
62
+ """Refuse the unknown values of the port filters, listing the accepted ones.
63
+
64
+ Raises:
65
+ ValueError: If a value is not one of :data:`CAUSALITIES`, :data:`TYPES`
66
+ or :data:`VARIABILITIES`.
67
+ """
68
+ for label, values, accepted in (("causality", causality, CAUSALITIES), ("type", types, TYPES),
69
+ ("variability", variabilities, VARIABILITIES)):
70
+ unknown = set(values or ()) - set(accepted)
71
+ if unknown:
72
+ raise ValueError(f"Unknown {label} {sorted(unknown)}. Available: {list(accepted)}.")
73
+
74
+
75
+ def select_ports(ports: list[dict[str, Any]], fmi_version: int | None, causality: list[str] | None = None,
76
+ types: list[str] | None = None, variabilities: list[str] | None = None) -> list[dict[str, Any]]:
77
+ """The ports of a description (`describe_fmu`, the bridges) that every filter set accepts.
78
+
79
+ Same rules as `FMU.apply_operation`: FMI 2.0 type names select their FMI
80
+ 3.0 family, an undeclared variability is the default of the standard.
81
+ """
82
+ # Any causality can be listed (`independent`, `calculatedParameter`...): only the other filters are checked.
83
+ check_port_filters(None, types, variabilities)
84
+ version = fmi_version or 2
85
+ selected = []
86
+ for port in ports:
87
+ port_causality = port.get("causality") or "local"
88
+ if causality and port_causality not in causality:
89
+ continue
90
+ if types and not matches_type(version, port.get("type"), types):
91
+ continue
92
+ if variabilities and (port.get("variability")
93
+ or default_variability(version, port_causality, port.get("type"))) not in variabilities:
94
+ continue
95
+ selected.append(port)
96
+ return selected
97
+
50
98
 
51
99
  @contextmanager
52
100
  def _captured_logs(level: int = logging.DEBUG):
@@ -124,6 +172,122 @@ def summarize_fmu(path: Path) -> dict[str, Any]:
124
172
  return summary
125
173
 
126
174
 
175
+ #: Aliases listed by `describe_port`: an FMI 2.0 FMU may share one value reference between many variables.
176
+ MAX_ALIASES = 20
177
+
178
+
179
+ def describe_port(path: Path, port: str) -> dict[str, Any]:
180
+ """Describe one port of an FMU with everything its descriptor declares.
181
+
182
+ The port pages (`describe_fmu`) keep a few fields per port to stay small;
183
+ this is the full card of a single port.
184
+
185
+ Args:
186
+ path: Path to an existing ``.fmu`` file.
187
+ port: Name of the port.
188
+
189
+ Returns:
190
+ A mapping with ``fmu``, ``fmi_version``, ``name``, ``type``,
191
+ ``causality`` and ``variability`` (the defaults of the standard when not
192
+ declared), ``attributes`` (every attribute as declared, FMI 2.0
193
+ ``<ScalarVariable>`` and type element merged, and the ``<Start>`` values
194
+ of FMI 3.0 ``String`` and ``Binary`` variables under ``start``), and
195
+ when they apply: ``dimensions`` (FMI 3.0 arrays), ``declared_type``
196
+ (name, attributes and enumeration items of the type definition, and
197
+ ``inherited``: the attributes the port takes from it), ``aliases`` (the
198
+ first :data:`MAX_ALIASES`, with ``aliases_total`` beyond) and ``terminals``
199
+ (terminal name, kind and member name).
200
+
201
+ Raises:
202
+ ValueError: If the FMU has no such port; the message suggests close names.
203
+ """
204
+ with FMU(str(path)) as fmu:
205
+ md = fmu.model_description
206
+ variables = {element.get("name"): element for element in md.variables()}
207
+ element = variables.get(port)
208
+ if element is None:
209
+ close = difflib.get_close_matches(port, list(variables), n=5)
210
+ hint = f" Close names: {close}." if close else ""
211
+ raise ValueError(f"'{path.name}' has no port '{port}'.{hint}")
212
+ variable = ModelVariable(element, md.fmi_version)
213
+ terminals = Terminals(fmu.tmp_directory)
214
+
215
+ attributes: dict[str, str] = {}
216
+ for attrs in variable.attrs_list:
217
+ for key, value in attrs.items():
218
+ attributes.setdefault(key, value)
219
+
220
+ card: dict[str, Any] = {
221
+ "fmu": path.name,
222
+ "fmi_version": md.fmi_version,
223
+ "name": port,
224
+ "type": variable.fmi_type,
225
+ "causality": variable.causality,
226
+ "variability": variable.variability,
227
+ "attributes": attributes,
228
+ }
229
+ if variable.dimensions:
230
+ card["dimensions"] = [{key: value} for key, value in variable.dimensions]
231
+
232
+ declared = _declared_type(md, variable)
233
+ if declared:
234
+ declared["inherited"] = {key: value for key, value in declared["attributes"].items()
235
+ if key not in attributes}
236
+ card["declared_type"] = declared
237
+
238
+ aliases = _aliases(md, variable, variables)
239
+ if aliases:
240
+ card["aliases"] = aliases[:MAX_ALIASES]
241
+ if len(aliases) > MAX_ALIASES:
242
+ card["aliases_total"] = len(aliases)
243
+
244
+ # `Terminals` lists the sub-terminals at the top level too: one pass covers them all.
245
+ memberships = [{"terminal": terminal.name, "kind": terminal.kind, "member": member}
246
+ for terminal in terminals
247
+ for member, name in terminal.members.items() if name == port]
248
+ if memberships:
249
+ card["terminals"] = memberships
250
+ return card
251
+
252
+
253
+ def _declared_type(md: ModelDescription, variable: ModelVariable) -> dict[str, Any] | None:
254
+ """The type definition named by `declaredType`, with its enumeration items."""
255
+ name = variable.get("declaredType")
256
+ definitions = md.root.find("TypeDefinitions")
257
+ if not name or definitions is None:
258
+ return None
259
+ for definition in definitions:
260
+ if definition.get("name") != name:
261
+ continue
262
+ # FMI-2: <SimpleType name="..."><Real unit="..."/></SimpleType>; FMI-3: <Float64Type name="..." unit="..."/>.
263
+ typed = definition[0] if md.fmi_version == 2 and len(definition) else definition
264
+ attributes = {key: value for key, value in definition.attrib.items() if key != "name"}
265
+ if typed is not definition:
266
+ attributes.update(typed.attrib)
267
+ declared: dict[str, Any] = {"name": name, "attributes": attributes}
268
+ items = [dict(item.attrib) for item in typed.findall("Item")]
269
+ if items:
270
+ declared["items"] = items
271
+ return declared
272
+ return {"name": name, "attributes": {}, "error": "no such type definition"}
273
+
274
+
275
+ def _aliases(md: ModelDescription, variable: ModelVariable,
276
+ variables: dict[str, Any]) -> list[dict[str, str]]:
277
+ """FMI-3: the `<Alias>` elements. FMI-2: the variables sharing the value reference and the type."""
278
+ if md.fmi_version == 3:
279
+ return [dict(alias.attrib) for alias in variable.element.findall("Alias")]
280
+ vr = variable.element.get("valueReference")
281
+ aliases = []
282
+ for name, element in variables.items():
283
+ if element is variable.element or element.get("valueReference") != vr:
284
+ continue
285
+ other = ModelVariable(element, md.fmi_version)
286
+ if other.fmi_type == variable.fmi_type:
287
+ aliases.append({"name": name, "causality": other.causality})
288
+ return aliases
289
+
290
+
127
291
  #: Most groups of messages returned by `check_fmu` per list: an industrial FMU can produce thousands of errors,
128
292
  #: which would fill the context window of the model.
129
293
  MAX_MESSAGE_GROUPS = 50
@@ -202,7 +366,7 @@ def dump_ports_csv(fmu_path: Path, csv_path: Path) -> dict[str, Any]:
202
366
  The file has one row per port, with columns ``name``, ``newName``,
203
367
  ``valueReference``, ``causality``, ``variability``, ``scalarType`` and
204
368
  ``startValue``, separated by semicolons. Editing the ``newName`` column
205
- and feeding it back to :func:`rename_ports_from_csv` is the intended
369
+ and feeding it back to :func:`rename_ports` is the intended
206
370
  round-trip.
207
371
 
208
372
  Args:
@@ -220,8 +384,13 @@ def dump_ports_csv(fmu_path: Path, csv_path: Path) -> dict[str, Any]:
220
384
  return {"fmu": fmu_path.name, "csv": str(csv_path), "ports": max(len(rows) - 1, 0)}
221
385
 
222
386
 
223
- def rename_ports_from_csv(fmu_path: Path, csv_path: Path, output_path: Path) -> dict[str, Any]:
224
- """Rename (or drop) the ports of an FMU according to a CSV mapping.
387
+ #: Names of a renaming mapping absent from the FMU listed in the report of `rename_ports`; the total is always given.
388
+ MAX_UNKNOWN_NAMES = 20
389
+
390
+
391
+ def rename_ports(fmu_path: Path, output_path: Path, mapping: dict[str, str] | None = None,
392
+ csv_path: Path | None = None) -> dict[str, Any]:
393
+ """Rename (or drop) the ports of an FMU, from a mapping or from a CSV file.
225
394
 
226
395
  The CSV is the one produced by :func:`dump_ports_csv`: column 0 is the
227
396
  current name, column 1 the new one. **An empty new name removes the
@@ -230,32 +399,52 @@ def rename_ports_from_csv(fmu_path: Path, csv_path: Path, output_path: Path) ->
230
399
 
231
400
  Args:
232
401
  fmu_path: FMU to read.
233
- csv_path: CSV mapping file.
234
402
  output_path: Destination FMU. The source is never modified.
403
+ mapping: Current name -> new name.
404
+ csv_path: CSV mapping file. Exactly one of `mapping` and `csv_path` is given.
235
405
 
236
406
  Returns:
237
- A mapping with ``fmu``, ``output``, ``renamed`` and ``removed``.
407
+ A mapping with ``fmu``, ``output``, ``renamed`` and ``removed`` (ports
408
+ actually renamed or removed), and when some names of the mapping are not
409
+ ports of the FMU: ``unknown`` (the first of them) and ``unknown_total``.
410
+
411
+ Raises:
412
+ ValueError: If neither or both of `mapping` and `csv_path` are given.
238
413
  """
239
- operation = OperationRenameFromCSV(str(csv_path))
240
- # `OperationRenameFromCSV` reads every row, header included: the CSV
241
- # produced by `dump_ports_csv` starts with `name;newName`, which would
242
- # otherwise be counted as a rename.
243
- translations = {old: new for old, new in operation.translations.items()
244
- if (old, new) != ("name", "newName")}
245
- renamed = sum(1 for old, new in translations.items() if new and new != old)
246
- removed = sum(1 for new in translations.values() if not new)
414
+ if (mapping is None) == (csv_path is None):
415
+ raise ValueError("Give either `mapping` or `csv`, not both.")
416
+ if csv_path is not None:
417
+ operation: OperationRename = OperationRenameFromCSV(str(csv_path))
418
+ # `OperationRenameFromCSV` reads every row, header included: the CSV
419
+ # produced by `dump_ports_csv` starts with `name;newName`, which must not
420
+ # be taken for a port.
421
+ if operation.translations.get("name") == "newName":
422
+ del operation.translations["name"]
423
+ else:
424
+ operation = OperationRename(mapping)
247
425
 
248
426
  with FMU(str(fmu_path)) as fmu:
249
427
  fmu.apply_operation(operation)
250
428
  fmu.repack(str(output_path))
251
429
 
252
- return {"fmu": fmu_path.name, "output": str(output_path),
253
- "renamed": renamed, "removed": removed}
430
+ translations = operation.translations
431
+ report: dict[str, Any] = {
432
+ "fmu": fmu_path.name, "output": str(output_path),
433
+ "renamed": sum(1 for old in operation.found if translations[old] and translations[old] != old),
434
+ "removed": sum(1 for old in operation.found if not translations[old]),
435
+ }
436
+ unknown = [old for old in translations if old not in operation.found]
437
+ if unknown:
438
+ report["unknown"] = unknown[:MAX_UNKNOWN_NAMES]
439
+ report["unknown_total"] = len(unknown)
440
+ return report
254
441
 
255
442
 
256
443
  def apply_operation(fmu_path: Path, output_path: Path, operation: str,
257
444
  argument: str | None = None,
258
- causality: list[str] | None = None) -> dict[str, Any]:
445
+ causality: list[str] | None = None,
446
+ types: list[str] | None = None,
447
+ variabilities: list[str] | None = None) -> dict[str, Any]:
259
448
  """Apply one descriptor operation to an FMU and write the result.
260
449
 
261
450
  Args:
@@ -265,6 +454,8 @@ def apply_operation(fmu_path: Path, output_path: Path, operation: str,
265
454
  argument: Required by the parameterised operations (``trim_until``,
266
455
  ``remove_regexp``, ``keep_only_regexp``), rejected by the others.
267
456
  causality: Restrict the operation to these causalities.
457
+ types: Restrict the operation to these types (see :func:`check_port_filters`).
458
+ variabilities: Restrict the operation to these variabilities.
268
459
 
269
460
  Returns:
270
461
  A mapping with ``fmu``, ``output`` and ``operation`` (what was done,
@@ -285,11 +476,7 @@ def apply_operation(fmu_path: Path, output_path: Path, operation: str,
285
476
  if argument and not needs_argument:
286
477
  raise ValueError(f"Operation '{operation}' does not take an `argument`.")
287
478
 
288
- if causality:
289
- unknown = set(causality) - set(CAUSALITIES)
290
- if unknown:
291
- raise ValueError(f"Unknown causality {sorted(unknown)}. "
292
- f"Available: {list(CAUSALITIES)}.")
479
+ check_port_filters(causality, types, variabilities)
293
480
 
294
481
  # A malformed regular expression surfaces here, as a plain `re.error`:
295
482
  # turn it into something the caller can act upon.
@@ -299,11 +486,9 @@ def apply_operation(fmu_path: Path, output_path: Path, operation: str,
299
486
  raise ValueError(f"Cannot apply '{operation}': {exc}") from None
300
487
 
301
488
  with FMU(str(fmu_path)) as fmu:
302
- fmu.apply_operation(instance, causality or None)
489
+ fmu.apply_operation(instance, causality or None, types=types or None,
490
+ variabilities=variabilities or None)
303
491
  fmu.repack(str(output_path))
304
492
 
305
493
  return {"fmu": fmu_path.name, "output": str(output_path),
306
494
  "operation": repr(instance)}
307
-
308
-
309
-
@@ -45,6 +45,9 @@ DEFAULT_OPTIONS: dict[str, Any] = {
45
45
  #: Default name of the container being described.
46
46
  DEFAULT_CONTAINER_NAME = "container.fmu"
47
47
 
48
+ #: Marker of the files written by `HeadlessAssemblyBridge.state` (the assembly state of `fmutool-agent`).
49
+ STATE_FORMAT = "fmutool-agent-state/1"
50
+
48
51
 
49
52
  class _FmuDescriptor(OperationAbstract):
50
53
  """Reads an FMU descriptor and collects what the assistant needs.
@@ -165,6 +168,49 @@ class HeadlessAssemblyBridge:
165
168
  self._start_values: dict[tuple[str, str], str] = {}
166
169
  self._options: dict[str, Any] = dict(DEFAULT_OPTIONS)
167
170
 
171
+ # -- state -------------------------------------------------------------
172
+
173
+ def state(self) -> dict[str, Any]:
174
+ """What the client asked for, as JSON values: `from_state` rebuilds the same bridge.
175
+
176
+ This is not the assembly description (`save_as_json`): it keeps the
177
+ names given to the FMUs and nothing derived from them, so that a tool
178
+ called in another process (`fmutool-agent`) finds the assembly as left.
179
+ """
180
+ return {
181
+ "format": STATE_FORMAT,
182
+ "name": self._name,
183
+ "fmus": {name: str(path) for name, path in self._paths.items()},
184
+ "links": [list(link) for link in self._links],
185
+ "exposed_inputs": [list(item) for item in self._exposed_inputs],
186
+ "exposed_outputs": [list(item) for item in self._exposed_outputs],
187
+ "start_values": [[fmu, port, value] for (fmu, port), value in self._start_values.items()],
188
+ "options": dict(self._options),
189
+ }
190
+
191
+ @classmethod
192
+ def from_state(cls, state: dict[str, Any]) -> "HeadlessAssemblyBridge":
193
+ """The bridge saved by `state`. The FMUs are read again from their files.
194
+
195
+ Raises:
196
+ ValueError: If `state` was not produced by `state`.
197
+ FileNotFoundError: If an FMU of the assembly no longer exists.
198
+ """
199
+ if not isinstance(state, dict) or state.get("format") != STATE_FORMAT:
200
+ raise ValueError(f"Not an assembly state (expected \"format\": \"{STATE_FORMAT}\").")
201
+ bridge = cls(state.get("name", DEFAULT_CONTAINER_NAME))
202
+ for name, path in state.get("fmus", {}).items():
203
+ description = describe_fmu(Path(path))
204
+ description["fmu"] = name
205
+ bridge._paths[name] = Path(path)
206
+ bridge._descriptions[name] = description
207
+ bridge._links = [tuple(link) for link in state.get("links", [])]
208
+ bridge._exposed_inputs = [tuple(item) for item in state.get("exposed_inputs", [])]
209
+ bridge._exposed_outputs = [tuple(item) for item in state.get("exposed_outputs", [])]
210
+ bridge._start_values = {(fmu, port): value for fmu, port, value in state.get("start_values", [])}
211
+ bridge._options.update(state.get("options", {}))
212
+ return bridge
213
+
168
214
  # -- helpers -----------------------------------------------------------
169
215
 
170
216
  def _description(self, fmu: str) -> dict[str, Any]:
@@ -84,10 +84,14 @@ Beyond assembling, single-FMU tools are also available. They read or rewrite
84
84
  **one** `.fmu` file and never touch the assembly:
85
85
  - `summarize_fmu(path)` — identity, capabilities, platforms, port counts.
86
86
  - `check_fmu(path)` — FMI schema conformity and registered checkers.
87
- - `dump_ports_csv(fmu, path)` / `rename_ports_from_csv(fmu, csv, output)` —
88
- bulk renaming. An **empty** new name **removes** the port.
87
+ - `describe_port(fmu, port)` — everything declared about one port: min, max,
88
+ nominal, declared type, aliases, terminals.
89
+ - `rename_ports(fmu, output, mapping=...)` — renaming from a mapping, or from
90
+ a CSV written by `dump_ports_csv(fmu, path)` (bulk renaming). An **empty**
91
+ new name **removes** the port.
89
92
  - `apply_operation(fmu, output, operation, ...)` — prefix stripping, trimming
90
- and regexp filtering of port names.
93
+ and regexp filtering of port names, restricted with `causality`, `type` and
94
+ `variability` if needed.
91
95
 
92
96
  These rewrite the FMU interface, so they produce a **new** file and leave the
93
97
  source untouched. Warn the user that anything already connected to the old
@@ -13,21 +13,13 @@ from typing import Any
13
13
 
14
14
  from pydantic import BaseModel, ConfigDict, Field, SerializerFunctionWrapHandler, model_serializer
15
15
 
16
+ # Shared with the command line, which runs without Pydantic: defined in `tools`, re-exported here.
17
+ from .tools import DEFAULT_PORT_LIMIT, MAX_DESCRIPTION_LENGTH, MAX_PORT_LIMIT, format_start_value # noqa: F401
18
+
16
19
  #: Value kinds accepted for a start value, before conversion to the FMI
17
20
  #: textual representation.
18
21
  StartValue = bool | int | float | str
19
22
 
20
- #: Maximum number of ports returned by a single call, to keep the answer
21
- #: readable and the context small on industrial FMUs.
22
- DEFAULT_PORT_LIMIT = 50
23
-
24
- #: Largest page of ports a client may ask for: about 31k characters (~9k tokens) of compact ports.
25
- MAX_PORT_LIMIT = 200
26
-
27
- #: Descriptions of the ports longer than this are cut (with `…`): they help to match ports by meaning, but some
28
- #: generators write whole paragraphs, which would fill the context window of the model.
29
- MAX_DESCRIPTION_LENGTH = 80
30
-
31
23
 
32
24
  class ContainerOptions(BaseModel):
33
25
  """Container options to change; the others keep their value."""
@@ -55,18 +47,16 @@ class ContainerOptions(BaseModel):
55
47
  )
56
48
  auto_link: bool | None = Field(
57
49
  default=None,
58
- description="Connect the ports with the same name and type. Enabled by "
59
- "default: explicit links are for the other ports.",
50
+ description="Connect the ports with the same name and type (default: on); "
51
+ "links are for the others.",
60
52
  )
61
53
  auto_input: bool | None = Field(
62
54
  default=None,
63
- description="Automatically expose unconnected inputs as container "
64
- "inputs. Enabled by default.",
55
+ description="Expose the unconnected inputs (default: on).",
65
56
  )
66
57
  auto_output: bool | None = Field(
67
58
  default=None,
68
- description="Automatically expose unconnected outputs as container "
69
- "outputs. Enabled by default.",
59
+ description="Expose the unconnected outputs (default: on).",
70
60
  )
71
61
  auto_parameter: bool | None = Field(
72
62
  default=None,
@@ -83,10 +73,8 @@ class ContainerOptions(BaseModel):
83
73
  )
84
74
  reset_ports: bool | None = Field(
85
75
  default=None,
86
- description="Add a `container.reset` input to each embedded FMU: when "
87
- "true, the container resets the FMU and initializes it again "
88
- "at the current time. Wire it with a link, or expose it as "
89
- "`container.<fmu>.reset`.",
76
+ description="Add a `container.reset` input to each FMU: true resets and "
77
+ "initializes it again. Link it, or expose it as `container.<fmu>.reset`.",
90
78
  )
91
79
 
92
80
  def changes(self) -> dict[str, Any]:
@@ -117,23 +105,6 @@ def option_reference() -> list[dict[str, Any]]:
117
105
  return reference
118
106
 
119
107
 
120
- def format_start_value(value: StartValue) -> str:
121
- """Render ``value`` the way ``modelDescription.xml`` expects it.
122
-
123
- Booleans are the trap here: ``str(True)`` yields ``"True"``, which FMI
124
- does not accept.
125
-
126
- Examples:
127
- >>> format_start_value(True)
128
- 'true'
129
- >>> format_start_value(0.01)
130
- '0.01'
131
- """
132
- if isinstance(value, bool):
133
- return "true" if value else "false"
134
- return str(value)
135
-
136
-
137
108
  # ---------------------------------------------------------------------------
138
109
  # FMU description
139
110
  # ---------------------------------------------------------------------------
@@ -165,14 +136,6 @@ class Port(BaseModel):
165
136
  """
166
137
  return {key: value for key, value in handler(self).items() if value is not None}
167
138
 
168
- @classmethod
169
- def from_description(cls, port: dict[str, Any]) -> "Port":
170
- """A port of a bridge description, its description cut to `MAX_DESCRIPTION_LENGTH` characters."""
171
- description = port.get("description")
172
- if description and len(description) > MAX_DESCRIPTION_LENGTH:
173
- port = {**port, "description": description[:MAX_DESCRIPTION_LENGTH - 1].rstrip() + "…"}
174
- return cls(**port)
175
-
176
139
 
177
140
  class FmuPorts(BaseModel):
178
141
  """A page of ports, plus what it took to get there.