You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
Extras of a dependency's dependency are not installed #1609
Pyproject.toml requires PyOTA package, which requires requests[security]. The security extra is not installed though. This can be observed by the fact the the lockfile has no pyOpenSSL entry, which is a part of the security extra of requests.
Note that we remove requests = "*" from pyproject.toml, then the security extra will be installed as expected. It seems the issue only occurs when the package that needs extras is referenced elsewhere with no mention of the extras.
Reacted by Paul Angerer, Joseph Kahn, Michael Egger, Shimi Liderman, André Sassi, Rémy Greinhofer, finswimmer, Daniel Mohns, Danielle Hanks, Robin Hes and 4 more
I can definitely reproduce and I know why that happens but actually fixing this is not trivial. Unfortunately, it's unlikely that it will be fixed before the 1.0.0 release because it will need a tweak in the resolution logic.
For the time being, a workaround is to declare your dependency on requests like the following:
There is a case where not even the workaround works. I'm not sure how related this is, maybe I should file another bug report for this...?
Anyways I'll try to briefly explain it here: Let's imagine a world where the PyOTA package we required has not been released on PyPI, but only on a git server. Then our pyproject.toml (with the workaround) will look something like:
Running poetry install will then create a perfect poetry.lock that includes the requests[security] extra. However, the next time we run poetry update what happens is, that the security extra gets removed (copy-pasting command line output here):
Following poetry update calls will not bring the security extra back.
The obvious workaround for this is to require the packages of the security extra explicitly, but this gets very awkward if the extra contains many packages.
P.S. Thanks for poetry! Despite these issues it's still an amazing tool.
The only way we can solve the extras issues currently is by always resolving the extra dependencies even though they were not opted in. That would fix the issue but it might introduce another which is that resolution conflict might be raised by extra dependencies even though they were never opted in.
I don't see a perfect solution for this at the moment. The Python ecosystem is so unique and complex (some might say convoluted) that coming up with a perfect dependency resolver is almost impossible and will sometimes require the help of the end user by hinting it on how it should proceed.
@sdispater I haven't looked at how the code works, but do you really need to resolve all extras to fix this? It seems like you can keep a list of required extras when resolving a dependency, and if that dependency is required again by some other path you don't skip it or resolve it again from scratch, but just check if there are new extras and only resolve them. You may need to keep a list of required extras for each package to append to whenever you resolve an extra, and you may need some work on how you resolve a dependency in order to be able to do more work on it afterwards (i.e. resolve more extras), but seems doable.
Another (maybe simpler) alternative, is to consider requests[security] as a new virtual dependency, which has the same versions available as requests, but installs no package and depends on the concatenated lists of requirements for requests and for security extra. In other words, when you find requests = {version = "x", extras = ["security"]} you understand that as "requests[security]" = {version = "x"} and know that to find the metadata of requests[security], you look at the requests metadata, but take the combined requirements from requests and from its security extra instead. The current resolver should be able to resolve this correctly and without any false-positive conflicts. You can pre-create all these virtual extra packages as soon as you parse the metadata of requests if you wish, but only really require these virtual dependencies when you see them referenced somewhere.
Having this problem when installing a google lib that does not require the grpcio-gcp extra on google-api-core (e.g. google-cloud-bigtable), then installing one that does (e.g. google-cloud-spanner). The grpcio-gcp extra does not get added unless the adds are done with the one requiring grpcio-gcp first.
Activity
sdispater commentedon Nov 21, 2019
This is a tricky one.
I can definitely reproduce and I know why that happens but actually fixing this is not trivial. Unfortunately, it's unlikely that it will be fixed before the
1.0.0release because it will need a tweak in the resolution logic.For the time being, a workaround is to declare your dependency on
requestslike the following:hukkin commentedon Nov 22, 2019
Thanks @sdispater for having a look.
There is a case where not even the workaround works. I'm not sure how related this is, maybe I should file another bug report for this...?
Anyways I'll try to briefly explain it here: Let's imagine a world where the
PyOTApackage we required has not been released on PyPI, but only on a git server. Then ourpyproject.toml(with the workaround) will look something like:Running
poetry installwill then create a perfectpoetry.lockthat includes therequests[security]extra. However, the next time we runpoetry updatewhat happens is, that thesecurityextra gets removed (copy-pasting command line output here):Following
poetry updatecalls will not bring thesecurityextra back.The obvious workaround for this is to require the packages of the
securityextra explicitly, but this gets very awkward if the extra contains many packages.P.S. Thanks for poetry! Despite these issues it's still an amazing tool.
sdispater commentedon Nov 22, 2019
The only way we can solve the extras issues currently is by always resolving the extra dependencies even though they were not opted in. That would fix the issue but it might introduce another which is that resolution conflict might be raised by extra dependencies even though they were never opted in.
I don't see a perfect solution for this at the moment. The Python ecosystem is so unique and complex (some might say convoluted) that coming up with a perfect dependency resolver is almost impossible and will sometimes require the help of the end user by hinting it on how it should proceed.
absassi commentedon Jan 8, 2020
@sdispater I haven't looked at how the code works, but do you really need to resolve all extras to fix this? It seems like you can keep a list of required extras when resolving a dependency, and if that dependency is required again by some other path you don't skip it or resolve it again from scratch, but just check if there are new extras and only resolve them. You may need to keep a list of required extras for each package to append to whenever you resolve an extra, and you may need some work on how you resolve a dependency in order to be able to do more work on it afterwards (i.e. resolve more extras), but seems doable.
Another (maybe simpler) alternative, is to consider
requests[security]as a new virtual dependency, which has the same versions available asrequests, but installs no package and depends on the concatenated lists of requirements forrequestsand forsecurityextra. In other words, when you findrequests = {version = "x", extras = ["security"]}you understand that as"requests[security]" = {version = "x"}and know that to find the metadata ofrequests[security], you look at therequestsmetadata, but take the combined requirements fromrequestsand from itssecurityextra instead. The current resolver should be able to resolve this correctly and without any false-positive conflicts. You can pre-create all these virtual extra packages as soon as you parse the metadata ofrequestsif you wish, but only really require these virtual dependencies when you see them referenced somewhere.daniellehanks commentedon Apr 20, 2020
Having this problem when installing a google lib that does not require the grpcio-gcp extra on google-api-core (e.g. google-cloud-bigtable), then installing one that does (e.g. google-cloud-spanner). The grpcio-gcp extra does not get added unless the adds are done with the one requiring grpcio-gcp first.
mvoitko commentedon Oct 17, 2020
Still relevant to me.
Poetry version 1.1.2
google-cloud-bigquery is installed. pandas is not.
abn commentedon Oct 17, 2020
@mvoitko can you please try
1.1.3? There is also an issue with nested extras that will be resolved later with1.1.4.mvoitko commentedon Oct 23, 2020
@abn updating helped
vlad0337187 commentedon Apr 15, 2022
updating to
1.1.3didn't help me.I still see extras of dependency in
pyproject.tomlof main app, it it wasn't installedgithub-actions commentedon Mar 2, 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.