Skip to content

Commit a2c56f6

Browse files
committed
MAINT: Align fmu init with fmu-settings init behavior
1 parent a36902e commit a2c56f6

File tree

6 files changed

+311
-390
lines changed

6 files changed

+311
-390
lines changed

pyproject.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,7 @@ classifiers = [
3131
dynamic = ["version"]
3232
dependencies = [
3333
"fmu-datamodels",
34-
"fmu-settings",
34+
"fmu-settings>=0.28.0",
3535
"fmu-settings-api",
3636
"fmu-settings-gui",
3737
"rich",

src/fmu_settings_cli/copy/copy.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -577,7 +577,7 @@ def log_copy_event_to_target(self: Self) -> None:
577577
try:
578578
target_fmu_dir = get_fmu_directory(self.target)
579579
except FileNotFoundError:
580-
target_fmu_dir = init_fmu_directory(self.target)
580+
target_fmu_dir = init_fmu_directory(self.target, force=True)
581581
except Exception as e:
582582
error("Failed opening project fmu directory.", reason=str(e))
583583
raise typer.Exit(1) from e

src/fmu_settings_cli/init/cli.py

Lines changed: 37 additions & 77 deletions
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,19 @@
11
"""The 'init' command."""
22

33
from pathlib import Path
4-
from typing import TYPE_CHECKING, Annotated, Final
4+
from typing import TYPE_CHECKING, Annotated
55

66
import typer
77
from fmu.settings._global_config import (
88
InvalidGlobalConfigurationError,
99
find_global_config,
1010
load_global_configuration_if_present,
1111
)
12-
from fmu.settings._init import init_fmu_directory
12+
from fmu.settings._init import (
13+
InvalidFMUProjectPathError,
14+
init_fmu_directory,
15+
)
1316
from pydantic import ValidationError
14-
from rich.table import Table
1517

1618
from fmu_settings_cli.prints import (
1719
error,
@@ -30,28 +32,6 @@
3032
add_completion=True,
3133
)
3234

33-
REQUIRED_FMU_PROJECT_SUBDIRS: Final[list[str]] = ["ert"]
34-
35-
36-
def is_fmu_project(path: Path) -> tuple[bool, list[str]]:
37-
"""Ensures the provided directory looks like an FMU project.
38-
39-
Args:
40-
path: The directory to check
41-
42-
Returns:
43-
Tuple of bool and list of strings, indicating whether the provided path does or
44-
does not appear to be a valid FMU project, and what directories are lacking for
45-
it to be so, respectively.
46-
"""
47-
missing: list[str] = []
48-
for dir_name in REQUIRED_FMU_PROJECT_SUBDIRS:
49-
dir_ = path / dir_name
50-
if not dir_.exists() or not dir_.is_dir():
51-
missing.append(dir_name)
52-
53-
return len(missing) == 0, missing
54-
5535

5636
def _find_global_config_source(base_path: Path) -> Path | None:
5737
"""Find which global config file would have been imported."""
@@ -83,65 +63,39 @@ def init( # noqa: PLR0912
8363
show_default=False,
8464
),
8565
] = False,
86-
skip_config_import: Annotated[
87-
bool,
88-
typer.Option(
89-
"--skip-config-import",
90-
help=(
91-
"Skip searching for and importing masterdata set in the global "
92-
"configuration or global variables."
93-
),
94-
show_default=False,
95-
),
96-
] = False,
9766
) -> None:
9867
"""The main entry point for the init command."""
9968
if ctx.invoked_subcommand is not None: # pragma: no cover
10069
return
10170

10271
cwd = Path.cwd()
10372

