DEV Community

Cover image for A Code Quality Toolbox for Python Projects
Magda (she/her)
Magda (she/her)

Posted on • Updated on

A Code Quality Toolbox for Python Projects

When I started shifting more and more towards working with Python, I looked back at the world of JS and thought wow, they have so many nice tools for formatting and linting! I found myself in the wild world of Python programming where PEP8 sets the standards, but whether or not you follow them and how you write your code is pretty much up to you. This is my letter to myself back in time, to share some of the tips I now have in my toolbox for maintaining a nice and clean Python project.

Formatting

If you want to speed up your coding and rely on a computer to do the polishing for you, you can use a code formatter to automatically walk through and format your code. In the world of python, Black is one of the most used formatters. It could be compared to Prettier in the world of JS - they are both opinionated formatters, i.e. they make some choices for you. (You don't have to fight your colleague over whether to use single or double quotes anymore! Great!)

This is how black responds to a file with print("hello" ).

$ pip install black
$ black my-sample.py
reformatted my-sample.py
All done! ✨ 🍰 ✨
1 file reformatted.
Enter fullscreen mode Exit fullscreen mode

Linting

Linting differs from formatting in that it will not change the code it looks at, but will notify you if it doesn't follow the specified standards. A good option for linting in python is flake8. Here is how flake8 responds to the same file contents as black did above.

$ pip install flake8
$ flake8 my-sample.py
my-sample.py:1:14: E202 whitespace before ')'
Enter fullscreen mode Exit fullscreen mode

In addition to this out of the box -linting, there are loads of flake8 extensions that can help you with for example switching from .format() to using f-strings or checking that your naming follows the PEP8 guidelines. For example, adding flake8-length adds line length checking to the linting.

$ pip install flake8-length
$ flake8 test.py
test.py:1:80: LN001 line is too long (169 > 79)
Enter fullscreen mode Exit fullscreen mode

If you like to keep your imports in tact, there are also rules to enforce a specific order amongst them. One tool that does that is isort. Isort follows the order:

  1. absolute imports
  2. built-in modules
  3. third-party libraries
  4. imports from the same project You can also integrate isort into flake8 using the flake8-isort plugin!

Type checking

Type annotation support was introduced in python 3.5 and there are tools for watching that the typing is in tact. A good option for checking your type annotations is using mypy. Given a sample file that looks like this:

def return_hello(name: str) -> int:
    return f'Hello, {name}!'
Enter fullscreen mode Exit fullscreen mode

We can run mypy and see that our type hints indeed are off:

$ pip install mypy
$ mypy my-sample.py
my-sample.py:2: error: Incompatible return value type (got "str", expected "int")
Found 1 error in 1 file (checked 1 source file)
Enter fullscreen mode Exit fullscreen mode

Some other good alternatives for type checking are Pyright (which is seen in VSCode via Microsofts PyLance plugin) and Pyre.

Wiring it up

You could choose to manually run these tools from time to time in your project, but you will have a better time if you make them part of your pull request routine. Using GitHub actions, you can set up for example a flake8 action. You can alternatively build an action from scratch - here we run isort with the check-only option:

name: Check import order

on: [push]

jobs:
  build:
    runs-on: ubuntu-latest
    steps:
    - uses: actions/checkout@v1
    - name: Set up Python 3.9
      uses: actions/setup-python@v1
      with:
        python-version: 3.9
    - name: Install isort
      run: |
        python -m pip install --upgrade pip
        pip install isort
    - name: Check import order
      run: isort . -c -v
Enter fullscreen mode Exit fullscreen mode

Final thoughts

I love rules, so seeing how systematically one can unify ones codebase using tools like these just makes my day. However I also know lots of devs who don't feel like this kind of rigour is their jam - it should always be discussed in the team how and why we want to set the codebase standards.

Hope this text gave you all some ideas of what tools are out there and what you could pick into your own toolkit as well! If you know of a useful tool I didn't mention - please let me know in the comments! 😊

Discussion (0)