From 13545d19ef3a3e6498099201bb8fe3bbd85ebeec Mon Sep 17 00:00:00 2001 From: digital-garbage <133010426+digital-garbage@users.noreply.github.com> Date: Wed, 30 Sep 2026 16:54:24 +0300 Subject: [PATCH] fix: the updater installs URL requirements (spaCy model wheel) from their URL Co-Authored-By: Claude Sonnet 5.5 --- movie_editor/backend/git_update.py | 15 ++++++++++++++- movie_editor/tests/test_git_update.py | 14 ++++++++++++++ 2 files changed, 28 insertions(+), 1 deletion(-) diff --git a/movie_editor/backend/git_update.py b/movie_editor/backend/git_update.py index 7040282b..65248d56 100644 --- a/movie_editor/backend/git_update.py +++ b/movie_editor/backend/git_update.py @@ -281,6 +281,19 @@ def _satisfies(have: str, spec: str) -> bool: return True +def install_target(name: str) -> str: + """What to hand pip for a missing `name`: the URL when requirements.txt gives one + (`name @ https://...`, e.g. a model wheel that is not on PyPI), else the bare name.""" + try: + for line in (REPO_ROOT / REQUIREMENTS).read_text(encoding="utf-8").splitlines(): + m = re.match(r"^\s*([A-Za-z0-9._-]+)\s*@\s*(\S+)", line.split("#", 1)[0]) + if m and m.group(1).lower().replace("-", "_") == name.lower().replace("-", "_"): + return m.group(2) + except OSError: + pass + return name + + def install_requirements(timeout: int = 900) -> dict: """Install ONLY the requirements that are absent. Never upgrades anything. @@ -321,7 +334,7 @@ def install_requirements(timeout: int = 900) -> dict: # nothing under it is not installed, it is broken. The freeze diff below is what says # whether anything already present moved as a result. cmd = [sys.executable, "-m", "pip", "install", "--disable-pip-version-check", - *status["missing"]] + *[install_target(n) for n in status["missing"]]] try: proc = subprocess.run(cmd, cwd=REPO_ROOT, capture_output=True, text=True, timeout=timeout) diff --git a/movie_editor/tests/test_git_update.py b/movie_editor/tests/test_git_update.py index 60545b2c..a724397e 100644 --- a/movie_editor/tests/test_git_update.py +++ b/movie_editor/tests/test_git_update.py @@ -344,3 +344,17 @@ def test_a_pip_timeout_is_reported_not_raised(monkeypatch): monkeypatch.setattr(gu.subprocess, "run", boom) out = gu.install_requirements() assert out["ok"] is False and "did not finish" in out["detail"] + + +def test_a_url_requirement_is_installed_from_its_url_not_its_name(monkeypatch): + """`en_core_web_sm` is not on PyPI: by name pip fails and takes every other package in the + same command with it.""" + from movie_editor.backend import git_update as gu + assert gu.parse_requirement("en_core_web_sm @ https://x/y.whl")[0] == "en_core_web_sm" + assert gu.install_target("en_core_web_sm").startswith("https://github.com/explosion/") + assert gu.install_target("gguf") == "gguf" + calls = _fake_pip(monkeypatch, gu, {"missing": ["gguf", "en_core_web_sm"], + "below_floor": [], "present": []}) + gu.install_requirements() + install = [c for c in calls if c[3] == "install"][0] + assert install[-2] == "gguf" and install[-1].endswith(".whl")