Static code analysis tools for Python and CI

1 minute read

Python has some great free and open-source static code analysis tools. I recommend integrating them into you Continuous Integration (CI) pipelines so they run every time you commit and push.

The 3 linters I usually run are:

  • mypy: checks type hints consistency. When I started using type hints, I was skeptical of them as they didn’t seem to belong to Python. But now that I’m used to them it’s hard to go back. Type hints not only make the code much more readable, they can also avoid a lot of bugs by using mypy.
  • pylint: checks for syntax errors and style problems. This one checks a ton of things, so it’s always necessary to tune it to your needs. At a minimum, you should run it to check for errors. In my professional career I’ve seen production code with syntax errors that weren’t detected until I used pylint.
  • bandit: checks for security issues. Security is extremely important and bandit will tell you about potential issues. It can show false positives, but they can be ignored.

In addition to these, in my CI I also always integrate the pre-commit checks. Local pre-commit checks can be bypassed, so you need to run them in the pipeline to ensure that the code has been formatted with black and nobody cheated!

Below you can find an example Gitlab CI template for Python projects. Note that I’m using pip-tools to manage dependencies.

image: python-3.9

stages:
  - static_code_analysis


# Change pip's cache directory to be inside the project directory since we can
# only cache local items.
variables:
  PIP_CACHE_DIR: "$CI_PROJECT_DIR/.cache/pip"

cache:
  paths:
    - .cache/pip
    - venv/
    - .mypy_cache

before_script:
  - python3 -m venv venv
  - . venv/bin/activate
  - export PYTHONPATH="$CI_PROJECT_DIR"
  - pip install --upgrade pip pip-tools wheel
  - pip-sync requirements.txt requirements-dev.txt

pre-commit:
  stage: static_code_analysis
  script:
  - pre-commit run --all-files

linters:
  stage: static_code_analysis
  script:
  - mypy app/ --config-file=mypy.ini
	- pylint app/ --rcfile=pylintrc
	- bandit app/ --recursive --quiet


Categories: ,

Updated:

Leave a comment