Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
29 changes: 23 additions & 6 deletions scripts/verify_python_distribution.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
import os
import re
import subprocess
import sys
import tarfile
import tempfile
import venv
Expand All @@ -22,6 +23,20 @@
from packaging.version import InvalidVersion, Version

REPOSITORY_ROOT = Path(__file__).resolve().parents[1]

# ``python scripts/verify_python_distribution.py`` puts ``scripts/`` on
# ``sys.path``, so the repository root is added explicitly before importing the
# shared subprocess policy. Duplicating that policy here is how the verifier and
# the runtime it checks would drift apart.
if str(REPOSITORY_ROOT) not in sys.path:
sys.path.insert(0, str(REPOSITORY_ROOT))

from core.platform_compat import (
configure_utf8_stdio,
subprocess_env,
subprocess_text_kwargs,
)

PACKAGE_NAME = "deepcode-hku"
MINIMUM_MCP_VERSION = Version("1.29")
UNSUPPORTED_MCP_VERSION = Version("2")
Expand Down Expand Up @@ -294,11 +309,12 @@ def _run(
stdin=None,
timeout: int = 180,
) -> None:
environment = {
**os.environ,
"PIP_DISABLE_PIP_VERSION_CHECK": "1",
"PYTHONNOUSERSITE": "1",
}
environment = subprocess_env(
{
"PIP_DISABLE_PIP_VERSION_CHECK": "1",
"PYTHONNOUSERSITE": "1",
}
)
try:
subprocess.run(
command,
Expand All @@ -307,7 +323,7 @@ def _run(
stdin=stdin,
check=True,
capture_output=True,
text=True,
**subprocess_text_kwargs(),
timeout=timeout,
)
except subprocess.CalledProcessError as exc:
Expand Down Expand Up @@ -381,6 +397,7 @@ def smoke_installed_wheel(wheel: Path) -> None:


def main(argv: list[str] | None = None) -> int:
configure_utf8_stdio()
parser = argparse.ArgumentParser(
description="Verify DeepCode Python artifacts and their installed runtime."
)
Expand Down
48 changes: 48 additions & 0 deletions tests/test_python_distribution_release.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@

import importlib.util
import json
import subprocess
import sys
from pathlib import Path

Expand Down Expand Up @@ -111,3 +112,50 @@ def test_packaged_web_manifest_requires_its_entry_assets():
del files["web/assets/app.js"]
with pytest.raises(release.DistributionVerificationError, match="resource missing"):
release.verify_web_assets(files.__getitem__, list(files), "web/", "2.2.0")


def test_smoke_failure_reports_output_that_the_reader_cannot_decode(tmp_path):
"""A rejected byte used to wipe out the whole diagnostic.

Reading without ``encoding`` decoded the child with the locale codec, so a
rejected byte raised inside subprocess's reader thread; the thread died, the
process result stayed clean, and ``_run`` reported the command with no
output at all. ``0x91`` is invalid UTF-8 and cp936, so the byte is rejected
on every runner.
"""

code = (
"import sys; "
"sys.stdout.buffer.write(b'partial \\x91 output\\n'); "
"sys.stdout.buffer.flush(); "
"sys.exit(3)"
)
with pytest.raises(release.DistributionVerificationError) as failure:
release._run([sys.executable, "-c", code], cwd=tmp_path)

message = str(failure.value)
assert "partial" in message
assert "output" in message
assert "\ufffd" in message


def test_smoke_children_are_told_to_write_utf8(monkeypatch, tmp_path):
"""The read side declares UTF-8, so the child has to speak it too.

Otherwise CJK output from pip or the CLI degrades into replacement
characters that the release report cannot be read from.
"""

observed = {}

def fake_run(command, **kwargs):
observed.update(kwargs)
raise subprocess.CalledProcessError(1, command, output="out", stderr="err")

monkeypatch.setattr(release.subprocess, "run", fake_run)
with pytest.raises(release.DistributionVerificationError, match="boom"):
release._run(["boom"], cwd=tmp_path)

assert observed["encoding"] == "utf-8"
assert observed["errors"] == "replace"
assert observed["env"]["PYTHONIOENCODING"] == "utf-8"
Loading