Skip to content

Commit 2846077

Browse files
authored
Diagnostic Error for Resolution Too Deep
2 parents 4b265b3 + 2bc540c commit 2846077

File tree

4 files changed

+91
-3
lines changed

4 files changed

+91
-3
lines changed

docs/html/topics/dependency-resolution.md

+65-2
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,7 @@ of how dependency resolution for Python packages works.
3939
The user requests `pip install tea`. The package `tea` declares a dependency on
4040
`hot-water`, `spoon`, `cup`, amongst others.
4141
42-
pip starts by picking the most recent version of `tea` and get the list of
42+
pip starts by picking the most recent version of `tea` and gets the list of
4343
dependencies of that version of `tea`. It will then repeat the process for
4444
those packages, picking the most recent version of `spoon` and then `cup`. Now,
4545
pip notices that the version of `cup` it has chosen is not compatible with the
@@ -298,7 +298,70 @@ In this situation, you could consider:
298298
- Refactoring your project to reduce the number of dependencies (for
299299
example, by breaking up a monolithic code base into smaller pieces).
300300

301-
### Getting help
301+
## Handling Resolution Too Deep Errors
302+
303+
Sometimes pip's dependency resolver may exceed its search depth and terminate
304+
with a `ResolutionTooDeepError` exception. This typically occurs when the
305+
dependency graph is extremely complex or when there are too many package
306+
versions to evaluate.
307+
308+
To address this error, consider the following strategies:
309+
310+
### Specify Reasonable Lower Bounds
311+
312+
By setting a higher lower bound for your dependencies, you narrow the search
313+
space. This excludes older versions that might trigger excessive backtracking.
314+
For example:
315+
316+
```{pip-cli}
317+
$ pip install "package_coffee>=0.44.0" "package_tea>=4.0.0"
318+
```
319+
320+
### Use the `--upgrade` Flag
321+
322+
The `--upgrade` flag directs pip to ignore already installed versions and
323+
search for the latest versions that meet your requirements. This can help
324+
avoid unnecessary resolution paths:
325+
326+
```{pip-cli}
327+
$ pip install --upgrade package_coffee package_tea
328+
```
329+
330+
### Utilize Constraint Files
331+
332+
If you need to impose additional version restrictions on transitive
333+
dependencies (dependencies of dependencies), consider using a constraint
334+
file. A constraint file specifies version limits for packages that are
335+
indirectly required. For example:
336+
337+
```
338+
# constraints.txt
339+
indirect_dependency>=2.0.0
340+
```
341+
342+
Then install your packages with:
343+
344+
```{pip-cli}
345+
$ pip install --constraint constraints.txt package_coffee package_tea
346+
```
347+
348+
### Use Upper Bounds Sparingly
349+
350+
Although upper bounds are generally discouraged because they can complicate
351+
dependency management, they may be necessary when certain versions are known
352+
to cause conflicts. Use them cautiously—for example:
353+
354+
```{pip-cli}
355+
$ pip install "package_coffee>=0.44.0,<1.0.0" "package_tea>=4.0.0"
356+
```
357+
358+
### Report ResolutionTooDeep Errors
359+
360+
If you encounter a `ResolutionTooDeep` error consider reporting it, to help
361+
the pip team have real world examples to test against, at the dedicated
362+
[pip issue](https://github.com/pypa/pip/issues/13281).
363+
364+
## Getting help
302365

303366
If none of the suggestions above work for you, we recommend that you ask
304367
for help on:

news/13282.feature.rst

+2
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
Provide hint, documentation, and link to the documentation when
2+
resolution too deep error occurs.

src/pip/_internal/exceptions.py

+20
Original file line numberDiff line numberDiff line change
@@ -807,3 +807,23 @@ def __init__(
807807
),
808808
hint_stmt="To proceed this package must be uninstalled.",
809809
)
810+
811+
812+
class ResolutionTooDeepError(DiagnosticPipError):
813+
"""Raised when the dependency resolver exceeds the maximum recursion depth."""
814+
815+
reference = "resolution-too-deep"
816+
817+
def __init__(self) -> None:
818+
super().__init__(
819+
message="Dependency resolution exceeded maximum depth",
820+
context=(
821+
"Pip cannot resolve the current dependencies as the dependency graph "
822+
"is too complex for pip to solve efficiently."
823+
),
824+
hint_stmt=(
825+
"Try adding lower bounds to constrain your dependencies, "
826+
"for example: 'package>=2.0.0' instead of just 'package'. "
827+
),
828+
link="https://pip.pypa.io/en/stable/topics/dependency-resolution/#handling-resolution-too-deep-errors",
829+
)

src/pip/_internal/resolution/resolvelib/resolver.py

+4-1
Original file line numberDiff line numberDiff line change
@@ -5,11 +5,12 @@
55
from typing import TYPE_CHECKING, Dict, List, Optional, Set, Tuple, cast
66

77
from pip._vendor.packaging.utils import canonicalize_name
8-
from pip._vendor.resolvelib import BaseReporter, ResolutionImpossible
8+
from pip._vendor.resolvelib import BaseReporter, ResolutionImpossible, ResolutionTooDeep
99
from pip._vendor.resolvelib import Resolver as RLResolver
1010
from pip._vendor.resolvelib.structs import DirectedGraph
1111

1212
from pip._internal.cache import WheelCache
13+
from pip._internal.exceptions import ResolutionTooDeepError
1314
from pip._internal.index.package_finder import PackageFinder
1415
from pip._internal.operations.prepare import RequirementPreparer
1516
from pip._internal.req.constructors import install_req_extend_extras
@@ -102,6 +103,8 @@ def resolve(
102103
collected.constraints,
103104
)
104105
raise error from e
106+
except ResolutionTooDeep:
107+
raise ResolutionTooDeepError from None
105108

106109
req_set = RequirementSet(check_supported_wheels=check_supported_wheels)
107110
# process candidates with extras last to ensure their base equivalent is

0 commit comments

Comments
 (0)