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

Fix graphviz CLI failing #271

Merged
merged 1 commit into from
Jul 17, 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
1 change: 1 addition & 0 deletions pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -95,6 +95,7 @@ html.skip_covered = false
paths.source = ["src", ".tox/*/lib/python*/site-packages", "*/src"]
run.parallel = true
run.plugins = ["covdefaults"]
report.fail_under = 89
subtract_omit = "*/__main__.py"

[tool.mypy]
Expand Down
21 changes: 11 additions & 10 deletions src/pipdeptree/__main__.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
from __future__ import annotations

import sys
from typing import Sequence

from pipdeptree._cli import get_options
from pipdeptree._discovery import get_installed_distributions
Expand All @@ -11,29 +12,29 @@
from ._validate import validate


def main() -> None | int:
args = get_options()
result = handle_non_host_target(args)
def main(args: Sequence[str] | None = None) -> None | int:
options = get_options(args)
result = handle_non_host_target(options)
if result is not None:
return result

pkgs = get_installed_distributions(local_only=args.local_only, user_only=args.user_only)
pkgs = get_installed_distributions(local_only=options.local_only, user_only=options.user_only)
tree = PackageDAG.from_pkgs(pkgs)
is_text_output = not any([args.json, args.json_tree, args.output_format])
is_text_output = not any([options.json, options.json_tree, options.output_format])

return_code = validate(args, is_text_output, tree)
return_code = validate(options, is_text_output, tree)

# Reverse the tree (if applicable) before filtering, thus ensuring, that the filter will be applied on ReverseTree
if args.reverse:
if options.reverse:
tree = tree.reverse()

show_only = set(args.packages.split(",")) if args.packages else None
exclude = set(args.exclude.split(",")) if args.exclude else None
show_only = set(options.packages.split(",")) if options.packages else None
exclude = set(options.exclude.split(",")) if options.exclude else None

if show_only is not None or exclude is not None:
tree = tree.filter_nodes(show_only, exclude)

render(args, tree)
render(options, tree)

return return_code

Expand Down
8 changes: 4 additions & 4 deletions src/pipdeptree/_cli.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

import sys
from argparse import ArgumentDefaultsHelpFormatter, ArgumentParser, Namespace
from typing import TYPE_CHECKING, cast
from typing import TYPE_CHECKING, Sequence, cast

from .version import __version__

Expand All @@ -22,7 +22,7 @@ class Options(Namespace):
json: bool
json_tree: bool
mermaid: bool
graph_output: str | None
output_format: str | None
depth: float
encoding: str

Expand Down Expand Up @@ -135,9 +135,9 @@ def build_parser() -> ArgumentParser:
return parser


def get_options() -> Options:
def get_options(args: Sequence[str] | None) -> Options:
parser = build_parser()
return cast(Options, parser.parse_args())
return cast(Options, parser.parse_args(args))


