Poetry: Wildcard '*' does not work in Python versioning

Created on 25 Mar 2019  路  11Comments  路  Source: python-poetry/poetry

  • [x] I am on the latest Poetry version.
  • [x] I have searched the issues of this repo and believe that this is not a duplicate.
  • [x] If an exception occurs when executing a command, I executed it again in debug mode (-vvv option).

Issue


Failed to use wildcard on Python version, while adding or updating. However it install when if manually write the dependencies on file. As the wildcard suggests, I want to make this package available to all python versions.
After running poetry install using the above gist, running poetry add coverage --dev -vvv returned the following output:

Using virtualenv: C:\Users\admin\AppData\Local\pypoetry\Cache\virtualenvs\django-reusable-app-py3.6
PyPI: No release information found for coverage-2.5, skipping
PyPI: No release information found for coverage-2.6, skipping
PyPI: No release information found for coverage-2.75, skipping
PyPI: No release information found for coverage-2.76, skipping
PyPI: No release information found for coverage-2.77, skipping
PyPI: No release information found for coverage-2.78, skipping
PyPI: No release information found for coverage-2.8, skipping
PyPI: No release information found for coverage-2.80, skipping
PyPI: No release information found for coverage-2.85, skipping
PyPI: 32 packages found for coverage *
Using version ^4.5 for coverage

Updating dependencies
Resolving dependencies...
   1: fact: todo is 0.1.0
   1: derived: todo
   1: fact: todo depends on django (*)
   1: fact: todo depends on coverage (^4.5)
   1: selecting todo (0.1.0)
   1: derived: coverage (^4.5)
   1: derived: django (*)
PyPI: No release information found for coverage-2.5, skipping
PyPI: No release information found for coverage-2.6, skipping
PyPI: No release information found for coverage-2.75, skipping
PyPI: No release information found for coverage-2.76, skipping
PyPI: No release information found for coverage-2.77, skipping
PyPI: No release information found for coverage-2.78, skipping
PyPI: No release information found for coverage-2.8, skipping
PyPI: No release information found for coverage-2.80, skipping
PyPI: No release information found for coverage-2.85, skipping
PyPI: 4 packages found for coverage >=4.5,<5.0
   1: fact: coverage (4.5.3) requires Python >=2.6, !=3.0.*, !=3.1.*, !=3.2.*, <4
   1: derived: not coverage (4.5.3)
   1: fact: coverage (4.5.2) requires Python >=2.6, !=3.0.*, !=3.1.*, !=3.2.*, <4
   1: derived: not coverage (4.5.2)
   1: fact: coverage (4.5.1) requires Python >=2.6, !=3.0.*, !=3.1.*, !=3.2.*, <4
   1: derived: not coverage (4.5.1)
   1: fact: coverage (4.5) requires Python >=2.6, !=3.0.*, !=3.1.*, !=3.2.*, <4
   1: derived: not coverage (4.5)
   1: fact: no versions of coverage match >4.5,<4.5.1 || >4.5.1,<4.5.2 || >4.5.2,<4.5.3 || >4.5.3,<5.0
   1: conflict: no versions of coverage match >4.5,<4.5.1 || >4.5.1,<4.5.2 || >4.5.2,<4.5.3 || >4.5.3,<5.0
   1: ! coverage (>4.5,<4.5.1 || >4.5.1,<4.5.2 || >4.5.2,<4.5.3 || >4.5.3,<5.0) is partially satisfied by not coverage (4.5)
   1: ! which is caused by "coverage (4.5) requires Python >=2.6, !=3.0.*, !=3.1.*, !=3.2.*, <4"
   1: ! thus: coverage is forbidden
   1: ! coverage (>=4.5,<4.5.1 || >4.5.1,<4.5.2 || >4.5.2,<4.5.3 || >4.5.3,<5.0) is partially satisfied by not coverage (4.5.1)
   1: ! which is caused by "coverage (4.5.1) requires Python >=2.6, !=3.0.*, !=3.1.*, !=3.2.*, <4"
   1: ! thus: coverage is forbidden
   1: ! coverage (>=4.5,<4.5.2 || >4.5.2,<4.5.3 || >4.5.3,<5.0) is partially satisfied by not coverage (4.5.2)
   1: ! which is caused by "coverage (4.5.2) requires Python >=2.6, !=3.0.*, !=3.1.*, !=3.2.*, <4"
   1: ! thus: coverage is forbidden
   1: ! coverage (>=4.5,<4.5.3 || >4.5.3,<5.0) is partially satisfied by not coverage (4.5.3)
   1: ! which is caused by "coverage (4.5.3) requires Python >=2.6, !=3.0.*, !=3.1.*, !=3.2.*, <4"
   1: ! thus: coverage is forbidden
   1: ! coverage (>=4.5,<5.0) is satisfied by coverage (^4.5)
   1: ! which is caused by "todo depends on coverage (^4.5)"
   1: ! thus: version solving failed
   1: Version solving took 0.106 seconds.
   1: Tried 1 solutions.

[SolverProblemError]
The current project must support the following Python versions: *
Because no versions of coverage match >4.5,<4.5.1 || >4.5.1,<4.5.2 || >4.5.2,<4.5.3 || >4.5.3,<5.0
 and coverage (4.5) requires Python >=2.6, !=3.0.*, !=3.1.*, !=3.2.*, <4, coverage is forbidden.
And because coverage (4.5.1) requires Python >=2.6, !=3.0.*, !=3.1.*, !=3.2.*, <4
 and coverage (4.5.2) requires Python >=2.6, !=3.0.*, !=3.1.*, !=3.2.*, <4, coverage is forbidden.
So, because coverage (4.5.3) requires Python >=2.6, !=3.0.*, !=3.1.*, !=3.2.*, <4
 and todo depends on coverage (^4.5), version solving failed.

Exception trace:
 c:\users\admin\appdata\local\programs\python\python36\lib\site-packages\cleo\application.py in run() at line 94
   status_code = self.do_run(input_, output_)
 c:\users\admin\appdata\local\programs\python\python36\lib\site-packages\poetry\console\application.py in do_run() at line 88
   return super(Application, self).do_run(i, o)
 c:\users\admin\appdata\local\programs\python\python36\lib\site-packages\cleo\application.py in do_run() at line 197
   status_code = command.run(input_, output_)
 c:\users\admin\appdata\local\programs\python\python36\lib\site-packages\poetry\console\commands\command.py in run() at line 77
   return super(BaseCommand, self).run(i, o)
 c:\users\admin\appdata\local\programs\python\python36\lib\site-packages\cleo\commands\base_command.py in run() at line 146
   status_code = self.execute(input_, output_)
 c:\users\admin\appdata\local\programs\python\python36\lib\site-packages\cleo\commands\command.py in execute() at line 107
   return self.handle()
 c:\users\admin\appdata\local\programs\python\python36\lib\site-packages\poetry\console\commands\add.py in handle() at line 139
   status = installer.run()
 c:\users\admin\appdata\local\programs\python\python36\lib\site-packages\poetry\installation\installer.py in run() at line 76
   self._do_install(local_repo)
 c:\users\admin\appdata\local\programs\python\python36\lib\site-packages\poetry\installation\installer.py in _do_install() at line 158
   ops = solver.solve(use_latest=self._whitelist)
 c:\users\admin\appdata\local\programs\python\python36\lib\site-packages\poetry\puzzle\solver.py in solve() at line 38
   packages, depths = self._solve(use_latest=use_latest)
 c:\users\admin\appdata\local\programs\python\python36\lib\site-packages\poetry\puzzle\solver.py in _solve() at line 180
   raise SolverProblemError(e)

Most helpful comment

@AndreGuerra123 To understand why this limitation exists, you have to understand how the resolver at the heart of Poetry works.

Using a wildcard Python constraint (which will likely be prohibited in the 1.0 release of Poetry) means that your package is compatible with any Python version, past or future, so it's not limited to the currently released Python versions.

Now, when the resolver sees a package (like coverage in your case) which declares being compatible with Python >=2.6, !=3.0.*, !=3.1.*, !=3.2.*, <4, it can't select it because that would lead to a gap in dependencies for the difference between * and >=2.6, !=3.0.*, !=3.1.*, !=3.2.*, <4 which is <2.6 or >=4.

This was done intentionally because it is, in my opinion, the logical way to resolve dependencies.

All 11 comments

Using "*" for python version is not technically correct. You can't claim that your package will support python 4.x or 100.x because nobody knows what that will be yet. Poetry is strict about that. You have to be more specific.

It is funny especially with the API compatibility which Python guarantees.

Well, that's a very opinionated view.
Since those versions don't exist, they shouldn't go to the compatibility matrix.
The same error is happening if I state:

