Adding linting as part of python server reload

Posted on 2023-01-23
Tags: python

As a python dev who does a fair amount work with javascript and typescript, I easily get jealous of features JS ecosystem. One of these features is how react-script integrates eslint as part of development server. The idea is whenever you change a file, the webserver warns you if there are problems with the files. So I went looking around how would I could implement this in python.


For Django, you can create and invoke system checks. These checks will run for whenever specific commands like python runserver are ran or independently via python check. These can range from very simply checks to actually calling the database.

A small snippet that runs flake8 on the codebase

from django.core.checks import Warning, register
import subprocess

def flake8(app_configs, **kwargs):
    errors = []
    result ="flake8", "."),  capture_output=True)
                "Found a bunch of flake8 errors.",
                hint="\n" +result.stdout.decode(),
    return errors

You then import it in of the root of the app

from import * # noqa

The output of the python runserver. It also reruns it whenever there is a file change

?: (myapp.FLAKE8) Found a bunch of flake8 errors.
./myapp/ F401 'os' imported but unused

System check identified 1 issue (0 silenced).
January 10, 2023 - 10:48:32
Django version 4.1, using settings 'myapp.settings'
Starting development server at
Quit the server with CONTROL-C.

Useful links:



For uvicorn/FastAPI, there isn't a documented guide on how to inject checks. What we can do is extend uvicorn's ChangReload, which handles the reloading, to run a few checks whenever reloading. We can create a script that modifies ChangeReload

import uvicorn
from uvicorn.supervisors import ChangeReload
from fastapi import FastAPI
import subprocess
import logging

logger = logging.getLogger("uvicorn.error")

class ChangeReloadWithLinting(ChangeReload):
    def flake_check(self) -> None:
        result ="flake8", "."), capture_output=True)
        if result.returncode:
                "Found the following error running flake8: \n %s",

    def restart(self) -> None:
        # Run check whenever we restart/file change

    def startup(self) -> None:
        # Run check on 1st load

app = FastAPI()
if __name__ == "__main__":
    config = uvicorn.Config(
        "startserver:app", # Change to path of app
    server = uvicorn.Server(config)
    sock = config.bind_socket()
    ChangeReloadWithLinting(config,, sockets=[sock]).run()

The output of running python

WARNING:  StatReload detected changes in ''. Reloading...
WARNING:  Found the following error running flake8:
 ./ F401 'os' imported but unused

INFO:     Shutting down
INFO:     Waiting for application shutdown.
INFO:     Application shutdown complete.
INFO:     Finished server process [253163]
INFO:     Started server process [253194]
INFO:     Waiting for application startup.
INFO:     Application startup complete.

Just a warning that ChangeReload is considered as a private class so compatibility and stability are not guaranteed.

Useful links:



It is very possible to integrate linting as part of the python webserver. You can also easily extend these to more complex checks.