ert 16.0.9__py3-none-any.whl → 19.0.0rc2__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (286) hide show
  1. _ert/events.py +19 -2
  2. _ert/forward_model_runner/client.py +6 -2
  3. _ert/forward_model_runner/fm_dispatch.py +9 -6
  4. _ert/forward_model_runner/reporting/event.py +1 -0
  5. _ert/forward_model_runner/runner.py +1 -2
  6. _ert/utils.py +12 -0
  7. ert/__main__.py +58 -38
  8. ert/analysis/_enif_update.py +8 -4
  9. ert/analysis/_es_update.py +19 -6
  10. ert/analysis/_update_commons.py +16 -6
  11. ert/base_model_context.py +1 -1
  12. ert/cli/main.py +17 -12
  13. ert/cli/monitor.py +7 -0
  14. ert/config/__init__.py +17 -6
  15. ert/config/_create_observation_dataframes.py +118 -21
  16. ert/config/_get_num_cpu.py +1 -1
  17. ert/config/_observations.py +91 -2
  18. ert/config/_read_summary.py +74 -328
  19. ert/config/design_matrix.py +62 -23
  20. ert/config/distribution.py +1 -1
  21. ert/config/ensemble_config.py +9 -17
  22. ert/config/ert_config.py +155 -58
  23. ert/config/everest_control.py +234 -0
  24. ert/config/{everest_constraints_config.py → everest_response.py} +27 -15
  25. ert/config/field.py +99 -90
  26. ert/config/forward_model_step.py +122 -17
  27. ert/config/gen_data_config.py +5 -10
  28. ert/config/gen_kw_config.py +11 -41
  29. ert/config/known_response_types.py +14 -0
  30. ert/config/parameter_config.py +1 -33
  31. ert/config/parsing/_option_dict.py +10 -2
  32. ert/config/parsing/config_errors.py +1 -1
  33. ert/config/parsing/config_keywords.py +2 -1
  34. ert/config/parsing/config_schema.py +23 -11
  35. ert/config/parsing/config_schema_deprecations.py +3 -3
  36. ert/config/parsing/config_schema_item.py +26 -11
  37. ert/config/parsing/context_values.py +3 -3
  38. ert/config/parsing/file_context_token.py +1 -1
  39. ert/config/parsing/observations_parser.py +6 -2
  40. ert/config/parsing/queue_system.py +9 -0
  41. ert/config/parsing/schema_item_type.py +1 -0
  42. ert/config/queue_config.py +42 -50
  43. ert/config/response_config.py +0 -8
  44. ert/config/rft_config.py +275 -0
  45. ert/config/summary_config.py +3 -8
  46. ert/config/surface_config.py +73 -26
  47. ert/config/workflow_fixtures.py +2 -1
  48. ert/config/workflow_job.py +135 -54
  49. ert/dark_storage/client/__init__.py +2 -2
  50. ert/dark_storage/client/_session.py +4 -4
  51. ert/dark_storage/client/client.py +2 -2
  52. ert/dark_storage/common.py +12 -3
  53. ert/dark_storage/compute/misfits.py +11 -7
  54. ert/dark_storage/endpoints/compute/misfits.py +6 -4
  55. ert/dark_storage/endpoints/ensembles.py +4 -0
  56. ert/dark_storage/endpoints/experiment_server.py +30 -24
  57. ert/dark_storage/endpoints/experiments.py +2 -2
  58. ert/dark_storage/endpoints/observations.py +8 -6
  59. ert/dark_storage/endpoints/parameters.py +4 -12
  60. ert/dark_storage/endpoints/responses.py +24 -5
  61. ert/dark_storage/json_schema/ensemble.py +3 -0
  62. ert/dark_storage/json_schema/experiment.py +1 -1
  63. ert/data/_measured_data.py +6 -5
  64. ert/ensemble_evaluator/__init__.py +8 -1
  65. ert/ensemble_evaluator/config.py +2 -1
  66. ert/ensemble_evaluator/evaluator.py +81 -29
  67. ert/ensemble_evaluator/event.py +6 -0
  68. ert/ensemble_evaluator/snapshot.py +3 -1
  69. ert/ensemble_evaluator/state.py +1 -0
  70. ert/field_utils/__init__.py +8 -0
  71. ert/field_utils/field_utils.py +228 -15
  72. ert/field_utils/grdecl_io.py +1 -1
  73. ert/field_utils/roff_io.py +1 -1
  74. ert/gui/__init__.py +5 -2
  75. ert/gui/ertnotifier.py +1 -1
  76. ert/gui/ertwidgets/__init__.py +23 -16
  77. ert/gui/ertwidgets/analysismoduleedit.py +2 -2
  78. ert/gui/ertwidgets/checklist.py +1 -1
  79. ert/gui/ertwidgets/closabledialog.py +2 -0
  80. ert/gui/ertwidgets/copyablelabel.py +2 -0
  81. ert/gui/ertwidgets/create_experiment_dialog.py +3 -1
  82. ert/gui/ertwidgets/ensembleselector.py +2 -2
  83. ert/gui/ertwidgets/listeditbox.py +2 -0
  84. ert/gui/ertwidgets/models/__init__.py +2 -0
  85. ert/gui/ertwidgets/models/activerealizationsmodel.py +5 -1
  86. ert/gui/ertwidgets/models/path_model.py +1 -1
  87. ert/gui/ertwidgets/models/targetensemblemodel.py +5 -1
  88. ert/gui/ertwidgets/models/text_model.py +4 -1
  89. ert/gui/ertwidgets/pathchooser.py +0 -3
  90. ert/gui/ertwidgets/searchbox.py +17 -4
  91. ert/gui/ertwidgets/stringbox.py +2 -0
  92. ert/gui/{suggestor → ertwidgets/suggestor}/_suggestor_message.py +13 -4
  93. ert/gui/{suggestor → ertwidgets/suggestor}/suggestor.py +63 -30
  94. ert/gui/main.py +41 -13
  95. ert/gui/main_window.py +3 -7
  96. ert/gui/model/fm_step_list.py +3 -0
  97. ert/gui/model/real_list.py +1 -0
  98. ert/gui/model/snapshot.py +1 -0
  99. ert/gui/simulation/combobox_with_description.py +3 -0
  100. ert/gui/simulation/ensemble_experiment_panel.py +8 -2
  101. ert/gui/simulation/ensemble_information_filter_panel.py +7 -2
  102. ert/gui/simulation/ensemble_smoother_panel.py +8 -2
  103. ert/gui/simulation/evaluate_ensemble_panel.py +17 -7
  104. ert/gui/simulation/experiment_panel.py +18 -6
  105. ert/gui/simulation/manual_update_panel.py +35 -10
  106. ert/gui/simulation/multiple_data_assimilation_panel.py +13 -9
  107. ert/gui/simulation/run_dialog.py +47 -20
  108. ert/gui/simulation/single_test_run_panel.py +6 -3
  109. ert/gui/simulation/view/progress_widget.py +2 -0
  110. ert/gui/simulation/view/realization.py +5 -1
  111. ert/gui/simulation/view/update.py +2 -0
  112. ert/gui/summarypanel.py +20 -1
  113. ert/gui/tools/event_viewer/panel.py +3 -4
  114. ert/gui/tools/event_viewer/tool.py +2 -0
  115. ert/gui/tools/load_results/load_results_panel.py +1 -1
  116. ert/gui/tools/load_results/load_results_tool.py +2 -0
  117. ert/gui/tools/manage_experiments/export_dialog.py +136 -0
  118. ert/gui/tools/manage_experiments/manage_experiments_panel.py +2 -0
  119. ert/gui/tools/manage_experiments/storage_info_widget.py +121 -16
  120. ert/gui/tools/manage_experiments/storage_widget.py +4 -3
  121. ert/gui/tools/plot/customize/color_chooser.py +5 -2
  122. ert/gui/tools/plot/customize/customize_plot_dialog.py +2 -0
  123. ert/gui/tools/plot/customize/default_customization_view.py +4 -0
  124. ert/gui/tools/plot/customize/limits_customization_view.py +3 -0
  125. ert/gui/tools/plot/customize/statistics_customization_view.py +3 -0
  126. ert/gui/tools/plot/customize/style_chooser.py +2 -0
  127. ert/gui/tools/plot/customize/style_customization_view.py +3 -0
  128. ert/gui/tools/plot/data_type_keys_widget.py +2 -0
  129. ert/gui/tools/plot/data_type_proxy_model.py +3 -0
  130. ert/gui/tools/plot/plot_api.py +50 -28
  131. ert/gui/tools/plot/plot_ensemble_selection_widget.py +17 -10
  132. ert/gui/tools/plot/plot_widget.py +15 -2
  133. ert/gui/tools/plot/plot_window.py +41 -19
  134. ert/gui/tools/plot/plottery/plot_config.py +2 -0
  135. ert/gui/tools/plot/plottery/plot_context.py +14 -0
  136. ert/gui/tools/plot/plottery/plots/__init__.py +2 -0
  137. ert/gui/tools/plot/plottery/plots/cesp.py +3 -1
  138. ert/gui/tools/plot/plottery/plots/distribution.py +6 -1
  139. ert/gui/tools/plot/plottery/plots/ensemble.py +13 -5
  140. ert/gui/tools/plot/plottery/plots/gaussian_kde.py +12 -2
  141. ert/gui/tools/plot/plottery/plots/histogram.py +3 -1
  142. ert/gui/tools/plot/plottery/plots/misfits.py +436 -0
  143. ert/gui/tools/plot/plottery/plots/observations.py +18 -4
  144. ert/gui/tools/plot/plottery/plots/statistics.py +62 -20
  145. ert/gui/tools/plot/plottery/plots/std_dev.py +3 -1
  146. ert/gui/tools/plot/widgets/clearable_line_edit.py +9 -0
  147. ert/gui/tools/plot/widgets/filter_popup.py +2 -0
  148. ert/gui/tools/plot/widgets/filterable_kw_list_model.py +3 -0
  149. ert/gui/tools/plugins/plugin.py +1 -1
  150. ert/gui/tools/plugins/plugins_tool.py +2 -0
  151. ert/gui/tools/plugins/process_job_dialog.py +3 -0
  152. ert/gui/tools/workflows/workflow_dialog.py +2 -0
  153. ert/gui/tools/workflows/workflows_tool.py +2 -0
  154. ert/libres_facade.py +5 -7
  155. ert/logging/__init__.py +4 -1
  156. ert/mode_definitions.py +2 -0
  157. ert/plugins/__init__.py +4 -6
  158. ert/plugins/hook_implementations/workflows/csv_export.py +2 -3
  159. ert/plugins/hook_implementations/workflows/gen_data_rft_export.py +10 -2
  160. ert/plugins/hook_specifications/__init__.py +0 -10
  161. ert/plugins/hook_specifications/jobs.py +0 -9
  162. ert/plugins/plugin_manager.py +53 -124
  163. ert/resources/forward_models/run_reservoirsimulator.py +8 -4
  164. ert/resources/forward_models/template_render.py +10 -10
  165. ert/resources/shell_scripts/delete_directory.py +2 -2
  166. ert/run_models/__init__.py +24 -6
  167. ert/run_models/_create_run_path.py +133 -38
  168. ert/run_models/ensemble_experiment.py +10 -4
  169. ert/run_models/ensemble_information_filter.py +8 -1
  170. ert/run_models/ensemble_smoother.py +9 -3
  171. ert/run_models/evaluate_ensemble.py +8 -6
  172. ert/run_models/event.py +7 -3
  173. ert/run_models/everest_run_model.py +337 -113
  174. ert/run_models/initial_ensemble_run_model.py +25 -24
  175. ert/run_models/manual_update.py +6 -3
  176. ert/run_models/manual_update_enif.py +37 -0
  177. ert/run_models/model_factory.py +78 -18
  178. ert/run_models/multiple_data_assimilation.py +22 -11
  179. ert/run_models/run_model.py +72 -73
  180. ert/run_models/single_test_run.py +7 -4
  181. ert/run_models/update_run_model.py +4 -2
  182. ert/runpaths.py +5 -6
  183. ert/sample_prior.py +9 -4
  184. ert/scheduler/__init__.py +10 -5
  185. ert/scheduler/driver.py +40 -0
  186. ert/scheduler/event.py +3 -1
  187. ert/scheduler/job.py +23 -13
  188. ert/scheduler/lsf_driver.py +15 -5
  189. ert/scheduler/openpbs_driver.py +10 -4
  190. ert/scheduler/scheduler.py +5 -0
  191. ert/scheduler/slurm_driver.py +20 -5
  192. ert/services/__init__.py +2 -2
  193. ert/services/_base_service.py +37 -20
  194. ert/services/_storage_main.py +20 -18
  195. ert/services/ert_server.py +317 -0
  196. ert/shared/_doc_utils/__init__.py +4 -2
  197. ert/shared/_doc_utils/ert_jobs.py +1 -4
  198. ert/shared/net_utils.py +43 -18
  199. ert/shared/storage/connection.py +3 -3
  200. ert/shared/version.py +3 -3
  201. ert/storage/__init__.py +14 -1
  202. ert/storage/local_ensemble.py +44 -13
  203. ert/storage/local_experiment.py +54 -34
  204. ert/storage/local_storage.py +90 -58
  205. ert/storage/migration/to10.py +3 -2
  206. ert/storage/migration/to11.py +9 -10
  207. ert/storage/migration/to12.py +19 -20
  208. ert/storage/migration/to13.py +28 -27
  209. ert/storage/migration/to14.py +3 -3
  210. ert/storage/migration/to15.py +25 -0
  211. ert/storage/migration/to16.py +38 -0
  212. ert/storage/migration/to17.py +42 -0
  213. ert/storage/migration/to18.py +11 -0
  214. ert/storage/migration/to19.py +34 -0
  215. ert/storage/migration/to20.py +23 -0
  216. ert/storage/migration/to21.py +25 -0
  217. ert/storage/migration/to6.py +3 -2
  218. ert/storage/migration/to7.py +12 -13
  219. ert/storage/migration/to8.py +9 -11
  220. ert/storage/migration/to9.py +5 -4
  221. ert/storage/realization_storage_state.py +7 -7
  222. ert/substitutions.py +12 -28
  223. ert/validation/active_range.py +7 -7
  224. ert/validation/ensemble_realizations_argument.py +4 -2
  225. ert/validation/rangestring.py +16 -16
  226. ert/workflow_runner.py +6 -3
  227. {ert-16.0.9.dist-info → ert-19.0.0rc2.dist-info}/METADATA +21 -15
  228. ert-19.0.0rc2.dist-info/RECORD +524 -0
  229. {ert-16.0.9.dist-info → ert-19.0.0rc2.dist-info}/WHEEL +1 -1
  230. everest/api/everest_data_api.py +14 -1
  231. everest/assets/everest_logo.svg +406 -0
  232. everest/bin/config_branch_script.py +30 -14
  233. everest/bin/everconfigdump_script.py +2 -10
  234. everest/bin/everest_script.py +53 -33
  235. everest/bin/everlint_script.py +3 -5
  236. everest/bin/kill_script.py +7 -5
  237. everest/bin/main.py +11 -24
  238. everest/bin/monitor_script.py +64 -35
  239. everest/bin/utils.py +58 -43
  240. everest/bin/visualization_script.py +23 -13
  241. everest/config/__init__.py +4 -1
  242. everest/config/control_config.py +81 -6
  243. everest/config/control_variable_config.py +4 -3
  244. everest/config/everest_config.py +102 -79
  245. everest/config/forward_model_config.py +5 -3
  246. everest/config/install_data_config.py +7 -5
  247. everest/config/install_job_config.py +45 -3
  248. everest/config/install_template_config.py +3 -3
  249. everest/config/optimization_config.py +19 -6
  250. everest/config/output_constraint_config.py +8 -2
  251. everest/config/server_config.py +6 -55
  252. everest/config/simulator_config.py +62 -17
  253. everest/config/utils.py +25 -105
  254. everest/config/validation_utils.py +34 -15
  255. everest/config_file_loader.py +30 -21
  256. everest/detached/__init__.py +0 -6
  257. everest/detached/client.py +7 -52
  258. everest/detached/everserver.py +19 -45
  259. everest/everest_storage.py +24 -40
  260. everest/gui/everest_client.py +2 -3
  261. everest/gui/main_window.py +2 -2
  262. everest/optimizer/everest2ropt.py +68 -42
  263. everest/optimizer/opt_model_transforms.py +15 -20
  264. everest/optimizer/utils.py +0 -29
  265. everest/plugins/hook_specs.py +0 -24
  266. everest/strings.py +1 -6
  267. everest/util/__init__.py +3 -1
  268. ert/config/everest_objective_config.py +0 -95
  269. ert/config/ext_param_config.py +0 -107
  270. ert/gui/tools/export/__init__.py +0 -3
  271. ert/gui/tools/export/export_panel.py +0 -83
  272. ert/gui/tools/export/export_tool.py +0 -67
  273. ert/gui/tools/export/exporter.py +0 -36
  274. ert/plugins/hook_specifications/ecl_config.py +0 -29
  275. ert/services/storage_service.py +0 -127
  276. ert/summary_key_type.py +0 -234
  277. ert-16.0.9.dist-info/RECORD +0 -521
  278. everest/bin/everexport_script.py +0 -53
  279. everest/config/sampler_config.py +0 -103
  280. everest/simulator/__init__.py +0 -88
  281. everest/simulator/everest_to_ert.py +0 -252
  282. /ert/gui/{suggestor → ertwidgets/suggestor}/__init__.py +0 -0
  283. /ert/gui/{suggestor → ertwidgets/suggestor}/_colors.py +0 -0
  284. {ert-16.0.9.dist-info → ert-19.0.0rc2.dist-info}/entry_points.txt +0 -0
  285. {ert-16.0.9.dist-info → ert-19.0.0rc2.dist-info}/licenses/COPYING +0 -0
  286. {ert-16.0.9.dist-info → ert-19.0.0rc2.dist-info}/top_level.txt +0 -0
