From fc4bb3fb1e2ed233fbb0203007f1e1c6f14e6ac9 Mon Sep 17 00:00:00 2001 From: mercael Date: Thu, 24 Sep 2026 22:28:20 +0300 Subject: [PATCH 1/2] cli: reject init --force at the curriculum source --- pythonlings/core/curriculum.py | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/pythonlings/core/curriculum.py b/pythonlings/core/curriculum.py index 530f5d2..350d90c 100644 --- a/pythonlings/core/curriculum.py +++ b/pythonlings/core/curriculum.py @@ -92,6 +92,12 @@ def _sync_originals(root: Path, src_root: Path) -> None: def init_workspace(path: Path, *, force: bool = False) -> Path: path = path.expanduser().resolve() + src_root = source_root().resolve() + if path == src_root: + raise WorkspaceError( + f"cannot init the curriculum source at {path}; " + "pick another location with --path " + ) if path.exists() and any(path.iterdir()) and not force: raise WorkspaceError( f"{path} isn't empty and isn't a pythonlings workspace. " @@ -99,7 +105,6 @@ def init_workspace(path: Path, *, force: bool = False) -> Path: ) path.mkdir(parents=True, exist_ok=True) - src_root = source_root() _copy_path(src_root / "info.toml", path / "info.toml", overwrite=True) for dirname in CURRICULUM_DIRS: _copy_path(src_root / dirname, path / dirname, overwrite=True) From ddeab9f5d39a06365821591008985f4ae2f8598b Mon Sep 17 00:00:00 2001 From: mercael Date: Thu, 24 Sep 2026 22:28:21 +0300 Subject: [PATCH 2/2] cli: reject init --force at the curriculum source --- tests/unit/test_curriculum.py | 28 +++++++++++++++++++++++----- 1 file changed, 23 insertions(+), 5 deletions(-) diff --git a/tests/unit/test_curriculum.py b/tests/unit/test_curriculum.py index fb2b4fb..cdeff0f 100644 --- a/tests/unit/test_curriculum.py +++ b/tests/unit/test_curriculum.py @@ -1,5 +1,7 @@ from pathlib import Path +import pytest + from pythonlings.core import curriculum @@ -35,12 +37,28 @@ def test_init_workspace_refuses_non_empty_directory(tmp_path: Path) -> None: target.mkdir() (target / "notes.txt").write_text("keep me", encoding="utf-8") - try: + with pytest.raises(curriculum.WorkspaceError) as excinfo: curriculum.init_workspace(target) - except curriculum.WorkspaceError as exc: - assert "isn't empty and isn't a pythonlings workspace" in str(exc) - else: - raise AssertionError("expected WorkspaceError") + + assert "isn't empty and isn't a pythonlings workspace" in str(excinfo.value) + + +def test_init_workspace_rejects_curriculum_source(tmp_path: Path) -> None: + src_root = curriculum.source_root().resolve() + + with pytest.raises(curriculum.WorkspaceError) as excinfo: + curriculum.init_workspace(src_root) + + assert "cannot init the curriculum source" in str(excinfo.value) + + +def test_init_workspace_rejects_curriculum_source_with_force() -> None: + src_root = curriculum.source_root().resolve() + + with pytest.raises(curriculum.WorkspaceError) as excinfo: + curriculum.init_workspace(src_root, force=True) + + assert "cannot init the curriculum source" in str(excinfo.value) def test_force_init_preserves_existing_gitignore_entries(tmp_path: Path) -> None: