From 3dd23864cb384278079c37da2f20eab44bfa8ca3 Mon Sep 17 00:00:00 2001 From: DavHau Date: Tue, 22 Aug 2023 12:39:14 +0200 Subject: [PATCH] pip: don't crash on cycles, fix them instead pip does allow cycles and they are common in larger dependency trees. Instead of crashing on them, we should allow the user to deal with them. As a result of this, it can happen that during the installation of individual dependencies, some dep(s) might be missing, which then can be fixed by including them manually or with a `--no-deps` --- .../lock_file_from_report.py | 17 +++++----------- .../src/tests/test_evaluate_requirements.py | 20 +++++++++++++++++++ 2 files changed, 25 insertions(+), 12 deletions(-) diff --git a/pkgs/fetchPipMetadata/src/fetch_pip_metadata/lock_file_from_report.py b/pkgs/fetchPipMetadata/src/fetch_pip_metadata/lock_file_from_report.py index 06cd0fd4..63184331 100644 --- a/pkgs/fetchPipMetadata/src/fetch_pip_metadata/lock_file_from_report.py +++ b/pkgs/fetchPipMetadata/src/fetch_pip_metadata/lock_file_from_report.py @@ -143,14 +143,6 @@ def evaluate_requirements(env, reqs, dependencies, root_name, extras, seen): requirements to save space in the file. A circuit breaker is included to avoid infinite recursion in nix. """ - if root_name in seen: - print( - f"fatal: cycle detected: {root_name} ({' '.join(seen)})", - file=sys.stderr, # noqa: E501 - ) - sys.exit(1) - # we copy "seen", because we want to track cycles per - # tree-branch and the original would be visible for all branches. seen = seen.copy() seen.append(root_name) @@ -160,10 +152,11 @@ def evaluate_requirements(env, reqs, dependencies, root_name, extras, seen): for req in reqs[root_name]: if (not req.marker) or evaluate_extras(req, extras, env): req_name = canonicalize_name(req.name) - dependencies[root_name].add(req_name) - evaluate_requirements( - env, reqs, dependencies, req_name, req.extras, seen - ) # noqa: 501 + if req_name not in seen: + dependencies[root_name].add(req_name) + evaluate_requirements( + env, reqs, dependencies, req_name, req.extras, seen + ) # noqa: 501 return dependencies diff --git a/pkgs/fetchPipMetadata/src/tests/test_evaluate_requirements.py b/pkgs/fetchPipMetadata/src/tests/test_evaluate_requirements.py index decd5a62..59e9ef80 100644 --- a/pkgs/fetchPipMetadata/src/tests/test_evaluate_requirements.py +++ b/pkgs/fetchPipMetadata/src/tests/test_evaluate_requirements.py @@ -68,3 +68,23 @@ def test_platform_mismatch(): seen=[], ) assert result == dict(root_package=set()) + + +def test_cycle(): + result = l.evaluate_requirements( + env={}, + reqs=dict( + root_package={Requirement("foo")}, + foo={Requirement("bar")}, + bar={Requirement("foo")}, + ), + dependencies=dict(), + root_name="root_package", + extras=None, + seen=[], + ) + assert result == dict( + root_package={"foo"}, + foo={"bar"}, + bar=set(), + )