python = ">= 0.0.0, < 3.8"

python = ">= 0.0.0, < 3.8" isn't strict enough. It's unlikely that all of your dependencies support both Python 1.0 and Python 3.7. What is the minimum version of Python you need to support?

For a new Django project, I'd recommend python = "^3.6" or python = "^3.7".

For a Django 1.1 project, python 2 is enough. I'm writing a boilerplate. This is my current tox.ini:

[tox]
skipsdist = True
envlist =
  {py27}-django{109,110,111}
  {py340,py35,py36,py370}-django{111,20,21}

[testenv]
whitelist_externals = poetry
skip_install = true
commands =
    poetry run coverage run --branch runtests.py

deps =
  django109: Django<=1.9
  django110: Django>=1.10,<1.11
  django111: Django>=1.11,<2.0
  django20: Django>=2.0,<2.1
  django21: Django>=2.1

For that envlist you'll want to declare your Python support as python = "^2.7 || ^3.4".

@AndreGuerra123 To understand why this limitation exists, you have to understand how the resolver at the heart of Poetry works.

Using a wildcard Python constraint (which will likely be prohibited in the 1.0 release of Poetry) means that your package is compatible with any Python version, past or future, so it's not limited to the currently released Python versions.

Now, when the resolver sees a package (like coverage in your case) which declares being compatible with Python >=2.6, !=3.0.*, !=3.1.*, !=3.2.*, <4, it can't select it because that would lead to a gap in dependencies for the difference between * and >=2.6, !=3.0.*, !=3.1.*, !=3.2.*, <4 which is <2.6 or >=4.

This was done intentionally because it is, in my opinion, the logical way to resolve dependencies.

Thank you for the enlightenment, however I'm not fully understanding it .
I have to apologise beforehand, sometimes I get tunnel vision.

What I get you are saying is that, since there are some incompatibilities <2.6 or >=4 (in all possible packages possibilities) between these two packages and therefore cannot be declared together.
However, there are possible solutions. So, let's say I have Python 2.7.3 installed. This version should be valid for both the packages independently of the above restriction, or am I wrong?

In another notice, if I declare

coverage="*"

it works.

What it means is pretty clear.

What you put in the Python version is EXACTLY all the Python versions your library supports.

If your code does not work in Python 1, you should not put *
If your code includes a dependency that does not work with Python 2.5, you cannot put *
If your code includes a dependency that does not work with Python 3.1, you cannot put *

In short: you cannot put *, as there is no case in which that would actually make sense.

Using "*" for python version is not technically correct. You can't claim that your package will support python 4.x or 100.x because nobody knows what that will be yet. Poetry is strict about that. You have to be more specific.

In short: you cannot put *, as there is no case in which that would actually make sense.

I disagree. There's no reason to assume that a pure-python math library (with functions like add(x, y) for example) will not be python 4.x, 5.x, or 100.x compatible, and it would be wrong to preemptively prevent users from using your library with python 4.x on the GUESS that SOME future version MAY be incompatible. That would be a good way to get the 2-to-3 mess all over again.

Regarding library versions, I would argue that best practice (though admittedly not common practice) is to ensure backwards compatibility when releasing new versions (or at least, not break compatibility, or assume it will be broken), and to trust future versions of code that provides backwards-compatibility guarantees, so that you get the latest security fixes ASAP.

While you may not agree, at least some projects (even private ones, according to corporate policies) may do this, and it should be supported, since it's a MORE robust and formal approach, not an unsafe one.

Dependency resolution should not have political opinions. It just needs to resolve the versions, to the versions specified.

Is the python = "^2.7 || ^3.4" syntax that @jacebrowning mentioned documented anywhere? I just got really worried that we wouldn't be able to use Poetry, because we're targeting 2.7, 3.5, 3.6, 3.7, and 3.8 -- surely other people are in the same boat and afaict this isn't discussed on https://poetry.eustace.io/docs/versions/. It may also be worth documenting that adding a python = ... line to dev-dependencies will cause failures.

Was this page helpful?
0 / 5 - 0 ratings

Related issues

mozartilize picture mozartilize  路  3Comments

EdgyEdgemond picture EdgyEdgemond  路  3Comments

jhrmnn picture jhrmnn  路  3Comments

AWegnerGitHub picture AWegnerGitHub  路  3Comments

sobolevn picture sobolevn  路  3Comments