Skip to content

build: cap the spaCy stack on Python 3.9 so the privacy extras install from wheels - #390

Merged
kevincostner17 merged 1 commit into
mainfrom
build/py39-privacy-extra
Sep 15, 2026
Merged

kevincostner17 merged 1 commit into
mainfrom
build/py39-privacy-extra

Conversation

@kevincostner17

Copy link
Copy Markdown
Contributor

Summary

On Python 3.9, pip install "freshdata-cleaner[privacy]" and [all] fail. The newest presidio-analyzer requires Python >=3.10, so pip falls back to presidio-analyzer 2.2.x, which accepts any spacy. pip then picks spacy 3.8.16. That release declares Requires-Python >=3.9 but ships only cp310+ wheels, so pip builds it from the sdist, and the build needs thinc>=8.3.12 (Python >=3.10 only).

The same gap exists further down, per PyPI metadata:

  • spacy: 3.8.7 is the last release with cp39 wheels. 3.8.8+ are cp310+ only.
  • thinc: 8.3.4 is the last release that has cp39 wheels and whose blis also has them. 8.3.5 is yanked, 8.3.6 needs blis>=1.3, and 8.3.7–8.3.9 have no cp39 wheels.
  • blis: 1.2.0 is the last release with cp39 wheels. 1.2.1 and 1.3.x have none.

Capping only spacy lets pip install, but it still compiles thinc and blis from source, which fails without a C/C++ toolchain. Both extras now carry:

"spacy<3.8.8; python_version<'3.10'",
"thinc<8.3.5; python_version<'3.10'",
"blis<1.2.1; python_version<'3.10'",

Python 3.10+ requirements and resolutions are unchanged. uv.lock and constraints/ci.txt were regenerated with uv 0.12.10 (make constraints). Only the <3.10 pins move: spacy 3.8.11 → 3.8.7, thinc 8.3.9 → 8.3.4, blis 1.3.3 → 1.2.0, plus langcodes, which spacy 3.8.7 requires.

Known gap: on Linux aarch64 with Python 3.9, thinc 8.3.4 and blis 1.2.0 have no cp39 wheels, so pip still compiles those two there.

Tests

  • tests/test_packaging.py::test_privacy_extras_cap_spacy_stack_on_python39 checks that privacy and all both carry the three Python 3.9 caps.

Verification

  • pip 26.0.1, Python 3.9.6: before, pip install --dry-run fails with No matching distribution found for thinc<8.4.0,>=8.3.12. After, .[privacy] and .[all] resolve to spacy 3.8.7, thinc 8.3.4 and blis 1.2.0; the only sdist is pyffx.
  • A real --no-cache-dir install into a clean 3.9 venv built only pyffx, and spacy, thinc, blis, presidio_analyzer, presidio_anonymizer and pyffx all import.
  • uv pip compile --python-version 3.9 --extra privacy / --extra all: spacy 3.8.11 / thinc 8.3.9 / blis 1.3.3 before, spacy 3.8.7 / thinc 8.3.4 / blis 1.2.0 after.
  • A wheels-only (--only-binary :all:) Python 3.9 resolve succeeds for macOS arm64/x86_64, manylinux x86_64/aarch64 and Windows.
  • The CI lockfile job steps pass (uv lock --check, then export and git diff --exit-code constraints/ci.txt).
  • ruff check . passes. tests/test_packaging.py passes on Python 3.12 and 3.9.

Closes #278

…rivacy extras

On Python 3.9 the [privacy] and [all] extras did not install with pip.
The newest presidio-analyzer needs Python >=3.10, so pip falls back to
presidio-analyzer 2.2.x, whose spacy requirement is unbounded. pip then
takes spacy 3.8.16. That release declares Requires-Python >=3.9 but
publishes only cp310+ wheels, so pip builds it from the sdist, whose
build requirement thinc>=8.3.12,<8.4 is Python >=3.10 only:

  ERROR: No matching distribution found for thinc<8.4.0,>=8.3.12
  ERROR: Failed to build 'spacy' when installing build dependencies

The same pattern repeats one and two levels down, per PyPI metadata:

- spacy: 3.8.7 is the last release with cp39 wheels (macOS x86_64/arm64,
  manylinux and musllinux x86_64/aarch64, win_amd64). 3.8.8-3.8.16 ship
  cp310+ only, and 3.8.13+ require thinc>=8.3.12 (Requires-Python >=3.10).
- thinc: 8.3.7-8.3.9 ship no cp39 wheels. 8.3.6 does, but it requires
  blis>=1.3, which has no cp39 wheels, and 8.3.5 is yanked. 8.3.4 ships
  cp39 wheels and needs blis>=1.2,<1.3.
- blis: 1.2.0 is the last release with cp39 wheels. 1.2.1 and all of 1.3.x
  are sdist-only for 3.9.

Capping only spacy lets pip install, but it still compiles thinc 8.3.9
(and blis 1.3.3) from source, which fails without a C/C++ toolchain.
Add "spacy<3.8.8", "thinc<8.3.5" and "blis<1.2.1", each marked
python_version<'3.10', to both extras. With them, a --no-cache-dir
pip 26.0.1 install on Python 3.9.6 resolves spacy 3.8.7, thinc 8.3.4 and
blis 1.2.0 from wheels, and only the pure-Python pyffx sdist is built.
Python 3.10+ requirements and resolutions are unchanged.

Regenerate uv.lock and constraints/ci.txt with uv 0.12.10 (make
constraints). Only the <3.10 pins move: spacy 3.8.11 -> 3.8.7,
thinc 8.3.9 -> 8.3.4, blis 1.3.3 -> 1.2.0, plus langcodes, which spacy
3.8.7 requires. tests/test_packaging.py now asserts both extras carry
the caps.

Closes #278
@coderabbitai

coderabbitai Bot commented Sep 15, 2026

Copy link
Copy Markdown
Contributor

Important

  • 🔍 Trigger review

This repository does not receive automatic reviews because it has fewer than 10 stars.

⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Advanced

Run ID: 672b258f-c4e1-4953-8667-d140f261c984


Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@kevincostner17
kevincostner17 merged commit d837154 into main Sep 15, 2026
19 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[privacy] and [all] extras fail to install on Python 3.9 (spacy 3.8.16 sdist needs py3.10)

1 participant