From c5eb52ad81e0ca2f2ce074975e1c369c60c1f25b Mon Sep 17 00:00:00 2001 From: cleverhoods Date: Wed, 15 Apr 2026 18:17:03 +0200 Subject: [PATCH 1/3] Remove en-core-web-sm direct dependency, auto-download spaCy model on first run --- UNRELEASED.md | 1 + pyproject.toml | 4 ---- src/reporails_cli/core/mapper/mapper.py | 22 ++++++++++++++++++---- 3 files changed, 19 insertions(+), 8 deletions(-) diff --git a/UNRELEASED.md b/UNRELEASED.md index f7dca27f..c92b0b4b 100644 --- a/UNRELEASED.md +++ b/UNRELEASED.md @@ -239,6 +239,7 @@ - [TESTS]: Rewrite `test_summary.py` for `CombinedResult` schema - [ACTION]: Add `parse_result.py` — compute score, level, violations from `CombinedResult` JSON - [CLI]: `--strict` exits 1 on any finding, not just errors +- [BUILD]: Remove `en-core-web-sm` direct URL dependency (rejected by PyPI). spaCy model auto-downloads on first run if missing. - [TESTS]: Fix remaining MCP and CLI integration tests for `CombinedResult` schema — remove `score`/`level` assertions, use `files`/`stats` ### Fixed diff --git a/pyproject.toml b/pyproject.toml index a34749af..85f2820d 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -35,7 +35,6 @@ dependencies = [ # hard requirement — the fallback verb lexicon drops charge accuracy # from 96% to ~78%. With the torch blocker active, spaCy loads in ~1s. "spacy>=3.8.11,<4", - "en-core-web-sm @ https://github.com/explosion/spacy-models/releases/download/en_core_web_sm-3.8.0/en_core_web_sm-3.8.0-py3-none-any.whl", ] [project.optional-dependencies] @@ -86,9 +85,6 @@ requires = ["hatchling"] build-backend = "hatchling.build" [tool.hatch.metadata] -# Required because we pin en_core_web_sm via a direct URL (spaCy models -# are distributed as GitHub release wheels, not via PyPI). -allow-direct-references = true [tool.hatch.build.targets.wheel] packages = ["src/reporails_cli"] diff --git a/src/reporails_cli/core/mapper/mapper.py b/src/reporails_cli/core/mapper/mapper.py index 0ecf9fc9..3b73c0e9 100644 --- a/src/reporails_cli/core/mapper/mapper.py +++ b/src/reporails_cli/core/mapper/mapper.py @@ -2091,10 +2091,24 @@ def nlp(self) -> Any | None: # tok.text / tok.i / root.children. That needs tok2vec + # tagger + parser only; ner / lemmatizer / attribute_ruler # are dead weight on both load time and per-doc inference. - self._nlp = spacy.load( - "en_core_web_sm", - disable=["ner", "lemmatizer", "attribute_ruler"], - ) + try: + self._nlp = spacy.load( + "en_core_web_sm", + disable=["ner", "lemmatizer", "attribute_ruler"], + ) + except OSError: + # Model not installed — download it once + import subprocess + import sys + + subprocess.run( + [sys.executable, "-m", "spacy", "download", "en_core_web_sm"], + capture_output=True, + ) + self._nlp = spacy.load( + "en_core_web_sm", + disable=["ner", "lemmatizer", "attribute_ruler"], + ) except (ImportError, OSError): self._nlp = None return self._nlp From a97847ddce96b7d07ac93a5cac81f806502da232 Mon Sep 17 00:00:00 2001 From: cleverhoods Date: Wed, 15 Apr 2026 18:18:59 +0200 Subject: [PATCH 2/3] Add twine check before PyPI publish to catch metadata errors --- .github/workflows/release.yml | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index df604ec9..66ea124c 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -99,6 +99,11 @@ jobs: # sdist separately for PyPI (model not included — source-only) uv build --sdist + - name: Verify PyPI metadata + run: | + pip install twine --quiet + twine check dist/* + - name: Verify wheel install run: | python -m venv /tmp/verify-wheel From 8754e518169ec0f4127286c905bd86cb649bb68e Mon Sep 17 00:00:00 2001 From: cleverhoods Date: Wed, 15 Apr 2026 18:19:57 +0200 Subject: [PATCH 3/3] Update uv.lock after removing en-core-web-sm direct dependency --- uv.lock | 10 ---------- 1 file changed, 10 deletions(-) diff --git a/uv.lock b/uv.lock index 3add990a..c7fcea96 100644 --- a/uv.lock +++ b/uv.lock @@ -557,14 +557,6 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/55/e2/2537ebcff11c1ee1ff17d8d0b6f4db75873e3b0fb32c2d4a2ee31ecb310a/docstring_parser-0.17.0-py3-none-any.whl", hash = "sha256:cf2569abd23dce8099b300f9b4fa8191e9582dda731fd533daf54c4551658708", size = 36896, upload-time = "2025-07-21T07:35:00.684Z" }, ] -[[package]] -name = "en-core-web-sm" -version = "3.8.0" -source = { url = "https://github.com/explosion/spacy-models/releases/download/en_core_web_sm-3.8.0/en_core_web_sm-3.8.0-py3-none-any.whl" } -wheels = [ - { url = "https://github.com/explosion/spacy-models/releases/download/en_core_web_sm-3.8.0/en_core_web_sm-3.8.0-py3-none-any.whl", hash = "sha256:1932429db727d4bff3deed6b34cfc05df17794f4a52eeb26cf8928f7c1a0fb85" }, -] - [[package]] name = "filelock" version = "3.25.2" @@ -1857,7 +1849,6 @@ name = "reporails-cli" version = "0.5.0" source = { editable = "." } dependencies = [ - { name = "en-core-web-sm" }, { name = "httpx" }, { name = "markdown-it-py" }, { name = "mcp" }, @@ -1903,7 +1894,6 @@ dev = [ [package.metadata] requires-dist = [ - { name = "en-core-web-sm", url = "https://github.com/explosion/spacy-models/releases/download/en_core_web_sm-3.8.0/en_core_web_sm-3.8.0-py3-none-any.whl" }, { name = "httpx", specifier = ">=0.27.0" }, { name = "markdown-it-py", specifier = ">=3.0.0" }, { name = "mcp", specifier = ">=1.0.0" },