Skip to content

Commit

Permalink
Merge pull request #1400 from diseraluca/issue/1397
Browse files Browse the repository at this point in the history
Extends git_hook to allow for a user-specified configuration file.
  • Loading branch information
timothycrosley committed Aug 23, 2020
2 parents a35d565 + b6a96b2 commit dad6237
Show file tree
Hide file tree
Showing 3 changed files with 51 additions and 3 deletions.
11 changes: 10 additions & 1 deletion README.md
Expand Up @@ -556,7 +556,7 @@ include the following in `.git/hooks/pre-commit`:
import sys
from isort.hooks import git_hook

sys.exit(git_hook(strict=True, modify=True, lazy=True))
sys.exit(git_hook(strict=True, modify=True, lazy=True, settings_file=""))
```

If you just want to display warnings, but allow the commit to happen
Expand All @@ -569,6 +569,15 @@ Set it to `True` to ensure all tracked files are properly isorted,
leave it out or set it to `False` to check only files added to your
index.

If you want to use a specific configuration file for the hook, you can pass its
path to settings_file. If no path is specifically requested, `git_hook` will
search for the configuration file starting at the directory containing the first
staged file, as per `git diff-index` ordering, and going upward in the directory
structure until a valid configuration file is found or
[`MAX_CONFIG_SEARCH_DEPTH`](src/config.py:35) directories are checked.
The settings_file parameter is used to support users who keep their configuration
file in a directory that might not be a parent of all the other files.

## Setuptools integration

Upon installation, isort enables a `setuptools` command that checks
Expand Down
14 changes: 12 additions & 2 deletions isort/hooks.py
Expand Up @@ -33,7 +33,9 @@ def get_lines(command: List[str]) -> List[str]:
return [line.strip() for line in stdout.splitlines()]


def git_hook(strict: bool = False, modify: bool = False, lazy: bool = False) -> int:
def git_hook(
strict: bool = False, modify: bool = False, lazy: bool = False, settings_file: str = ""
) -> int:
"""
Git pre-commit hook to check staged files for isort errors
Expand All @@ -46,6 +48,11 @@ def git_hook(strict: bool = False, modify: bool = False, lazy: bool = False) ->
:param bool lazy - if True, also check/fix unstaged files.
This is useful if you frequently use ``git commit -a`` for example.
If False, ony check/fix the staged files for isort errors.
:param str settings_file - A path to a file to be used as
the configuration file for this run.
When settings_file is the empty string, the configuration file
will be searched starting at the directory containing the first
staged file, if any, and going upward in the directory structure.
:return number of errors if in strict mode, 0 otherwise.
"""
Expand All @@ -60,7 +67,10 @@ def git_hook(strict: bool = False, modify: bool = False, lazy: bool = False) ->
return 0

errors = 0
config = Config(settings_path=os.path.dirname(os.path.abspath(files_modified[0])))
config = Config(
settings_file=settings_file,
settings_path=os.path.dirname(os.path.abspath(files_modified[0])),
)
for filename in files_modified:
if filename.endswith(".py"):
# Get the staged contents of the file
Expand Down
29 changes: 29 additions & 0 deletions tests/test_hooks.py
@@ -1,4 +1,5 @@
import os
from pathlib import Path
from unittest.mock import MagicMock, patch

from isort import exceptions, hooks
Expand Down Expand Up @@ -53,3 +54,31 @@ class FakeProcessResponse(object):
with patch("subprocess.run", MagicMock(return_value=FakeProcessResponse())) as run_mock:
with patch("isort.api", MagicMock(side_effect=exceptions.FileSkipped("", ""))):
hooks.git_hook(modify=True)


def test_git_hook_uses_the_configuration_file_specified_in_settings_path(tmp_path: Path) -> None:
subdirectory_path = tmp_path / "subdirectory"
configuration_file_path = subdirectory_path / ".isort.cfg"

# Inserting the modified file in the parent directory of the configuration file ensures that it
# will not be found by the normal search routine
modified_file_path = configuration_file_path.parent.parent / "somefile.py"

# This section will be used to check that the configuration file was indeed loaded
section = "testsection"

os.mkdir(subdirectory_path)
with open(configuration_file_path, "w") as fd:
fd.write("[isort]\n")
fd.write(f"sections={section}")

with open(modified_file_path, "w") as fd:
pass

files_modified = [str(modified_file_path.absolute())]
with patch("isort.hooks.get_lines", MagicMock(return_value=files_modified)):
with patch("isort.hooks.get_output", MagicMock(return_value="")):
with patch("isort.api.check_code_string", MagicMock()) as run_mock:
hooks.git_hook(settings_file=str(configuration_file_path))

assert run_mock.call_args[1]["config"].sections == (section,)

0 comments on commit dad6237

Please sign in to comment.