From 1c3f987efbeb146c5b4abe2dba8f572695e8c483 Mon Sep 17 00:00:00 2001 From: Riccardo Porreca Date: Sat, 4 Feb 2023 18:13:50 +0100 Subject: [PATCH 1/4] Include test for lockfile-relative source paths * This was broken in #189, which introduced absolute source paths, and will be handled in #229. --- .../sources/environment.yaml | 8 +++++ tests/test_conda_lock.py | 30 +++++++++++++++++++ 2 files changed, 38 insertions(+) create mode 100644 tests/test-source-paths/sources/environment.yaml diff --git a/tests/test-source-paths/sources/environment.yaml b/tests/test-source-paths/sources/environment.yaml new file mode 100644 index 00000000..97a937a0 --- /dev/null +++ b/tests/test-source-paths/sources/environment.yaml @@ -0,0 +1,8 @@ +channels: + - conda-forge +platforms: + - linux-64 +dependencies: + - python ==3.9.6 + - pydantic ==1.7 + - flask <2 diff --git a/tests/test_conda_lock.py b/tests/test_conda_lock.py index ed853094..afd0497a 100644 --- a/tests/test_conda_lock.py +++ b/tests/test_conda_lock.py @@ -897,6 +897,36 @@ def test_run_lock_with_locked_environment_files( ] +@pytest.fixture +def source_paths(tmp_path: Path) -> Path: + return clone_test_dir("test-source-paths", tmp_path) + + +def test_run_lock_relative_source_path( + monkeypatch: "pytest.MonkeyPatch", source_paths: Path, conda_exe: str +): + """run_lock() stores and restores lockfile-relative source paths""" + source_paths.joinpath("lockfile").mkdir() + monkeypatch.chdir(source_paths) + environment = Path("sources/environment.yaml") + lockfile = Path("lockfile/conda-lock.yml") + run_lock([environment], lockfile_path=lockfile, conda_exe="mamba") + lock_content = parse_conda_lock_file(lockfile) + locked_environment = lock_content.metadata.sources[0] + assert Path(locked_environment) == Path("../sources/environment.yaml") + make_lock_files = MagicMock() + monkeypatch.setattr("conda_lock.conda_lock.make_lock_files", make_lock_files) + run_lock( + DEFAULT_FILES, lockfile_path=lockfile, conda_exe=conda_exe, update=["pydantic"] + ) + if sys.version_info < (3, 8): + # backwards compat + src_files = make_lock_files.call_args_list[0][1]["src_files"] + else: + src_files = make_lock_files.call_args.kwargs["src_files"] + assert [p.resolve() for p in src_files] == [environment.resolve()] + + def test_run_lock_with_pip( monkeypatch: "pytest.MonkeyPatch", pip_environment: Path, conda_exe: str ): From bc9d2ac9b33acd28d6bcb5fbed291e782e9fa92b Mon Sep 17 00:00:00 2001 From: Riccardo Porreca Date: Sat, 4 Feb 2023 21:49:04 +0100 Subject: [PATCH 2/4] Store lockfile-relative sources in lockfiles, unless on different drives * Fixes #229, relying on what introduced in #204 for the input metadata, by explicitly handling only the case of different drives for keeping absolute paths, addressing #175. --- conda_lock/conda_lock.py | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/conda_lock/conda_lock.py b/conda_lock/conda_lock.py index 4390ef09..ef1a6680 100644 --- a/conda_lock/conda_lock.py +++ b/conda_lock/conda_lock.py @@ -809,7 +809,7 @@ def create_lockfile_from_spec( for dep in deps: locked[(dep.manager, dep.name, dep.platform)] = dep - spec_sources: Dict[str, pathlib.Path] = {} + meta_sources: Dict[str, pathlib.Path] = {} for source in spec.sources: try: path = relative_path(lockfile_path.parent, source) @@ -817,7 +817,7 @@ def create_lockfile_from_spec( if "Paths don't have the same drive" not in str(e): raise e path = str(source.resolve()) - spec_sources[path] = source + meta_sources[path] = source if MetadataOption.TimeStamp in metadata_choices: time_metadata = TimeMeta.create() @@ -842,10 +842,10 @@ def create_lockfile_from_spec( if metadata_choices & {MetadataOption.InputSha, MetadataOption.InputMd5}: inputs_metadata: Optional[Dict[str, InputMeta]] = { - relative_path: InputMeta.create( + meta_src: InputMeta.create( metadata_choices=metadata_choices, src_file=src_file ) - for relative_path, src_file in spec_sources.items() + for meta_src, src_file in meta_sources.items() } else: inputs_metadata = None @@ -858,7 +858,7 @@ def create_lockfile_from_spec( content_hash=spec.content_hash(), channels=[c for c in spec.channels], platforms=spec.platforms, - sources=[str(source.resolve()) for source in spec.sources], + sources=list(meta_sources.keys()), git_metadata=git_metadata, time_metadata=time_metadata, inputs_metadata=inputs_metadata, From 5cb6ccce5b4d1546d38c7f92ac20c76dbc2aa5a8 Mon Sep 17 00:00:00 2001 From: Riccardo Porreca Date: Wed, 10 Aug 2022 12:01:34 +0200 Subject: [PATCH 3/4] Handle absolute sources path read from the lockfile * Addressing the inconsistency with the absolute source paths introduced in #175 and noticed in #229. --- conda_lock/conda_lock.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/conda_lock/conda_lock.py b/conda_lock/conda_lock.py index ef1a6680..3e2397e0 100644 --- a/conda_lock/conda_lock.py +++ b/conda_lock/conda_lock.py @@ -1056,7 +1056,9 @@ def run_lock( lock_content = parse_conda_lock_file(lockfile_path) # reconstruct native paths locked_environment_files = [ - pathlib.Path( + pathlib.Path(p) + if pathlib.Path(p).is_absolute + else pathlib.Path( pathlib.PurePosixPath(lockfile_path).parent / pathlib.PurePosixPath(p) ) From f558cbadbd23f504a98e9d82cb17ee094524874a Mon Sep 17 00:00:00 2001 From: Riccardo Porreca Date: Sat, 4 Feb 2023 21:54:21 +0100 Subject: [PATCH 4/4] Handle both Windows and Posix absolute sources path from the lockfile (#229) --- conda_lock/conda_lock.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/conda_lock/conda_lock.py b/conda_lock/conda_lock.py index 3e2397e0..12e59d8b 100644 --- a/conda_lock/conda_lock.py +++ b/conda_lock/conda_lock.py @@ -1057,7 +1057,9 @@ def run_lock( # reconstruct native paths locked_environment_files = [ pathlib.Path(p) - if pathlib.Path(p).is_absolute + # absolute paths could be locked for both flavours + if pathlib.PurePosixPath(p).is_absolute() + or pathlib.PureWindowsPath(p).is_absolute() else pathlib.Path( pathlib.PurePosixPath(lockfile_path).parent / pathlib.PurePosixPath(p)