From 1b705c519b925deb720b646ab5847084e400585e Mon Sep 17 00:00:00 2001 From: Helen Sherwood-Taylor Date: Thu, 15 Jan 2015 22:02:15 +0000 Subject: Added git hook and documentation --- ACKNOWLEDGEMENTS.md | 1 + README.md | 19 +++++++++++++ isort/hooks.py | 82 +++++++++++++++++++++++++++++++++++++++++++++++++++++ isort/isort.py | 2 +- 4 files changed, 103 insertions(+), 1 deletion(-) create mode 100644 isort/hooks.py diff --git a/ACKNOWLEDGEMENTS.md b/ACKNOWLEDGEMENTS.md index 51a96dc6..bda4b724 100644 --- a/ACKNOWLEDGEMENTS.md +++ b/ACKNOWLEDGEMENTS.md @@ -38,6 +38,7 @@ Code Contributors - Elliott Sales de Andrade (@qulogic) - Kasper Jacobsen (@dinoshauer) - Sebastian Pipping (@hartwork) +- Helen Sherwood-Taylor (@helenst) -------------------------------------------- diff --git a/README.md b/README.md index 7a5f4ef7..e32d334e 100644 --- a/README.md +++ b/README.md @@ -391,6 +391,25 @@ https://gist.github.com/acdha/8717683 Which can help to ensure a certain level of code quality throughout a project. + +Git hook +======== + +isort provides a hook function that can be integrated into your Git pre-commit script to check +Python code before committing. + +To cause the commit to fail if there are isort errors (strict mode), include the following in +`.git/hooks/pre-commit`: + + from isort.hooks import git_hook + + if __name__ == '__main__': + sys.exit(git_hook(strict=True)) + +If you just want to display warnings, but allow the commit to happen anyway, call git_hook without +the `strict` parameter. + + Why isort? ====================== diff --git a/isort/hooks.py b/isort/hooks.py new file mode 100644 index 00000000..15b6d408 --- /dev/null +++ b/isort/hooks.py @@ -0,0 +1,82 @@ +"""isort.py. + +Defines a git hook to allow pre-commit warnings and errors about import order. + +usage: + exit_code = git_hook(strict=True) + +Copyright (C) 2015 Helen Sherwood-Taylor + +Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated +documentation files (the "Software"), to deal in the Software without restriction, including without limitation +the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and +to permit persons to whom the Software is furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all copies or +substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED +TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL +THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF +CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR +OTHER DEALINGS IN THE SOFTWARE. + +""" +import subprocess + +from isort import SortImports + + +def get_output(command): + """ + Run a command and return raw output + + :param str command: the command to run + :returns: the stdout output of the command + """ + return subprocess.check_output(command.split()) + + +def get_lines(command): + """ + Run a command and return lines of output + + :param str command: the command to run + :returns: list of whitespace-stripped lines output by command + """ + stdout = get_output(command) + return [line.strip().decode('utf-8') for line in stdout.splitlines()] + + +def git_hook(strict=False): + """ + Git pre-commit hook to check staged files for isort errors + + :param bool strict - if True, return number of errors on exit, + causing the hook to fail. If False, return zero so it will + just act as a warning. + + :return number of errors if in strict mode, 0 otherwise. + """ + + # Get list of files modified and staged + diff_cmd = "git diff-index --cached --name-only --diff-filter=ACMRTUXB HEAD" + files_modified = get_lines(diff_cmd) + + errors = 0 + for filename in files_modified: + if filename.endswith('.py'): + # Get the staged contents of the file + staged_cmd = "git show :%s" % filename + staged_contents = get_output(staged_cmd) + + sort = SortImports( + file_path=filename, + file_contents=staged_contents.decode(), + check=True + ) + + if sort.incorrectly_sorted: + errors += 1 + + return errors if strict else 0 diff --git a/isort/isort.py b/isort/isort.py index 6b6518eb..d7a3a71b 100644 --- a/isort/isort.py +++ b/isort/isort.py @@ -83,7 +83,7 @@ class SortImports(object): file_name = file_path self.file_path = file_path or "" - if file_path: + if file_path and not file_contents: file_path = os.path.abspath(file_path) if self._should_skip(file_path): if self.config['verbose']: -- cgit v1.2.1