Declare coremltools and scikit-learn only where they work - #22090
Merged
Conversation
🔗 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. |
This PR needs a
|
shoumikhin
force-pushed
the
coreml-markers-match-reality
branch
from
August 24, 2026 18:36
b6dc58f to
3b5c8d1
Compare
|
Gasoonjia
approved these changes
Aug 24, 2026
Gasoonjia
left a comment
Contributor
There was a problem hiding this comment.
LGTM maybe @metascroy can you take another look?
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.
shoumikhin
force-pushed
the
coreml-markers-match-reality
branch
from
August 24, 2026 22:58
d4ec800 to
ea369fa
Compare
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
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:
It imports, it reports version 9.0, and then it cannot write a model, because
libmilstoragepythonis what stores the weights of an mlprogram. The same version on Linux x86_64 installscoremltools-9.0-cp3XX-none-manylinux1_x86_64.whl, which carrieslibmilstoragepython.soandlibmodelpackage.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.pyimports it and calls it fromTurboQuantKVCache.__init__, andbackends/mlx/llm/turboquant_cache.pyre-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
TurboQuantKVCachenow needspip install scipy, becauseTurboQuantKVCache.__init__calls the codebook solver unconditionally. scipy wasnever declared in
setup.py; it only ever arrived as scikit-learn's transitivedependency, 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.pydropsbackends/apple/coremlfrom 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 insetup.pyand once as a Python condition inconftest.py, in two different languages, with only a comment holding them together. The test reads both out of their real files withastrather 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 bareModuleNotFoundError.scikit-learn and scipy move to
requirements-examples.txt. Two example scripts import scikit-learn,examples/openvino/aot_optimize_and_infer.pyandexamples/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.txtis where example-only dependencies already live, next to timm and transformers, and it is whatinstall_requirements.pyand the example CI jobs install. Putting scikit-learn in theopenvinoextra 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
packagingacross macOS, Linux x86_64, Linux aarch64, Windows and Python 3.10 through 3.15:scikit-learn now evaluates identically, and the
conftest.pycondition agrees with the coremltools marker on every one of those combinations. That is what the new test covers, and it passes:Confirmed the test can fail. Widening the
conftest.pycondition to also accept Linux aarch64 turns four cases red with a message naming the platform and the Python version: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.