An overview of Python development tooling in 2020
18 Dec 2020
This is a review of what tools are available to Python developers who like to work in minimal and self-built development environments as of late 2020. Language servers, linters, a bit of everything.
This is aimed mostly for people who do not work in an IDE (e.g. PyCharm) or IDE-like (e.g. VS Code) editor. These tools provide a wrapped version of many of these functionalities, but I like to know everything that might pop a little warning or error here and there from under the hood. PyCharm works great, VS Code with the Python extension works kinda well.
Python dev tools ecosystem is nice but a bit messy and it can be hard to understand which tool does what and how to use them, what is deprecated, what is supported or recommended by the Python developers, etc. If you are feeling a bit lost, I hope this post will help you see the bigger picture better.
Let's look at what types of tools are available to you: coding tools, type checkers, linters, formatters and language servers.
"Coding" tools is a bit vague, for the lack of a better term. Those programs are here to assist you during the development process, they provide useful features such as static analysis to jump to definitions and references, refactoring methods and more, that is to say the main features most people expect out of the box from IDEs.
- Jedi is a well-known coding tool that provides autocompletion, jumps, refactoring helpers and more. It is still actively maintained and as it is a Python package itself so it can easily be embedded in larger tools and integrated in a lot of editors.
- Rope is a similar alternative to Jedi with a bit less following. It is sometimes used by other tools solely for its ability to easily jump between symbols.
These tools are quite complex and as such I have never found them to be reliable 100% of the time, but it would be a great loss to overlook them. I have limited experience with Rope: on the projects I used it, it tended to perform a bit worse than Jedi. Both are worth at least checking out.
Python is a dynamic, strongly typed language. This is an interesting combination that is sometimes obscured by the fact that types themselves often do not appear in the code. Since Python 3.5, type hints have been maid to provide developers ways to declare types and for tools to optionally use them during static analysis. It is often improved by each minor release so it is expected to stay and grow in usage in the future.
The only specific typing tool that comes to my mind is Mypy, a static type checker that now works using those type hints. Other tools may do some kind of type checking using more or less complex introspection, with or without using type hints: as of today, the majority of Python code produced still does not use type annotations or at least not everywhere (I don't have stats to back this up though, this is just from browsing code bases experience).
Linters are static analysis tools that can produce a variety of different types of diagnotics: syntax errors, missing imports, unused variables, performance issues, code style issues, deprecation warnings, etc. Even though the common premise for most of these tools is that diagnotics are expected to be produced each time a file is saved, an efficient linter can produce this information almost in real-time.
- Pylint is probably the most complete linter out there and provides
you a lot of different diagnostics: errors, styling, refactoring hints. Its
list of possible diagnostics is quite long so running Pylint
against a code base that has not previously used it can throw a few hundred
messages to your face. It is a bit of a pain to configure, but once done a
pylint.rccan be committed to a project for all members to comply with it and maintain consistency over the code base; there even is a code quality scoring feature if you like being judged each time you save a file.
- Pyflakes is a lighter alternative to Pylint that focuses on error diagnostics and do not analyse code style. It is a good choice for smaller teams and people who get pissed by how obnoxious Pylint can be sometimes.
- pycodestyle tells you parts of your code do not respect the famous code style conventions of PEP 8.
- Flake8 wraps Pyflakes, pycodestyle and a few other plugins together so you can benefit the best of all those plugins with limited overhead.
- pydocstyle is similar tool to pycodestyle for documentation not respecting the docstring conventions of PEP 257.
- McCabe is a complexity checker, useful for more higher-level diagnostics, e.g. algorithmic complexity and over-nested loops, which can lead to a slower program, but most importantly a harder to understand program, which is something Python actively fight against. McCabe is embedded in Flake8.
I have a personal preference for Pyflakes for its speed and simplicity while providing useful diagnostics. I also try to respect the PEP 8 (most of the time).
Formatters are also static analysis tools that reformat parts of your code so it complies with a configuration, whether it's a project-shared convention or a public convention. They are often called right when a file is saved to automatically format it, or in your VCS hooks before a commit/push.
- autopep8 formats your code using the output of pycodestyle, no more than that!
- YAPF is Google's formatter which is more advanced than autopep8 for reformatting, e.g. when compliance is there but the perceived code style is not as good as it may be. It lets you pick a bunch of different coding conventions, including PEP 8.
- Black is a complete Python code style convention and a tool that strictly applies it. It is meant to externalise the burden of deciding which code conventions to use within your team.
- Isort focuses on formatting your imports. It is not attached to a particular PEP and let's you pick different conventions.
I tend to not use formatters as I prefer to act on style diagnostics myself, or only when the modifications are really simple and hard to argue against.
Language servers (LS) are what all the cool kids use now. The idea behind it is neat especially for language developers: instead of implementing language support for a plethora of different editors, just implement a single program, the language server, that implements the Language Server Protocol (LSP); now editors just need to implement a generic LSP client and boom, they can operate common development operations for every program when an LS is installed. Depending on the LS, this can include code completion, go to definition, rename symbol, find references and more.
As it originates from an initiative at VS Code to streamline dev tools implementation and integration, some of the most advanced LS available originate from VS Code extensions, but now there are very powerful, perfectly editor-agnostic LS for many major languages.
- The Palantir Python LS is the most commonly recommended Python LS. It is written in Python and unlike Microsoft's LS it tend to leverage different programs to provide a cohesive set of feature. It is based on Jedi but automatically integrates well with most of the tools presented above: coding tools and type checkers (Rope, Mypy), various linters (Pyflakes, McCabe, pycodestyle, pydocstyle) and formatters (YAPF, autopep8, Isort, Black). It can also respect the configurations of meta-tools such as Flake8.
- The Microsoft Python LS is the LS implementation used by the official Python extension of VS Code to provide its IDE-like environment. The extension used to base its features on Jedi, but recently this LS has been an option. It is written in C# and works quite well but I suspect its development is still tightly coupled with VS Code (not what you want for an LS) and thus a bit rougher to integrate to your system than other Python LS.
- Jedi LS, as the name might say, is an LS focused solely on supporting all Jedi features. It works as well as Jedi does and is enough for basic development needs.
That's it for now, I hope it has been useful to you. It's hard to track such a complex environment for what has become one of the most popular language worldwide, so if you feel like I missed an important tool or want to point out inaccuracies, please let me know about it.