@@ -1,9 +1,10 @@
1
1
  from typing import Any
2
2
 
3
- from PyQt6.QtCore import Qt
3
+ from PyQt6.QtCore import Qt, QTimer
4
4
  from PyQt6.QtCore import pyqtSignal as Signal
5
5
  from PyQt6.QtGui import QColor, QFocusEvent, QKeyEvent
6
6
  from PyQt6.QtWidgets import QLineEdit
7
+ from typing_extensions import override
7
8
 
8
9
 
9
10
  class SearchBox(QLineEdit):
@@ -11,16 +12,25 @@ class SearchBox(QLineEdit):
11
12
 
12
13
  filterChanged = Signal(object)
13
14
 
14
- def __init__(self) -> None:
15
+ def __init__(self, debounce_timeout: int = 1000) -> None:
15
16
  QLineEdit.__init__(self)
16
17
 
17
18
  self.setToolTip("Type to search!")
18
19
  self.active_color = self.palette().color(self.foregroundRole())
19
20
  self.disable_search = True
20
21
  self.presentSearch()
21
- self.textChanged.connect(self.__emitFilterChanged)
22
+ self.textChanged.connect(self._start_debounce_timer)
23
+ self._debounce_timout = debounce_timeout
24
+ self._debounce_timer = QTimer(self)
25
+ self._debounce_timer.setSingleShot(True)
26
+ self._debounce_timer.timeout.connect(self._emit_filter_changed)
22
27
 
