Skip to content

Declare coremltools and scikit-learn only where they work - #22090

Merged
shoumikhin merged 3 commits into
mainfrom
coreml-markers-match-reality
Aug 24, 2026
Merged

Declare coremltools and scikit-learn only where they work#22090
shoumikhin merged 3 commits into
mainfrom
coreml-markers-match-reality

Conversation

@shoumikhin

@shoumikhin shoumikhin commented Aug 24, 2026

Copy link
Copy Markdown
Contributor

Summary

Two dependency markers in the wheel do not match where the packages they name are usable.

1. coremltools on Linux aarch64. coremltools is declared on Darwin and on Linux. Linux is deliberate: the Core ML export flow runs there, so a model can be lowered for Apple hardware from a Linux machine. The problem is that the marker cannot tell the two Linux architectures apart, and coremltools publishes no build for Linux aarch64.

On that architecture pip falls back to the source archive and produces a pure-Python install with none of the compiled extensions. Measured with coremltools 9.0 on a Linux aarch64 machine:

Tag: py3-none-any
Root-Is-Purelib: true
$ find <site-packages>/coremltools -name '*.so'      # no output at all
IMPORT FAIL coremltools.libmilstoragepython ModuleNotFoundError
IMPORT FAIL coremltools.libcoremlpython     ModuleNotFoundError
IMPORT FAIL coremltools.libmodelpackage     ModuleNotFoundError

It imports, it reports version 9.0, and then it cannot write a model, because libmilstoragepython is what stores the weights of an mlprogram. The same version on Linux x86_64 installs coremltools-9.0-cp3XX-none-manylinux1_x86_64.whl, which carries libmilstoragepython.so and libmodelpackage.so. So the Linux half of the marker is narrowed to x86_64, and users on other Linux architectures are no longer handed a package that looks installed and cannot do the job.

2. scikit-learn has no marker at all. It is there for Core ML palettization, so it should follow coremltools, but instead it installs everywhere, including Windows, where coremltools is already excluded. A Windows install therefore carries scikit-learn and scipy for a backend it cannot use. This gives it the same marker.

Effect by platform

For coremltools, macOS and Linux x86_64 are unchanged at every supported Python version. The Python 3.14 exclusion was already in the marker before this change. What changes is Linux on any architecture other than x86_64.

For scikit-learn, it is no longer installed on Windows, on non-x86_64 Linux, or on Python 3.14, and scipy no longer arrives behind it there. Nothing in the shipped library imports either one at module scope. The one library module that uses scipy, the TurboQuant codebook solver in extension/llm/modules/turboquant/codebook.py, already imports it inside the function and raises a message telling the user to install it. That module is not example-only: extension/llm/modules/turboquant/kv_cache.py imports it and calls it from TurboQuantKVCache.__init__, and backends/mlx/llm/turboquant_cache.py re-exports that class. See the install-step note below.

There is no new extra. There is one new install step, on the platforms where scipy
stops arriving: a wheel user on Windows, non-x86_64 Linux, or Python 3.14 who
constructs TurboQuantKVCache now needs pip install scipy, because
TurboQuantKVCache.__init__ calls the codebook solver unconditionally. scipy was
never declared in setup.py; it only ever arrived as scikit-learn's transitive
dependency, so gating scikit-learn gates it too. The guarded import names scipy and
the install command, so the failure is actionable rather than a bare
ModuleNotFoundError, but it is a real change for those users.

Follow-on changes

  • conftest.py drops backends/apple/coreml from collection wherever coremltools is not declared. Every test file there that defines tests imports coremltools at module scope, so collection would otherwise fail. Windows was already covered by an existing rule; this extends it to the other Linux architectures.

  • A new test, .ci/scripts/tests/test_coreml_markers.py. The rule for where coremltools can be installed is now written twice, once as a PEP 508 marker in setup.py and once as a Python condition in conftest.py, in two different languages, with only a comment holding them together. The test reads both out of their real files with ast rather than restating them a third time, and checks that they agree across nine platforms and six Python versions. If one is changed and the other is not, this fails in CI instead of failing at collection with a bare ModuleNotFoundError.

  • scikit-learn and scipy move to requirements-examples.txt. Two example scripts import scikit-learn, examples/openvino/aot_optimize_and_infer.py and examples/qualcomm/scripts/mobilebert_fine_tune.py, and three Qualcomm example scripts import scipy directly. Both used to arrive by accident, scikit-learn as an unmarked base dependency and scipy as its transitive, and neither was ever declared where it is used. requirements-examples.txt is where example-only dependencies already live, next to timm and transformers, and it is what install_requirements.py and the example CI jobs install. Putting scikit-learn in the openvino extra instead would not have been enough, since that script also needs timm and transformers, which the extra does not carry.

