diff --git a/packages/create-python-app-core/src/create_python_app_core/paths.py b/packages/create-python-app-core/src/create_python_app_core/paths.py index dbba7bd..dd270c2 100644 --- a/packages/create-python-app-core/src/create_python_app_core/paths.py +++ b/packages/create-python-app-core/src/create_python_app_core/paths.py @@ -7,6 +7,7 @@ from dataclasses import dataclass from pathlib import Path from urllib.parse import parse_qs, unquote, urlparse +from urllib.request import url2pathname from create_python_app_core.errors import CpaError @@ -54,10 +55,14 @@ def resolve_source(spec: str, *, cache_dir: Path | None = None) -> ResolvedSourc if spec.startswith("file://"): parsed = urlparse(spec) query = parse_qs(parsed.query) - path = Path(unquote(parsed.path)) + raw_path = unquote(parsed.path or "/") if parsed.netloc and parsed.netloc != "localhost": # file://host/path — uncommon; treat netloc+path - path = Path(f"/{parsed.netloc}{unquote(parsed.path)}") + raw_path = f"//{parsed.netloc}{raw_path}" + path_text = url2pathname(raw_path) + if os.name == "nt" and re.match(r"^/[A-Za-z]:", path_text): + path_text = path_text[1:] + path = Path(path_text) subdir = (query.get("subdir") or [None])[0] return ResolvedSource( kind="file", diff --git a/packages/create-python-app-core/tests/test_paths.py b/packages/create-python-app-core/tests/test_paths.py index bd78228..102eeb1 100644 --- a/packages/create-python-app-core/tests/test_paths.py +++ b/packages/create-python-app-core/tests/test_paths.py @@ -1,3 +1,4 @@ +import os from pathlib import Path import pytest @@ -18,6 +19,16 @@ def test_file_url(tmp_path: Path) -> None: assert src.subdir == "templates/foo" +def test_windows_drive_letter_file_url() -> None: + if os.name != "nt": + pytest.skip("Windows path handling is only relevant on Windows") + + src = resolve_source("file:///E:/create-python/cpa-templates?subdir=templates/foo") + assert src.kind == "file" + assert src.subdir == "templates/foo" + assert src.local_path == Path(r"E:\create-python\cpa-templates") + + def test_github_url_with_ref() -> None: src = resolve_source("https://github.com/org/repo?ref=main&subdir=templates/x") assert src.kind == "github"