From 1a36695e0f91e7395aac8dfb2564474aa0ca9428 Mon Sep 17 00:00:00 2001 From: Elad-Zaharan Date: Mon, 1 Jun 2026 18:20:02 +0300 Subject: [PATCH 1/3] fixing relative path in quam state and others --- .../cli/project/commands/create.py | 34 ++++++- .../test_cli/test_project/test_create.py | 92 +++++++++++++++++++ 2 files changed, 123 insertions(+), 3 deletions(-) diff --git a/qualibrate_config/cli/project/commands/create.py b/qualibrate_config/cli/project/commands/create.py index 597f3a7..0fdb192 100644 --- a/qualibrate_config/cli/project/commands/create.py +++ b/qualibrate_config/cli/project/commands/create.py @@ -30,22 +30,36 @@ ) @click.option( "--storage-location", - type=click.Path(file_okay=False, dir_okay=True, path_type=Path), + type=click.Path( + file_okay=False, dir_okay=True, resolve_path=True, path_type=Path + ), required=False, help=STORAGE_LOCATION_HELP, ) @click.option( "--calibration-library-folder", - type=click.Path(file_okay=False, dir_okay=True, path_type=Path), + type=click.Path( + file_okay=False, dir_okay=True, resolve_path=True, path_type=Path + ), required=False, help=CALIBRATION_LIBRARY_FOLDER_HELP, ) @click.option( "--quam-state-path", - type=click.Path(file_okay=False, dir_okay=True, path_type=Path), + type=click.Path( + file_okay=False, dir_okay=True, resolve_path=True, path_type=Path + ), required=False, help=QUAM_STATE_PATH_HELP, ) +@click.option( + "--yes", + "-y", + "assume_yes", + is_flag=True, + default=False, + help="Skip confirmation of expanded path values.", +) @click.pass_context def create_command( ctx: click.Context, @@ -54,7 +68,21 @@ def create_command( storage_location: Path | None, calibration_library_folder: Path | None, quam_state_path: Path | None, + assume_yes: bool, ) -> None: + supplied_paths = [ + ("--storage-location", storage_location), + ("--calibration-library-folder", calibration_library_folder), + ("--quam-state-path", quam_state_path), + ] + supplied_paths = [(flag, p) for flag, p in supplied_paths if p is not None] + if supplied_paths and not assume_yes: + click.echo("The following paths will be saved to the project config:") + for flag, p in supplied_paths: + click.echo(f" {flag}: {p}") + if not click.confirm("Continue?", default=True): + click.secho("Aborted.", fg="yellow") + sys.exit(1) try: create_project( config_path, diff --git a/tests/integration/test_cli/test_project/test_create.py b/tests/integration/test_cli/test_project/test_create.py index 0b4b53c..f1a743e 100644 --- a/tests/integration/test_cli/test_project/test_create.py +++ b/tests/integration/test_cli/test_project/test_create.py @@ -59,6 +59,7 @@ def test_full_project_creation_pipeline(tmp_path): str(calibration_folder), "--quam-state-path", str(quam_state), + "--yes", ] print(f"{args = }") result = runner.invoke(create_command, args) @@ -89,3 +90,94 @@ def test_full_project_creation_pipeline(tmp_path): calibration_folder ) assert project_config["quam"]["state_path"] == str(quam_state) + + +def test_relative_paths_are_expanded(tmp_path, monkeypatch): + runner = CliRunner() + config_path = tmp_path / "config.toml" + projects_path = tmp_path / "projects" + projects_path.mkdir() + cwd = tmp_path / "cwd" + cwd.mkdir() + monkeypatch.chdir(cwd) + new_project_name = "rel_project" + original_config = { + QUALIBRATE_CONFIG_KEY: { + "version": QualibrateConfig.version, + "project": "init_project", + "storage": { + "location": str(tmp_path / "old_storage"), + "type": "local_storage", + }, + "calibration_library": { + "folder": str(tmp_path / "old_calibration"), + "resolver": "qualibrate.QualibrationLibrary", + }, + }, + QUAM_CONFIG_KEY: {QUAM_STATE_PATH_CONFIG_KEY: str(tmp_path / "qstate")}, + } + with config_path.open("wb") as f: + tomli_w.dump(original_config, f) + + args = [ + new_project_name, + "--config-path", + str(config_path), + "--storage-location", + "../storage_rel", + "--calibration-library-folder", + "../calibration_rel", + "--quam-state-path", + "../quam_rel", + "--yes", + ] + result = runner.invoke(create_command, args) + assert result.exit_code == 0, result.output + + project_config_file = projects_path / new_project_name / "config.toml" + with project_config_file.open("rb") as f: + project_config = tomllib.load(f) + + expected_storage = str((cwd / ".." / "storage_rel").resolve()) + expected_calibration = str((cwd / ".." / "calibration_rel").resolve()) + expected_quam = str((cwd / ".." / "quam_rel").resolve()) + + assert ( + project_config["qualibrate"]["storage"]["location"] == expected_storage + ) + assert ( + project_config["qualibrate"]["calibration_library"]["folder"] + == expected_calibration + ) + assert project_config["quam"]["state_path"] == expected_quam + + +def test_confirmation_prompt_can_be_declined(tmp_path): + runner = CliRunner() + config_path = tmp_path / "config.toml" + projects_path = tmp_path / "projects" + projects_path.mkdir() + original_config = { + QUALIBRATE_CONFIG_KEY: { + "version": QualibrateConfig.version, + "project": "init_project", + "storage": { + "location": str(tmp_path / "old_storage"), + "type": "local_storage", + }, + }, + } + with config_path.open("wb") as f: + tomli_w.dump(original_config, f) + + args = [ + "declined_project", + "--config-path", + str(config_path), + "--quam-state-path", + str(tmp_path / "quam"), + ] + result = runner.invoke(create_command, args, input="n\n") + assert result.exit_code == 1 + assert "Aborted" in result.output + assert not (projects_path / "declined_project").exists() From 0b4f910b558160d26a4c2f9d2b741c215ce1be50 Mon Sep 17 00:00:00 2001 From: Elad-Zaharan Date: Tue, 2 Jun 2026 09:57:27 +0300 Subject: [PATCH 2/3] changed p to path --- qualibrate_config/cli/project/commands/create.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/qualibrate_config/cli/project/commands/create.py b/qualibrate_config/cli/project/commands/create.py index 0fdb192..fe6a349 100644 --- a/qualibrate_config/cli/project/commands/create.py +++ b/qualibrate_config/cli/project/commands/create.py @@ -75,11 +75,11 @@ def create_command( ("--calibration-library-folder", calibration_library_folder), ("--quam-state-path", quam_state_path), ] - supplied_paths = [(flag, p) for flag, p in supplied_paths if p is not None] + supplied_paths = [(flag, path) for flag, path in supplied_paths if path is not None] if supplied_paths and not assume_yes: click.echo("The following paths will be saved to the project config:") - for flag, p in supplied_paths: - click.echo(f" {flag}: {p}") + for flag, path in supplied_paths: + click.echo(f" {flag}: {path}") if not click.confirm("Continue?", default=True): click.secho("Aborted.", fg="yellow") sys.exit(1) From 95806198e0da61059e8e051bf4df8bfa1e0feb0e Mon Sep 17 00:00:00 2001 From: Elad-Zaharan Date: Tue, 2 Jun 2026 10:09:42 +0300 Subject: [PATCH 3/3] linted --- qualibrate_config/cli/project/commands/create.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/qualibrate_config/cli/project/commands/create.py b/qualibrate_config/cli/project/commands/create.py index fe6a349..5b5c4bf 100644 --- a/qualibrate_config/cli/project/commands/create.py +++ b/qualibrate_config/cli/project/commands/create.py @@ -75,7 +75,9 @@ def create_command( ("--calibration-library-folder", calibration_library_folder), ("--quam-state-path", quam_state_path), ] - supplied_paths = [(flag, path) for flag, path in supplied_paths if path is not None] + supplied_paths = [ + (flag, path) for flag, path in supplied_paths if path is not None + ] if supplied_paths and not assume_yes: click.echo("The following paths will be saved to the project config:") for flag, path in supplied_paths: