diff --git a/.gitignore b/.gitignore index a90a066c..3452cad8 100644 --- a/.gitignore +++ b/.gitignore @@ -88,7 +88,7 @@ ipython_config.py # pyenv # For a library or package, you might want to ignore these files since the code is # intended to run in multiple environments; otherwise, check them in: -# .python-version +.python-version # pipenv # According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control. diff --git a/lean/commands/research.py b/lean/commands/research.py index 70061cfd..9d962326 100644 --- a/lean/commands/research.py +++ b/lean/commands/research.py @@ -149,6 +149,14 @@ def research(project: Path, research_image, paths_to_mount) + # Mount project dir to the Notebooks directory first, avoid using volumes to prevent overwriting mounting logic for /LeanCLI + run_options["mounts"].append(Mount( + target=f"{LEAN_ROOT_PATH}/Notebooks", + source=str(project), + type="bind", + read_only=False + )) + # Mount the config in the notebooks directory as well local_config_path = next(m["Source"] for m in run_options["mounts"] if m["Target"].endswith("config.json")) run_options["mounts"].append(Mount(target=f"{LEAN_ROOT_PATH}/Notebooks/config.json", @@ -166,12 +174,6 @@ def research(project: Path, # Make Ctrl+C stop Jupyter Lab immediately run_options["stop_signal"] = "SIGKILL" - # Mount the project to the notebooks directory - run_options["volumes"][str(project)] = { - "bind": f"{LEAN_ROOT_PATH}/Notebooks", - "mode": "rw" - } - # Allow notebooks to be embedded in iframes run_options["commands"].append("mkdir -p ~/.jupyter") run_options["commands"].append( diff --git a/tests/commands/test_research.py b/tests/commands/test_research.py index 9dd57e80..688483e0 100644 --- a/tests/commands/test_research.py +++ b/tests/commands/test_research.py @@ -280,3 +280,43 @@ def test_research_runs_lean_container_with_paths_to_mount() -> None: assert mount is not None assert mount["Target"] == "/Files/file.json" + +def test_research_mounts_project_directory_to_leancli_and_notebooks() -> None: + create_fake_lean_cli_directory() + + docker_manager = mock.MagicMock() + container.initialize(docker_manager) + + project_dir = Path.cwd() / "CSharp Project" + (project_dir / "Main.cs").touch() + original_csproj = project_dir / "CSharp Project.csproj" + original_csproj.write_text(""" + + + + + +""") + + result = CliRunner().invoke(lean, ["research", "CSharp Project"]) + + assert result.exit_code == 0 + + docker_manager.run_image.assert_called_once() + args, kwargs = docker_manager.run_image.call_args + + leancli_volume = next(((k, v) for (k, v) in kwargs["volumes"].items() if v['bind'] == f"/LeanCLI"), None) + notebooks_mount = next((m for m in kwargs["mounts"] if m["Target"] == f"{LEAN_ROOT_PATH}/Notebooks"), None) + + assert leancli_volume is not None, "/LeanCLI is not mounted" + assert notebooks_mount is not None, "/Notebooks is not mounted" + assert leancli_volume[0] == str(project_dir) + assert notebooks_mount["Source"] == str(project_dir) + + temp_csproj_mounts = [ + m for m in kwargs["mounts"] + if m["Target"].startswith(f"/LeanCLI") and m["Target"].endswith(".csproj") + ] + + assert len(temp_csproj_mounts) > 0, "No temporary csproj file mounts detected" + assert all(m["Source"] != str(original_csproj) for m in temp_csproj_mounts), "Temporary csproj did not correctly overwrite user file"