Python Code Reviews
Style Guide
Developers should follow the PEP8 style guide with type hints. The use of type hints throughout paired with linting and type hint checking avoids common errors that are tricky to debug.
Projects should check Python code with automated tools.
Linting should be added to build validation, and both linting and code formatting can be added to your pre-commit hooks and VS Code.
Code Analysis / Linting
The 2 most popular python linters are Pylint and Flake8. Both check adherence to PEP8
but vary a bit in what other rules they check. In general Pylint
tends to be a bit more stringent and give more false positives but both are good options for linting python code.
Both Pylint
and Flake8
can be configured in VS Code using the VS Code python extension
.
Flake8
Flake8 is a simple and fast wrapper around Pyflakes
(for detecting coding errors) and pycodestyle
(for pep8).
Install Flake8
Add an extension for the pydocstyle
(for doc strings) tool to flake8.
Add an extension for pep8-naming
(for naming conventions in pep8) tool to flake8.
Run Flake8
Pylint
Install Pylint
Run Pylint
Automatic Code Formatting
Black
Black
is an unapologetic code formatting tool. It removes all need from pycodestyle
nagging about formatting, so the team can focus on content vs style. It's not possible to configure black for your own style needs.
Format python code
Autopep8
Autopep8
is more lenient and allows more configuration if you want less stringent formatting.
Format python code
yapf
yapf Yet Another Python Formatter is a python formatter from Google based on ideas from gofmt. This is also more configurable, and a good option for automatic code formatting.
Format python code
VS Code Extensions
Python
The Python language extension
is the base extension you should have installed for python development with VS Code. It enables intellisense, debugging, linting (with the above linters), testing with pytest or unittest, and code formatting with the formatters mentioned above.
Pyright
The Pyright extension
augments VS Code with static type checking when you use type hints
Build validation
To automate linting with flake8
and testing with pytest
in Azure Devops you can add the following snippet to you azure-pipelines.yaml
file.
trigger:
branches:
include:
- develop
- master
paths:
include:
- src/*
pool:
vmImage: 'ubuntu-latest'
jobs:
- job: LintAndTest
displayName: Lint and Test
steps:
- checkout: self
lfs: true
- task: UsePythonVersion@0
displayName: 'Set Python version to 3.6'
inputs:
versionSpec: '3.6'
- script: pip3 install --user -r requirements.txt
displayName: 'Install dependencies'
- script: |
# Install Flake8
pip3 install --user flake8
# Install PyTest
pip3 install --user pytest
displayName: 'Install Flake8 and PyTest'
- script: |
python3 -m flake8
displayName: 'Run Flake8 linter'
- script: |
# Run PyTest tester
python3 -m pytest --junitxml=./test-results.xml
displayName: 'Run PyTest Tester'
- task: PublishTestResults@2
displayName: 'Publish PyTest results'
condition: succeededOrFailed()
inputs:
testResultsFiles: '**/test-*.xml'
testRunTitle: 'Publish test results for Python $(python.version)'
To perform a PR validation on GitHub you can use a similar YAML configuration with GitHub Actions
Pre-commit hooks
Pre-commit hooks allow you to format and lint code locally before submitting the pull request.
Adding pre-commit hooks for your python repository is easy using the pre-commit package
-
Install pre-commit and add to the requirements.txt
-
Add a
.pre-commit-config.yaml
file in the root of the repository, with the desired pre-commit actions -
Each individual developer that wants to set up pre-commit hooks can then run
At the next attempted commit any lint failures will block the commit.
Note: Installing pre-commit hooks is voluntary and done by each developer individually. Thus, it's not a replacement for build validation on the server
Code Review Checklist
In addition to the Code Review Checklist you should also look for these python specific code review items
- Are all new packages used included in requirements.txt
- Does the code pass all lint checks?
- Do functions use type hints, and are there any type hint errors?
- Is the code readable and using pythonic constructs wherever possible.