23
- def __emitFilterChanged(self, _filter: Any) -> None:
28
+ def _start_debounce_timer(self, _filter: Any) -> None:
29
+ if not self._debounce_timer.isActive():
30
+ self._debounce_timer.start(self._debounce_timout)
31
+ self._debounce_timer.setInterval(self._debounce_timout)
32
+
33
+ def _emit_filter_changed(self) -> None:
24
34
  self.filterChanged.emit(self.filter())
25
35
 
26
36
  def filter(self) -> str:
@@ -55,14 +65,17 @@ class SearchBox(QLineEdit):
55
65
  if not self.text():
56
66
  self.presentSearch()
57
67
 
68
+ @override
58
69
  def focusInEvent(self, a0: QFocusEvent | None) -> None:
59
70
  QLineEdit.focusInEvent(self, a0)
60
71
  self.enterSearch()
61
72
 
73
+ @override
62
74
  def focusOutEvent(self, a0: QFocusEvent | None) -> None:
63
75
  QLineEdit.focusOutEvent(self, a0)
64
76
  self.exitSearch()
65
77
 
78
+ @override
66
79
  def keyPressEvent(self, a0: QKeyEvent | None) -> None:
67
80
  if a0 and a0.key() == Qt.Key.Key_Escape:
68
81
  self.clear()