104-
if not force:
105-
has_all_fmu_subdirs, missing_dirs = is_fmu_project(cwd)
106-
if not has_all_fmu_subdirs:
107-
dirs_table = Table("Directory")
108-
for dir_ in missing_dirs:
109-
dirs_table.add_row(dir_)
110-
111-
error(
112-
f"This directory ({cwd}) does not appear to be an FMU project. "
113-
"Expected the following directories:",
114-
dirs_table,
115-
)
116-
raise typer.Abort
117-
11873
global_config: GlobalConfiguration | None = None
119-
if not skip_config_import:
120-
try:
121-
global_config = find_global_config(cwd)
122-
except ValidationError as e:
123-
validation_warning(
124-
e,
125-
"Unable to import masterdata.",
126-
reason="Validation of the global config/global variables failed.",
127-
suggestion=(
128-
"You will need to establish valid SMDA masterdata in FMU "
129-
"Settings by running and opening 'fmu settings'."
130-
),
131-
)
132-
except InvalidGlobalConfigurationError:
133-
warning(
134-
"Unable to import masterdata.",
135-
reason=(
136-
"The global config contains data that is not valid SMDA "
137-
"masterdata. This can happen when the file contains placeholder "
138-
"values or Drogon data."
139-
),
140-
suggestion=(
141-
"You will need to establish valid SMDA masterdata in FMU "
142-
"Settings by running and opening 'fmu settings'."
143-
),
144-
)
74+
try:
75+
global_config = find_global_config(cwd)
76+
except ValidationError as e:
77+
validation_warning(
78+
e,
79+
"Unable to import masterdata.",
80+
reason="Validation of the global config/global variables failed.",
81+
suggestion=(
82+
"You will need to establish valid SMDA masterdata in FMU "
83+
"Settings by running and opening 'fmu settings'."
84+
),
85+
)
86+
except InvalidGlobalConfigurationError:
87+
warning(
88+
"Unable to import masterdata.",
89+
reason=(
90+
"The global config contains data that is not valid SMDA "
91+
"masterdata. This can happen when the file contains placeholder "
92+
"values or Drogon data."
93+
),
94+
suggestion=(
95+
"You will need to establish valid SMDA masterdata in FMU "
96+
"Settings by running and opening 'fmu settings'."
97+
),
98+
)
14599

146100
if global_config:
147101
imported_sections = ", ".join(
@@ -157,7 +111,13 @@ def init( # noqa: PLR0912
157111
success(f"Successfully imported {imported_sections}{source_suffix}.")
158112

159113
try:
160-
fmu_dir = init_fmu_directory(cwd, global_config=global_config)
114+
fmu_dir = init_fmu_directory(cwd, global_config=global_config, force=force)
115+
except InvalidFMUProjectPathError as e:
116+
error(
117+
"Unable to create .fmu directory.",
118+
reason=str(e),
119+
)
120+
raise typer.Abort from e
161121
except FileExistsError as e:
162122
error(
163123
"Unable to create .fmu directory.",

tests/conftest.py

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -27,10 +27,9 @@
2727
StratigraphyElement,
2828
)
2929
from fmu.settings import ProjectFMUDirectory
30-
from fmu.settings._init import init_fmu_directory
30+
from fmu.settings._init import REQUIRED_FMU_PROJECT_SUBDIRS, init_fmu_directory
3131
from pytest import MonkeyPatch
3232

33-
from fmu_settings_cli.init.cli import REQUIRED_FMU_PROJECT_SUBDIRS
3433
from fmu_settings_cli.settings import constants
3534

3635

tests/test_init/test_init_main.py

Lines changed: 23 additions & 61 deletions
Original file line numberDiff line numberDiff line change
@@ -9,21 +9,22 @@
99
import yaml
1010
from fmu.datamodels.fmu_results.global_configuration import GlobalConfiguration
1111
from fmu.settings import find_nearest_fmu_directory
12+
from fmu.settings._init import REQUIRED_FMU_PROJECT_SUBDIRS, is_fmu_project
1213
from pydantic import ValidationError
1314
from typer.testing import CliRunner
1415

1516
from fmu_settings_cli.__main__ import app
16-
from fmu_settings_cli.init.cli import REQUIRED_FMU_PROJECT_SUBDIRS, is_fmu_project
17+
from fmu_settings_cli.init.cli import _find_global_config_source
1718

1819
runner = CliRunner()
1920

2021

2122
@pytest.mark.parametrize(
2223
"dirs, expected",
2324
[
24-
(["foo"], (False, REQUIRED_FMU_PROJECT_SUBDIRS)),
25-
(["foo/ert"], (False, REQUIRED_FMU_PROJECT_SUBDIRS)),
26-
(["ertt"], (False, REQUIRED_FMU_PROJECT_SUBDIRS)),
25+
(["foo"], (False, list(REQUIRED_FMU_PROJECT_SUBDIRS))),
26+
(["foo/ert"], (False, list(REQUIRED_FMU_PROJECT_SUBDIRS))),
27+
(["ertt"], (False, list(REQUIRED_FMU_PROJECT_SUBDIRS))),
2728
(REQUIRED_FMU_PROJECT_SUBDIRS, (True, [])),
2829
],
2930
)
@@ -48,8 +49,11 @@ def test_init_creates_user_fmu_if_exist(in_tmp_path: Path) -> None:
4849

4950
assert result.exit_code == 1
5051
stderr = " ".join(result.stderr.split())
51-
assert "does not appear to be an FMU project" in stderr
52-
assert "ert" in stderr
52+
missing_dirs = ", ".join(
53+
f"'{dir_name}'" for dir_name in REQUIRED_FMU_PROJECT_SUBDIRS
54+
)
55+
assert "Failed initializing .fmu directory." in stderr
56+
assert f"Did not find: {missing_dirs}." in stderr
5357
assert (home / ".fmu").exists()
5458

5559

@@ -58,8 +62,11 @@ def test_init_checks_if_fmu_dir_fails(in_tmp_path: Path) -> None:
5862
result = runner.invoke(app, ["init"])
5963
assert result.exit_code == 1
6064
stderr = " ".join(result.stderr.split())
61-
assert "does not appear to be an FMU project" in stderr
62-
assert "ert" in stderr
65+
missing_dirs = ", ".join(
66+
f"'{dir_name}'" for dir_name in REQUIRED_FMU_PROJECT_SUBDIRS
67+
)
68+
assert "Failed initializing .fmu directory." in stderr
69+
assert f"Did not find: {missing_dirs}." in stderr
6370

6471

6572
def test_init_checks_if_fmu_dir_passes(in_tmp_path: Path) -> None:
@@ -148,10 +155,12 @@ def test_init_adds_global_variables_with_masterdata(
148155
assert result.exit_code == 0
149156
stdout = " ".join(result.stdout.split())
150157
assert "Success: Successfully imported access, masterdata, model from" in stdout
151-
assert "fmuconfig/output/global_variables.yml" in stdout
152158
assert "Success: All done!" in stdout
153159
assert "Info: Project stratigraphy was not imported by 'fmu init'." in stdout
154160
assert "Open 'fmu settings' to import stratigraphy from RMS" in stdout
161+
assert _find_global_config_source(tmp_path) == (
162+
fmuconfig_out / "global_variables.yml"
163+
)
155164

156165
fmu_dir = find_nearest_fmu_directory()
157166
fmu_dir_cfg = fmu_dir.config.load()
@@ -180,35 +189,8 @@ def test_init_adds_input_global_config_with_masterdata(
180189
assert result.exit_code == 0
181190
stdout = " ".join(result.stdout.split())
182191
assert "Success: Successfully imported access, masterdata, model from" in stdout
183-
assert "fmuconfig/input/global_master_config.yml" in stdout
184192
assert "Success: All done!" in stdout
185-
186-
187-
def test_init_skips_adding_global_variables_with_masterdata(
188-
in_fmu_project: Path,
189-
generate_strict_valid_globalconfiguration: Callable[[], GlobalConfiguration],
190-
) -> None:
191-
"""Tests that 'fmu init' skips adding masterdata with skip flag."""
192-
tmp_path = in_fmu_project
193-
194-
valid_global_cfg = generate_strict_valid_globalconfiguration()
195-
196-
fmuconfig_out = tmp_path / "fmuconfig/output"
197-
fmuconfig_out.mkdir(parents=True, exist_ok=True)
198-
199-
(fmuconfig_out / "global_variables.yml").write_text(
200-
yaml.dump(valid_global_cfg.model_dump(mode="json", by_alias=True))
201-
)
202-
203-
result = runner.invoke(app, ["init", "--skip-config-import"])
204-
assert result.exit_code == 0
205-
assert "Success: All done!" in result.stdout
206-
207-
fmu_dir = find_nearest_fmu_directory()
208-
fmu_dir_cfg = fmu_dir.config.load()
209-
assert fmu_dir_cfg.masterdata is None
210-
assert fmu_dir_cfg.access is None
211-
assert fmu_dir_cfg.model is None
193+
assert _find_global_config_source(tmp_path) == global_config_path
212194

213195

214196
def test_init_raises_when_import_drogon_masterdata(
@@ -235,26 +217,6 @@ def test_init_raises_when_import_drogon_masterdata(
235217
assert "placeholder values or Drogon data" in stderr
236218
assert "Success: All done!" in result.stdout
237219

238-
239-
def test_init_skips_raising_when_import_drogon_masterdata_with_skip(
240-
in_fmu_project: Path, global_variables_with_masterdata: dict[str, Any]
241-
) -> None:
242-
"""Tests that 'fmu init' skips raising on Drogon masterdata with skip flag."""
243-
tmp_path = in_fmu_project
244-
245-
fmuconfig_out = tmp_path / "fmuconfig/output"
246-
fmuconfig_out.mkdir(parents=True, exist_ok=True)
247-
248-
(fmuconfig_out / "global_variables.yml").write_text(
249-
yaml.dump(global_variables_with_masterdata)
250-
)
251-
252-
result = runner.invoke(app, ["init", "--skip-config-import"])
253-
assert result.exit_code == 0
254-
# _not_ in
255-
assert "Reason: Invalid name in 'model': Drogon" not in result.stderr
256-
assert "Success: All done!" in result.stdout
257-
258220
fmu_dir = find_nearest_fmu_directory()
259221
fmu_dir_cfg = fmu_dir.config.load()
260222
assert fmu_dir_cfg.masterdata is None
@@ -267,7 +229,7 @@ def test_init_fmu_dir_exists_error(in_fmu_project: Path) -> None:
267229
fmu_dir = in_fmu_project / ".fmu"
268230
fmu_dir.mkdir()
269231

270-
result = runner.invoke(app, ["init", "--skip-config-import"])
232+
result = runner.invoke(app, ["init"])
271233
assert result.exit_code == 1
272234
assert "Error: Unable to create .fmu directory" in result.stderr
273235
assert ".fmu already exists" in result.stderr
@@ -280,7 +242,7 @@ def test_init_fmu_dir_no_permissions_error(in_fmu_project: Path) -> None:
280242
with patch(
281243
"fmu_settings_cli.init.cli.init_fmu_directory", side_effect=PermissionError
282244
):
283-
result = runner.invoke(app, ["init", "--skip-config-import"])
245+
result = runner.invoke(app, ["init"])
284246
assert result.exit_code == 1
285247
assert "Error: Unable to create .fmu directory" in result.stderr
286248
assert "lacking permissions to create" in result.stderr
@@ -296,7 +258,7 @@ def test_init_fmu_dir_validation_error(in_fmu_project: Path) -> None:
296258
"fmu_settings_cli.init.cli.init_fmu_directory",
297259
side_effect=ValidationError("Foo", []),
298260
):
299-
result = runner.invoke(app, ["init", "--skip-config-import"])
261+
result = runner.invoke(app, ["init"])
300262
assert result.exit_code == 1
301263

302264
assert "Error: Unable to create .fmu directory" in result.stderr
@@ -309,7 +271,7 @@ def test_init_fmu_dir_some_error(in_fmu_project: Path) -> None:
309271
"fmu_settings_cli.init.cli.init_fmu_directory",
310272
side_effect=ValueError("Foo"),
311273
):
312-
result = runner.invoke(app, ["init", "--skip-config-import"])
274+
result = runner.invoke(app, ["init"])
313275
assert result.exit_code == 1
314276

315277
assert "Error: Unable to create .fmu directory" in result.stderr

0 commit comments

Comments
 (0)