Skip to content

Commit

Permalink
feat(python_file_finder): improve ignore handling (#908)
Browse files Browse the repository at this point in the history
* test(functional): more tests for gitignore

* test(python_file_finder): add tests for gitignore

* feat(python_file_finder): only use gitignore files when using git

* test(functional): use `.ignore` in non-git projects
  • Loading branch information
mkniewallner authored Oct 29, 2024
1 parent d9a1ba1 commit 919e33a
Show file tree
Hide file tree
Showing 12 changed files with 200 additions and 5 deletions.
3 changes: 1 addition & 2 deletions src/python_file_finder.rs
Original file line number Diff line number Diff line change
Expand Up @@ -61,9 +61,8 @@ fn build_walker(

walk_builder
.types(build_types(ignore_notebooks).unwrap())
.standard_filters(use_git_ignore)
.hidden(false)
.git_ignore(use_git_ignore)
.require_git(false)
.filter_entry(move |entry| entry_satisfies_predicate(entry, re.as_ref()))
.build()
}
Expand Down
File renamed without changes.
2 changes: 2 additions & 0 deletions tests/fixtures/project_with_gitignore/.gitignore
Original file line number Diff line number Diff line change
@@ -1 +1,3 @@
/build
foobar.py
/src/barfoo.py
2 changes: 2 additions & 0 deletions tests/fixtures/project_with_gitignore/src/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
/baz.py
/src/bar.py
1 change: 1 addition & 0 deletions tests/fixtures/project_with_gitignore/src/barfoo.py
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
import hello
1 change: 1 addition & 0 deletions tests/fixtures/project_with_gitignore/src/baz.py
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
import hej
1 change: 0 additions & 1 deletion tests/fixtures/project_with_src_directory/.gitignore

This file was deleted.

1 change: 1 addition & 0 deletions tests/fixtures/project_with_src_directory/.ignore
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
src/this_file_is_ignored.py
87 changes: 85 additions & 2 deletions tests/functional/cli/test_cli_gitignore.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,9 +14,13 @@


@pytest.mark.xdist_group(name=Project.GITIGNORE)
def test_cli_gitignore_is_used(pip_venv_factory: PipVenvFactory) -> None:
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}")

assert result.returncode == 1
Expand Down Expand Up @@ -61,9 +65,64 @@ def test_cli_gitignore_is_used(pip_venv_factory: PipVenvFactory) -> None:


@pytest.mark.xdist_group(name=Project.GITIGNORE)
def test_cli_gitignore_is_not_used(pip_venv_factory: PipVenvFactory) -> None:
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}")

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,
},
},
]


@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}")

assert result.returncode == 1
Expand Down Expand Up @@ -104,4 +163,28 @@ def test_cli_gitignore_is_not_used(pip_venv_factory: PipVenvFactory) -> 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,
},
},
]
107 changes: 107 additions & 0 deletions tests/unit/test_python_file_finder.py
Original file line number Diff line number Diff line change
Expand Up @@ -174,3 +174,110 @@ def test_duplicates_are_removed(tmp_path: Path) -> None:
files = get_all_python_files_in((Path(), Path()), exclude=(), extend_exclude=(), using_default_exclude=False)

assert sorted(files) == [Path("dir/subdir/file1.py")]


def test_gitignore_used_in_git_project(tmp_path: Path) -> None:
"""Test that gitignore files are respected when project uses git."""
git_project_path = tmp_path / "git_project"
git_project_path.mkdir()

# Simulate the presence of a gitignore outside the git project, that should not be used.
with (tmp_path / ".gitignore").open("w") as f:
f.write("*")

with run_within_dir(tmp_path / git_project_path):
# Simulate the fact that the project is a git repository.
Path(".git").mkdir()

create_files([
Path("file1.py"),
Path("file2.py"),
Path("file3.py"),
Path("dir1/file.py"),
Path("dir2/file2.py"),
Path("dir3/file3.py"),
Path("dir3/file4.py"),
])

with Path(".gitignore").open("w") as f:
f.write("""/file1.py
/dir1/file.py
file2.py""")

with Path("dir3/.gitignore").open("w") as f:
f.write("/file3.py")

files = get_all_python_files_in((Path(),), exclude=(), extend_exclude=(), using_default_exclude=True)

assert sorted(files) == [
Path("dir3/file4.py"),
Path("file3.py"),
]


def test_gitignore_ignored_when_not_using_default_exclude(tmp_path: Path) -> None:
"""Test that gitignore files are ignored when project uses git but does not use default exclude."""
git_project_path = tmp_path / "git_project"
git_project_path.mkdir()

# Simulate the presence of a gitignore outside the git project, that should not be used.
with (tmp_path / ".gitignore").open("w") as f:
f.write("*")

with run_within_dir(tmp_path / git_project_path):
# Simulate the fact that the project is a git repository.
Path(".git").mkdir()

create_files([
Path("file1.py"),
Path("file2.py"),
Path("file3.py"),
Path("dir1/file.py"),
Path("dir2/file2.py"),
Path("dir3/file3.py"),
Path("dir3/file4.py"),
])

with Path(".gitignore").open("w") as f:
f.write("""/file1.py
/dir1/file.py
file2.py""")

with Path("dir3/.gitignore").open("w") as f:
f.write("/file3.py")

files = get_all_python_files_in(
(Path(),),
exclude=("file3.py",),
extend_exclude=(),
using_default_exclude=False,
)

assert sorted(files) == [
Path("dir1/file.py"),
Path("dir2/file2.py"),
Path("dir3/file3.py"),
Path("dir3/file4.py"),
Path("file1.py"),
Path("file2.py"),
]


def test_gitignore_ignored_in_non_git_project(tmp_path: Path) -> None:
"""Test that gitignore files are ignored when project does not use git."""
with run_within_dir(tmp_path):
create_files([
Path("file1.py"),
Path("file2.py"),
])

# This will be ignored, since project is not a git project.
with Path(".gitignore").open("w") as f:
f.write("/file1.py")

files = get_all_python_files_in((Path(),), exclude=(), extend_exclude=(), using_default_exclude=True)

assert sorted(files) == [
Path("file1.py"),
Path("file2.py"),
]

0 comments on commit 919e33a

Please sign in to comment.