Measuring Python code complexity with wily

development-tools python

It is good to have some idea about our code complexity. This is especially true for large codebases and large teams where complexity can seriously slow down development and introduce bugs. Every developer probably has some opinion whether a particular code or project is complex, but what if we want to express it with some numbers? Measuring complexity metrics can help us to have some objective criteria of complexity, which can be used to compare projects between themselves, judge project changes or to simply convince someone else that the codebase is indeed complex.

There is a project called wily based on Halstead complexity measures that we can use to measure complexity in Python projects. There was a talk called Wily Python: Writing simpler and more maintainable Python by its author Anthony Shaw at this year’s Pycon Cleveland. In this talk, Anthony explains the Halstead metrics and introduces us to wily.

There are a couple of things that we can use wily for:

Let’s now try wily and use it to measure complexity of simple Flask application: Flask API Quickstart. It is worth mentioning that wily works with Git repositories, and so we need to point it to a repository, not just a folder.

First, we need to install wily from PyPi and run build command to compute the statistics for the project. In Fedora we can do it like this:

pip3 install wily --user
wily build ~/path/to/flask-api-quickstart

Now, the basic database is computed and we can use wily to generate complexity reports. We can get basic overview of the project right on the command line with report command:

# [in flask-api-quickstart]
wily report .
╒════════════╤══════════════╤════════════╤═════════════════╤═════════════════════════╤═══════════════════╤═════════════════════════╕
│ Revision   │ Author       │ Date       │ Lines of Code   │ Maintainability Index   │ Unique Operands   │ Cyclomatic Complexity   │
╞════════════╪══════════════╪════════════╪═════════════════╪═════════════════════════╪═══════════════════╪═════════════════════════╡
│ a8d5e92    │ Petr Stribny │ 2019-05-22 │ 830 (0)         │ 81.431 (0.0)            │ 18 (0)            │ 6.31579 (0.0)           │
├────────────┼──────────────┼────────────┼─────────────────┼─────────────────────────┼───────────────────┼─────────────────────────┤
│ f564377    │ Petr Stribny │ 2019-05-22 │ 830 (+12)       │ 81.431 (+1.02358)       │ 18 (0)            │ 6.31579 (-0.239766)     │
├────────────┼──────────────┼────────────┼─────────────────┼─────────────────────────┼───────────────────┼─────────────────────────┤
│ ff9d9ee    │ Petr Stribny │ 2019-05-22 │ 818 (0)         │ 80.4074 (0.0)           │ 18 (0)            │ 6.55556 (0.0)           │
├────────────┼──────────────┼────────────┼─────────────────┼─────────────────────────┼───────────────────┼─────────────────────────┤
│ 9e7f49d    │ Petr Stribny │ 2018-10-07 │ 818 (0)         │ 80.4074 (0.0)           │ 18 (0)            │ 6.55556 (0.0)           │
├────────────┼──────────────┼────────────┼─────────────────┼─────────────────────────┼───────────────────┼─────────────────────────┤
│ 80338d3    │ Petr Stribny │ 2018-10-07 │ 818 (0)         │ 80.4074 (0.0)           │ 18 (0)            │ 6.55556 (0.0)           │
├────────────┼──────────────┼────────────┼─────────────────┼─────────────────────────┼───────────────────┼─────────────────────────┤
│ b636f0e    │ Petr Stribny │ 2018-10-06 │ 818 (0)         │ 80.4074 (0.0)           │ 18 (0)            │ 6.55556 (0.0)           │
├────────────┼──────────────┼────────────┼─────────────────┼─────────────────────────┼───────────────────┼─────────────────────────┤
│ 6cd91c4    │ Petr Stribny │ 2018-10-06 │ 818 (0)         │ 80.4074 (0)             │ 18 (0)            │ 6.55556 (0)             │
╘════════════╧══════════════╧════════════╧═════════════════╧═════════════════════════╧═══════════════════╧═════════════════════════╛

As we can see, wily produced a table showing git revisions with associated author and date, and added complexity metrics lines of code, maintainability index, unique operands and cyclomatic complexity to each revision. The nice thing about this table is that it shows the increase or decrease of any measurement for every revision. For instance, we can quickly see that I committed the whole project in the first commit and then only made small changes, based on lines of code metric. The only downside of this (and any other) report produced by wily is that it is only for Python code. So what we don’t see here are any other changes happening in the project–something to keep in mind while using wily.

I produced this report for the whole project, but changing the path to a specific file allows us to investigate single files as well.

There are also other metrics that we can get from wily. Running a special command list-metrics will reveal all available metrics, divided in groups:

All of the metrics have a code (displayed when we run list-metrics) which can be used in commands to choose what metrics will be included in the reports. As an example, let’s say we want to get number of comment lines together with all lines of code:

wily report . single_comments comments loc
╒════════════╤══════════════╤════════════╤════════════════════════╤═══════════════════════╤═════════════════╕
│ Revision   │ Author       │ Date       │ Single comment lines   │ Multi-line comments   │ Lines of Code   │
╞════════════╪══════════════╪════════════╪════════════════════════╪═══════════════════════╪═════════════════╡
│ a8d5e92    │ Petr Stribny │ 2019-05-22 │ 29 (0)                 │ 20 (0)                │ 830 (0)         │
├────────────┼──────────────┼────────────┼────────────────────────┼───────────────────────┼─────────────────┤
│ f564377    │ Petr Stribny │ 2019-05-22 │ 29 (0)                 │ 20 (0)                │ 830 (+12)       │
├────────────┼──────────────┼────────────┼────────────────────────┼───────────────────────┼─────────────────┤
│ ff9d9ee    │ Petr Stribny │ 2019-05-22 │ 29 (0)                 │ 20 (0)                │ 818 (0)         │
├────────────┼──────────────┼────────────┼────────────────────────┼───────────────────────┼─────────────────┤
│ 9e7f49d    │ Petr Stribny │ 2018-10-07 │ 29 (0)                 │ 20 (0)                │ 818 (0)         │
├────────────┼──────────────┼────────────┼────────────────────────┼───────────────────────┼─────────────────┤
│ 80338d3    │ Petr Stribny │ 2018-10-07 │ 29 (0)                 │ 20 (0)                │ 818 (0)         │
├────────────┼──────────────┼────────────┼────────────────────────┼───────────────────────┼─────────────────┤
│ b636f0e    │ Petr Stribny │ 2018-10-06 │ 29 (0)                 │ 20 (0)                │ 818 (0)         │
├────────────┼──────────────┼────────────┼────────────────────────┼───────────────────────┼─────────────────┤
│ 6cd91c4    │ Petr Stribny │ 2018-10-06 │ 29 (0)                 │ 20 (0)                │ 818 (0)         │
╘════════════╧══════════════╧════════════╧════════════════════════╧═══════════════════════╧═════════════════╛

There is also another way to look at the data: charts. Wily can generate HTML charts on its own based on all the available metrics. To generate a chart, we can just replace report command with graph. It will automatically open a web browser and display the generated chart in a new window.

Overall I think that wily is a neat tool to quickly examine a Python project on a variety of complexity metrics. Of course, analyzing those metrics and draw conclusions about a given codebase is another, more difficult topic.

If you want to learn more about wily, head to wily documentation or the wily github repository.

Last updated on 22.5.2019.