Test plan

Evaluated both markers with packaging across macOS, Linux x86_64, Linux aarch64, Windows and Python 3.10 through 3.15:

coremltools
   linux x86_64 py3.10    -> True
   linux aarch64 py3.10   -> False
   linux x86_64 py3.13    -> True
   linux x86_64 py3.14    -> False
   darwin arm64 py3.12    -> True
   windows AMD64 py3.12   -> False

scikit-learn now evaluates identically, and the conftest.py condition agrees with the coremltools marker on every one of those combinations. That is what the new test covers, and it passes:

167 passed

Confirmed the test can fail. Widening the conftest.py condition to also accept Linux aarch64 turns four cases red with a message naming the platform and the Python version:

AssertionError: on Linux/aarch64 with Python 3.13 setup.py does not declare
coremltools while conftest.py collects the Core ML tests, so pytest will either
fail at collection on a missing import or silently skip tests that could have run

Confirmed the crippled install by hand on a Linux aarch64 machine, as shown above, and confirmed on Linux x86_64 that the published wheel for the same version ships the compiled extensions.

The unit test jobs that collect the Core ML tests are the Linux x86_64 job on Python 3.10 and the macOS arm64 job on Python 3.11. Both are platforms where coremltools is still declared, so those tests collect and run exactly as before. The Windows job already skipped the whole Apple directory.

Copilot AI lite review requested due to automatic review settings August 24, 2026 17:16
@pytorch-bot

pytorch-bot Bot commented Aug 24, 2026

Copy link
Copy Markdown

🔗 Helpful Links

🧪 See artifacts and rendered test results at hud.pytorch.org/pr/pytorch/executorch/22090

Note: Links to docs will display an error until the docs builds have been completed.

This comment was automatically generated by Dr. CI and updates every 15 minutes.

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copilot was unable to review this pull request because the user who requested the review has reached their quota limit.

@meta-cla meta-cla Bot added the CLA Signed This label is managed by the Facebook bot. Authors need to sign the CLA before a PR can be reviewed. label Aug 24, 2026
@github-actions

Copy link
Copy Markdown

This PR needs a release notes: label

If your change should be included in the release notes (i.e. would users of this library care about this change?), please use a label starting with release notes:. This helps us keep track and include your important work in the next release notes.

To add a label, you can comment to pytorchbot, for example
@pytorchbot label "release notes: none"

For more information, see
https://github.com/pytorch/pytorch/wiki/PyTorch-AutoLabel-Bot#why-categorize-for-release-notes-and-how-does-it-work.

Copilot AI review requested due to automatic review settings August 24, 2026 18:36
@shoumikhin
shoumikhin force-pushed the coreml-markers-match-reality branch from b6dc58f to 3b5c8d1 Compare August 24, 2026 18:36

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copilot was unable to review this pull request because the user who requested the review has reached their quota limit.

Copilot AI review requested due to automatic review settings August 24, 2026 21:41
@linux-foundation-easycla

linux-foundation-easycla Bot commented Aug 24, 2026

Copy link
Copy Markdown

CLA Missing ID

  • ✅ login: shoumikhin / name: Anthony Shoumikhin (5c2556a)
  • ✅ login: shoumikhin / name: shoumikhin (0790e23)
  • ❌ The email address for the commit (ea369fa) is not linked to the GitHub account, preventing the EasyCLA check. Consult this Help Article and GitHub Help to resolve. (To view the commit's email address, add .patch at the end of this PR page's URL.) For further assistance with EasyCLA, please visit our EasyCLA portal and chat with our support bot.

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copilot was unable to review this pull request because the user who requested the review has reached their quota limit.

@Gasoonjia Gasoonjia left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM maybe @metascroy can you take another look?

shoumikhin and others added 2 commits August 24, 2026 15:57
Two dependency markers in the wheel do not match where the packages
they name are usable.

coremltools is declared on Darwin and on Linux. Linux is deliberate:
the Core ML export flow runs there, so a model can be lowered for Apple
hardware from a Linux machine. The problem is that the marker cannot
tell the two Linux architectures apart, and coremltools publishes no
build for Linux aarch64. On that architecture pip falls back to the
source archive and produces a pure-Python install with none of the
compiled extensions. Measured with coremltools 9.0 on a Linux aarch64
machine: the installed package contains no shared objects at all, and
libcoremlpython, libmodelpackage and libmilstoragepython are all
missing. It imports, it reports its version, and then it cannot write a
model, because libmilstoragepython is what stores the weights of an
mlprogram. The same version on Linux x86_64 installs a binary wheel
that carries those extensions. Narrow the Linux half of the marker to
x86_64, so users on other Linux architectures are not given a package
that looks installed and cannot do the job.