__all__ = [
Expand Down
12 changes: 9 additions & 3 deletions src/pipdeptree/_render/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -21,10 +21,16 @@ def render(options: Options, tree: PackageDAG) -> None:
elif options.mermaid:
print(render_mermaid(tree)) # noqa: T201
elif options.output_format:
assert options.graph_output is not None # noqa: S101
render_graphviz(tree, output_format=options.graph_output, reverse=options.reverse)
assert options.output_format is not None # noqa: S101
render_graphviz(tree, output_format=options.output_format, reverse=options.reverse)
else:
render_text(tree, options.depth, options.encoding_type, options.all, options.freeze)
render_text(
tree,
max_depth=options.depth,
encoding=options.encoding_type,
list_all=options.all,
frozen=options.freeze,
)


__all__ = [
Expand Down
5 changes: 3 additions & 2 deletions src/pipdeptree/_render/text.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,10 +9,11 @@

def render_text(
tree: PackageDAG,
*,
max_depth: float,
encoding: str,
list_all: bool = True, # noqa: FBT001, FBT002
frozen: bool = False, # noqa: FBT001, FBT002
list_all: bool = True,
frozen: bool = False,
) -> None:
"""
Print tree as text on console.
Expand Down
40 changes: 40 additions & 0 deletions tests/render/test_render.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
from __future__ import annotations

from math import inf
from typing import TYPE_CHECKING
from unittest.mock import ANY

from pipdeptree.__main__ import main

if TYPE_CHECKING:
from pytest_mock import MockerFixture


def test_json_routing(mocker: MockerFixture) -> None:
render = mocker.patch("pipdeptree._render.render_json")
main(["--json"])
render.assert_called_once_with(ANY)


def test_json_tree_routing(mocker: MockerFixture) -> None:
render = mocker.patch("pipdeptree._render.render_json_tree")
main(["--json-tree"])
render.assert_called_once_with(ANY)


def test_mermaid_routing(mocker: MockerFixture) -> None:
render = mocker.patch("pipdeptree._render.render_mermaid")
main(["--mermaid"])
render.assert_called_once_with(ANY)


def test_grahpviz_routing(mocker: MockerFixture) -> None:
render = mocker.patch("pipdeptree._render.render_graphviz")
main(["--graph-output", "dot"])
render.assert_called_once_with(ANY, output_format="dot", reverse=False)


def test_text_routing(mocker: MockerFixture) -> None:
render = mocker.patch("pipdeptree._render.render_text")
main([])
render.assert_called_once_with(ANY, encoding="utf-8", frozen=False, list_all=False, max_depth=inf)
21 changes: 3 additions & 18 deletions tests/render/test_text.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
from __future__ import annotations

import sys
from typing import TYPE_CHECKING

import pytest
Expand All @@ -11,20 +10,6 @@
from pipdeptree._models import PackageDAG


class MockStdout:
"""
A wrapper to stdout that mocks the `encoding` attribute (to have `render_text()` render with unicode/non-unicode)
and `write()` (so that `print()` calls can write to stdout).
"""

def __init__(self, encoding: str) -> None:
self.stdout = sys.stdout
self.encoding = encoding

def write(self, text: str) -> None:
self.stdout.write(text)


@pytest.mark.parametrize(
("list_all", "reverse", "unicode", "expected_output"),
[
Expand Down Expand Up @@ -258,7 +243,7 @@ def test_render_text( # noqa: PLR0913
) -> None:
tree = example_dag.reverse() if reverse else example_dag
encoding = "utf-8" if unicode else "ascii"
render_text(tree, float("inf"), encoding, list_all=list_all, frozen=False)
render_text(tree, max_depth=float("inf"), encoding=encoding, list_all=list_all, frozen=False)
captured = capsys.readouterr()
assert "\n".join(expected_output).strip() == captured.out.strip()

Expand Down Expand Up @@ -359,7 +344,7 @@ def test_render_text_given_depth(
expected_output: list[str],
example_dag: PackageDAG,
) -> None:
render_text(example_dag, level, encoding="utf-8" if unicode else "ascii")
render_text(example_dag, max_depth=level, encoding="utf-8" if unicode else "ascii")
captured = capsys.readouterr()
assert "\n".join(expected_output).strip() == captured.out.strip()

Expand Down Expand Up @@ -518,6 +503,6 @@ def test_render_text_encoding(
expected_output: list[str],
example_dag: PackageDAG,
) -> None:
render_text(example_dag, level, encoding, True, False)
render_text(example_dag, max_depth=level, encoding=encoding, list_all=True, frozen=False)
captured = capsys.readouterr()
assert "\n".join(expected_output).strip() == captured.out.strip()
6 changes: 3 additions & 3 deletions tox.ini
Original file line number Diff line number Diff line change
Expand Up @@ -25,12 +25,12 @@ set_env =
_COVERAGE_SRC = {envsitepackagesdir}/sphinx_argparse_cli
commands =
python -m pytest {tty:--color=yes} {posargs: \
--junitxml {toxworkdir}{/}junit.{envname}.xml --cov {envsitepackagesdir}{/}pipdeptree \
--cov {toxinidir}{/}tests --cov-fail-under=85 \
--cov {envsitepackagesdir}{/}pipdeptree --cov {toxinidir}{/}tests \
--cov-config=pyproject.toml --no-cov-on-fail --cov-report term-missing:skip-covered --cov-context=test \
--cov-report html:{envtmpdir}{/}htmlcov --cov-report xml:{toxworkdir}{/}coverage.{envname}.xml \
--junitxml {toxworkdir}{/}junit.{envname}.xml \
tests}
diff-cover --compare-branch {env:DIFF_AGAINST:origin/main} {toxworkdir}{/}coverage.{envname}.xml
diff-cover --compare-branch {env:DIFF_AGAINST:origin/main} {toxworkdir}{/}coverage.{envname}.xml --fail-under 100

[testenv:fix]
description = format the code base to adhere to our styles, and complain about what we cannot do automatically
Expand Down