Repository navigation
Multi-architecture wheel selection across disperate sources (with markers) #5205
Description
-
I am on the latest Poetry version.
-
I have searched the issues of this repo and believe that this is not a duplicate.
-
If an exception occurs when executing a command, I executed it again in debug mode (
-vvvoption). -
OS version and name: Ubuntu 18.04 on both aarch64 and x86_64
-
Poetry version: 1.1.12
-
Link of a Gist with the contents of your pyproject.toml file: (see below for variants)
Issue
I'm trying to build a project that will be used in multi-architecture environments (aarch64 and x86_64 specifically). One of my project's dependencies (jaxlib) only offers prebuilt wheels for x86_64 via PiPy. As a solution, I've built and hosted the wheel for aarch64 separately, which necessitates adding secondary dependency sources in pyproject.toml like so:
[tool.poetry]
name = "temp"
version = "0.1.0"
description = ""
authors = ["merberich <merberich@gmail.com>"]
[tool.poetry.dependencies]
python = "^3.9"
cupy-cuda102 = "^10.1.0"
jaxlib = [
{ version = "0.1.71" },
{ url = "<valid-url-to-aarch64-wheel-host>" }
]
jax = "0.2.20"
[tool.poetry.dev-dependencies]
[build-system]
requires = ["poetry-core>=1.0.0"]
build-backend = "poetry.core.masonry.api"Building a new poetry.lock for this project produces jaxlib references:
cat poetry.lock | grep jaxlib
cpu = ["jaxlib (==0.1.71)"]
cuda102 = ["jaxlib (==0.1.71+cuda102)"]
cuda111 = ["jaxlib (==0.1.71+cuda111)"]
minimum-jaxlib = ["jaxlib (==0.1.69)"]
tpu = ["jaxlib (==0.1.71)", "libtpu-nightly (==0.1.dev20210809)", "requests"]
name = "jaxlib"
jaxlib = [
{file = "jaxlib-0.1.71-cp37-none-macosx_10_9_x86_64.whl", hash = "sha256:ad36895ceb68782bb74f0657da127cece06c19ce1e72ad9c660f79bce549618e"},
{file = "jaxlib-0.1.71-cp37-none-manylinux2010_x86_64.whl", hash = "sha256:059eb572121e3f13e3b841c07137a72f3d0aeb76dc6ddf178922a327994f60b8"},
{file = "jaxlib-0.1.71-cp38-none-macosx_10_9_x86_64.whl", hash = "sha256:c823b65c95aa7b6d8eb4a45bc6389d43c8d6dd20fe0c531345753819c70cff54"},
{file = "jaxlib-0.1.71-cp38-none-manylinux2010_x86_64.whl", hash = "sha256:8f4447d6053b55bab9565e365b60c80ff186b0cb05407146ea844d328eaba2bf"},
{file = "jaxlib-0.1.71-cp39-none-macosx_10_9_x86_64.whl", hash = "sha256:f5fc1873c25a7b07f9406bcb09540cef6e2b151aa139be52e34cf35f7b8390b0"},
{file = "jaxlib-0.1.71-cp39-none-manylinux2010_x86_64.whl", hash = "sha256:c66a1bdb57934093938fd6e1767216c198bd1a102b8f5636fdb1f9a5b0d11067"},
Note that for each of these wheels, the supported architecture is always x86_64... which my aarch64 machine does not use (IMO these wheels should not be considered valid sources on my aarch64 machine). Instead, poetry install loads the secondary source specified in pyproject.toml, which breaks the lockfile boundary:
poetry install
Installing dependencies from lock file
Package operations: 10 installs, 0 updates, 0 removals
• Installing numpy (1.22.2)
• Installing six (1.16.0)
• Installing absl-py (1.0.0)
• Installing fastrlock (0.8)
• Installing flatbuffers (2.0)
• Installing opt-einsum (3.3.0)
• Installing scipy (1.6.1)
• Installing cupy-cuda102 (10.1.0)
• Installing jax (0.2.20)
• Installing jaxlib (0.1.71 <valid-url-to-aarch64-wheel-host>)
So the real issue here is that the lockfile does not contain the secondary source, which is necessary to build on this machine - instead, poetry install has to reference the pyproject.toml to identify secondary sources, which defeats the purpose of having a lockfile...
Possibly worth note: I've also tried to use markers to have the lockfile generation see that both sources are needed to cover all relevant architectures:
jaxlib = [
{ version = "0.1.71", markers = "platform_machine == 'x86_64'" },
{ url = "<valid-url-to-aarch64-wheel-host>", markers = "platform_machine == 'aarch64'" }
]Unfortunately, this didnt cause any change in results.
Our workaround will be to host an alternative package registry with dependencies provided for both x86_64 and aarch64 (and this way ALL wheels should appear a 'valid' sources in the lockfile), but that seems like a lot of extra infrastructure just to account for something the lockfile could/should contain.
I think the correct solution would involve having the lockfile list alternatives for cases where markers are used to specify multiarch environments. The behavior to avoid would be having poetry look outside the lockfile when one exists.
Activity
sneakers-the-rat commentedon Feb 25, 2022
+1 experiencing this same thing trying to package something for x86_64 and armv7l (the raspberry pi). Lockfile either references packages from piwheels or pypi, but not both (as it should, choosing depending on architecture). Have tried to look through the source for awhile to try and contribute to this, but still can't quite figure out where this would be decided. If you give me a pointer I'll try to write a patch if wanted
sneakers-the-rat commentedon Feb 25, 2022
Relatedly: when I have piwheels set as a source repository, I would expect it to also add entries from pypi as fallbacks, at least the source distributions so wheels could be built.
Instead, given this:
I just get an installation error for packages when installing on x86_64 because only the arm6l and 6l wheels are listed in the lockfile, eg.
sneakers-the-rat commentedon Mar 8, 2022
OK I've gotten as far as getting the files and hashes for multiple repositories to be stored in poetry.lock, but still need to figure out how to make the installer add the additional repository urls as
--extra-index-url.So when choosing a version, we arrive at this line, which gets a complete version of the package including its files and hashes:
poetry/src/poetry/mixology/version_solver.py
Line 394 in b06658f
This is after a single package is chosen despite there being multiple matching packages (eg. from having multiple matches on separate repositories)
poetry/src/poetry/mixology/version_solver.py
Line 381 in b06658f
So I found that if you add the files from the remaining packages like this:
then I end up with a lockfile like this, where I am correctly keeping wheels from PyPI and from piwheels (note the armv6l and v7l for the raspi)
I think i'm being too general in my file adding step there, as I probably need to filter by matching versino, but since elsewhere all hashes are added to the install stage, then if the secondary repository was to be added as an
--extra-index-urlthen that would solve the problem. ya?merberich commentedon Mar 9, 2022
This definitely looks like promising direction, and would at least solve my problem. As long as all of the available dependencies for different platforms end up in the lockfile, that's scope for this bug.
Separately, and outside of scope (probably in a separate Issue), it might warrant investigation how we would select between
plat-Bin a setup like:repo 1:
plat-Aplat-Brepo 2:
plat-Bplat-CSo the lockfile would end up with at least:
But the selection mechanism for which repo is preferred for
plat-Bwould be my question. I think your implementation would just default to the first repository scanned. Is that always desired behavior?sneakers-the-rat commentedon Mar 9, 2022
Very good questions. I think this is wrapped up in a bunch of issues that I'm seeing open, and tried to start a meta-discussion over here: #4137 (comment)
I think basically the same set of parameters that are true for package dependencies might generalize to sources (eg. use
repo-1forPlat-A(or even just a refinement of the existing specifications forsourceandmarkers), but I'm still pretty new and am getting a hang of the library -- hence wanting to start a discussion because this seems like it's part of a larger constellation of bugs :)edit: I also think that the .lockfile should also save the source of a given
file/hashcombination, that makes sense to me (otherwise the strategy of thePipInstallerseems to be to add extra--extra-index-urls, where if source was specified then it would be possible to simplify that to pair a specific set of hashes with a single repository URL)poetry/src/poetry/installation/pip_installer.py
Lines 66 to 76 in b06658f
merberich commentedon Mar 9, 2022
Oh wow, that linked comment walks through a bunch of other methods I ended up trying XD
Very glad this is getting looked at, thank you!
sneakers-the-rat commentedon Mar 10, 2022
to add to examples:
results in
even though they are definitely not duplicates.
edit: on 1.1.13
neersighted commentedon Oct 2, 2022
I've done a quick skim and haven't looked too deeply at the individual issues discussed here, as they are disparate. Many of the attempted uses of Poetry here are misconceptions (e.g. a URL dependency cannot augment an index package, and Poetry will not mix wheels from two different package sources (imagine what would happen to the Torch folks!)).
However, there are two example usages that either should work (as in, the code that enables them is buggy), or (more likely) we want to make work in the future, as they fit the architecture of Poetry:
From @merberich:
From @sneakers-the-rat:
Essentially, the use of markers is critical to make it clear to Poetry what you want. The latter would also be enhanced by #5984 (comment) as we could make usage of
piwheelsmuch faster by allowing non-pip semantics.Anyway, those two examples are what I would consider 'correct' given the design of Poetry. However, I have not tried to reproduce them on 1.2, or dug into what might be required to fix them (or even introduce this as a feature -- I'm not 100% sure the solver will support this currently, and it may be a lot of work).
Still, hopefully this helps put those who might be interested in contributing on the right track -- these examples should hopefully be possible one day 😄
[-]Poetry does not consider wheel architecture when adding to lockfile[/-][+]Multi-architecture wheel selection across disperate sources (with markers)[/+]radoering commentedon Oct 2, 2022
The first example (version and url dependency) should already work with poetry 1.2.1. The second example (two version dependencies from different sources) should be fixed by #6679.
sneakers-the-rat commentedon Oct 3, 2022
thanks y'all <3
github-actions commentedon Mar 1, 2024
This issue has been automatically locked since there has not been any recent activity after it was closed. Please open a new issue for related bugs.