python-poetry / poetry

Python packaging and dependency management made easy
https://python-poetry.org
MIT License
31.23k stars 2.26k forks source link

Cryptic 'None' message on version conflict error #8196

Open salty-horse opened 1 year ago

salty-horse commented 1 year ago

Issue

I'm getting a crash in the same line as described in #5016 from a year ago, but with the latest version of poetry.

Unlike that error, without verbose output, the output is just 'None' in red.

My package requirement is just google-auth = 1.35.0.

$ poetry add  firebase-admin
Using version ^6.2.0 for firebase-admin

Updating dependencies
Resolving dependencies... (2.2s)

'None'

With verbose output, the bottom of the stack trace has:

  KeyError  'None'

  at ~/.local/share/pypoetry/venv/lib/python3.10/site-packages/poetry/mixology/version_solver.py:188 in _propagate
      184│             # Iterate in reverse because conflict resolution tends to produce more
      185│             # general incompatibilities as time goes on. If we look at those first,
      186│             # we can derive stronger assignments sooner and more eagerly find
      187│             # conflicts.
    → 188│             for incompatibility in reversed(self._incompatibilities[package]):
      189│                 if incompatibility in self._contradicted_incompatibilities:
      190│                     continue
      191│ 
      192│                 result = self._propagate_incompatibility(incompatibility)

Full gist of -vvv: https://gist.github.com/salty-horse/e4b3fd13b26da3529df29a4ff859a185

Allowing for google-auth = "^2" makes it resolve correctly. Poetry should tell me the ^1.33.1 requirement is blocking the installation instead of crashing.

kevin-hanselman commented 11 months ago

I'm experiencing the same issue and verbose output, but on poetry update (not add, although I'd guess that it's hitting the same code path), using Poetry 1.6.1 and Python 3.11.6.

Strangely, when I rollback to Poetry 1.5.1 (as the OP mentions), poetry update succeeds. Regardless, printing 'None' and exiting with an error code is clearly a bug.

tungol commented 3 months ago

I hit the same issue on poetry 1.8.3. I can see that the control flow is something like this:

  1. VersionSolver._propagate calls VersionSolver._propagate_incompatibility
  2. _propagate_incompatibility returns a conflict, so _resolve_conflict gets called, and then _propagate_incompatibility is called again.
  3. The second call to _propagate_incompatibility returns None. The first time it got called in this function, a None result is accounted for, but this time there's no handling of None, and it gets converted to the string 'None' and added to changed
  4. On the next loop, we look up 'None' in self.self._incompatibilities and it throws the error.

I tried following the example of the check for None the first time around with

result = self._propagate_incompatibility(root_cause)
if result is not None:
    changed.add(str(result))

But that just dumped me into an infinite loop. I suspect raising an error might be the correct action in that situation, but I don't know what error that might be.

I went looking for a minimal reproduction, but unfortunately my case seems to hinge on an internal package listed as a dependency. Interestingly, if I narrow the requirement so only a single version of that package is allowed, then the conflict is handled properly.

tungol commented 3 months ago

With a bunch of logging statements inserted into _propagate, the failing case looks like this:

Source (artifactory): 0 packages found for requests >=2.25.dev0,<2.25.0
Falling back to installed packages to discover metadata for requests
Found 0 compatible packages for requests
   1: fact: no versions of requests match >=2.25.dev0,<2.25.0
   1: _propagate: requests
   1: changed package: requests
   1: incompatibility: no versions of requests match >=2.25.dev0,<2.25.0
   1: _propagate_incompatibility result1: <object object at 0x10a1a2d30>  # this is the _conflict object
   1: conflict: no versions of requests match >=2.25.dev0,<2.25.0
   1: _resolve_conflict root cause: no versions of requests match >=2.25.dev0,<2.25.0
   1: _propagate_incompatibility result2: None
   1: changed package: None

and then self._incompatibilities[package] throws the KeyError.

thatch commented 2 weeks ago

I also get this on 1.8.3 on a complex internal dep tree, which involves a case of ~ constraint on a local version dep. Simplified version of the tree:

a ~= 1+h82
b # multiple versions
. c # multiple versions
. a # no specifier, but has 1+h82 and 1+h85 -- both depend on the same pin of c, which is not the newest and would c on the line above this to be invalid
. . c == 0.1