|
| 1 | +# -*- coding: utf-8 -*- |
| 2 | +"""End-to-end: run the wppm CLI against a real venv. |
| 3 | +
|
| 4 | +These are the commands that returned "OSError: Invalid Python distribution" |
| 5 | +for any venv before the target-resolution fix. |
| 6 | +""" |
| 7 | +import json |
| 8 | +import subprocess |
| 9 | +import sys |
| 10 | +from pathlib import Path |
| 11 | + |
| 12 | +import pytest |
| 13 | + |
| 14 | +from conftest import windows_only |
| 15 | + |
| 16 | +REPO_ROOT = Path(__file__).resolve().parent.parent |
| 17 | + |
| 18 | +pytestmark = windows_only |
| 19 | + |
| 20 | + |
| 21 | +def wppm(*args, expect_ok=True): |
| 22 | + """Run `python -m wppm ...` from the repo, not from an installed copy.""" |
| 23 | + proc = subprocess.run( |
| 24 | + [sys.executable, "-X", "utf8", "-m", "wppm", *args], |
| 25 | + capture_output=True, text=True, cwd=str(REPO_ROOT), timeout=300, |
| 26 | + encoding="utf-8", errors="replace", |
| 27 | + ) |
| 28 | + if expect_ok: |
| 29 | + assert proc.returncode == 0, f"exit {proc.returncode}\n{proc.stdout}\n{proc.stderr}" |
| 30 | + return proc |
| 31 | + |
| 32 | + |
| 33 | +class TestListing: |
| 34 | + def test_lists_packages_of_a_venv(self, real_venv): |
| 35 | + out = wppm("-t", str(real_venv), "-ls").stdout |
| 36 | + assert "pip" in out |
| 37 | + |
| 38 | + def test_scripts_target_gives_the_same_listing(self, real_venv): |
| 39 | + """-t <venv>\\Scripts used to print nothing at all.""" |
| 40 | + root = wppm("-t", str(real_venv), "-ls").stdout |
| 41 | + scripts = wppm("-t", str(real_venv / "Scripts"), "-ls").stdout |
| 42 | + assert scripts.strip() == root.strip() |
| 43 | + assert "pip" in scripts |
| 44 | + |
| 45 | + def test_json_listing_is_valid_json(self, real_venv): |
| 46 | + out = wppm("-t", str(real_venv), "-ls", "pip", "-j").stdout |
| 47 | + assert any(row["package"] == "pip" for row in json.loads(out)) |
| 48 | + |
| 49 | + def test_filters_by_expression(self, real_venv): |
| 50 | + out = wppm("-t", str(real_venv), "-ls", "^pip$", "-j").stdout |
| 51 | + assert [r["package"] for r in json.loads(out)] == ["pip"] |
| 52 | + |
| 53 | + def test_does_not_list_the_running_interpreters_packages(self, real_venv): |
| 54 | + """A -t listing must describe the target, not whatever runs wppm.""" |
| 55 | + names = {r["package"] for r in json.loads( |
| 56 | + wppm("-t", str(real_venv), "-ls", "-j").stdout)} |
| 57 | + assert "pytest" not in names |
| 58 | + |
| 59 | + |
| 60 | +class TestTrees: |
| 61 | + def test_downward_tree(self, real_venv): |
| 62 | + assert "pip==" in wppm("-t", str(real_venv), "-p", "pip", "-l1").stdout |
| 63 | + |
| 64 | + def test_upward_tree(self, real_venv): |
| 65 | + assert "pip==" in wppm("-t", str(real_venv), "-r", "pip", "-l1").stdout |
| 66 | + |
| 67 | + def test_tree_json_parses(self, real_venv): |
| 68 | + out = wppm("-t", str(real_venv), "-p", "pip", "-l1", "-j").stdout |
| 69 | + assert json.loads(out) |
| 70 | + |
| 71 | + |
| 72 | +class TestMarkdown: |
| 73 | + def test_generates_a_package_index(self, real_venv): |
| 74 | + out = wppm("-t", str(real_venv), "-md").stdout |
| 75 | + assert "### Python packages" in out |
| 76 | + assert "pip" in out |
| 77 | + |
| 78 | + def test_reports_plain_python_not_winpython(self, real_venv): |
| 79 | + """WINPYVER2 is unset here, so it must not claim to be WinPython.""" |
| 80 | + assert "## Python" in wppm("-t", str(real_venv), "-md").stdout |
| 81 | + |
| 82 | + def test_tools_section_reports_the_target_python_version(self, real_venv): |
| 83 | + """Sanity check only: this venv comes from the running interpreter, so it |
| 84 | + cannot tell target from runner -- test_distribution.py does that. |
| 85 | + """ |
| 86 | + data = json.loads(wppm("-t", str(real_venv), "-md", "-j").stdout) |
| 87 | + tools = {t["name"]: t["version"] for t in data["tools"]} |
| 88 | + expected = subprocess.run( |
| 89 | + [str(real_venv / "Scripts" / "python.exe"), "-c", |
| 90 | + "import platform;print(platform.python_version())"], |
| 91 | + capture_output=True, text=True, |
| 92 | + ).stdout.strip() |
| 93 | + assert tools["Python"].startswith(expected) |
| 94 | + |
| 95 | + def test_json_manifest_has_the_expected_shape(self, real_venv): |
| 96 | + data = json.loads(wppm("-t", str(real_venv), "-md", "-j").stdout) |
| 97 | + assert set(data) >= {"distribution", "tools", "packages", "wheelhouse"} |
| 98 | + assert set(data["distribution"]) >= {"name", "version", "python_version"} |
| 99 | + |
| 100 | + |
| 101 | +class TestBadTarget: |
| 102 | + def test_rejects_a_directory_that_is_not_a_python(self, tmp_path): |
| 103 | + proc = wppm("-t", str(tmp_path), "-md", expect_ok=False) |
| 104 | + assert proc.returncode != 0 |
| 105 | + assert "Invalid Python distribution" in proc.stdout + proc.stderr |
| 106 | + |
| 107 | + |
| 108 | +class TestHelp: |
| 109 | + def test_help_mentions_the_version(self): |
| 110 | + from wppm import __version__ |
| 111 | + assert __version__ in wppm("-h").stdout |
0 commit comments