diff --git a/conda_lock/conda_lock.py b/conda_lock/conda_lock.py index 18fef8f0..14af2ac7 100644 --- a/conda_lock/conda_lock.py +++ b/conda_lock/conda_lock.py @@ -759,7 +759,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) @@ -767,7 +767,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() @@ -792,10 +792,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 @@ -808,7 +808,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, @@ -970,7 +970,11 @@ def run_lock( lock_content = parse_conda_lock_file(lockfile_path) # reconstruct native paths locked_environment_files = [ - pathlib.Path( + pathlib.Path(p) + # 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) ) 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 59719719..337d19d8 100644 --- a/tests/test_conda_lock.py +++ b/tests/test_conda_lock.py @@ -921,6 +921,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 ):