Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Simplify loops #267

Merged
merged 3 commits into from
Jul 15, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
43 changes: 17 additions & 26 deletions src/pipdeptree/_models.py
Original file line number Diff line number Diff line change
Expand Up @@ -256,7 +256,7 @@ def get_children(self, node_key: str) -> list[ReqPackage]:
node = self.get_node_as_parent(node_key)
return self._obj[node] if node else []

def filter_nodes(self, include: set[str] | None, exclude: set[str] | None) -> PackageDAG: # noqa: C901, PLR0912
def filter_nodes(self, include: set[str] | None, exclude: set[str] | None) -> PackageDAG: # noqa: C901
"""
Filters nodes in a graph by given parameters.

Expand Down Expand Up @@ -294,23 +294,20 @@ def filter_nodes(self, include: set[str] | None, exclude: set[str] | None) -> Pa
continue
if include is None or any(fnmatch(node.key, i) for i in include):
stack.append(node)
while True:
if len(stack) > 0:
n = stack.pop()
cldn = [c for c in self._obj[n] if not any(fnmatch(c.key, e) for e in exclude)]
m[n] = cldn
seen.add(n.key)
for c in cldn:
if c.key not in seen:
cld_node = self.get_node_as_parent(c.key)
if cld_node:
stack.append(cld_node)
else:
# It means there's no root node corresponding to the child node i.e.
# a dependency is missing
continue
else:
break
while stack:
n = stack.pop()
cldn = [c for c in self._obj[n] if not any(fnmatch(c.key, e) for e in exclude)]
m[n] = cldn
seen.add(n.key)
for c in cldn:
if c.key not in seen:
cld_node = self.get_node_as_parent(c.key)
if cld_node:
stack.append(cld_node)
else:
# It means there's no root node corresponding to the child node i.e.
# a dependency is missing
continue

return self.__class__(m)

Expand All @@ -335,10 +332,7 @@ def reverse(self) -> ReversedPackageDAG:
# if v is already added to the dict, then ensure that
# we are using the same object. This check is required
# as we're using array mutation
try:
node: ReqPackage = [p for p in m if p.key == v.key][0]
except IndexError: # noqa: PERF203
node = v
node: ReqPackage = next((p for p in m if p.key == v.key), v)
m[node].append(k.as_parent_of(v))
if k.key not in child_keys:
m[k.as_requirement()] = []
Expand Down Expand Up @@ -383,10 +377,7 @@ def reverse(self) -> PackageDAG: # type: ignore[override]
child_keys = {r.key for r in chain.from_iterable(self._obj.values())}
for k, vs in self._obj.items():
for v in vs:
try:
node = [p for p in m if p.key == v.key][0]
except IndexError: # noqa: PERF203
node = v.as_parent_of(None)
node = next((p for p in m if p.key == v.key), v.as_parent_of(None))
m[node].append(k) # type: ignore[arg-type]
if k.key not in child_keys:
m[k.dist] = []
Expand Down
28 changes: 10 additions & 18 deletions src/pipdeptree/_render/mermaid.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
from __future__ import annotations

from textwrap import dedent
import itertools as it
from typing import TYPE_CHECKING, Final

from pipdeptree._models import ReversedPackageDAG
Expand Down Expand Up @@ -56,13 +56,12 @@ def mermaid_id(key: str) -> str:
node_ids_map[key] = key
return key
# If the key is a reserved keyword, append a number to it.
number = 0
while True:
for number in it.count():
new_id = f"{key}_{number}"
if new_id not in node_ids_map:
node_ids_map[key] = new_id
return new_id
number += 1
raise NotImplementedError

# Use a sets to avoid duplicate entries.
nodes: set[str] = set()
Expand Down Expand Up @@ -95,20 +94,13 @@ def mermaid_id(key: str) -> str:
edges.add(f'{package_key} -- "{edge_label}" --> {dependency_key}')

# Produce the Mermaid Markdown.
indent = " " * 4
output = dedent(
f"""\
flowchart TD
{indent}classDef missing stroke-dasharray: 5
""",
)
# Sort the nodes and edges to make the output deterministic.
output += indent
output += f"\n{indent}".join(node for node in sorted(nodes))
output += "\n" + indent
output += f"\n{indent}".join(edge for edge in sorted(edges))
output += "\n"
return output
lines = [
"flowchart TD",
"classDef missing stroke-dasharray: 5",
*sorted(nodes),
*sorted(edges),
]
return "".join(f"{' ' if i else ''}{line}\n" for i, line in enumerate(lines))


__all__ = [
Expand Down
2 changes: 1 addition & 1 deletion src/pipdeptree/_validate.py
Original file line number Diff line number Diff line change
Expand Up @@ -76,7 +76,7 @@ def cyclic_deps(tree: PackageDAG) -> list[tuple[DistPackage, ReqPackage, ReqPack
if val is not None:
entry = tree.get(val)
if entry is not None:
p_as_dep_of_r = [x for x in entry if x.key == p.key][0]
p_as_dep_of_r = next(x for x in entry if x.key == p.key)
cyclic.append((p, r, p_as_dep_of_r))
return cyclic

Expand Down
3 changes: 1 addition & 2 deletions tests/conftest.py
Original file line number Diff line number Diff line change
Expand Up @@ -21,8 +21,7 @@ def func(simple_graph: MockGraph) -> Iterator[Mock]:
as_req = Mock(key=nk, project_name=nk, specs=[("==", nv)])
m.as_requirement = Mock(return_value=as_req)
reqs = []
for child in children:
ck, cv = child
for ck, cv in children:
r = Mock(key=ck, project_name=ck, specs=cv)
reqs.append(r)
m.requires = Mock(return_value=reqs)
Expand Down