{
  "$type": "site.standard.document",
  "canonicalUrl": "https://rednafi.com/python/pre-commit/",
  "description": "Automate Python code quality with pre-commit hooks running Black, isort, flake8, and mypy before each git commit for consistent formatting.",
  "path": "/python/pre-commit/",
  "publishedAt": "2020-04-06T00:00:00.000Z",
  "site": "at://did:plc:fgtm2c26vfcj74rfmeggbyqj/site.standard.publication/3mnl6f7ob462z",
  "tags": [
    "Python",
    "Git",
    "DevOps"
  ],
  "textContent": "[Pre-commit hooks] can be a neat way to run automated ad-hoc _tasks_ before submitting a new\ngit commit. These tasks may include linting, trimming trailing whitespaces, running code\nformatter before code reviews etc. Let's see how multiple Python linters and formatters can\nbe applied automatically before each commit to impose strict conformity on your codebase.\n\nTo keep my sanity, I only use three linters in all of my python projects:\n\n- [Isort]: Isort is a Python utility to sort _imports_ alphabetically, and\n  automatically separate them by sections and type. It parses specified files for global\n  level import lines and puts them all at the top of the file grouped together by the type\n  of import:\n    - Future\n    - Python Standard Library\n    - Third Party\n    - Current Python Project\n    - Explicitly Local (. before import, as in: from . import x)\n    - Custom Separate Sections (Defined by forced_separate list in the configuration file)\n    - Custom Sections (Defined by sections list in configuration file)\n\n        Inside each section, the imports are sorted alphabetically. This also automatically\n        removes duplicate python imports, and wraps long from imports to the specified line\n        length (defaults to 79).\n\n- [Black]: Black is the uncompromising Python code formatter. It uses consistent rules\n  to format your python code and makes sure that they look the same regardless of the\n  project you're reading.\n\n- [Flake8]: _Flake8_ is a wrapper around _PyFlakes_, _pycodestyle_, Ned Batchelder's\n  [McCabe script]. The combination of these three linters makes sure that your code is\n  compliant with [PEP-8] and free of some obvious code smells.\n\nInstalling pre-commit\n\n- Install using pip:\n\n    \n\n- Install via curl:\n\n    \n\nDefining the pre-commit config file\n\nPre-commit configuration is a .pre-commit-config.yaml file where you define your hooks\n(tasks) that you want to run before every commit. Once you have defined your hooks in the\nconfig file, they will run automatically every time you say\ngit commit -m \"Commit message\". The following example shows how _black_ and a few other\nlinters can be added as hooks to the config:\n\nInstalling the git hook scripts\n\nRun:\n\nThis will set up the git hook scripts and should show the following output in your terminal:\n\nNow you'll be able to implicitly or explicitly run the hooks before each commit.\n\nRunning the hooks against all the files\n\nBy default, the hooks will run every time you say:\n\nHowever, if you wish to run the hooks manually on every file, you can do so via:\n\nRunning the linters as pre-commit hooks\n\nTo run the above mentioned linters as pre-commit hooks, you need to add their respective\nsettings to the .pre-commit-config.yaml file. However, there're a few minor issues that\nneed to be taken care of.\n\n- The default line length of black formatter is 88 (you should embrace that) but flake8\n  caps the line at 79 characters. This raises conflict and can cause failures.\n\n- _Flake8_ can be overly strict at times. You'll want to ignore basic errors like unused\n  imports, spacing issues etc. However, since your IDE / editor also points out these issues\n  anyway, you should solve them manually. You will need to configure _flake8_ to ignore some\n  of these minor errors.\n\nThe following one is an example of how you can define your .pre-commit-config.yaml and\nconfigure the individual hooks so that _isort_, _black_, _flake8_ linters can run without\nany conflicts.\n\nYou can add the above lines to your configuration and run:\n\nThis should apply the pre-commit hooks to your code base harmoniously. From now on, before\neach commit, the hooks will make sure that your code complies with the rules imposed by the\nlinters.\n\n\n\n\n[pre-commit hooks]:\n    https://pre-commit.com/#introduction\n\n[mccabe script]:\n    https://github.com/PyCQA/mccabe\n\n[pep-8]:\n  https://www.python.org/dev/peps/pep-0008/\n\n[isort]:\n    https://github.com/timothycrosley/isort\n\n[black]:\n    https://github.com/psf/black\n\n[flake8]:\n    https://github.com/PyCQA/flake8",
  "title": "Running Python linters with pre-commit hooks"
}