Skip to content

Commit 8ae931f

Browse files
authored
Merge pull request #657 from dhellmann/improve-graph-why-output
feat(graph): Improve `why` command output
2 parents 493ceb4 + 504cbf5 commit 8ae931f

File tree

2 files changed

+40
-8
lines changed

2 files changed

+40
-8
lines changed

src/fromager/commands/bootstrap.py

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -374,9 +374,14 @@ def write_constraints_file(
374374
output.write(f"{dep_name}=={node.version}\n")
375375

376376
for dep_name in conflicting_deps:
377-
logger.error("finding why %s was being used", dep_name)
378377
for node in graph.get_nodes_by_name(dep_name):
379-
find_why(graph, node, -1, 1, [])
378+
find_why(
379+
graph=graph,
380+
node=node,
381+
max_depth=-1,
382+
depth=0,
383+
req_type=[],
384+
)
380385

381386
return ret
382387

src/fromager/commands/graph.py

Lines changed: 33 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -205,8 +205,7 @@ def why(
205205
if version:
206206
package_nodes = [node for node in package_nodes if node.version in version]
207207
for node in package_nodes:
208-
print(f"\n{node.key}")
209-
find_why(graph, node, depth, 1, requirement_type)
208+
find_why(graph, node, depth, 0, requirement_type)
210209

211210

212211
def find_why(
@@ -215,22 +214,50 @@ def find_why(
215214
max_depth: int,
216215
depth: int,
217216
req_type: list[RequirementType],
218-
):
217+
seen: set[str] | None = None,
218+
) -> None:
219+
if seen is None:
220+
seen = set()
221+
222+
if node.key in seen:
223+
print(f"{' ' * depth} * {node.key} has a cycle")
224+
return
225+
226+
# Print the name of the package we are asking about. We do this here because
227+
# we might be invoked for multiple packages and we want the format to be
228+
# consistent.
229+
if depth == 0:
230+
print(f"\n{node.key}")
231+
232+
seen = set([node.key]).union(seen)
219233
all_skipped = True
220234
is_toplevel = False
221235
for parent in node.parents:
236+
# Show the toplevel dependencies regardless of the req_type because they
237+
# are the ones that are actually installed and may influence other
238+
# dependencies.
222239
if parent.destination_node.key == ROOT:
223240
is_toplevel = True
224-
print(f" * {node.key} is a toplevel dependency")
241+
print(
242+
f"{' ' * depth} * {node.key} is a toplevel dependency with req {parent.req}"
243+
)
225244
continue
245+
# Skip dependencies that don't match the req_type.
226246
if req_type and parent.req_type not in req_type:
227247
continue
228248
all_skipped = False
229249
print(
230-
f"{' ' * depth} * is an {parent.req_type} dependency of {parent.destination_node.key} with req {parent.req}"
250+
f"{' ' * depth} * {node.key} is an {parent.req_type} dependency of {parent.destination_node.key} with req {parent.req}"
231251
)
232252
if max_depth and (max_depth == -1 or depth <= max_depth):
233-
find_why(graph, parent.destination_node, max_depth, depth + 1, [])
253+
find_why(
254+
graph=graph,
255+
node=parent.destination_node,
256+
max_depth=max_depth,
257+
depth=depth + 1,
258+
req_type=req_type,
259+
seen=seen,
260+
)
234261

235262
if all_skipped and not is_toplevel:
236263
print(

0 commit comments

Comments
 (0)