@@ -4,6 +4,7 @@ from typing import TYPE_CHECKING, Any
4
4
 
5
5
  from PyQt6.QtGui import QPalette
6
6
  from PyQt6.QtWidgets import QLineEdit
7
+ from typing_extensions import override
7
8
 
8
9
  from .validationsupport import ValidationSupport
9
10
 
@@ -101,6 +102,7 @@ class StringBox(QLineEdit):
101
102
  def model(self) -> TextModel:
102
103
  return self._model
103
104
 
105
+ @override
104
106
  def setValidator(self, validator: ArgumentDefinition) -> None: # type: ignore
105
107
  self._validator = validator
106
108
 
@@ -13,10 +13,11 @@ from PyQt6.QtWidgets import (
13
13
  QVBoxLayout,
14
14
  QWidget,
15
15
  )
16
+ from typing_extensions import override
16
17
 
17
18
  from ert.gui import is_dark_mode
18
19
 
19
- from ..ertwidgets.copyablelabel import _CopyButton
20
+ from ..copy_button import CopyButton
20
21
  from ._colors import (
21
22
  BLUE_BACKGROUND,
22
23
  BLUE_TEXT,
@@ -33,6 +34,16 @@ def _svg_icon(image_name: str) -> QSvgWidget:
33
34
  return widget
34
35
 
35
36
 
37
+ class _CopyButton(CopyButton):
38
+ def __init__(self, message: str) -> None:
39
+ super().__init__()
40
+ self.message = message
41
+
42
+ @override
43
+ def copy(self) -> None:
44
+ self.copy_text(self.message)
45
+
46
+
36
47
  class SuggestorMessage(QWidget):
37
48
  def __init__(
38
49
  self,
@@ -100,9 +111,7 @@ class SuggestorMessage(QWidget):
100
111
  else:
101
112
  self._expand_collapse_label = QLabel()
102
113
  self._hbox.addWidget(self.lbl, alignment=Qt.AlignmentFlag.AlignTop)
103
- self._hbox.addWidget(
104
- _CopyButton(QLabel(message)), alignment=Qt.AlignmentFlag.AlignTop
105
- )
114
+ self._hbox.addWidget(_CopyButton(message), alignment=Qt.AlignmentFlag.AlignTop)
106
115
 
107
116
  def _toggle_expand(self, _link: Any) -> None:
108
117
  if self._expanded:
@@ -19,9 +19,11 @@ from PyQt6.QtWidgets import (
19
19
  QVBoxLayout,
20
20
  QWidget,
21
21
  )
22
+ from typing_extensions import override
22
23
 
23
24
  from ert.gui import is_dark_mode
24
25
 
26
+ from .. import CopyButton
25
27
  from ._colors import BLUE_TEXT
26
28
  from ._suggestor_message import SuggestorMessage
27
29
 
@@ -105,6 +107,32 @@ QPushButton:hover {{
105
107
  """
106
108
 
107
109
 
110
+ class _CopyAllButton(CopyButton):
111
+ def __init__(
112
+ self,
113
+ errors: list[ErrorInfo],
114
+ warnings: list[WarningInfo],
115
+ deprecations: list[WarningInfo],
116
+ ) -> None:
117
+ super().__init__()
118
+ self.setText(" Copy all messages")
119
+ self.all_messages = "\n\n".join(
120
+ [
121
+ f"{info.message}" + (f"\n{info.location()}" if info.location() else "")
122
+ for info in (errors + warnings + deprecations)
123
+ ]
124
+ )
125
+ self.setStyleSheet(SECONDARY_BUTTON_STYLE)
126
+
127
+ @override
128
+ def copy(self) -> None:
129
+ logger.info(
130
+ "Copy all button in Suggestor used. "
131
+ f"Copied {len(self.all_messages)} characters"
132
+ )
133
+ self.copy_text(self.all_messages)
134
+
135
+
108
136
  class Suggestor(QWidget):
109
137
  def __init__(
110
138
  self,
@@ -145,7 +173,24 @@ class Suggestor(QWidget):
145
173
  data_layout.addWidget(self._help_panel(help_links))
146
174
  self.__layout.addWidget(data_widget)
147
175
 
148
- self.__layout.addWidget(self._action_buttons())
176
+ action_buttons = QWidget(parent=self)
177
+ action_buttons_layout = QHBoxLayout()
178
+ action_buttons_layout.setContentsMargins(0, 24, 0, 0)
179
+
180
+ if any([errors, warnings, deprecations]):
181
+ action_buttons_layout.addWidget(
182
+ _CopyAllButton(errors, warnings, deprecations)
183
+ )
184
+
185
+ action_buttons_layout.addStretch()
186
+
187
+ if continue_action:
188
+ action_buttons_layout.addWidget(self._continue_button())
189
+
190
+ action_buttons_layout.addWidget(self._close_button())
191
+
192
+ action_buttons.setLayout(action_buttons_layout)
193
+ self.__layout.addWidget(action_buttons)
149
194
 
150
195
  def _help_panel(self, help_links: dict[str, str]) -> QFrame:
151
196
  help_button_frame = QFrame(parent=self)
@@ -204,35 +249,23 @@ class Suggestor(QWidget):
204
249
  area_layout.addWidget(self._messages(errors, warnings, deprecations))
205
250
  return problem_area
206
251
 
207
- def _action_buttons(self) -> QWidget:
208
- def run_pressed() -> None:
209
- assert self._continue_action
210
- self._continue_action()
211
- self.close()
212
-
213
- buttons = QWidget(parent=self)
214
- buttons_layout = QHBoxLayout()
215
- buttons_layout.insertStretch(-1, -1)
216
- buttons_layout.setContentsMargins(0, 24, 0, 0)
217
-
218
- give_up = QPushButton("Close")
219
- give_up.setObjectName("close_button")
220
- give_up.setStyleSheet(BUTTON_STYLE)
221
- give_up.pressed.connect(self.close)
222
-
223
- if self._continue_action:
224
- run = QPushButton("Open ERT")
225
- run.setStyleSheet(BUTTON_STYLE)
226
- run.setObjectName("run_ert_button")
227
- run.pressed.connect(run_pressed)
228
- buttons_layout.addWidget(run)
229
-
230
- give_up.setStyleSheet(SECONDARY_BUTTON_STYLE)
231
-
232
- buttons_layout.addWidget(give_up)
233
- buttons.setLayout(buttons_layout)
234
-
235
- return buttons
252
+ def _continue_button(self) -> QWidget:
253
+ assert self._continue_action
254
+ continue_button = QPushButton("Open ERT")
255
+ continue_button.setStyleSheet(BUTTON_STYLE)
256
+ continue_button.setObjectName("run_ert_button")
257
+ continue_button.pressed.connect(self._continue_action)
258
+ continue_button.pressed.connect(self.close)
259
+ return continue_button
260
+
261
+ def _close_button(self) -> QPushButton:
262
+ close_button = QPushButton("Close")
263
+ close_button.setObjectName("close_button")
264
+ close_button.pressed.connect(self.close)
265
+ close_button.setStyleSheet(
266
+ SECONDARY_BUTTON_STYLE if self._continue_action else BUTTON_STYLE
267
+ )
268
+ return close_button
236
269
 
237
270
  def _messages(
238
271
  self,
ert/gui/main.py CHANGED
@@ -8,12 +8,13 @@ import traceback
8
8
  import types
9
9
  from collections import Counter
10
10
  from importlib.resources import files
11
+ from pathlib import Path
11
12
  from signal import SIG_DFL, SIGINT, signal
12
13
 
13
14
  from opentelemetry.trace import Status, StatusCode
14
15
  from PyQt6.QtCore import QDir
15
16
  from PyQt6.QtGui import QIcon
16
- from PyQt6.QtWidgets import QApplication, QWidget
17
+ from PyQt6.QtWidgets import QApplication, QMessageBox, QWidget
17
18
 
18
19
  from ert.config import (
19
20
  ErrorInfo,
@@ -26,12 +27,17 @@ from ert.gui.tools.event_viewer import (
26
27
  add_gui_log_handler,
27
28
  )
28
29
  from ert.namespace import Namespace
29
- from ert.plugins import ErtPluginContext, ErtRuntimePlugins
30
- from ert.services import StorageService
31
- from ert.storage import ErtStorageException, local_storage_set_ert_config, open_storage
30
+ from ert.plugins import ErtRuntimePlugins, get_site_plugins
31
+ from ert.services import ErtServer
32
+ from ert.storage import (
33
+ ErtStorageException,
34
+ LocalStorage,
35
+ local_storage_set_ert_config,
36
+ )
37
+ from ert.storage.local_storage import _LOCAL_STORAGE_VERSION, _storage_version
32
38
  from ert.trace import trace, tracer
33
39
 
34
- from .suggestor import Suggestor
40
+ from .ertwidgets import Suggestor
35
41
 
36
42
  logger = logging.getLogger(__name__)
37
43
 
@@ -113,7 +119,7 @@ def run_gui(args: Namespace, plugins: ErtRuntimePlugins | None = None) -> int:
113
119
  return show_window()
114
120
 
115
121
  try:
116
- with StorageService.init_service(project=os.path.abspath(ens_path)):
122
+ with ErtServer.init_service(project=Path(ens_path).absolute()):
117
123
  return show_window()
118
124
  except PermissionError as pe:
119
125
  print(f"Error: {pe}", file=sys.stderr)
@@ -149,18 +155,40 @@ def _start_initial_gui_window(
149
155
  if runtime_plugins is not None:
150
156
  ert_config = ErtConfig.with_plugins(runtime_plugins).from_file(args.config)
151
157
  else:
152
- with ErtPluginContext() as default_runtime_plugins:
153
- ert_config = ErtConfig.with_plugins(default_runtime_plugins).from_file(
154
- args.config
155
- )
158
+ ert_config = ErtConfig.with_plugins(get_site_plugins()).from_file(
159
+ args.config
160
+ )
156
161
  local_storage_set_ert_config(ert_config)
157
162
 
158
163
  storage_path = None
159
164
  if ert_config is not None:
160
165
  try:
161
- # Open write to initialize the storage,so that
162
- # dark storage can be mounted onto it
163
- open_storage(ert_config.ens_path, mode="w").close()
166
+ if LocalStorage.check_migration_needed(Path(ert_config.ens_path)):
167
+ storage_version = _storage_version(Path(ert_config.ens_path))
168
+ current_version = _LOCAL_STORAGE_VERSION
169
+
170
+ migrate_dialog = QMessageBox.warning(
171
+ None,
172
+ f"Migrate storage to version {current_version}?",
173
+ f"Ert storage is version {storage_version} and needs to be migrated"
174
+ f" to version {current_version} to be compatible with the current"
175
+ f" version of Ert\n\n"
176
+ f"After migration, this storage can only be opened with current or"
177
+ f" later versions of Ert\n\n"
178
+ "Do you wish to continue migrating storage?\n",
179
+ QMessageBox.StandardButton.Yes | QMessageBox.StandardButton.No,
180
+ )
181
+
182
+ if migrate_dialog == QMessageBox.StandardButton.Yes:
183
+ logger.info(
184
+ f"Migrating from version {storage_version} to"
185
+ f" version {current_version}"
186
+ )
187
+ else:
188
+ logger.info("Storage migration cancelled by user")
189
+ os._exit(0)
190
+
191
+ LocalStorage.perform_migration(Path(ert_config.ens_path))
164
192
  storage_path = ert_config.ens_path
165
193
  except ErtStorageException as err:
166
194
  validation_messages.errors.append(
ert/gui/main_window.py CHANGED
@@ -9,7 +9,7 @@ from pathlib import Path
9
9
  from PyQt6.QtCore import QCoreApplication, QEvent, QSize, Qt
10
10
  from PyQt6.QtCore import pyqtSignal as Signal
11
11
  from PyQt6.QtCore import pyqtSlot as Slot
12
- from PyQt6.QtGui import QAction, QCloseEvent, QCursor, QFontDatabase, QIcon, QMouseEvent
12
+ from PyQt6.QtGui import QAction, QCloseEvent, QCursor, QIcon, QMouseEvent
13
13
  from PyQt6.QtWidgets import (
14
14
  QButtonGroup,
15
15
  QFrame,
@@ -21,6 +21,7 @@ from PyQt6.QtWidgets import (
21
21
  QVBoxLayout,
22
22
  QWidget,
23
23
  )
24
+ from typing_extensions import override
24
25
 
25
26
  from ert.config import ErtConfig, ErtScriptWorkflow
26
27
  from ert.gui import is_dark_mode, is_high_contrast_mode
@@ -30,7 +31,6 @@ from ert.gui.find_ert_info import find_ert_info
30
31
  from ert.gui.simulation import ExperimentPanel
31
32
  from ert.gui.simulation.run_dialog import RunDialog
32
33
  from ert.gui.tools.event_viewer import EventViewerTool, GUILogHandler
33
- from ert.gui.tools.export import ExportTool
34
34
  from ert.gui.tools.load_results import LoadResultsTool
35
35
  from ert.gui.tools.manage_experiments import ManageExperimentsPanel
36
36
  from ert.gui.tools.plot.plot_window import PlotWindow
@@ -95,7 +95,6 @@ class ErtMainWindow(QMainWindow):
95
95
  log_handler: GUILogHandler | None = None,
96
96
  ) -> None:
97
97
  QMainWindow.__init__(self)
98
- self.available_fonts = QFontDatabase.families()
99
98
  self.notifier = ErtNotifier()
100
99
  self.plugins_tool: PluginsTool | None = None
101
100
  self.ert_config = ert_config
@@ -373,10 +372,6 @@ class ErtMainWindow(QMainWindow):
373
372
  tools_menu.addAction(self._event_viewer_tool.getAction())
374
373
  self.close_signal.connect(self._event_viewer_tool.close_wnd)
375
374
 
376
- self.export_tool = ExportTool(self.ert_config, self.notifier)
377
- self.export_tool.setParent(self)
378
- tools_menu.addAction(self.export_tool.getAction())
379
-
380
375
  self.workflows_tool = WorkflowsTool(self.ert_config, self.notifier)
381
376
  self.workflows_tool.setParent(self)
382
377
  tools_menu.addAction(self.workflows_tool.getAction())
@@ -385,6 +380,7 @@ class ErtMainWindow(QMainWindow):
385
380
  self.load_results_tool.setParent(self)
386
381
  tools_menu.addAction(self.load_results_tool.getAction())
387
382
 
383
+ @override
388
384
  def closeEvent(self, closeEvent: QCloseEvent | None) -> None:
389
385
  for plot_window in self._external_plot_windows:
390
386
  if plot_window:
@@ -99,6 +99,7 @@ class FMStepListProxyModel(QAbstractProxyModel):
99
99
  def columnCount(self, parent: QModelIndex | None = None) -> int:
100
100
  return FM_STEP_COLUMN_SIZE
101
101
 
102
+ @override
102
103
  def rowCount(self, parent: QModelIndex | None = None) -> int:
103
104
  parent = parent or QModelIndex()
104
105
  if not parent.isValid():
@@ -127,6 +128,7 @@ class FMStepListProxyModel(QAbstractProxyModel):
127
128
  return self.createIndex(row, column, job_index.data(NodeRole))
128
129
  return QModelIndex()
129
130
 
131
+ @override
130
132
  def mapToSource(self, proxyIndex: QModelIndex) -> QModelIndex:
131
133
  if proxyIndex.isValid():
132
134
  sm = self.sourceModel()
@@ -138,6 +140,7 @@ class FMStepListProxyModel(QAbstractProxyModel):
138
140
  return sm.index(proxyIndex.row(), proxyIndex.column(), real_index)
139
141
  return QModelIndex()
140
142
 
143
+ @override
141
144
  def mapFromSource(self, sourceIndex: QModelIndex) -> QModelIndex:
142
145
  return (
143
146
  self.index(sourceIndex.row(), sourceIndex.column(), QModelIndex())
@@ -59,6 +59,7 @@ class RealListModel(QAbstractProxyModel):
59
59
  def columnCount(self, parent: QModelIndex | None = None) -> int:
60
60
  return 1
61
61
 
62
+ @override
62
63
  def rowCount(self, parent: QModelIndex | None = None) -> int:
63
64
  parent = parent or QModelIndex()
64
65
  if not parent.isValid():
ert/gui/model/snapshot.py CHANGED
@@ -269,6 +269,7 @@ class SnapshotModel(QAbstractItemModel):
269
269
  return FM_STEP_COLUMN_SIZE
270
270
  return 1
271
271
 
272
+ @override
272
273
  def rowCount(self, parent: QModelIndex | None = None) -> int:
273
274
  if parent is None:
274
275
  parent = QModelIndex()
@@ -11,6 +11,7 @@ from PyQt6.QtWidgets import (
11
11
  QVBoxLayout,
12
12
  QWidget,
13
13
  )
14
+ from typing_extensions import override
14
15
 
15
16
  LABEL_ROLE = -3994
16
17
  DESCRIPTION_ROLE = -4893
@@ -104,6 +105,7 @@ class _ComboBoxWithDescriptionDelegate(QStyledItemDelegate):
104
105
  widget.render(painter, QPoint(), QRegion(), QWidget.RenderFlag.DrawChildren)
105
106
  painter.restore()
106
107
 
108
+ @override
107
109
  def sizeHint(self, option: QStyleOptionViewItem, index: QModelIndex) -> QSize:
108
110
  label = index.data(LABEL_ROLE)
109
111
  description = index.data(DESCRIPTION_ROLE)
@@ -130,6 +132,7 @@ class QComboBoxWithDescription(QComboBox):
130
132
  model.setData(index, description, DESCRIPTION_ROLE)
131
133
  model.setData(index, group, GROUP_TITLE_ROLE)
132
134
 
135
+ @override
133
136
  def sizeHint(self) -> QSize:
134
137
  original_size_hint = super().sizeHint()
135
138
  new_width = int(original_size_hint.width() + 220)
@@ -8,6 +8,7 @@ from PyQt6.QtWidgets import (
8
8
  QLabel,
9
9
  QWidget,
10
10
  )
11
+ from typing_extensions import override
11
12
 
12
13
  from ert.config import AnalysisConfig, ParameterConfig
13
14
  from ert.gui.ertnotifier import ErtNotifier
@@ -16,6 +17,7 @@ from ert.gui.ertwidgets import (
16
17
  CopyableLabel,
17
18
  StringBox,
18
19
  TextModel,
20
+ get_parameters_button,
19
21
  )
20
22
  from ert.mode_definitions import ENSEMBLE_EXPERIMENT_MODE
21
23
  from ert.run_models import EnsembleExperiment
@@ -23,7 +25,6 @@ from ert.validation import ExperimentValidation, ProperNameArgument
23
25
  from ert.validation.active_range import ActiveRange
24
26
  from ert.validation.range_string_argument import RangeSubsetStringArgument
25
27
 
26
- from ..ertwidgets.parameterviewer import get_parameters_button
27
28
  from ._design_matrix_panel import DesignMatrixPanel
28
29
  from .experiment_config_panel import ExperimentConfigPanel
29
30
 
@@ -118,7 +119,9 @@ class EnsembleExperimentPanel(ExperimentConfigPanel):
118
119
  merged_parameters
119
120
  )
120
121
 
121
- layout.addRow("Parameters:", get_parameters_button(merged_parameters, self))
122
+ if merged_parameters:
123
+ layout.addRow("Parameters", get_parameters_button(merged_parameters, self))
124
+
122
125
  self.setLayout(layout)
123
126
 
124
127
  self._active_realizations_field.getValidationSupport().validationChanged.connect(
@@ -133,6 +136,7 @@ class EnsembleExperimentPanel(ExperimentConfigPanel):
133
136
 
134
137
  self.notifier.ertChanged.connect(self._update_experiment_name_placeholder)
135
138
 
139
+ @override
136
140
  @Slot(QWidget)
137
141
  def experimentTypeChanged(self, w: QWidget) -> None:
138
142
  if isinstance(w, EnsembleExperimentPanel):
@@ -143,6 +147,7 @@ class EnsembleExperimentPanel(ExperimentConfigPanel):
143
147
  self.notifier.storage.get_unique_experiment_name(ENSEMBLE_EXPERIMENT_MODE)
144
148
  )
145
149
 
150
+ @override
146
151
  def isConfigurationValid(self) -> bool:
147
152
  self.blockSignals(True)
148
153
  self._experiment_name_field.validateString()
@@ -154,6 +159,7 @@ class EnsembleExperimentPanel(ExperimentConfigPanel):
154
159
  and self._ensemble_name_field.isValid()
155
160
  )
156
161
 
162
+ @override
157
163
  def get_experiment_arguments(self) -> Arguments:
158
164
  return Arguments(
159
165
  mode=ENSEMBLE_EXPERIMENT_MODE,
@@ -5,6 +5,7 @@ from typing import TYPE_CHECKING
5
5
 
6
6
  from PyQt6.QtCore import pyqtSlot as Slot
7
7
  from PyQt6.QtWidgets import QFormLayout, QLabel, QWidget
8
+ from typing_extensions import override
8
9
 
9
10
  from ert.gui.ertnotifier import ErtNotifier
10
11
  from ert.gui.ertwidgets import (
@@ -13,6 +14,7 @@ from ert.gui.ertwidgets import (
13
14
  StringBox,
14
15
  TargetEnsembleModel,
15
16
  TextModel,
17
+ get_parameters_button,
16
18
  )
17
19
  from ert.mode_definitions import ENIF_MODE
18
20
  from ert.run_models import EnsembleInformationFilter
@@ -23,7 +25,6 @@ from ert.validation import (
23
25
  from ert.validation.active_range import ActiveRange
24
26
  from ert.validation.range_string_argument import RangeSubsetStringArgument
25
27
 
26
- from ..ertwidgets.parameterviewer import get_parameters_button
27
28
  from ._design_matrix_panel import DesignMatrixPanel
28
29
  from .experiment_config_panel import ExperimentConfigPanel
29
30
 
@@ -110,7 +111,8 @@ class EnsembleInformationFilterPanel(ExperimentConfigPanel):
110
111
  merged_parameters
111
112
  )
112
113
 
113
- layout.addRow("Parameters:", get_parameters_button(merged_parameters, self))
114
+ if merged_parameters:
115
+ layout.addRow("Parameters", get_parameters_button(merged_parameters, self))
114
116
 
115
117
  self.setLayout(layout)
116
118
 
@@ -126,6 +128,7 @@ class EnsembleInformationFilterPanel(ExperimentConfigPanel):
126
128
 
127
129
  self.notifier.ertChanged.connect(self._update_experiment_name_placeholder)
128
130
 
131
+ @override
129
132
  @Slot(QWidget)
130
133
  def experimentTypeChanged(self, w: QWidget) -> None:
131
134
  if isinstance(w, EnsembleInformationFilterPanel):
@@ -136,6 +139,7 @@ class EnsembleInformationFilterPanel(ExperimentConfigPanel):
136
139
  self.notifier.storage.get_unique_experiment_name(ENIF_MODE)
137
140
  )
138
141
 
142
+ @override
139
143
  def isConfigurationValid(self) -> bool:
140
144
  return (
141
145
  self._experiment_name_field.isValid()
@@ -143,6 +147,7 @@ class EnsembleInformationFilterPanel(ExperimentConfigPanel):
143
147
  and self._active_realizations_field.isValid()
144
148
  )
145
149
 
150
+ @override
146
151
  def get_experiment_arguments(self) -> Arguments:
147
152
  arguments = Arguments(
148
153
  mode=ENIF_MODE,
@@ -6,6 +6,7 @@ from typing import TYPE_CHECKING
6
6
  from PyQt6.QtCore import Qt
7
7
  from PyQt6.QtCore import pyqtSlot as Slot
8
8
  from PyQt6.QtWidgets import QFormLayout, QHBoxLayout, QLabel, QWidget
9
+ from typing_extensions import override
9
10
 
10
11
  from ert.gui.ertnotifier import ErtNotifier
11
12
  from ert.gui.ertwidgets import (
@@ -15,6 +16,7 @@ from ert.gui.ertwidgets import (
15
16
  StringBox,
16
17
  TargetEnsembleModel,
17
18
  TextModel,
19
+ get_parameters_button,
18
20
  )
19
21
  from ert.mode_definitions import ENSEMBLE_SMOOTHER_MODE
20
22
  from ert.run_models import EnsembleSmoother
@@ -25,7 +27,6 @@ from ert.validation import (
25
27
  from ert.validation.active_range import ActiveRange
26
28
  from ert.validation.range_string_argument import RangeSubsetStringArgument
27
29
 
28
- from ..ertwidgets.parameterviewer import get_parameters_button
29
30
  from ._design_matrix_panel import DesignMatrixPanel
30
31
  from .experiment_config_panel import ExperimentConfigPanel
31
32
 
@@ -129,7 +130,9 @@ class EnsembleSmootherPanel(ExperimentConfigPanel):
129
130
  merged_parameters
130
131
  )
131
132
 
132
- layout.addRow("Parameters:", get_parameters_button(merged_parameters, self))
133
+ if merged_parameters:
134
+ layout.addRow("Parameters", get_parameters_button(merged_parameters, self))
135
+
133
136
  self.setLayout(layout)
134
137
 
135
138
  self._experiment_name_field.getValidationSupport().validationChanged.connect(
@@ -144,6 +147,7 @@ class EnsembleSmootherPanel(ExperimentConfigPanel):
144
147
 
145
148
  self.notifier.ertChanged.connect(self._update_experiment_name_placeholder)
146
149
 
150
+ @override
147
151
  @Slot(QWidget)
148
152
  def experimentTypeChanged(self, w: QWidget) -> None:
149
153
  if isinstance(w, EnsembleSmootherPanel):
@@ -154,6 +158,7 @@ class EnsembleSmootherPanel(ExperimentConfigPanel):
154
158
  self.notifier.storage.get_unique_experiment_name(ENSEMBLE_SMOOTHER_MODE)
155
159
  )
156
160
 
161
+ @override
157
162
  def isConfigurationValid(self) -> bool:
158
163
  return (
159
164
  self._experiment_name_field.isValid()
@@ -161,6 +166,7 @@ class EnsembleSmootherPanel(ExperimentConfigPanel):
161
166
  and self._active_realizations_field.isValid()
162
167
  )
163
168
 
169
+ @override
164
170
  def get_experiment_arguments(self) -> Arguments:
165
171
  arguments = Arguments(
166
172
  mode=ENSEMBLE_SMOOTHER_MODE,