diff --git a/Makefile b/Makefile index 4eed41339..7f426e6e3 100644 --- a/Makefile +++ b/Makefile @@ -21,7 +21,7 @@ test-unit: ## Run unit tests. .PHONY: test-functional test-functional: ## Run functional tests. @echo "🚀 Running functional tests" - @uv run pytest tests/functional -n auto --dist loadgroup + @uv run pytest tests/functional .PHONY: build build: ## Build wheel and sdist files using maturin. diff --git a/pyproject.toml b/pyproject.toml index c30add7b9..a310b32f7 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -40,6 +40,7 @@ docs = [ "mkdocs-material==9.7.2", ] test = [ + "inline-snapshot==0.32.2", "pdm==2.26.6", "poetry==2.3.2", "pytest==9.0.2", diff --git a/python/deptry/cli.py b/python/deptry/cli.py index 610be45b6..7c3183390 100644 --- a/python/deptry/cli.py +++ b/python/deptry/cli.py @@ -267,6 +267,13 @@ def display_deptry_version(ctx: click.Context, _param: click.Parameter, value: b is_flag=True, help="Enable experimental support for namespace package (PEP 420) when detecting local modules (https://peps.python.org/pep-0420/).", ) +# This flag is not exposed because it is used in functional tests to have consistent output between platforms. +@click.option( + "--enforce-posix-paths", + is_flag=True, + hidden=True, + help="Enforce posix paths in reporters.", +) @click.pass_context def cli( ctx: click.Context, @@ -288,6 +295,7 @@ def cli( pep621_dev_dependency_groups: tuple[str, ...], optional_dependencies_dev_groups: tuple[str, ...], experimental_namespace_package: bool, + enforce_posix_paths: bool, ) -> None: """Find dependency issues in your Python project. @@ -325,6 +333,7 @@ def cli( package_module_name_map=package_module_name_map, optional_dependencies_dev_groups=pep621_dev_dependency_groups or optional_dependencies_dev_groups, experimental_namespace_package=experimental_namespace_package, + enforce_posix_paths=enforce_posix_paths, ).run() diff --git a/python/deptry/core.py b/python/deptry/core.py index deab1804a..4576386c5 100644 --- a/python/deptry/core.py +++ b/python/deptry/core.py @@ -40,6 +40,7 @@ class Core: package_module_name_map: Mapping[str, tuple[str, ...]] optional_dependencies_dev_groups: tuple[str, ...] experimental_namespace_package: bool + enforce_posix_paths: bool github_output: bool github_warning_errors: tuple[str, ...] @@ -84,13 +85,17 @@ def run(self) -> None: self.per_rule_ignores, standard_library_modules, ) - TextReporter(violations, use_ansi=not self.no_ansi).report() + TextReporter(violations, enforce_posix_paths=self.enforce_posix_paths, use_ansi=not self.no_ansi).report() if self.json_output: - JSONReporter(violations, self.json_output).report() + JSONReporter( + violations, enforce_posix_paths=self.enforce_posix_paths, json_output=self.json_output + ).report() if self.github_output: - GithubReporter(violations, warning_ids=self.github_warning_errors).report() + GithubReporter( + violations, enforce_posix_paths=self.enforce_posix_paths, warning_ids=self.github_warning_errors + ).report() self._exit(violations) diff --git a/python/deptry/reporters/base.py b/python/deptry/reporters/base.py index 47ac0fd6b..c5d1c9ee8 100644 --- a/python/deptry/reporters/base.py +++ b/python/deptry/reporters/base.py @@ -5,6 +5,8 @@ from typing import TYPE_CHECKING if TYPE_CHECKING: + from pathlib import Path + from deptry.violations import Violation @@ -13,7 +15,13 @@ class Reporter(ABC): """Base class for all violation reporters.""" violations: list[Violation] + enforce_posix_paths: bool @abstractmethod def report(self) -> None: raise NotImplementedError() + + def _format_path(self, path: Path) -> str: + if self.enforce_posix_paths: + return str(path.as_posix()) + return str(path) diff --git a/python/deptry/reporters/github.py b/python/deptry/reporters/github.py index b598a077a..69fcddc82 100644 --- a/python/deptry/reporters/github.py +++ b/python/deptry/reporters/github.py @@ -26,19 +26,19 @@ def _log_violations(self, violations: list[Violation]) -> None: def _print_github_annotation(self, violation: Violation) -> None: annotation_severity = "warning" if violation.error_code in self.warning_ids else "error" - file_name = violation.location.file ret = _build_workflow_command( annotation_severity, violation.error_code, violation.get_error_message(), - str(file_name), + self._format_path(violation.location.file), # For dependency files (like "pyproject.toml"), we don't extract a line. Setting the first line in that case # allows a comment to be added in GitHub, even if it's not on the proper line, otherwise it doesn't appear # at all. line=violation.location.line or 1, column=violation.location.column, ) + logging.info(ret) diff --git a/python/deptry/reporters/json.py b/python/deptry/reporters/json.py index 06e7b6a7a..8ffcd689a 100644 --- a/python/deptry/reporters/json.py +++ b/python/deptry/reporters/json.py @@ -27,7 +27,7 @@ def report(self) -> None: }, "module": violation.issue.name, "location": { - "file": str(violation.location.file), + "file": self._format_path(violation.location.file), "line": violation.location.line, "column": violation.location.column, }, diff --git a/python/deptry/reporters/text.py b/python/deptry/reporters/text.py index 51cf7f2fd..bfb07cccf 100644 --- a/python/deptry/reporters/text.py +++ b/python/deptry/reporters/text.py @@ -61,14 +61,16 @@ def _format_error(self, violation: Violation) -> str: ) def _format_location(self, location: Location) -> str: + path = self._format_path(location.file) + if location.line is not None and location.column is not None: return self._stylize( "{BOLD}{file}{RESET}{CYAN}:{RESET}{line}{CYAN}:{RESET}{column}", - file=location.file, + file=path, line=location.line, column=location.column, ) - return self._stylize("{BOLD}{file}{RESET}", file=location.file) + return self._stylize("{BOLD}{file}{RESET}", file=path) def _stylize(self, text: str, **kwargs: Any) -> str: return text.format(**kwargs, **self._get_colors()) diff --git a/tests/functional/cli/test_cli.py b/tests/functional/cli/test_cli.py index ed3a6171e..ab0e43dcf 100644 --- a/tests/functional/cli/test_cli.py +++ b/tests/functional/cli/test_cli.py @@ -1,15 +1,17 @@ from __future__ import annotations +import sys import uuid from pathlib import Path from typing import TYPE_CHECKING import pytest from click.testing import CliRunner +from inline_snapshot import snapshot from deptry.cli import cli from tests.functional.utils import Project -from tests.utils import get_issues_report, stylize +from tests.utils import get_issues_report if TYPE_CHECKING: from tests.utils import PoetryVenvFactory @@ -18,479 +20,153 @@ @pytest.mark.xdist_group(name=Project.EXAMPLE) def test_cli_returns_error(poetry_venv_factory: PoetryVenvFactory) -> None: with poetry_venv_factory(Project.EXAMPLE) as virtual_env: - issue_report = f"{uuid.uuid4()}.json" - result = virtual_env.run(f"deptry . -o {issue_report}") + result = virtual_env.run_deptry(".") assert result.returncode == 1 - assert get_issues_report(Path(issue_report)) == [ - { - "error": { - "code": "DEP002", - "message": "'isort' defined as a dependency but not used in the codebase", - }, - "module": "isort", - "location": { - "file": str(Path("pyproject.toml")), - "line": None, - "column": None, - }, - }, - { - "error": { - "code": "DEP002", - "message": "'requests' defined as a dependency but not used in the codebase", - }, - "module": "requests", - "location": { - "file": str(Path("pyproject.toml")), - "line": None, - "column": None, - }, - }, - { - "error": { - "code": "DEP004", - "message": "'black' imported but declared as a dev dependency", - }, - "module": "black", - "location": { - "file": str(Path("src/main.py")), - "line": 4, - "column": 8, - }, - }, - { - "error": { - "code": "DEP001", - "message": "'white' imported but missing from the dependency definitions", - }, - "module": "white", - "location": { - "file": str(Path("src/main.py")), - "line": 6, - "column": 8, - }, - }, - ] + assert result.stderr == snapshot("""\ +Scanning 2 files... + +pyproject.toml: DEP002 'isort' defined as a dependency but not used in the codebase +pyproject.toml: DEP002 'requests' defined as a dependency but not used in the codebase +src/main.py:4:8: DEP004 'black' imported but declared as a dev dependency +src/main.py:6:8: DEP001 'white' imported but missing from the dependency definitions +Found 4 dependency issues. + +For more information, see the documentation: https://deptry.com/ +""") @pytest.mark.xdist_group(name=Project.EXAMPLE) def test_cli_ignore_notebooks(poetry_venv_factory: PoetryVenvFactory) -> None: with poetry_venv_factory(Project.EXAMPLE) as virtual_env: - issue_report = f"{uuid.uuid4()}.json" - result = virtual_env.run(f"deptry . --ignore-notebooks -o {issue_report}") + result = virtual_env.run_deptry(". --ignore-notebooks") assert result.returncode == 1 - assert get_issues_report(Path(issue_report)) == [ - { - "error": { - "code": "DEP002", - "message": "'arrow' defined as a dependency but not used in the codebase", - }, - "module": "arrow", - "location": { - "file": str(Path("pyproject.toml")), - "line": None, - "column": None, - }, - }, - { - "error": { - "code": "DEP002", - "message": "'isort' defined as a dependency but not used in the codebase", - }, - "module": "isort", - "location": { - "file": str(Path("pyproject.toml")), - "line": None, - "column": None, - }, - }, - { - "error": { - "code": "DEP002", - "message": "'requests' defined as a dependency but not used in the codebase", - }, - "module": "requests", - "location": { - "file": str(Path("pyproject.toml")), - "line": None, - "column": None, - }, - }, - { - "error": { - "code": "DEP004", - "message": "'black' imported but declared as a dev dependency", - }, - "module": "black", - "location": { - "file": str(Path("src/main.py")), - "line": 4, - "column": 8, - }, - }, - { - "error": { - "code": "DEP001", - "message": "'white' imported but missing from the dependency definitions", - }, - "module": "white", - "location": { - "file": str(Path("src/main.py")), - "line": 6, - "column": 8, - }, - }, - ] + assert result.stderr == snapshot("""\ +Scanning 1 file... + +pyproject.toml: DEP002 'arrow' defined as a dependency but not used in the codebase +pyproject.toml: DEP002 'isort' defined as a dependency but not used in the codebase +pyproject.toml: DEP002 'requests' defined as a dependency but not used in the codebase +src/main.py:4:8: DEP004 'black' imported but declared as a dev dependency +src/main.py:6:8: DEP001 'white' imported but missing from the dependency definitions +Found 5 dependency issues. + +For more information, see the documentation: https://deptry.com/ +""") @pytest.mark.xdist_group(name=Project.EXAMPLE) def test_cli_ignore_flags(poetry_venv_factory: PoetryVenvFactory) -> None: with poetry_venv_factory(Project.EXAMPLE) as virtual_env: - result = virtual_env.run("deptry . --per-rule-ignores DEP001=white,DEP002=isort|pkginfo|requests,DEP004=black") + result = virtual_env.run_deptry(". --per-rule-ignores DEP001=white,DEP002=isort|pkginfo|requests,DEP004=black") assert result.returncode == 0 + assert result.stderr == snapshot("""\ +Scanning 2 files... + +Success! No dependency issues found. +""") @pytest.mark.xdist_group(name=Project.EXAMPLE) def test_cli_ignore_flag(poetry_venv_factory: PoetryVenvFactory) -> None: with poetry_venv_factory(Project.EXAMPLE) as virtual_env: - result = virtual_env.run("deptry . --ignore DEP001,DEP002,DEP003,DEP004") + result = virtual_env.run_deptry(". --ignore DEP001,DEP002,DEP003,DEP004") assert result.returncode == 0 + assert result.stderr == snapshot("""\ +Scanning 2 files... + +Success! No dependency issues found. +""") @pytest.mark.xdist_group(name=Project.EXAMPLE) def test_cli_exclude(poetry_venv_factory: PoetryVenvFactory) -> None: with poetry_venv_factory(Project.EXAMPLE) as virtual_env: - issue_report = f"{uuid.uuid4()}.json" - result = virtual_env.run(f"deptry . --exclude src/notebook.ipynb -o {issue_report}") + result = virtual_env.run_deptry(". --exclude src/notebook\\.ipynb") assert result.returncode == 1 - assert get_issues_report(Path(issue_report)) == [ - { - "error": { - "code": "DEP002", - "message": "'arrow' defined as a dependency but not used in the codebase", - }, - "module": "arrow", - "location": { - "file": str(Path("pyproject.toml")), - "line": None, - "column": None, - }, - }, - { - "error": { - "code": "DEP002", - "message": "'isort' defined as a dependency but not used in the codebase", - }, - "module": "isort", - "location": { - "file": str(Path("pyproject.toml")), - "line": None, - "column": None, - }, - }, - { - "error": { - "code": "DEP002", - "message": "'requests' defined as a dependency but not used in the codebase", - }, - "module": "requests", - "location": { - "file": str(Path("pyproject.toml")), - "line": None, - "column": None, - }, - }, - { - "error": { - "code": "DEP004", - "message": "'black' imported but declared as a dev dependency", - }, - "module": "black", - "location": { - "file": str(Path("src/main.py")), - "line": 4, - "column": 8, - }, - }, - { - "error": { - "code": "DEP001", - "message": "'white' imported but missing from the dependency definitions", - }, - "module": "white", - "location": { - "file": str(Path("src/main.py")), - "line": 6, - "column": 8, - }, - }, - ] + assert result.stderr == snapshot("""\ +Scanning 1 file... + +pyproject.toml: DEP002 'arrow' defined as a dependency but not used in the codebase +pyproject.toml: DEP002 'isort' defined as a dependency but not used in the codebase +pyproject.toml: DEP002 'requests' defined as a dependency but not used in the codebase +src/main.py:4:8: DEP004 'black' imported but declared as a dev dependency +src/main.py:6:8: DEP001 'white' imported but missing from the dependency definitions +Found 5 dependency issues. + +For more information, see the documentation: https://deptry.com/ +""") @pytest.mark.xdist_group(name=Project.EXAMPLE) def test_cli_extend_exclude(poetry_venv_factory: PoetryVenvFactory) -> None: with poetry_venv_factory(Project.EXAMPLE) as virtual_env: - issue_report = f"{uuid.uuid4()}.json" - result = virtual_env.run(f"deptry . -ee src/notebook.ipynb -o {issue_report}") + result = virtual_env.run_deptry(". -ee src/notebook\\.ipynb") assert result.returncode == 1 - assert get_issues_report(Path(issue_report)) == [ - { - "error": { - "code": "DEP002", - "message": "'arrow' defined as a dependency but not used in the codebase", - }, - "module": "arrow", - "location": { - "file": str(Path("pyproject.toml")), - "line": None, - "column": None, - }, - }, - { - "error": { - "code": "DEP002", - "message": "'isort' defined as a dependency but not used in the codebase", - }, - "module": "isort", - "location": { - "file": str(Path("pyproject.toml")), - "line": None, - "column": None, - }, - }, - { - "error": { - "code": "DEP002", - "message": "'requests' defined as a dependency but not used in the codebase", - }, - "module": "requests", - "location": { - "file": str(Path("pyproject.toml")), - "line": None, - "column": None, - }, - }, - { - "error": { - "code": "DEP004", - "message": "'black' imported but declared as a dev dependency", - }, - "module": "black", - "location": { - "file": str(Path("src/main.py")), - "line": 4, - "column": 8, - }, - }, - { - "error": { - "code": "DEP001", - "message": "'white' imported but missing from the dependency definitions", - }, - "module": "white", - "location": { - "file": str(Path("src/main.py")), - "line": 6, - "column": 8, - }, - }, - ] + assert result.stderr == snapshot("""\ +Scanning 1 file... + +pyproject.toml: DEP002 'arrow' defined as a dependency but not used in the codebase +pyproject.toml: DEP002 'isort' defined as a dependency but not used in the codebase +pyproject.toml: DEP002 'requests' defined as a dependency but not used in the codebase +src/main.py:4:8: DEP004 'black' imported but declared as a dev dependency +src/main.py:6:8: DEP001 'white' imported but missing from the dependency definitions +Found 5 dependency issues. + +For more information, see the documentation: https://deptry.com/ +""") @pytest.mark.xdist_group(name=Project.EXAMPLE) def test_cli_known_first_party(poetry_venv_factory: PoetryVenvFactory) -> None: with poetry_venv_factory(Project.EXAMPLE) as virtual_env: - issue_report = f"{uuid.uuid4()}.json" - result = virtual_env.run(f"deptry . --known-first-party white -o {issue_report}") + result = virtual_env.run_deptry(". --known-first-party white") assert result.returncode == 1 - assert get_issues_report(Path(issue_report)) == [ - { - "error": { - "code": "DEP002", - "message": "'isort' defined as a dependency but not used in the codebase", - }, - "module": "isort", - "location": { - "file": str(Path("pyproject.toml")), - "line": None, - "column": None, - }, - }, - { - "error": { - "code": "DEP002", - "message": "'requests' defined as a dependency but not used in the codebase", - }, - "module": "requests", - "location": { - "file": str(Path("pyproject.toml")), - "line": None, - "column": None, - }, - }, - { - "error": { - "code": "DEP004", - "message": "'black' imported but declared as a dev dependency", - }, - "module": "black", - "location": { - "file": str(Path("src/main.py")), - "line": 4, - "column": 8, - }, - }, - ] + assert result.stderr == snapshot("""\ +Scanning 2 files... + +pyproject.toml: DEP002 'isort' defined as a dependency but not used in the codebase +pyproject.toml: DEP002 'requests' defined as a dependency but not used in the codebase +src/main.py:4:8: DEP004 'black' imported but declared as a dev dependency +Found 3 dependency issues. + +For more information, see the documentation: https://deptry.com/ +""") @pytest.mark.xdist_group(name=Project.EXAMPLE) def test_cli_not_verbose(poetry_venv_factory: PoetryVenvFactory) -> None: with poetry_venv_factory(Project.EXAMPLE) as virtual_env: - issue_report = f"{uuid.uuid4()}.json" - result = virtual_env.run(f"deptry . -o {issue_report}") + result = virtual_env.run_deptry(".") assert result.returncode == 1 - assert "The project contains the following dependencies:" not in result.stderr - assert get_issues_report(Path(issue_report)) == [ - { - "error": { - "code": "DEP002", - "message": "'isort' defined as a dependency but not used in the codebase", - }, - "module": "isort", - "location": { - "file": str(Path("pyproject.toml")), - "line": None, - "column": None, - }, - }, - { - "error": { - "code": "DEP002", - "message": "'requests' defined as a dependency but not used in the codebase", - }, - "module": "requests", - "location": { - "file": str(Path("pyproject.toml")), - "line": None, - "column": None, - }, - }, - { - "error": { - "code": "DEP004", - "message": "'black' imported but declared as a dev dependency", - }, - "module": "black", - "location": { - "file": str(Path("src/main.py")), - "line": 4, - "column": 8, - }, - }, - { - "error": { - "code": "DEP001", - "message": "'white' imported but missing from the dependency definitions", - }, - "module": "white", - "location": { - "file": str(Path("src/main.py")), - "line": 6, - "column": 8, - }, - }, - ] + assert result.stderr == snapshot("""\ +Scanning 2 files... + +pyproject.toml: DEP002 'isort' defined as a dependency but not used in the codebase +pyproject.toml: DEP002 'requests' defined as a dependency but not used in the codebase +src/main.py:4:8: DEP004 'black' imported but declared as a dev dependency +src/main.py:6:8: DEP001 'white' imported but missing from the dependency definitions +Found 4 dependency issues. + +For more information, see the documentation: https://deptry.com/ +""") @pytest.mark.xdist_group(name=Project.EXAMPLE) def test_cli_verbose(poetry_venv_factory: PoetryVenvFactory) -> None: with poetry_venv_factory(Project.EXAMPLE) as virtual_env: - issue_report = f"{uuid.uuid4()}.json" - result = virtual_env.run(f"deptry . --verbose -o {issue_report}") + result = virtual_env.run_deptry(". --verbose") assert result.returncode == 1 assert "The project contains the following dependencies:" in result.stderr assert "The project contains the following dev dependencies:" in result.stderr - assert get_issues_report(Path(issue_report)) == [ - { - "error": { - "code": "DEP002", - "message": "'isort' defined as a dependency but not used in the codebase", - }, - "module": "isort", - "location": { - "file": str(Path("pyproject.toml")), - "line": None, - "column": None, - }, - }, - { - "error": { - "code": "DEP002", - "message": "'requests' defined as a dependency but not used in the codebase", - }, - "module": "requests", - "location": { - "file": str(Path("pyproject.toml")), - "line": None, - "column": None, - }, - }, - { - "error": { - "code": "DEP004", - "message": "'black' imported but declared as a dev dependency", - }, - "module": "black", - "location": { - "file": str(Path("src/main.py")), - "line": 4, - "column": 8, - }, - }, - { - "error": { - "code": "DEP001", - "message": "'white' imported but missing from the dependency definitions", - }, - "module": "white", - "location": { - "file": str(Path("src/main.py")), - "line": 6, - "column": 8, - }, - }, - ] - - -@pytest.mark.xdist_group(name=Project.EXAMPLE) -def test_cli_with_no_ansi(poetry_venv_factory: PoetryVenvFactory) -> None: - with poetry_venv_factory(Project.EXAMPLE) as virtual_env: - result = virtual_env.run("deptry . --no-ansi") - - expected_output = [ - "Scanning 2 files...", - "", - f"{Path('pyproject.toml')}: DEP002 'isort' defined as a dependency but not used in the codebase", - f"{Path('pyproject.toml')}: DEP002 'requests' defined as a dependency but not used in the codebase", - f"{Path('src/main.py')}:4:8: DEP004 'black' imported but declared as a dev dependency", - f"{Path('src/main.py')}:6:8: DEP001 'white' imported but missing from the dependency definitions", - "Found 4 dependency issues.", - "", - "For more information, see the documentation: https://deptry.com/", - "", - ] - - assert result.returncode == 1 - assert result.stderr == "\n".join(expected_output) @pytest.mark.xdist_group(name=Project.EXAMPLE) @@ -498,92 +174,47 @@ def test_cli_with_not_json_output(poetry_venv_factory: PoetryVenvFactory) -> Non with poetry_venv_factory(Project.EXAMPLE) as virtual_env: json_files_count = len(list(Path().glob("*.json"))) - result = virtual_env.run("deptry .") - - expected_output = [ - "Scanning 2 files...", - "", - stylize( - "{BOLD}{file}{RESET}{CYAN}:{RESET} {BOLD}{RED}DEP002{RESET} 'isort' defined as a dependency but not" - " used in the codebase", - file=Path("pyproject.toml"), - ), - stylize( - "{BOLD}{file}{RESET}{CYAN}:{RESET} {BOLD}{RED}DEP002{RESET} 'requests' defined as a dependency but" - " not used in the codebase", - file=Path("pyproject.toml"), - ), - stylize( - "{BOLD}{file}{RESET}{CYAN}:{RESET}4{CYAN}:{RESET}8{CYAN}:{RESET} {BOLD}{RED}DEP004{RESET} 'black'" - " imported but declared as a dev dependency", - file=Path("src/main.py"), - ), - stylize( - "{BOLD}{file}{RESET}{CYAN}:{RESET}6{CYAN}:{RESET}8{CYAN}:{RESET} {BOLD}{RED}DEP001{RESET} 'white'" - " imported but missing from the dependency definitions", - file=Path("src/main.py"), - ), - stylize("{BOLD}{RED}Found 4 dependency issues.{RESET}"), - "", - "For more information, see the documentation: https://deptry.com/", - "", - ] + result = virtual_env.run_deptry(".") assert result.returncode == 1 # Assert that we have the same number of JSON files as before running the command. assert len(list(Path().glob("*.json"))) == json_files_count - assert result.stderr == "\n".join(expected_output) + assert result.stderr == snapshot("""\ +Scanning 2 files... + +pyproject.toml: DEP002 'isort' defined as a dependency but not used in the codebase +pyproject.toml: DEP002 'requests' defined as a dependency but not used in the codebase +src/main.py:4:8: DEP004 'black' imported but declared as a dev dependency +src/main.py:6:8: DEP001 'white' imported but missing from the dependency definitions +Found 4 dependency issues. + +For more information, see the documentation: https://deptry.com/ +""") @pytest.mark.xdist_group(name=Project.EXAMPLE) def test_cli_with_json_output(poetry_venv_factory: PoetryVenvFactory) -> None: with poetry_venv_factory(Project.EXAMPLE) as virtual_env: issue_report = f"{uuid.uuid4()}.json" - result = virtual_env.run(f"deptry . -o {issue_report}") - - expected_output = [ - "Scanning 2 files...", - "", - stylize( - "{BOLD}{file}{RESET}{CYAN}:{RESET} {BOLD}{RED}DEP002{RESET} 'isort' defined as a dependency but not" - " used in the codebase", - file=Path("pyproject.toml"), - ), - stylize( - "{BOLD}{file}{RESET}{CYAN}:{RESET} {BOLD}{RED}DEP002{RESET} 'requests' defined as a dependency but" - " not used in the codebase", - file=Path("pyproject.toml"), - ), - stylize( - "{BOLD}{file}{RESET}{CYAN}:{RESET}4{CYAN}:{RESET}8{CYAN}:{RESET} {BOLD}{RED}DEP004{RESET} 'black'" - " imported but declared as a dev dependency", - file=Path("src/main.py"), - ), - stylize( - "{BOLD}{file}{RESET}{CYAN}:{RESET}6{CYAN}:{RESET}8{CYAN}:{RESET} {BOLD}{RED}DEP001{RESET} 'white'" - " imported but missing from the dependency definitions", - file=Path("src/main.py"), - ), - stylize("{BOLD}{RED}Found 4 dependency issues.{RESET}"), - "", - "For more information, see the documentation: https://deptry.com/", - "", - ] + result = virtual_env.run_deptry(f". -o {issue_report}") # Assert that we still write to console when generating a JSON report. - assert result.stderr == "\n".join(expected_output) - assert get_issues_report(Path(issue_report)) == [ + assert result.stderr == snapshot("""\ +Scanning 2 files... + +pyproject.toml: DEP002 'isort' defined as a dependency but not used in the codebase +pyproject.toml: DEP002 'requests' defined as a dependency but not used in the codebase +src/main.py:4:8: DEP004 'black' imported but declared as a dev dependency +src/main.py:6:8: DEP001 'white' imported but missing from the dependency definitions +Found 4 dependency issues. + +For more information, see the documentation: https://deptry.com/ +""") + assert get_issues_report(Path(issue_report)) == snapshot([ { - "error": { - "code": "DEP002", - "message": "'isort' defined as a dependency but not used in the codebase", - }, + "error": {"code": "DEP002", "message": "'isort' defined as a dependency but not used in the codebase"}, "module": "isort", - "location": { - "file": str(Path("pyproject.toml")), - "line": None, - "column": None, - }, + "location": {"file": "pyproject.toml", "line": None, "column": None}, }, { "error": { @@ -591,147 +222,205 @@ def test_cli_with_json_output(poetry_venv_factory: PoetryVenvFactory) -> None: "message": "'requests' defined as a dependency but not used in the codebase", }, "module": "requests", - "location": { - "file": str(Path("pyproject.toml")), - "line": None, - "column": None, - }, + "location": {"file": "pyproject.toml", "line": None, "column": None}, }, { - "error": { - "code": "DEP004", - "message": "'black' imported but declared as a dev dependency", - }, + "error": {"code": "DEP004", "message": "'black' imported but declared as a dev dependency"}, "module": "black", - "location": { - "file": str(Path("src/main.py")), - "line": 4, - "column": 8, - }, + "location": {"file": "src/main.py", "line": 4, "column": 8}, }, { - "error": { - "code": "DEP001", - "message": "'white' imported but missing from the dependency definitions", - }, + "error": {"code": "DEP001", "message": "'white' imported but missing from the dependency definitions"}, "module": "white", - "location": { - "file": str(Path("src/main.py")), - "line": 6, - "column": 8, - }, + "location": {"file": "src/main.py", "line": 6, "column": 8}, }, - ] + ]) @pytest.mark.xdist_group(name=Project.EXAMPLE) def test_cli_with_github_output(poetry_venv_factory: PoetryVenvFactory) -> None: with poetry_venv_factory(Project.EXAMPLE) as virtual_env: - result = virtual_env.run("deptry . --github-output") - - expected_output = [ - "Scanning 2 files...", - "", - stylize( - "{BOLD}{file}{RESET}{CYAN}:{RESET} {BOLD}{RED}DEP002{RESET} 'isort' defined as a dependency but not" - " used in the codebase", - file=Path("pyproject.toml"), - ), - stylize( - "{BOLD}{file}{RESET}{CYAN}:{RESET} {BOLD}{RED}DEP002{RESET} 'requests' defined as a dependency but" - " not used in the codebase", - file=Path("pyproject.toml"), - ), - stylize( - "{BOLD}{file}{RESET}{CYAN}:{RESET}4{CYAN}:{RESET}8{CYAN}:{RESET} {BOLD}{RED}DEP004{RESET} 'black'" - " imported but declared as a dev dependency", - file=Path("src/main.py"), - ), - stylize( - "{BOLD}{file}{RESET}{CYAN}:{RESET}6{CYAN}:{RESET}8{CYAN}:{RESET} {BOLD}{RED}DEP001{RESET} 'white'" - " imported but missing from the dependency definitions", - file=Path("src/main.py"), - ), - stylize("{BOLD}{RED}Found 4 dependency issues.{RESET}"), - "", - "For more information, see the documentation: https://deptry.com/", - f"::error file={Path('pyproject.toml')},line=1,title=DEP002::'isort' defined as a dependency but not used in the codebase", - f"::error file={Path('pyproject.toml')},line=1,title=DEP002::'requests' defined as a dependency but not used in the codebase", - f"::error file={Path('src/main.py')},line=4,col=8,title=DEP004::'black' imported but declared as a dev dependency", - f"::error file={Path('src/main.py')},line=6,col=8,title=DEP001::'white' imported but missing from the dependency definitions", - "", - ] + result = virtual_env.run_deptry(". --github-output") assert result.returncode == 1 - assert result.stderr == "\n".join(expected_output) + assert result.stderr == snapshot("""\ +Scanning 2 files... + +pyproject.toml: DEP002 'isort' defined as a dependency but not used in the codebase +pyproject.toml: DEP002 'requests' defined as a dependency but not used in the codebase +src/main.py:4:8: DEP004 'black' imported but declared as a dev dependency +src/main.py:6:8: DEP001 'white' imported but missing from the dependency definitions +Found 4 dependency issues. + +For more information, see the documentation: https://deptry.com/ +::error file=pyproject.toml,line=1,title=DEP002::'isort' defined as a dependency but not used in the codebase +::error file=pyproject.toml,line=1,title=DEP002::'requests' defined as a dependency but not used in the codebase +::error file=src/main.py,line=4,col=8,title=DEP004::'black' imported but declared as a dev dependency +::error file=src/main.py,line=6,col=8,title=DEP001::'white' imported but missing from the dependency definitions +""") @pytest.mark.xdist_group(name=Project.EXAMPLE) def test_cli_with_github_output_warning_errors(poetry_venv_factory: PoetryVenvFactory) -> None: with poetry_venv_factory(Project.EXAMPLE) as virtual_env: - result = virtual_env.run("deptry . --github-output --github-warning-errors DEP001,DEP004") - - expected_output = [ - "Scanning 2 files...", - "", - stylize( - "{BOLD}{file}{RESET}{CYAN}:{RESET} {BOLD}{RED}DEP002{RESET} 'isort' defined as a dependency but not" - " used in the codebase", - file=Path("pyproject.toml"), - ), - stylize( - "{BOLD}{file}{RESET}{CYAN}:{RESET} {BOLD}{RED}DEP002{RESET} 'requests' defined as a dependency but" - " not used in the codebase", - file=Path("pyproject.toml"), - ), - stylize( - "{BOLD}{file}{RESET}{CYAN}:{RESET}4{CYAN}:{RESET}8{CYAN}:{RESET} {BOLD}{RED}DEP004{RESET} 'black'" - " imported but declared as a dev dependency", - file=Path("src/main.py"), - ), - stylize( - "{BOLD}{file}{RESET}{CYAN}:{RESET}6{CYAN}:{RESET}8{CYAN}:{RESET} {BOLD}{RED}DEP001{RESET} 'white'" - " imported but missing from the dependency definitions", - file=Path("src/main.py"), - ), - stylize("{BOLD}{RED}Found 4 dependency issues.{RESET}"), - "", - "For more information, see the documentation: https://deptry.com/", - f"::error file={Path('pyproject.toml')},line=1,title=DEP002::'isort' defined as a dependency but not used in the codebase", - f"::error file={Path('pyproject.toml')},line=1,title=DEP002::'requests' defined as a dependency but not used in the codebase", - f"::warning file={Path('src/main.py')},line=4,col=8,title=DEP004::'black' imported but declared as a dev dependency", - f"::warning file={Path('src/main.py')},line=6,col=8,title=DEP001::'white' imported but missing from the dependency definitions", - "", - ] + result = virtual_env.run_deptry(". --github-output --github-warning-errors DEP001,DEP004") assert result.returncode == 1 - assert result.stderr == "\n".join(expected_output) + assert result.stderr == snapshot("""\ +Scanning 2 files... + +pyproject.toml: DEP002 'isort' defined as a dependency but not used in the codebase +pyproject.toml: DEP002 'requests' defined as a dependency but not used in the codebase +src/main.py:4:8: DEP004 'black' imported but declared as a dev dependency +src/main.py:6:8: DEP001 'white' imported but missing from the dependency definitions +Found 4 dependency issues. + +For more information, see the documentation: https://deptry.com/ +::error file=pyproject.toml,line=1,title=DEP002::'isort' defined as a dependency but not used in the codebase +::error file=pyproject.toml,line=1,title=DEP002::'requests' defined as a dependency but not used in the codebase +::warning file=src/main.py,line=4,col=8,title=DEP004::'black' imported but declared as a dev dependency +::warning file=src/main.py,line=6,col=8,title=DEP001::'white' imported but missing from the dependency definitions +""") def test_cli_config_does_not_supress_output(poetry_venv_factory: PoetryVenvFactory) -> None: """Regression test that ensures that passing `--config` option does not suppress output.""" with poetry_venv_factory(Project.WITHOUT_DEPTRY_OPTION) as virtual_env: - result = virtual_env.run("deptry . --config pyproject.toml") - - expected_output = [ - "Scanning 0 file...", - "", - stylize( - "{BOLD}{file}{RESET}{CYAN}:{RESET} {BOLD}{RED}DEP002{RESET} 'isort' defined as a dependency but not" - " used in the codebase", - file=Path("pyproject.toml"), - ), - stylize("{BOLD}{RED}Found 1 dependency issue.{RESET}"), - "", - "For more information, see the documentation: https://deptry.com/", - "", - ] + result = virtual_env.run_deptry(". --config pyproject.toml") assert result.returncode == 1 - assert result.stderr == "\n".join(expected_output) + assert result.stderr == snapshot("""\ +Scanning 0 file... + +pyproject.toml: DEP002 'isort' defined as a dependency but not used in the codebase +Found 1 dependency issue. + +For more information, see the documentation: https://deptry.com/ +""") + + +@pytest.mark.xdist_group(name=Project.EXAMPLE) +def test_ansi(poetry_venv_factory: PoetryVenvFactory) -> None: + with poetry_venv_factory(Project.EXAMPLE) as virtual_env: + result = virtual_env.run_deptry(".", no_ansi=False) + + assert result.returncode == 1 + assert result.stderr == snapshot("""\ +Scanning 2 files... + +\x1b[1mpyproject.toml\x1b[m\x1b[36m:\x1b[m \x1b[1m\x1b[31mDEP002\x1b[m 'isort' defined as a dependency but not used in the codebase +\x1b[1mpyproject.toml\x1b[m\x1b[36m:\x1b[m \x1b[1m\x1b[31mDEP002\x1b[m 'requests' defined as a dependency but not used in the codebase +\x1b[1msrc/main.py\x1b[m\x1b[36m:\x1b[m4\x1b[36m:\x1b[m8\x1b[36m:\x1b[m \x1b[1m\x1b[31mDEP004\x1b[m 'black' imported but declared as a dev dependency +\x1b[1msrc/main.py\x1b[m\x1b[36m:\x1b[m6\x1b[36m:\x1b[m8\x1b[36m:\x1b[m \x1b[1m\x1b[31mDEP001\x1b[m 'white' imported but missing from the dependency definitions +\x1b[1m\x1b[31mFound 4 dependency issues.\x1b[m + +For more information, see the documentation: https://deptry.com/ +""") def test_cli_help() -> None: result = CliRunner().invoke(cli, "--help") assert result.exit_code == 0 + + +@pytest.mark.xdist_group(name=Project.EXAMPLE) +@pytest.mark.skipif(sys.platform != "win32", reason="Explicitly tests paths output for Windows systems") +def test_cli_paths_respect_windows(poetry_venv_factory: PoetryVenvFactory) -> None: + with poetry_venv_factory(Project.EXAMPLE) as virtual_env: + issue_report = f"{uuid.uuid4()}.json" + result = virtual_env.run_deptry(f". -o {issue_report} --github-output", enforce_posix_paths=False) + + assert result.returncode == 1 + assert result.stderr == snapshot("""\ +Scanning 2 files... + +pyproject.toml: DEP002 'isort' defined as a dependency but not used in the codebase +pyproject.toml: DEP002 'requests' defined as a dependency but not used in the codebase +src\\main.py:4:8: DEP004 'black' imported but declared as a dev dependency +src\\main.py:6:8: DEP001 'white' imported but missing from the dependency definitions +Found 4 dependency issues. + +For more information, see the documentation: https://deptry.com/ +::error file=pyproject.toml,line=1,title=DEP002::'isort' defined as a dependency but not used in the codebase +::error file=pyproject.toml,line=1,title=DEP002::'requests' defined as a dependency but not used in the codebase +::error file=src\\main.py,line=4,col=8,title=DEP004::'black' imported but declared as a dev dependency +::error file=src\\main.py,line=6,col=8,title=DEP001::'white' imported but missing from the dependency definitions +""") + + assert get_issues_report(Path(issue_report)) == snapshot([ + { + "error": {"code": "DEP002", "message": "'isort' defined as a dependency but not used in the codebase"}, + "module": "isort", + "location": {"file": "pyproject.toml", "line": None, "column": None}, + }, + { + "error": { + "code": "DEP002", + "message": "'requests' defined as a dependency but not used in the codebase", + }, + "module": "requests", + "location": {"file": "pyproject.toml", "line": None, "column": None}, + }, + { + "error": {"code": "DEP004", "message": "'black' imported but declared as a dev dependency"}, + "module": "black", + "location": {"file": "src\\main.py", "line": 4, "column": 8}, + }, + { + "error": {"code": "DEP001", "message": "'white' imported but missing from the dependency definitions"}, + "module": "white", + "location": {"file": "src\\main.py", "line": 6, "column": 8}, + }, + ]) + + +@pytest.mark.xdist_group(name=Project.EXAMPLE) +@pytest.mark.skipif(sys.platform == "win32", reason="Explicitly tests paths output for non-Windows systems") +def test_cli_paths_respect_non_windows(poetry_venv_factory: PoetryVenvFactory) -> None: + with poetry_venv_factory(Project.EXAMPLE) as virtual_env: + issue_report = f"{uuid.uuid4()}.json" + result = virtual_env.run_deptry(f". -o {issue_report} --github-output", enforce_posix_paths=False) + + assert result.returncode == 1 + assert result.stderr == snapshot("""\ +Scanning 2 files... + +pyproject.toml: DEP002 'isort' defined as a dependency but not used in the codebase +pyproject.toml: DEP002 'requests' defined as a dependency but not used in the codebase +src/main.py:4:8: DEP004 'black' imported but declared as a dev dependency +src/main.py:6:8: DEP001 'white' imported but missing from the dependency definitions +Found 4 dependency issues. + +For more information, see the documentation: https://deptry.com/ +::error file=pyproject.toml,line=1,title=DEP002::'isort' defined as a dependency but not used in the codebase +::error file=pyproject.toml,line=1,title=DEP002::'requests' defined as a dependency but not used in the codebase +::error file=src/main.py,line=4,col=8,title=DEP004::'black' imported but declared as a dev dependency +::error file=src/main.py,line=6,col=8,title=DEP001::'white' imported but missing from the dependency definitions +""") + + assert get_issues_report(Path(issue_report)) == snapshot([ + { + "error": {"code": "DEP002", "message": "'isort' defined as a dependency but not used in the codebase"}, + "module": "isort", + "location": {"file": "pyproject.toml", "line": None, "column": None}, + }, + { + "error": { + "code": "DEP002", + "message": "'requests' defined as a dependency but not used in the codebase", + }, + "module": "requests", + "location": {"file": "pyproject.toml", "line": None, "column": None}, + }, + { + "error": {"code": "DEP004", "message": "'black' imported but declared as a dev dependency"}, + "module": "black", + "location": {"file": "src/main.py", "line": 4, "column": 8}, + }, + { + "error": {"code": "DEP001", "message": "'white' imported but missing from the dependency definitions"}, + "module": "white", + "location": {"file": "src/main.py", "line": 6, "column": 8}, + }, + ]) diff --git a/tests/functional/cli/test_cli_gitignore.py b/tests/functional/cli/test_cli_gitignore.py index ce78d064f..8479d2acd 100644 --- a/tests/functional/cli/test_cli_gitignore.py +++ b/tests/functional/cli/test_cli_gitignore.py @@ -1,13 +1,12 @@ from __future__ import annotations -import uuid from pathlib import Path from typing import TYPE_CHECKING import pytest +from inline_snapshot import snapshot from tests.functional.utils import Project -from tests.utils import get_issues_report if TYPE_CHECKING: from tests.utils import PipVenvFactory @@ -16,175 +15,72 @@ @pytest.mark.xdist_group(name=Project.GITIGNORE) def test_cli_gitignore_used(pip_venv_factory: PipVenvFactory) -> None: with pip_venv_factory(Project.GITIGNORE) as virtual_env: - issue_report = f"{uuid.uuid4()}.json" - # Simulate the fact that the project is a git repository. Path(".git").mkdir(exist_ok=True) - result = virtual_env.run(f"deptry . -o {issue_report}") + result = virtual_env.run_deptry(".") assert result.returncode == 1 - assert get_issues_report(Path(issue_report)) == [ - { - "error": { - "code": "DEP002", - "message": "'requests' defined as a dependency but not used in the codebase", - }, - "module": "requests", - "location": { - "file": str(Path("pyproject.toml")), - "line": None, - "column": None, - }, - }, - { - "error": { - "code": "DEP002", - "message": "'mypy' defined as a dependency but not used in the codebase", - }, - "module": "mypy", - "location": { - "file": str(Path("pyproject.toml")), - "line": None, - "column": None, - }, - }, - { - "error": { - "code": "DEP002", - "message": "'pytest' defined as a dependency but not used in the codebase", - }, - "module": "pytest", - "location": { - "file": str(Path("pyproject.toml")), - "line": None, - "column": None, - }, - }, - ] + assert result.stderr == snapshot("""\ +Assuming the corresponding module name of package 'black' is 'black'. Install the package or configure a package_module_name_map entry to override this behaviour. +Assuming the corresponding module name of package 'mypy' is 'mypy'. Install the package or configure a package_module_name_map entry to override this behaviour. +Assuming the corresponding module name of package 'pytest' is 'pytest'. Install the package or configure a package_module_name_map entry to override this behaviour. +Scanning 3 files... + +pyproject.toml: DEP002 'requests' defined as a dependency but not used in the codebase +pyproject.toml: DEP002 'mypy' defined as a dependency but not used in the codebase +pyproject.toml: DEP002 'pytest' defined as a dependency but not used in the codebase +Found 3 dependency issues. + +For more information, see the documentation: https://deptry.com/ +""") @pytest.mark.xdist_group(name=Project.GITIGNORE) def test_cli_gitignore_used_for_non_root_directory(pip_venv_factory: PipVenvFactory) -> None: with pip_venv_factory(Project.GITIGNORE) as virtual_env: - issue_report = f"{uuid.uuid4()}.json" - # Simulate the fact that the project is a git repository. Path(".git").mkdir(exist_ok=True) - result = virtual_env.run(f"deptry src -o {issue_report}") + result = virtual_env.run_deptry("src") assert result.returncode == 1 - assert get_issues_report(Path(issue_report)) == [ - { - "error": { - "code": "DEP002", - "message": "'requests' defined as a dependency but not used in the codebase", - }, - "module": "requests", - "location": { - "file": str(Path("pyproject.toml")), - "line": None, - "column": None, - }, - }, - { - "error": { - "code": "DEP002", - "message": "'mypy' defined as a dependency but not used in the codebase", - }, - "module": "mypy", - "location": { - "file": str(Path("pyproject.toml")), - "line": None, - "column": None, - }, - }, - { - "error": { - "code": "DEP002", - "message": "'pytest' defined as a dependency but not used in the codebase", - }, - "module": "pytest", - "location": { - "file": str(Path("pyproject.toml")), - "line": None, - "column": None, - }, - }, - ] + assert result.stderr == snapshot("""\ +Assuming the corresponding module name of package 'black' is 'black'. Install the package or configure a package_module_name_map entry to override this behaviour. +Assuming the corresponding module name of package 'mypy' is 'mypy'. Install the package or configure a package_module_name_map entry to override this behaviour. +Assuming the corresponding module name of package 'pytest' is 'pytest'. Install the package or configure a package_module_name_map entry to override this behaviour. +Scanning 3 files... + +pyproject.toml: DEP002 'requests' defined as a dependency but not used in the codebase +pyproject.toml: DEP002 'mypy' defined as a dependency but not used in the codebase +pyproject.toml: DEP002 'pytest' defined as a dependency but not used in the codebase +Found 3 dependency issues. + +For more information, see the documentation: https://deptry.com/ +""") @pytest.mark.xdist_group(name=Project.GITIGNORE) def test_cli_gitignore_not_used_when_using_exclude(pip_venv_factory: PipVenvFactory) -> None: with pip_venv_factory(Project.GITIGNORE) as virtual_env: - issue_report = f"{uuid.uuid4()}.json" - # Simulate the fact that the project is a git repository. Path(".git").mkdir(exist_ok=True) - result = virtual_env.run(f"deptry . --exclude build/|src/bar.py -o {issue_report}") + result = virtual_env.run_deptry(". --exclude build/|src/bar\\.py") assert result.returncode == 1 - assert get_issues_report(Path(issue_report)) == [ - { - "error": { - "code": "DEP002", - "message": "'isort' defined as a dependency but not used in the codebase", - }, - "module": "isort", - "location": { - "file": str(Path("pyproject.toml")), - "line": None, - "column": None, - }, - }, - { - "error": { - "code": "DEP002", - "message": "'requests' defined as a dependency but not used in the codebase", - }, - "module": "requests", - "location": { - "file": str(Path("pyproject.toml")), - "line": None, - "column": None, - }, - }, - { - "error": { - "code": "DEP002", - "message": "'pytest' defined as a dependency but not used in the codebase", - }, - "module": "pytest", - "location": { - "file": str(Path("pyproject.toml")), - "line": None, - "column": None, - }, - }, - { - "error": { - "code": "DEP001", - "message": "'hello' imported but missing from the dependency definitions", - }, - "module": "hello", - "location": { - "file": str(Path("src/barfoo.py")), - "line": 1, - "column": 8, - }, - }, - { - "error": { - "code": "DEP001", - "message": "'hej' imported but missing from the dependency definitions", - }, - "module": "hej", - "location": { - "file": str(Path("src/baz.py")), - "line": 1, - "column": 8, - }, - }, - ] + assert result.stderr == snapshot("""\ +Assuming the corresponding module name of package 'black' is 'black'. Install the package or configure a package_module_name_map entry to override this behaviour. +Assuming the corresponding module name of package 'mypy' is 'mypy'. Install the package or configure a package_module_name_map entry to override this behaviour. +Assuming the corresponding module name of package 'pytest' is 'pytest'. Install the package or configure a package_module_name_map entry to override this behaviour. +Scanning 5 files... + +pyproject.toml: DEP002 'isort' defined as a dependency but not used in the codebase +pyproject.toml: DEP002 'requests' defined as a dependency but not used in the codebase +pyproject.toml: DEP002 'pytest' defined as a dependency but not used in the codebase +src/barfoo.py:1:8: DEP001 'hello' imported but missing from the dependency definitions +src/baz.py:1:8: DEP001 'hej' imported but missing from the dependency definitions +Found 5 dependency issues. + +For more information, see the documentation: https://deptry.com/ +""") diff --git a/tests/functional/cli/test_cli_multiple_source_directories.py b/tests/functional/cli/test_cli_multiple_source_directories.py index de60ad96b..1592b385c 100644 --- a/tests/functional/cli/test_cli_multiple_source_directories.py +++ b/tests/functional/cli/test_cli_multiple_source_directories.py @@ -1,13 +1,11 @@ from __future__ import annotations -import uuid -from pathlib import Path from typing import TYPE_CHECKING import pytest +from inline_snapshot import snapshot from tests.functional.utils import Project -from tests.utils import get_issues_report if TYPE_CHECKING: from tests.utils import PipVenvFactory @@ -16,24 +14,16 @@ @pytest.mark.xdist_group(name=Project.MULTIPLE_SOURCE_DIRECTORIES) def test_cli_with_multiple_source_directories(pip_venv_factory: PipVenvFactory) -> None: with pip_venv_factory(Project.MULTIPLE_SOURCE_DIRECTORIES) as virtual_env: - issue_report = f"{uuid.uuid4()}.json" - result = virtual_env.run(f"deptry src worker -o {issue_report}") + result = virtual_env.run_deptry("src worker") assert result.returncode == 1 - assert get_issues_report(Path(issue_report)) == [ - { - "error": {"code": "DEP002", "message": "'arrow' defined as a dependency but not used in the codebase"}, - "module": "arrow", - "location": {"file": str(Path("pyproject.toml")), "line": None, "column": None}, - }, - { - "error": {"code": "DEP001", "message": "'httpx' imported but missing from the dependency definitions"}, - "module": "httpx", - "location": {"file": str(Path("src/foo.py")), "line": 1, "column": 8}, - }, - { - "error": {"code": "DEP001", "message": "'celery' imported but missing from the dependency definitions"}, - "module": "celery", - "location": {"file": str(Path("worker/foo.py")), "line": 1, "column": 8}, - }, - ] + assert result.stderr == snapshot("""\ +Scanning 6 files... + +pyproject.toml: DEP002 'arrow' defined as a dependency but not used in the codebase +src/foo.py:1:8: DEP001 'httpx' imported but missing from the dependency definitions +worker/foo.py:1:8: DEP001 'celery' imported but missing from the dependency definitions +Found 3 dependency issues. + +For more information, see the documentation: https://deptry.com/ +""") diff --git a/tests/functional/cli/test_cli_namespace.py b/tests/functional/cli/test_cli_namespace.py index 27494511d..5c792b341 100644 --- a/tests/functional/cli/test_cli_namespace.py +++ b/tests/functional/cli/test_cli_namespace.py @@ -1,13 +1,11 @@ from __future__ import annotations -import uuid -from pathlib import Path from typing import TYPE_CHECKING import pytest +from inline_snapshot import snapshot from tests.functional.utils import Project -from tests.utils import get_issues_report if TYPE_CHECKING: from tests.utils import PipVenvFactory @@ -16,55 +14,37 @@ @pytest.mark.xdist_group(name=Project.NAMESPACE) def test_cli_with_namespace(pip_venv_factory: PipVenvFactory) -> None: with pip_venv_factory(Project.NAMESPACE) as virtual_env: - issue_report = f"{uuid.uuid4()}.json" - result = virtual_env.run(f"deptry . --experimental-namespace-package -o {issue_report}") + result = virtual_env.run_deptry(". --experimental-namespace-package") assert result.returncode == 1 - assert get_issues_report(Path(issue_report)) == [ - { - "error": {"code": "DEP004", "message": "'flake8' imported but declared as a dev dependency"}, - "module": "flake8", - "location": {"file": str(Path("foo/database/bar.py")), "line": 4, "column": 8}, - }, - { - "error": {"code": "DEP001", "message": "'white' imported but missing from the dependency definitions"}, - "module": "white", - "location": {"file": str(Path("foo/database/bar.py")), "line": 5, "column": 8}, - }, - { - "error": {"code": "DEP002", "message": "'arrow' defined as a dependency but not used in the codebase"}, - "module": "arrow", - "location": {"file": str(Path("pyproject.toml")), "line": None, "column": None}, - }, - ] + assert result.stderr == snapshot("""\ +Assuming the corresponding module name of package 'flake8' is 'flake8'. Install the package or configure a package_module_name_map entry to override this behaviour. +Scanning 2 files... + +foo/database/bar.py:4:8: DEP004 'flake8' imported but declared as a dev dependency +foo/database/bar.py:5:8: DEP001 'white' imported but missing from the dependency definitions +pyproject.toml: DEP002 'arrow' defined as a dependency but not used in the codebase +Found 3 dependency issues. + +For more information, see the documentation: https://deptry.com/ +""") @pytest.mark.xdist_group(name=Project.NAMESPACE) def test_cli_with_namespace_without_experimental_flag(pip_venv_factory: PipVenvFactory) -> None: with pip_venv_factory(Project.NAMESPACE) as virtual_env: - issue_report = f"{uuid.uuid4()}.json" - result = virtual_env.run(f"deptry . -o {issue_report}") + result = virtual_env.run_deptry(".") assert result.returncode == 1 - assert get_issues_report(Path(issue_report)) == [ - { - "error": {"code": "DEP004", "message": "'flake8' imported but declared as a dev dependency"}, - "module": "flake8", - "location": {"file": str(Path("foo/database/bar.py")), "line": 4, "column": 8}, - }, - { - "error": {"code": "DEP001", "message": "'white' imported but missing from the dependency definitions"}, - "module": "white", - "location": {"file": str(Path("foo/database/bar.py")), "line": 5, "column": 8}, - }, - { - "error": {"code": "DEP003", "message": "'foo' imported but it is a transitive dependency"}, - "module": "foo", - "location": {"file": str(Path("foo/database/bar.py")), "line": 7, "column": 1}, - }, - { - "error": {"code": "DEP002", "message": "'arrow' defined as a dependency but not used in the codebase"}, - "module": "arrow", - "location": {"file": str(Path("pyproject.toml")), "line": None, "column": None}, - }, - ] + assert result.stderr == snapshot("""\ +Assuming the corresponding module name of package 'flake8' is 'flake8'. Install the package or configure a package_module_name_map entry to override this behaviour. +Scanning 2 files... + +foo/database/bar.py:4:8: DEP004 'flake8' imported but declared as a dev dependency +foo/database/bar.py:5:8: DEP001 'white' imported but missing from the dependency definitions +foo/database/bar.py:7:1: DEP003 'foo' imported but it is a transitive dependency +pyproject.toml: DEP002 'arrow' defined as a dependency but not used in the codebase +Found 4 dependency issues. + +For more information, see the documentation: https://deptry.com/ +""") diff --git a/tests/functional/cli/test_cli_pdm.py b/tests/functional/cli/test_cli_pdm.py index fcacabc3b..46bdf8085 100644 --- a/tests/functional/cli/test_cli_pdm.py +++ b/tests/functional/cli/test_cli_pdm.py @@ -1,13 +1,11 @@ from __future__ import annotations -import uuid -from pathlib import Path from typing import TYPE_CHECKING import pytest +from inline_snapshot import snapshot from tests.functional.utils import Project -from tests.utils import get_issues_report if TYPE_CHECKING: from tests.utils import PDMVenvFactory @@ -16,117 +14,22 @@ @pytest.mark.xdist_group(name=Project.PDM) def test_cli_with_pdm(pdm_venv_factory: PDMVenvFactory) -> None: with pdm_venv_factory(Project.PDM) as virtual_env: - issue_report = f"{uuid.uuid4()}.json" - result = virtual_env.run(f"deptry . -o {issue_report}") + result = virtual_env.run_deptry(".") assert result.returncode == 1 - assert get_issues_report(Path(issue_report)) == [ - { - "error": { - "code": "DEP002", - "message": "'isort' defined as a dependency but not used in the codebase", - }, - "module": "isort", - "location": { - "file": str(Path("pyproject.toml")), - "line": None, - "column": None, - }, - }, - { - "error": { - "code": "DEP004", - "message": "'black' imported but declared as a dev dependency", - }, - "module": "black", - "location": { - "file": str(Path("src/main.py")), - "line": 4, - "column": 8, - }, - }, - { - "error": { - "code": "DEP004", - "message": "'certifi' imported but declared as a dev dependency", - }, - "module": "certifi", - "location": { - "file": str(Path("src/main.py")), - "line": 5, - "column": 8, - }, - }, - { - "error": { - "code": "DEP004", - "message": "'idna' imported but declared as a dev dependency", - }, - "module": "idna", - "location": { - "file": str(Path("src/main.py")), - "line": 7, - "column": 8, - }, - }, - { - "error": { - "code": "DEP004", - "message": "'mypy' imported but declared as a dev dependency", - }, - "module": "mypy", - "location": { - "file": str(Path("src/main.py")), - "line": 8, - "column": 8, - }, - }, - { - "error": { - "code": "DEP004", - "message": "'packaging' imported but declared as a dev dependency", - }, - "module": "packaging", - "location": { - "file": str(Path("src/main.py")), - "line": 9, - "column": 8, - }, - }, - { - "error": { - "code": "DEP004", - "message": "'pytest' imported but declared as a dev dependency", - }, - "module": "pytest", - "location": { - "file": str(Path("src/main.py")), - "line": 10, - "column": 8, - }, - }, - { - "error": { - "code": "DEP004", - "message": "'pytest_cov' imported but declared as a dev dependency", - }, - "module": "pytest_cov", - "location": { - "file": str(Path("src/main.py")), - "line": 11, - "column": 8, - }, - }, - { - "error": { - "code": "DEP001", - "message": "'white' imported but missing from the dependency definitions", - }, - "module": "white", - "location": { - "file": str(Path("src/main.py")), - "line": 12, - "column": 8, - }, - }, - ] + assert result.stderr == snapshot("""\ +Scanning 2 files... + +pyproject.toml: DEP002 'isort' defined as a dependency but not used in the codebase +src/main.py:4:8: DEP004 'black' imported but declared as a dev dependency +src/main.py:5:8: DEP004 'certifi' imported but declared as a dev dependency +src/main.py:7:8: DEP004 'idna' imported but declared as a dev dependency +src/main.py:8:8: DEP004 'mypy' imported but declared as a dev dependency +src/main.py:9:8: DEP004 'packaging' imported but declared as a dev dependency +src/main.py:10:8: DEP004 'pytest' imported but declared as a dev dependency +src/main.py:11:8: DEP004 'pytest_cov' imported but declared as a dev dependency +src/main.py:12:8: DEP001 'white' imported but missing from the dependency definitions +Found 9 dependency issues. + +For more information, see the documentation: https://deptry.com/ +""") diff --git a/tests/functional/cli/test_cli_pep_621.py b/tests/functional/cli/test_cli_pep_621.py index 4e761b594..6853d47b4 100644 --- a/tests/functional/cli/test_cli_pep_621.py +++ b/tests/functional/cli/test_cli_pep_621.py @@ -1,13 +1,11 @@ from __future__ import annotations -import uuid -from pathlib import Path from typing import TYPE_CHECKING import pytest +from inline_snapshot import snapshot from tests.functional.utils import Project -from tests.utils import get_issues_report if TYPE_CHECKING: from tests.utils import PipVenvFactory @@ -16,68 +14,27 @@ @pytest.mark.xdist_group(name=Project.PEP_621) def test_cli_with_pep_621(pip_venv_factory: PipVenvFactory) -> None: with pip_venv_factory(Project.PEP_621) as virtual_env: - issue_report = f"{uuid.uuid4()}.json" - result = virtual_env.run(f"deptry . -o {issue_report}") + result = virtual_env.run_deptry(".") assert result.returncode == 1 - assert get_issues_report(Path(issue_report)) == [ - { - "error": {"code": "DEP002", "message": "'isort' defined as a dependency but not used in the codebase"}, - "module": "isort", - "location": {"file": str(Path("pyproject.toml")), "line": None, "column": None}, - }, - { - "error": { - "code": "DEP002", - "message": "'requests' defined as a dependency but not used in the codebase", - }, - "module": "requests", - "location": {"file": str(Path("pyproject.toml")), "line": None, "column": None}, - }, - { - "error": {"code": "DEP002", "message": "'pytest' defined as a dependency but not used in the codebase"}, - "module": "pytest", - "location": {"file": str(Path("pyproject.toml")), "line": None, "column": None}, - }, - { - "error": { - "code": "DEP002", - "message": "'matplotlib' defined as a dependency but not used in the codebase", - }, - "module": "matplotlib", - "location": {"file": str(Path("pyproject.toml")), "line": None, "column": None}, - }, - { - "error": { - "code": "DEP005", - "message": "'asyncio' is defined as a dependency but it is included in the Python standard library.", - }, - "module": "asyncio", - "location": {"file": "pyproject.toml", "line": None, "column": None}, - }, - { - "error": {"code": "DEP004", "message": "'black' imported but declared as a dev dependency"}, - "module": "black", - "location": {"file": str(Path("src/main.py")), "line": 5, "column": 8}, - }, - { - "error": {"code": "DEP004", "message": "'certifi' imported but declared as a dev dependency"}, - "module": "certifi", - "location": {"file": str(Path("src/main.py")), "line": 6, "column": 8}, - }, - { - "error": {"code": "DEP004", "message": "'idna' imported but declared as a dev dependency"}, - "module": "idna", - "location": {"file": str(Path("src/main.py")), "line": 8, "column": 8}, - }, - { - "error": {"code": "DEP004", "message": "'packaging' imported but declared as a dev dependency"}, - "module": "packaging", - "location": {"file": str(Path("src/main.py")), "line": 9, "column": 8}, - }, - { - "error": {"code": "DEP001", "message": "'white' imported but missing from the dependency definitions"}, - "module": "white", - "location": {"file": str(Path("src/main.py")), "line": 10, "column": 8}, - }, - ] + assert result.stderr == snapshot("""\ +Assuming the corresponding module name of package 'black' is 'black'. Install the package or configure a package_module_name_map entry to override this behaviour. +Assuming the corresponding module name of package 'mypy' is 'mypy'. Install the package or configure a package_module_name_map entry to override this behaviour. +Assuming the corresponding module name of package 'pytest' is 'pytest'. Install the package or configure a package_module_name_map entry to override this behaviour. +Assuming the corresponding module name of package 'matplotlib' is 'matplotlib'. Install the package or configure a package_module_name_map entry to override this behaviour. +Scanning 2 files... + +pyproject.toml: DEP002 'isort' defined as a dependency but not used in the codebase +pyproject.toml: DEP002 'requests' defined as a dependency but not used in the codebase +pyproject.toml: DEP002 'pytest' defined as a dependency but not used in the codebase +pyproject.toml: DEP002 'matplotlib' defined as a dependency but not used in the codebase +pyproject.toml: DEP005 'asyncio' is defined as a dependency but it is included in the Python standard library. +src/main.py:5:8: DEP004 'black' imported but declared as a dev dependency +src/main.py:6:8: DEP004 'certifi' imported but declared as a dev dependency +src/main.py:8:8: DEP004 'idna' imported but declared as a dev dependency +src/main.py:9:8: DEP004 'packaging' imported but declared as a dev dependency +src/main.py:10:8: DEP001 'white' imported but missing from the dependency definitions +Found 10 dependency issues. + +For more information, see the documentation: https://deptry.com/ +""") diff --git a/tests/functional/cli/test_cli_poetry.py b/tests/functional/cli/test_cli_poetry.py index 145f49833..76b04cabd 100644 --- a/tests/functional/cli/test_cli_poetry.py +++ b/tests/functional/cli/test_cli_poetry.py @@ -1,13 +1,11 @@ from __future__ import annotations -import uuid -from pathlib import Path from typing import TYPE_CHECKING import pytest +from inline_snapshot import snapshot from tests.functional.utils import Project -from tests.utils import get_issues_report if TYPE_CHECKING: from tests.utils import PoetryVenvFactory @@ -16,93 +14,22 @@ @pytest.mark.xdist_group(name=Project.POETRY) def test_cli_with_poetry(poetry_venv_factory: PoetryVenvFactory) -> None: with poetry_venv_factory(Project.POETRY) as virtual_env: - issue_report = f"{uuid.uuid4()}.json" - result = virtual_env.run(f"deptry . -o {issue_report}") + result = virtual_env.run_deptry(".") assert result.returncode == 1 - assert get_issues_report(Path(issue_report)) == [ - { - "error": { - "code": "DEP002", - "message": "'isort' defined as a dependency but not used in the codebase", - }, - "module": "isort", - "location": { - "file": str(Path("pyproject.toml")), - "line": None, - "column": None, - }, - }, - { - "error": { - "code": "DEP002", - "message": "'requests' defined as a dependency but not used in the codebase", - }, - "module": "requests", - "location": { - "file": str(Path("pyproject.toml")), - "line": None, - "column": None, - }, - }, - { - "error": { - "code": "DEP004", - "message": "'black' imported but declared as a dev dependency", - }, - "module": "black", - "location": { - "file": str(Path("src/main.py")), - "line": 4, - "column": 8, - }, - }, - { - "error": { - "code": "DEP004", - "message": "'mypy' imported but declared as a dev dependency", - }, - "module": "mypy", - "location": { - "file": str(Path("src/main.py")), - "line": 6, - "column": 8, - }, - }, - { - "error": { - "code": "DEP004", - "message": "'pytest' imported but declared as a dev dependency", - }, - "module": "pytest", - "location": { - "file": str(Path("src/main.py")), - "line": 7, - "column": 8, - }, - }, - { - "error": { - "code": "DEP004", - "message": "'pytest_cov' imported but declared as a dev dependency", - }, - "module": "pytest_cov", - "location": { - "file": str(Path("src/main.py")), - "line": 8, - "column": 8, - }, - }, - { - "error": { - "code": "DEP001", - "message": "'white' imported but missing from the dependency definitions", - }, - "module": "white", - "location": { - "file": str(Path("src/main.py")), - "line": 9, - "column": 8, - }, - }, - ] + assert result.stderr == snapshot("""\ +Assuming the corresponding module name of package 'isort' is 'isort'. Install the package or configure a package_module_name_map entry to override this behaviour. +Assuming the corresponding module name of package 'requests' is 'requests'. Install the package or configure a package_module_name_map entry to override this behaviour. +Scanning 2 files... + +pyproject.toml: DEP002 'isort' defined as a dependency but not used in the codebase +pyproject.toml: DEP002 'requests' defined as a dependency but not used in the codebase +src/main.py:4:8: DEP004 'black' imported but declared as a dev dependency +src/main.py:6:8: DEP004 'mypy' imported but declared as a dev dependency +src/main.py:7:8: DEP004 'pytest' imported but declared as a dev dependency +src/main.py:8:8: DEP004 'pytest_cov' imported but declared as a dev dependency +src/main.py:9:8: DEP001 'white' imported but missing from the dependency definitions +Found 7 dependency issues. + +For more information, see the documentation: https://deptry.com/ +""") diff --git a/tests/functional/cli/test_cli_poetry_pep_621.py b/tests/functional/cli/test_cli_poetry_pep_621.py index f06aadf52..87a35aad0 100644 --- a/tests/functional/cli/test_cli_poetry_pep_621.py +++ b/tests/functional/cli/test_cli_poetry_pep_621.py @@ -1,13 +1,11 @@ from __future__ import annotations -import uuid -from pathlib import Path from typing import TYPE_CHECKING import pytest +from inline_snapshot import snapshot from tests.functional.utils import Project -from tests.utils import get_issues_report if TYPE_CHECKING: from tests.utils import PoetryVenvFactory @@ -16,93 +14,21 @@ @pytest.mark.xdist_group(name=Project.POETRY_PEP_621) def test_cli_with_poetry_pep_621(poetry_venv_factory: PoetryVenvFactory) -> None: with poetry_venv_factory(Project.POETRY_PEP_621) as virtual_env: - issue_report = f"{uuid.uuid4()}.json" - result = virtual_env.run(f"deptry . -o {issue_report}") + result = virtual_env.run_deptry(".") assert result.returncode == 1 - assert get_issues_report(Path(issue_report)) == [ - { - "error": { - "code": "DEP002", - "message": "'requests' defined as a dependency but not used in the codebase", - }, - "module": "requests", - "location": { - "file": str(Path("pyproject.toml")), - "line": None, - "column": None, - }, - }, - { - "error": { - "code": "DEP002", - "message": "'isort' defined as a dependency but not used in the codebase", - }, - "module": "isort", - "location": { - "file": str(Path("pyproject.toml")), - "line": None, - "column": None, - }, - }, - { - "error": { - "code": "DEP004", - "message": "'black' imported but declared as a dev dependency", - }, - "module": "black", - "location": { - "file": str(Path("src/main.py")), - "line": 4, - "column": 8, - }, - }, - { - "error": { - "code": "DEP004", - "message": "'mypy' imported but declared as a dev dependency", - }, - "module": "mypy", - "location": { - "file": str(Path("src/main.py")), - "line": 6, - "column": 8, - }, - }, - { - "error": { - "code": "DEP004", - "message": "'pytest' imported but declared as a dev dependency", - }, - "module": "pytest", - "location": { - "file": str(Path("src/main.py")), - "line": 7, - "column": 8, - }, - }, - { - "error": { - "code": "DEP004", - "message": "'pytest_cov' imported but declared as a dev dependency", - }, - "module": "pytest_cov", - "location": { - "file": str(Path("src/main.py")), - "line": 8, - "column": 8, - }, - }, - { - "error": { - "code": "DEP001", - "message": "'white' imported but missing from the dependency definitions", - }, - "module": "white", - "location": { - "file": str(Path("src/main.py")), - "line": 9, - "column": 8, - }, - }, - ] + assert result.stderr == snapshot("""\ +Assuming the corresponding module name of package 'isort' is 'isort'. Install the package or configure a package_module_name_map entry to override this behaviour. +Scanning 2 files... + +pyproject.toml: DEP002 'requests' defined as a dependency but not used in the codebase +pyproject.toml: DEP002 'isort' defined as a dependency but not used in the codebase +src/main.py:4:8: DEP004 'black' imported but declared as a dev dependency +src/main.py:6:8: DEP004 'mypy' imported but declared as a dev dependency +src/main.py:7:8: DEP004 'pytest' imported but declared as a dev dependency +src/main.py:8:8: DEP004 'pytest_cov' imported but declared as a dev dependency +src/main.py:9:8: DEP001 'white' imported but missing from the dependency definitions +Found 7 dependency issues. + +For more information, see the documentation: https://deptry.com/ +""") diff --git a/tests/functional/cli/test_cli_pyproject_different_directory.py b/tests/functional/cli/test_cli_pyproject_different_directory.py index f8e438b14..09894307d 100644 --- a/tests/functional/cli/test_cli_pyproject_different_directory.py +++ b/tests/functional/cli/test_cli_pyproject_different_directory.py @@ -1,13 +1,11 @@ from __future__ import annotations -import uuid -from pathlib import Path from typing import TYPE_CHECKING import pytest +from inline_snapshot import snapshot from tests.functional.utils import Project -from tests.utils import get_issues_report if TYPE_CHECKING: from tests.utils import PipVenvFactory @@ -18,69 +16,21 @@ def test_cli_with_pyproject_different_directory(pip_venv_factory: PipVenvFactory with pip_venv_factory( Project.PYPROJECT_DIFFERENT_DIRECTORY, install_command="pip install ./a_sub_directory" ) as virtual_env: - issue_report = f"{uuid.uuid4()}.json" - result = virtual_env.run(f"deptry src --config a_sub_directory/pyproject.toml -o {issue_report}") + result = virtual_env.run_deptry("src --config a_sub_directory/pyproject.toml") assert result.returncode == 1 - assert get_issues_report(Path(issue_report)) == [ - { - "error": { - "code": "DEP002", - "message": "'isort' defined as a dependency but not used in the codebase", - }, - "module": "isort", - "location": { - "file": str(Path("a_sub_directory/pyproject.toml")), - "line": None, - "column": None, - }, - }, - { - "error": { - "code": "DEP002", - "message": "'requests' defined as a dependency but not used in the codebase", - }, - "module": "requests", - "location": { - "file": str(Path("a_sub_directory/pyproject.toml")), - "line": None, - "column": None, - }, - }, - { - "error": { - "code": "DEP002", - "message": "'mypy' defined as a dependency but not used in the codebase", - }, - "module": "mypy", - "location": { - "file": str(Path("a_sub_directory/pyproject.toml")), - "line": None, - "column": None, - }, - }, - { - "error": { - "code": "DEP002", - "message": "'pytest' defined as a dependency but not used in the codebase", - }, - "module": "pytest", - "location": { - "file": str(Path("a_sub_directory/pyproject.toml")), - "line": None, - "column": None, - }, - }, - { - "error": { - "code": "DEP001", - "message": "'white' imported but missing from the dependency definitions", - }, - "module": "white", - "location": { - "file": str(Path("src/src_directory/foo.py")), - "line": 6, - "column": 8, - }, - }, - ] + assert result.stderr == snapshot("""\ +Assuming the corresponding module name of package 'black' is 'black'. Install the package or configure a package_module_name_map entry to override this behaviour. +Assuming the corresponding module name of package 'mypy' is 'mypy'. Install the package or configure a package_module_name_map entry to override this behaviour. +Assuming the corresponding module name of package 'pytest' is 'pytest'. Install the package or configure a package_module_name_map entry to override this behaviour. +Scanning 4 files... + +a_sub_directory/pyproject.toml: DEP002 'isort' defined as a dependency but not used in the codebase +a_sub_directory/pyproject.toml: DEP002 'requests' defined as a dependency but not used in the codebase +a_sub_directory/pyproject.toml: DEP002 'mypy' defined as a dependency but not used in the codebase +a_sub_directory/pyproject.toml: DEP002 'pytest' defined as a dependency but not used in the codebase +src/src_directory/foo.py:6:8: DEP001 'white' imported but missing from the dependency definitions +Found 5 dependency issues. + +For more information, see the documentation: https://deptry.com/ +""") diff --git a/tests/functional/cli/test_cli_requirements_in.py b/tests/functional/cli/test_cli_requirements_in.py index a73f30561..623ed96ad 100644 --- a/tests/functional/cli/test_cli_requirements_in.py +++ b/tests/functional/cli/test_cli_requirements_in.py @@ -1,13 +1,12 @@ from __future__ import annotations import uuid -from pathlib import Path from typing import TYPE_CHECKING import pytest +from inline_snapshot import snapshot from tests.functional.utils import Project -from tests.utils import get_issues_report if TYPE_CHECKING: from tests.utils import PipVenvFactory @@ -23,50 +22,24 @@ def test_cli_single_requirements_files(pip_venv_factory: PipVenvFactory) -> None Project.REQUIREMENTS_IN, install_command=("pip install -r requirements.txt -r requirements-dev.txt"), ) as virtual_env: - issue_report = f"{uuid.uuid4()}.json" - result = virtual_env.run(f"deptry . -o {issue_report}") + result = virtual_env.run_deptry(".") assert result.returncode == 1 - assert get_issues_report(Path(issue_report)) == [ - { - "error": {"code": "DEP002", "message": "'isort' defined as a dependency but not used in the codebase"}, - "module": "isort", - "location": {"file": str(Path("requirements.in")), "line": None, "column": None}, - }, - { - "error": { - "code": "DEP002", - "message": "'uvicorn' defined as a dependency but not used in the codebase", - }, - "module": "uvicorn", - "location": {"file": str(Path("requirements.in")), "line": None, "column": None}, - }, - { - "error": {"code": "DEP004", "message": "'black' imported but declared as a dev dependency"}, - "module": "black", - "location": {"file": str(Path("src/main.py")), "line": 4, "column": 8}, - }, - { - "error": {"code": "DEP003", "message": "'h11' imported but it is a transitive dependency"}, - "module": "h11", - "location": {"file": str(Path("src/main.py")), "line": 6, "column": 8}, - }, - { - "error": {"code": "DEP001", "message": "'white' imported but missing from the dependency definitions"}, - "module": "white", - "location": {"file": str(Path("src/main.py")), "line": 7, "column": 8}, - }, - { - "error": {"code": "DEP003", "message": "'bs4' imported but it is a transitive dependency"}, - "module": "bs4", - "location": {"file": str(Path("src/main.py")), "line": 9, "column": 8}, - }, - { - "error": {"code": "DEP001", "message": "'arrow' imported but missing from the dependency definitions"}, - "module": "arrow", - "location": {"file": str(Path("src/notebook.ipynb")), "line": 3, "column": 8}, - }, - ] + assert result.stderr == snapshot("""\ +Detected a 'requirements.in' file in the project and no 'requirements-files' were explicitly specified. Automatically using 'requirements.in' as the source for the project's dependencies. To specify a different source for the project's dependencies, use the '--requirements-files' option. +Scanning 2 files... + +requirements.in: DEP002 'isort' defined as a dependency but not used in the codebase +requirements.in: DEP002 'uvicorn' defined as a dependency but not used in the codebase +src/main.py:4:8: DEP004 'black' imported but declared as a dev dependency +src/main.py:6:8: DEP003 'h11' imported but it is a transitive dependency +src/main.py:7:8: DEP001 'white' imported but missing from the dependency definitions +src/main.py:9:8: DEP003 'bs4' imported but it is a transitive dependency +src/notebook.ipynb:3:8: DEP001 'arrow' imported but missing from the dependency definitions +Found 7 dependency issues. + +For more information, see the documentation: https://deptry.com/ +""") @pytest.mark.xdist_group(name=Project.REQUIREMENTS_IN) @@ -81,83 +54,25 @@ def test_cli_multiple_requirements_files(pip_venv_factory: PipVenvFactory) -> No install_command=("pip install -r requirements.txt -r requirements-dev.txt"), ) as virtual_env: issue_report = f"{uuid.uuid4()}.json" - result = virtual_env.run(f"deptry . --requirements-files requirements.txt -o {issue_report}") + result = virtual_env.run_deptry(f". --requirements-files requirements.txt -o {issue_report}") assert result.returncode == 1 - assert get_issues_report(Path(issue_report)) == [ - { - "error": {"code": "DEP002", "message": "'args' defined as a dependency but not used in the codebase"}, - "module": "args", - "location": {"file": str(Path("requirements.txt")), "line": None, "column": None}, - }, - { - "error": { - "code": "DEP002", - "message": "'certifi' defined as a dependency but not used in the codebase", - }, - "module": "certifi", - "location": {"file": str(Path("requirements.txt")), "line": None, "column": None}, - }, - { - "error": { - "code": "DEP002", - "message": "'charset-normalizer' defined as a dependency but not used in the codebase", - }, - "module": "charset-normalizer", - "location": {"file": str(Path("requirements.txt")), "line": None, "column": None}, - }, - { - "error": {"code": "DEP002", "message": "'clint' defined as a dependency but not used in the codebase"}, - "module": "clint", - "location": {"file": str(Path("requirements.txt")), "line": None, "column": None}, - }, - { - "error": {"code": "DEP002", "message": "'idna' defined as a dependency but not used in the codebase"}, - "module": "idna", - "location": {"file": str(Path("requirements.txt")), "line": None, "column": None}, - }, - { - "error": {"code": "DEP002", "message": "'isort' defined as a dependency but not used in the codebase"}, - "module": "isort", - "location": {"file": str(Path("requirements.txt")), "line": None, "column": None}, - }, - { - "error": { - "code": "DEP002", - "message": "'requests' defined as a dependency but not used in the codebase", - }, - "module": "requests", - "location": {"file": str(Path("requirements.txt")), "line": None, "column": None}, - }, - { - "error": { - "code": "DEP002", - "message": "'soupsieve' defined as a dependency but not used in the codebase", - }, - "module": "soupsieve", - "location": {"file": "requirements.txt", "line": None, "column": None}, - }, - { - "error": { - "code": "DEP002", - "message": "'uvicorn' defined as a dependency but not used in the codebase", - }, - "module": "uvicorn", - "location": {"file": str(Path("requirements.txt")), "line": None, "column": None}, - }, - { - "error": {"code": "DEP004", "message": "'black' imported but declared as a dev dependency"}, - "module": "black", - "location": {"file": str(Path("src/main.py")), "line": 4, "column": 8}, - }, - { - "error": {"code": "DEP001", "message": "'white' imported but missing from the dependency definitions"}, - "module": "white", - "location": {"file": str(Path("src/main.py")), "line": 7, "column": 8}, - }, - { - "error": {"code": "DEP001", "message": "'arrow' imported but missing from the dependency definitions"}, - "module": "arrow", - "location": {"file": str(Path("src/notebook.ipynb")), "line": 3, "column": 8}, - }, - ] + assert result.stderr == snapshot("""\ +Scanning 2 files... + +requirements.txt: DEP002 'args' defined as a dependency but not used in the codebase +requirements.txt: DEP002 'certifi' defined as a dependency but not used in the codebase +requirements.txt: DEP002 'charset-normalizer' defined as a dependency but not used in the codebase +requirements.txt: DEP002 'clint' defined as a dependency but not used in the codebase +requirements.txt: DEP002 'idna' defined as a dependency but not used in the codebase +requirements.txt: DEP002 'isort' defined as a dependency but not used in the codebase +requirements.txt: DEP002 'requests' defined as a dependency but not used in the codebase +requirements.txt: DEP002 'soupsieve' defined as a dependency but not used in the codebase +requirements.txt: DEP002 'uvicorn' defined as a dependency but not used in the codebase +src/main.py:4:8: DEP004 'black' imported but declared as a dev dependency +src/main.py:7:8: DEP001 'white' imported but missing from the dependency definitions +src/notebook.ipynb:3:8: DEP001 'arrow' imported but missing from the dependency definitions +Found 12 dependency issues. + +For more information, see the documentation: https://deptry.com/ +""") diff --git a/tests/functional/cli/test_cli_requirements_txt.py b/tests/functional/cli/test_cli_requirements_txt.py index 55e0fef95..262e0d916 100644 --- a/tests/functional/cli/test_cli_requirements_txt.py +++ b/tests/functional/cli/test_cli_requirements_txt.py @@ -1,13 +1,11 @@ from __future__ import annotations -import uuid -from pathlib import Path from typing import TYPE_CHECKING import pytest +from inline_snapshot import snapshot from tests.functional.utils import Project -from tests.utils import get_issues_report if TYPE_CHECKING: from tests.utils import PipVenvFactory @@ -21,87 +19,24 @@ def test_cli_single_requirements_files(pip_venv_factory: PipVenvFactory) -> None "pip install -r requirements.txt -r requirements-dev.txt -r requirements-2.txt -r requirements-typing.txt" ), ) as virtual_env: - issue_report = f"{uuid.uuid4()}.json" - result = virtual_env.run( - "deptry . --requirements-files requirements.txt --requirements-files-dev requirements-dev.txt -o" - f" {issue_report}" + result = virtual_env.run_deptry( + ". --requirements-files requirements.txt --requirements-files-dev requirements-dev.txt" ) assert result.returncode == 1 - assert get_issues_report(Path(issue_report)) == [ - { - "error": { - "code": "DEP002", - "message": "'isort' defined as a dependency but not used in the codebase", - }, - "module": "isort", - "location": { - "file": str(Path("requirements.txt")), - "line": None, - "column": None, - }, - }, - { - "error": { - "code": "DEP002", - "message": "'requests' defined as a dependency but not used in the codebase", - }, - "module": "requests", - "location": { - "file": str(Path("requirements.txt")), - "line": None, - "column": None, - }, - }, - { - "error": { - "code": "DEP004", - "message": "'black' imported but declared as a dev dependency", - }, - "module": "black", - "location": { - "file": str(Path("src/main.py")), - "line": 4, - "column": 8, - }, - }, - { - "error": { - "code": "DEP001", - "message": "'white' imported but missing from the dependency definitions", - }, - "module": "white", - "location": { - "file": str(Path("src/main.py")), - "line": 6, - "column": 8, - }, - }, - { - "error": { - "code": "DEP003", - "message": "'urllib3' imported but it is a transitive dependency", - }, - "module": "urllib3", - "location": { - "file": str(Path("src/main.py")), - "line": 7, - "column": 1, - }, - }, - { - "error": { - "code": "DEP003", - "message": "'urllib3' imported but it is a transitive dependency", - }, - "module": "urllib3", - "location": { - "file": str(Path("src/notebook.ipynb")), - "line": 2, - "column": 1, - }, - }, - ] + assert result.stderr == snapshot("""\ +Scanning 2 files... + +requirements.txt: DEP002 'isort' defined as a dependency but not used in the codebase +requirements.txt: DEP002 'requests' defined as a dependency but not used in the codebase +src/main.py:4:8: DEP004 'black' imported but declared as a dev dependency +src/main.py:6:8: DEP001 'white' imported but missing from the dependency definitions +src/main.py:7:1: DEP003 'urllib3' imported but it is a transitive dependency +src/notebook.ipynb:2:1: DEP003 'urllib3' imported but it is a transitive dependency +Found 6 dependency issues. + +For more information, see the documentation: https://deptry.com/ +""") @pytest.mark.xdist_group(name=Project.REQUIREMENTS_TXT) @@ -112,60 +47,19 @@ def test_cli_multiple_requirements_files(pip_venv_factory: PipVenvFactory) -> No "pip install -r requirements.txt -r requirements-dev.txt -r requirements-2.txt -r requirements-typing.txt" ), ) as virtual_env: - issue_report = f"{uuid.uuid4()}.json" - result = virtual_env.run( - "deptry . --requirements-files requirements.txt,requirements-2.txt --requirements-files-dev" - f" requirements-dev.txt -o {issue_report}" + result = virtual_env.run_deptry( + ". --requirements-files requirements.txt,requirements-2.txt --requirements-files-dev requirements-dev.txt" ) assert result.returncode == 1 - assert get_issues_report(Path(issue_report)) == [ - { - "error": { - "code": "DEP002", - "message": "'isort' defined as a dependency but not used in the codebase", - }, - "module": "isort", - "location": { - "file": str(Path("requirements.txt")), - "line": None, - "column": None, - }, - }, - { - "error": { - "code": "DEP002", - "message": "'requests' defined as a dependency but not used in the codebase", - }, - "module": "requests", - "location": { - "file": str(Path("requirements.txt")), - "line": None, - "column": None, - }, - }, - { - "error": { - "code": "DEP004", - "message": "'black' imported but declared as a dev dependency", - }, - "module": "black", - "location": { - "file": str(Path("src/main.py")), - "line": 4, - "column": 8, - }, - }, - { - "error": { - "code": "DEP001", - "message": "'white' imported but missing from the dependency definitions", - }, - "module": "white", - "location": { - "file": str(Path("src/main.py")), - "line": 6, - "column": 8, - }, - }, - ] + assert result.stderr == snapshot("""\ +Scanning 2 files... + +requirements.txt: DEP002 'isort' defined as a dependency but not used in the codebase +requirements.txt: DEP002 'requests' defined as a dependency but not used in the codebase +src/main.py:4:8: DEP004 'black' imported but declared as a dev dependency +src/main.py:6:8: DEP001 'white' imported but missing from the dependency definitions +Found 4 dependency issues. + +For more information, see the documentation: https://deptry.com/ +""") diff --git a/tests/functional/cli/test_cli_setuptools_dynamic_dependencies.py b/tests/functional/cli/test_cli_setuptools_dynamic_dependencies.py index 3553960cc..a140402db 100644 --- a/tests/functional/cli/test_cli_setuptools_dynamic_dependencies.py +++ b/tests/functional/cli/test_cli_setuptools_dynamic_dependencies.py @@ -1,13 +1,11 @@ from __future__ import annotations -import uuid -from pathlib import Path from typing import TYPE_CHECKING import pytest +from inline_snapshot import snapshot from tests.functional.utils import Project -from tests.utils import get_issues_report if TYPE_CHECKING: from tests.utils import PipVenvFactory @@ -19,93 +17,20 @@ def test_cli_setuptools_dynamic_dependencies(pip_venv_factory: PipVenvFactory) - Project.SETUPTOOLS_DYNAMIC_DEPENDENCIES, install_command="pip install -r requirements.txt -r requirements-2.txt -r cli-requirements.txt -r dev-requirements.txt", ) as virtual_env: - issue_report = f"{uuid.uuid4()}.json" - result = virtual_env.run(f"deptry . -o {issue_report}") + result = virtual_env.run_deptry(".") assert result.returncode == 1 - assert get_issues_report(Path(issue_report)) == [ - { - "error": { - "code": "DEP002", - "message": "'packaging' defined as a dependency but not used in the codebase", - }, - "module": "packaging", - "location": { - "file": "requirements-2.txt", - "line": None, - "column": None, - }, - }, - { - "error": { - "code": "DEP002", - "message": "'pkginfo' defined as a dependency but not used in the codebase", - }, - "module": "pkginfo", - "location": { - "file": str(Path("requirements.txt")), - "line": None, - "column": None, - }, - }, - { - "error": { - "code": "DEP002", - "message": "'requests' defined as a dependency but not used in the codebase", - }, - "module": "requests", - "location": { - "file": str(Path("requirements.txt")), - "line": None, - "column": None, - }, - }, - { - "error": { - "code": "DEP004", - "message": "'isort' imported but declared as a dev dependency", - }, - "module": "isort", - "location": { - "file": str(Path("src/main.py")), - "line": 5, - "column": 8, - }, - }, - { - "error": { - "code": "DEP001", - "message": "'white' imported but missing from the dependency definitions", - }, - "module": "white", - "location": { - "file": str(Path("src/main.py")), - "line": 6, - "column": 8, - }, - }, - { - "error": { - "code": "DEP003", - "message": "'urllib3' imported but it is a transitive dependency", - }, - "module": "urllib3", - "location": { - "file": str(Path("src/main.py")), - "line": 7, - "column": 1, - }, - }, - { - "error": { - "code": "DEP003", - "message": "'urllib3' imported but it is a transitive dependency", - }, - "module": "urllib3", - "location": { - "file": str(Path("src/notebook.ipynb")), - "line": 2, - "column": 1, - }, - }, - ] + assert result.stderr == snapshot("""\ +Scanning 2 files... + +requirements-2.txt: DEP002 'packaging' defined as a dependency but not used in the codebase +requirements.txt: DEP002 'pkginfo' defined as a dependency but not used in the codebase +requirements.txt: DEP002 'requests' defined as a dependency but not used in the codebase +src/main.py:5:8: DEP004 'isort' imported but declared as a dev dependency +src/main.py:6:8: DEP001 'white' imported but missing from the dependency definitions +src/main.py:7:1: DEP003 'urllib3' imported but it is a transitive dependency +src/notebook.ipynb:2:1: DEP003 'urllib3' imported but it is a transitive dependency +Found 7 dependency issues. + +For more information, see the documentation: https://deptry.com/ +""") diff --git a/tests/functional/cli/test_cli_src_directory.py b/tests/functional/cli/test_cli_src_directory.py index d22a10a04..86a6d2d74 100644 --- a/tests/functional/cli/test_cli_src_directory.py +++ b/tests/functional/cli/test_cli_src_directory.py @@ -1,13 +1,11 @@ from __future__ import annotations -import uuid -from pathlib import Path from typing import TYPE_CHECKING import pytest +from inline_snapshot import snapshot from tests.functional.utils import Project -from tests.utils import get_issues_report if TYPE_CHECKING: from tests.utils import PipVenvFactory @@ -16,81 +14,22 @@ @pytest.mark.xdist_group(name=Project.SRC_DIRECTORY) def test_cli_with_src_directory(pip_venv_factory: PipVenvFactory) -> None: with pip_venv_factory(Project.SRC_DIRECTORY) as virtual_env: - issue_report = f"{uuid.uuid4()}.json" - result = virtual_env.run(f"deptry src -o {issue_report}") + result = virtual_env.run_deptry("src") assert result.returncode == 1 - assert get_issues_report(Path(issue_report)) == [ - { - "error": { - "code": "DEP002", - "message": "'isort' defined as a dependency but not used in the codebase", - }, - "module": "isort", - "location": { - "file": str(Path("pyproject.toml")), - "line": None, - "column": None, - }, - }, - { - "error": { - "code": "DEP002", - "message": "'requests' defined as a dependency but not used in the codebase", - }, - "module": "requests", - "location": { - "file": str(Path("pyproject.toml")), - "line": None, - "column": None, - }, - }, - { - "error": { - "code": "DEP002", - "message": "'mypy' defined as a dependency but not used in the codebase", - }, - "module": "mypy", - "location": { - "file": str(Path("pyproject.toml")), - "line": None, - "column": None, - }, - }, - { - "error": { - "code": "DEP002", - "message": "'pytest' defined as a dependency but not used in the codebase", - }, - "module": "pytest", - "location": { - "file": str(Path("pyproject.toml")), - "line": None, - "column": None, - }, - }, - { - "error": { - "code": "DEP001", - "message": "'httpx' imported but missing from the dependency definitions", - }, - "module": "httpx", - "location": { - "file": str(Path("src/foobar.py")), - "line": 1, - "column": 8, - }, - }, - { - "error": { - "code": "DEP001", - "message": "'white' imported but missing from the dependency definitions", - }, - "module": "white", - "location": { - "file": str(Path("src/src_directory/foo.py")), - "line": 6, - "column": 8, - }, - }, - ] + assert result.stderr == snapshot("""\ +Assuming the corresponding module name of package 'black' is 'black'. Install the package or configure a package_module_name_map entry to override this behaviour. +Assuming the corresponding module name of package 'mypy' is 'mypy'. Install the package or configure a package_module_name_map entry to override this behaviour. +Assuming the corresponding module name of package 'pytest' is 'pytest'. Install the package or configure a package_module_name_map entry to override this behaviour. +Scanning 5 files... + +pyproject.toml: DEP002 'isort' defined as a dependency but not used in the codebase +pyproject.toml: DEP002 'requests' defined as a dependency but not used in the codebase +pyproject.toml: DEP002 'mypy' defined as a dependency but not used in the codebase +pyproject.toml: DEP002 'pytest' defined as a dependency but not used in the codebase +src/foobar.py:1:8: DEP001 'httpx' imported but missing from the dependency definitions +src/src_directory/foo.py:6:8: DEP001 'white' imported but missing from the dependency definitions +Found 6 dependency issues. + +For more information, see the documentation: https://deptry.com/ +""") diff --git a/tests/functional/cli/test_cli_uv.py b/tests/functional/cli/test_cli_uv.py index f2dadd516..a060aeaf7 100644 --- a/tests/functional/cli/test_cli_uv.py +++ b/tests/functional/cli/test_cli_uv.py @@ -1,13 +1,11 @@ from __future__ import annotations -import uuid -from pathlib import Path from typing import TYPE_CHECKING import pytest +from inline_snapshot import snapshot from tests.functional.utils import Project -from tests.utils import get_issues_report if TYPE_CHECKING: from tests.utils import UvVenvFactory @@ -16,117 +14,33 @@ @pytest.mark.xdist_group(name=Project.UV) def test_cli_with_uv(uv_venv_factory: UvVenvFactory) -> None: with uv_venv_factory(Project.UV) as virtual_env: - issue_report = f"{uuid.uuid4()}.json" - result = virtual_env.run(f"deptry . -o {issue_report}") + result = virtual_env.run_deptry(".") assert result.returncode == 1 - assert get_issues_report(Path(issue_report)) == [ - { - "error": { - "code": "DEP002", - "message": "'isort' defined as a dependency but not used in the codebase", - }, - "module": "isort", - "location": { - "file": str(Path("pyproject.toml")), - "line": None, - "column": None, - }, - }, - { - "error": { - "code": "DEP004", - "message": "'black' imported but declared as a dev dependency", - }, - "module": "black", - "location": { - "file": str(Path("src/main.py")), - "line": 4, - "column": 8, - }, - }, - { - "error": { - "code": "DEP004", - "message": "'certifi' imported but declared as a dev dependency", - }, - "module": "certifi", - "location": { - "file": str(Path("src/main.py")), - "line": 5, - "column": 8, - }, - }, - { - "error": { - "code": "DEP004", - "message": "'idna' imported but declared as a dev dependency", - }, - "module": "idna", - "location": { - "file": str(Path("src/main.py")), - "line": 7, - "column": 8, - }, - }, - { - "error": { - "code": "DEP004", - "message": "'mypy' imported but declared as a dev dependency", - }, - "module": "mypy", - "location": { - "file": str(Path("src/main.py")), - "line": 8, - "column": 8, - }, - }, - { - "error": { - "code": "DEP004", - "message": "'packaging' imported but declared as a dev dependency", - }, - "module": "packaging", - "location": { - "file": str(Path("src/main.py")), - "line": 9, - "column": 8, - }, - }, - { - "error": { - "code": "DEP004", - "message": "'pytest' imported but declared as a dev dependency", - }, - "module": "pytest", - "location": { - "file": str(Path("src/main.py")), - "line": 10, - "column": 8, - }, - }, - { - "error": { - "code": "DEP004", - "message": "'pytest_cov' imported but declared as a dev dependency", - }, - "module": "pytest_cov", - "location": { - "file": str(Path("src/main.py")), - "line": 11, - "column": 8, - }, - }, - { - "error": { - "code": "DEP001", - "message": "'white' imported but missing from the dependency definitions", - }, - "module": "white", - "location": { - "file": str(Path("src/main.py")), - "line": 12, - "column": 8, - }, - }, - ] + assert result.stderr == snapshot("""\ +Assuming the corresponding module name of package 'arrow' is 'arrow'. Install the package or configure a package_module_name_map entry to override this behaviour. +Assuming the corresponding module name of package 'pkginfo' is 'pkginfo'. Install the package or configure a package_module_name_map entry to override this behaviour. +Assuming the corresponding module name of package 'urllib3' is 'urllib3'. Install the package or configure a package_module_name_map entry to override this behaviour. +Assuming the corresponding module name of package 'isort' is 'isort'. Install the package or configure a package_module_name_map entry to override this behaviour. +Assuming the corresponding module name of package 'requests' is 'requests'. Install the package or configure a package_module_name_map entry to override this behaviour. +Assuming the corresponding module name of package 'certifi' is 'certifi'. Install the package or configure a package_module_name_map entry to override this behaviour. +Assuming the corresponding module name of package 'idna' is 'idna'. Install the package or configure a package_module_name_map entry to override this behaviour. +Assuming the corresponding module name of package 'black' is 'black'. Install the package or configure a package_module_name_map entry to override this behaviour. +Assuming the corresponding module name of package 'mypy' is 'mypy'. Install the package or configure a package_module_name_map entry to override this behaviour. +Assuming the corresponding module name of package 'pytest' is 'pytest'. Install the package or configure a package_module_name_map entry to override this behaviour. +Assuming the corresponding module name of package 'pytest-cov' is 'pytest_cov'. Install the package or configure a package_module_name_map entry to override this behaviour. +Scanning 2 files... + +pyproject.toml: DEP002 'isort' defined as a dependency but not used in the codebase +src/main.py:4:8: DEP004 'black' imported but declared as a dev dependency +src/main.py:5:8: DEP004 'certifi' imported but declared as a dev dependency +src/main.py:7:8: DEP004 'idna' imported but declared as a dev dependency +src/main.py:8:8: DEP004 'mypy' imported but declared as a dev dependency +src/main.py:9:8: DEP004 'packaging' imported but declared as a dev dependency +src/main.py:10:8: DEP004 'pytest' imported but declared as a dev dependency +src/main.py:11:8: DEP004 'pytest_cov' imported but declared as a dev dependency +src/main.py:12:8: DEP001 'white' imported but missing from the dependency definitions +Found 9 dependency issues. + +For more information, see the documentation: https://deptry.com/ +""") diff --git a/tests/functional/utils.py b/tests/functional/utils.py index f9bf3e327..c07987510 100644 --- a/tests/functional/utils.py +++ b/tests/functional/utils.py @@ -2,6 +2,7 @@ from enum import Enum +TEST_DEPTRY_COMMAND = "deptry --enforce-posix-paths" DEPTRY_WHEEL_DIRECTORY = "build/functional_tests/deptry" diff --git a/tests/unit/reporters/test_base.py b/tests/unit/reporters/test_base.py new file mode 100644 index 000000000..c734ba47b --- /dev/null +++ b/tests/unit/reporters/test_base.py @@ -0,0 +1,36 @@ +from __future__ import annotations + +import sys +from pathlib import Path + +import pytest + +from deptry.reporters import TextReporter + + +@pytest.mark.skipif(sys.platform == "win32", reason="Explicitly tests paths output for non-Windows systems") +def test__format_path_non_windows() -> None: + reporter = TextReporter([], enforce_posix_paths=False) + + assert reporter._format_path(Path("src/main.py")) == "src/main.py" + + +@pytest.mark.skipif(sys.platform != "win32", reason="Explicitly tests paths output for Windows systems") +def test__format_path_windows() -> None: + reporter = TextReporter([], enforce_posix_paths=False) + + assert reporter._format_path(Path("src/main.py")) == "src\\main.py" + + +@pytest.mark.skipif(sys.platform == "win32", reason="Explicitly tests paths output for non-Windows systems") +def test__format_path_enforce_posix_paths_non_windows() -> None: + reporter = TextReporter([], enforce_posix_paths=True) + + assert reporter._format_path(Path("src/main.py")) == "src/main.py" + + +@pytest.mark.skipif(sys.platform != "win32", reason="Explicitly tests paths output for Windows systems") +def test__format_path_enforce_posix_paths_windows() -> None: + reporter = TextReporter([], enforce_posix_paths=True) + + assert reporter._format_path(Path("src/main.py")) == "src/main.py" diff --git a/tests/unit/reporters/test_github.py b/tests/unit/reporters/test_github.py index 5d8ba7104..e34969523 100644 --- a/tests/unit/reporters/test_github.py +++ b/tests/unit/reporters/test_github.py @@ -45,7 +45,7 @@ def test_github_annotation( caplog: LogCaptureFixture, violation: Violation, warning_ids: tuple[str, ...], expected: str ) -> None: - reporter = GithubReporter(violations=[violation], warning_ids=warning_ids) + reporter = GithubReporter(violations=[violation], enforce_posix_paths=False, warning_ids=warning_ids) with caplog.at_level(logging.INFO): reporter.report() diff --git a/tests/unit/reporters/test_json.py b/tests/unit/reporters/test_json.py index 044dec055..5aec55e50 100644 --- a/tests/unit/reporters/test_json.py +++ b/tests/unit/reporters/test_json.py @@ -31,7 +31,8 @@ def test_simple(tmp_path: Path) -> None: Module("foo", package="foo-package"), Location(Path("foo.py"), 1, 2) ), ], - "output.json", + enforce_posix_paths=False, + json_output="output.json", ).report() with Path("output.json").open() as f: diff --git a/tests/unit/reporters/test_text.py b/tests/unit/reporters/test_text.py index 396addc12..e36022400 100644 --- a/tests/unit/reporters/test_text.py +++ b/tests/unit/reporters/test_text.py @@ -35,7 +35,7 @@ def test_logging_number_multiple(caplog: LogCaptureFixture) -> None: ), DEP004MisplacedDevDependencyViolation(Module("foo", package="foo-package"), Location(Path("foo.py"), 1, 2)), ] - TextReporter(violations).report() + TextReporter(violations, enforce_posix_paths=False).report() assert caplog.messages == [ ( @@ -70,9 +70,10 @@ def test_logging_number_multiple(caplog: LogCaptureFixture) -> None: def test_logging_number_single(caplog: LogCaptureFixture) -> None: with caplog.at_level(logging.INFO): - TextReporter([ - DEP001MissingDependencyViolation(Module("foo", package="foo-package"), Location(Path("foo.py"), 1, 2)) - ]).report() + TextReporter( + [DEP001MissingDependencyViolation(Module("foo", package="foo-package"), Location(Path("foo.py"), 1, 2))], + enforce_posix_paths=False, + ).report() assert caplog.messages == [ "", @@ -88,7 +89,7 @@ def test_logging_number_single(caplog: LogCaptureFixture) -> None: def test_logging_number_none(caplog: LogCaptureFixture) -> None: with caplog.at_level(logging.INFO): - TextReporter([]).report() + TextReporter([], enforce_posix_paths=False).report() assert caplog.messages == [ "", @@ -108,7 +109,7 @@ def test_logging_no_ansi(caplog: LogCaptureFixture) -> None: ), DEP004MisplacedDevDependencyViolation(Module("foo", package="foo-package"), Location(Path("foo.py"), 1, 2)), ] - TextReporter(violations, use_ansi=False).report() + TextReporter(violations, enforce_posix_paths=False, use_ansi=False).report() assert caplog.messages == [ ( @@ -133,4 +134,4 @@ def test_logging_no_ansi(caplog: LogCaptureFixture) -> None: ], ) def test__get_colors(use_ansi: bool, expected: dict[str, str]) -> None: - assert TextReporter([], use_ansi)._get_colors() == expected + assert TextReporter([], enforce_posix_paths=False, use_ansi=use_ansi)._get_colors() == expected diff --git a/tests/unit/test_core.py b/tests/unit/test_core.py index 4f85329dc..4a4b260e0 100644 --- a/tests/unit/test_core.py +++ b/tests/unit/test_core.py @@ -3,6 +3,7 @@ import logging import sys from pathlib import Path +from typing import Any from unittest import mock import pytest @@ -128,6 +129,7 @@ def test__get_local_modules( experimental_namespace_package=experimental_namespace_package, github_output=False, github_warning_errors=(), + enforce_posix_paths=False, )._get_local_modules() == expected ) @@ -153,6 +155,76 @@ def test__get_stdlib_packages_with_stdlib_module_names_future_version(version_in assert Core._get_standard_library_modules() == sys.stdlib_module_names +@mock.patch("deptry.reporters.TextReporter.report") +@mock.patch("deptry.reporters.JSONReporter.report") +@mock.patch("deptry.reporters.GithubReporter.report") +def test_text_reporter_only( + mock_github_reporter_report: Any, mock_json_reporter_report: Any, mock_text_reporter_report: Any +) -> None: + with pytest.raises(SystemExit): + Core( + root=(Path(),), + config=Path("pyproject.toml"), + no_ansi=False, + per_rule_ignores={}, + ignore=(), + exclude=(), + extend_exclude=(), + using_default_exclude=True, + ignore_notebooks=False, + requirements_files=(), + requirements_files_dev=(), + known_first_party=(), + json_output="", + package_module_name_map={}, + optional_dependencies_dev_groups=(), + using_default_requirements_files=True, + experimental_namespace_package=False, + github_output=False, + github_warning_errors=(), + enforce_posix_paths=False, + ).run() + + mock_text_reporter_report.assert_called() + mock_json_reporter_report.assert_not_called() + mock_github_reporter_report.assert_not_called() + + +@mock.patch("deptry.reporters.TextReporter.report") +@mock.patch("deptry.reporters.JSONReporter.report") +@mock.patch("deptry.reporters.GithubReporter.report") +def test_all_reporters( + mock_github_reporter_report: Any, mock_json_reporter_report: Any, mock_text_reporter_report: Any +) -> None: + with pytest.raises(SystemExit): + Core( + root=(Path(),), + config=Path("pyproject.toml"), + no_ansi=False, + per_rule_ignores={}, + ignore=(), + exclude=(), + extend_exclude=(), + using_default_exclude=True, + ignore_notebooks=False, + requirements_files=(), + requirements_files_dev=(), + known_first_party=(), + json_output="foo.json", + package_module_name_map={}, + optional_dependencies_dev_groups=(), + using_default_requirements_files=True, + experimental_namespace_package=False, + github_output=True, + github_warning_errors=(), + enforce_posix_paths=False, + ).run() + + mock_text_reporter_report.assert_called() + mock_json_reporter_report.assert_called() + mock_github_reporter_report.assert_called() + + def test__exit_with_violations() -> None: violations = [ DEP001MissingDependencyViolation(Module("foo"), Location(Path("foo.py"), 1, 2)), diff --git a/tests/utils.py b/tests/utils.py index 4cb84a755..e553c06e6 100644 --- a/tests/utils.py +++ b/tests/utils.py @@ -117,6 +117,19 @@ def run( cwd=cwd, ) + def run_deptry( + self, arguments: str = "", enforce_posix_paths: bool = True, no_ansi: bool = True + ) -> subprocess.CompletedProcess[str]: + command = f"deptry {arguments}" + + if enforce_posix_paths: + command += " --enforce-posix-paths" + + if no_ansi: + command += " --no-ansi" + + return self.run(command) + @staticmethod def _get_path_to_wheel_file(directory: Path) -> Path: """ diff --git a/uv.lock b/uv.lock index 1d2d305f0..fd4d846f1 100644 --- a/uv.lock +++ b/uv.lock @@ -28,6 +28,15 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/0b/31/349eae2bc9d9331dd8951684cf94528d91efaa71129dc30822ac111dfc66/anysqlite-0.0.5-py3-none-any.whl", hash = "sha256:cb345dc4f76f6b37f768d7a0b3e9cf5c700dfcb7a6356af8ab46a11f666edbe7", size = 3907, upload-time = "2023-10-02T13:49:26.943Z" }, ] +[[package]] +name = "asttokens" +version = "3.0.1" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/be/a5/8e3f9b6771b0b408517c82d97aed8f2036509bc247d46114925e32fe33f0/asttokens-3.0.1.tar.gz", hash = "sha256:71a4ee5de0bde6a31d64f6b13f2293ac190344478f081c3d1bccfcf5eacb0cb7", size = 62308, upload-time = "2025-11-15T16:43:48.578Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/d2/39/e7eaf1799466a4aef85b6a4fe7bd175ad2b1c6345066aa33f1f58d4b18d0/asttokens-3.0.1-py3-none-any.whl", hash = "sha256:15a3ebc0f43c2d0a50eeafea25e19046c68398e487b9f1f5b517f7c0f40f976a", size = 27047, upload-time = "2025-11-15T16:43:16.109Z" }, +] + [[package]] name = "babel" version = "2.18.0" @@ -506,6 +515,7 @@ docs = [ { name = "mkdocs-material" }, ] test = [ + { name = "inline-snapshot" }, { name = "pdm" }, { name = "poetry" }, { name = "pytest" }, @@ -532,6 +542,7 @@ docs = [ { name = "mkdocs-material", specifier = "==9.7.2" }, ] test = [ + { name = "inline-snapshot", specifier = "==0.32.2" }, { name = "pdm", specifier = "==2.26.6" }, { name = "poetry", specifier = "==2.3.2" }, { name = "pytest", specifier = "==9.0.2" }, @@ -620,6 +631,15 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/ab/84/02fc1827e8cdded4aa65baef11296a9bbe595c474f0d6d758af082d849fd/execnet-2.1.2-py3-none-any.whl", hash = "sha256:67fba928dd5a544b783f6056f449e5e3931a5c378b128bc18501f7ea79e296ec", size = 40708, upload-time = "2025-11-12T09:56:36.333Z" }, ] +[[package]] +name = "executing" +version = "2.2.1" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/cc/28/c14e053b6762b1044f34a13aab6859bbf40456d37d23aa286ac24cfd9a5d/executing-2.2.1.tar.gz", hash = "sha256:3632cc370565f6648cc328b32435bd120a1e4ebb20c77e3fdde9a13cd1e533c4", size = 1129488, upload-time = "2025-09-01T09:48:10.866Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/c1/ea/53f2148663b321f21b5a606bd5f191517cf40b7072c0497d3c92c4a13b1e/executing-2.2.1-py2.py3-none-any.whl", hash = "sha256:760643d3452b4d777d295bb167ccc74c64a81df23fb5e08eff250c425a4b2017", size = 28317, upload-time = "2025-09-01T09:48:08.5Z" }, +] + [[package]] name = "fastjsonschema" version = "2.21.2" @@ -767,6 +787,23 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/cb/b1/3846dd7f199d53cb17f49cba7e651e9ce294d8497c8c150530ed11865bb8/iniconfig-2.3.0-py3-none-any.whl", hash = "sha256:f631c04d2c48c52b84d0d0549c99ff3859c98df65b3101406327ecc7d53fbf12", size = 7484, upload-time = "2025-10-18T21:55:41.639Z" }, ] +[[package]] +name = "inline-snapshot" +version = "0.32.2" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "asttokens" }, + { name = "executing" }, + { name = "pytest" }, + { name = "rich" }, + { name = "tomli", marker = "python_full_version < '3.11'" }, + { name = "typing-extensions" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/4e/0f/abc1f55538a348525c441065845fdfeca73af634b5ffd573ed782e3d4bea/inline_snapshot-0.32.2.tar.gz", hash = "sha256:62374e28c471a0de9c60ad23758586fb13355ad449d3698b7b77ab597eed7f59", size = 2624220, upload-time = "2026-02-21T14:37:11.756Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/68/3c/2cdb9e4d004951816d5b3dc720dcebfa3cc9909cfe8e38de4bb72f628755/inline_snapshot-0.32.2-py3-none-any.whl", hash = "sha256:e2866e4f268435a9b8886f63a275cdb7489d13baddb2a0aab6625bf2975c06ce", size = 84285, upload-time = "2026-02-21T14:37:10.481Z" }, +] + [[package]] name = "installer" version = "0.7.0"