scikit-learn has no marker at all. It is there for Core ML
palettization, so it should follow coremltools, but instead it installs
everywhere, including Windows, where coremltools is already excluded.
That means a Windows install carries scikit-learn and scipy for a
backend it cannot use. Give it the same marker.

Three follow-on changes:

- conftest.py drops backends/apple/coreml from collection wherever
  coremltools is not declared. Every test file there that defines tests
  imports coremltools at module scope, so collection would otherwise
  fail. Windows was already covered by an existing rule; this extends it
  to the other Linux architectures.

- The two rules, the PEP 508 marker and the Python condition, say the
  same thing in two languages, and until now only a comment held them
  together. A new test, .ci/scripts/tests/test_coreml_markers.py, reads
  both out of their real files and checks that they agree across nine
  platforms and six Python versions, so a change to one that is not
  mirrored in the other fails in CI instead of at collection time.

- scikit-learn and scipy move to requirements-examples.txt. Two example
  scripts import scikit-learn, one under examples/openvino and one under
  examples/qualcomm, and three Qualcomm example scripts import scipy
  directly. Both used to arrive by accident, scikit-learn as an unmarked
  base dependency and scipy as its transitive, and neither was ever
  declared where it is used. requirements-examples.txt is where the
  example-only dependencies already live, next to timm and transformers,
  and it is what install_requirements.py and the example CI jobs install.

Effect by platform. For coremltools, macOS and Linux x86_64 are
unchanged at every supported Python version, and the Python 3.14
exclusion was already there before this change; what changes is Linux on
any architecture other than x86_64, which no longer gets a package it
cannot use. For scikit-learn, it is no longer installed on Windows, on
non-x86_64 Linux, or on Python 3.14, and scipy no longer follows it
there. Nothing in the shipped library imports either one at module
scope. The one library module that uses scipy, the TurboQuant codebook
solver, already imports it inside the function and raises a message
telling the user to install it.

Test plan: evaluated both markers with packaging across macOS, Linux
x86_64, Linux aarch64, Windows and Python 3.10 through 3.15, and
confirmed they are true only on macOS and Linux x86_64 below 3.14, and
that the conftest.py condition agrees with the marker on every one of
those combinations. The new test covers exactly that and passes, 109
cases. Also confirmed it fails when the two are made to disagree:
widening the conftest.py condition to accept Linux aarch64 turns four of
those cases red with a message naming the platform and the Python
version.

Confirmed the crippled install by hand on a Linux aarch64 machine: pip
installs coremltools 9.0 as a pure-Python wheel, no shared objects are
present, and all three compiled modules fail to import. Confirmed on
Linux x86_64 that the published wheel for the same version ships those
extensions.

The unit test jobs that collect the Core ML tests are the Linux x86_64
job on Python 3.10 and the macOS arm64 job on Python 3.11. Both are
platforms where coremltools is still declared, so those tests collect
and run as before. The Windows job already skipped the whole Apple
directory.
…rker tests

is_supported_platform_for_coreml_lowering() is a third copy of the Core ML
availability rule, so add it to export/utils.py and test it against the marker.
The version axis needed its own check: the existing one-directional assertion is
correctly loose on architecture (Darwin x86_64 installs coremltools but cannot
lower) but that looseness let the Python bound drift silently. Read the bound out
of setup.py instead of pinning a literal.

Three test-helper fixes:
- _base_dependency matched by startswith over every string constant in
  _base_dependencies(), including the function's own docstring. Compare PEP 503
  normalised project names, as setup.py and test_minimal_wheel.sh already do.
- the ignore-glob assertion used exact list equality, so adding a second correct
  glob failed it. Membership proves what the comment claims; the next test
  already covers a glob that stops matching.
- the module docstring undercounted the rule's locations.
Copilot AI review requested due to automatic review settings August 24, 2026 22:58
@shoumikhin
shoumikhin force-pushed the coreml-markers-match-reality branch from d4ec800 to ea369fa Compare August 24, 2026 22:58

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copilot was unable to review this pull request because the user who requested the review has reached their quota limit.

Copilot AI review requested due to automatic review settings August 24, 2026 23:17

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copilot was unable to review this pull request because the user who requested the review has reached their quota limit.

@shoumikhin
shoumikhin merged commit 381a30c into main Aug 24, 2026
345 of 347 checks passed
@shoumikhin
shoumikhin deleted the coreml-markers-match-reality branch August 24, 2026 23:18
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

CLA Signed This label is managed by the Facebook bot. Authors need to sign the CLA before a PR can be reviewed.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants