Adding linting as part of python server reload
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 manage.py runserver are ran or independently via
python manage.py 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 @register() def flake8(app_configs, **kwargs): errors =  result = subprocess.run(("flake8", "."), capture_output=True) if(result.returncode): errors.append( Warning( "Found a bunch of flake8 errors.", hint="\n" +result.stdout.decode(), id="myapp.FLAKE8", ) ) return errors
You then import it in
__init.py__.py of the root of the app
from path.to.check import * # noqa
The output of the
python manage.py runserver. It also reruns it whenever there is a file change
WARNINGS: ?: (myapp.FLAKE8) Found a bunch of flake8 errors. HINT: ./myapp/broken.py:1:1: 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 http://127.0.0.1:8000/ Quit the server with CONTROL-C.
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
runserver.py script that modifies
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 = subprocess.run(("flake8", "."), capture_output=True) if result.returncode: logger.warning( "Found the following error running flake8: \n %s", result.stdout.decode(), ) def restart(self) -> None: # Run check whenever we restart/file change self.flake_check() super().restart() def startup(self) -> None: # Run check on 1st load self.flake_check() super().startup() app = FastAPI() if __name__ == "__main__": config = uvicorn.Config( "startserver:app", # Change to path of app host="127.0.0.1", port=5000 log_level="info", reload=True, ) server = uvicorn.Server(config) sock = config.bind_socket() ChangeReloadWithLinting(config, target=server.run, sockets=[sock]).run()
The output of running
WARNING: StatReload detected changes in 'broken.py'. Reloading... WARNING: Found the following error running flake8: ./broken.py:1:1: F401 'os' imported but unused INFO: Shutting down INFO: Waiting for application shutdown. INFO: Application shutdown complete. INFO: Finished server process  INFO: Started server process  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.
It is very possible to integrate linting as part of the python webserver. You can also easily extend these to more complex checks.