Wily

The Zen of Python [1] emphasises complexity reduction in many ways:

Simple is better than complex.

Complex is better than complicated.

Flat is better than nested.

Wily is a command line tool for checking the complexity of Python code in tests and applications. For this purpose, Wily uses the following metrics:

Cyclomatic complexity

measures the complexity of code by the number of linearly independent paths in the control flow graph.

The Software Engineering Institute at Carnegie Mellon University distinguishes the following four levels of risk [2]:

Cyclomatic complexity

Risk assessment

1–10

Simple programme without much risk

11–20

moderate risk

21–50

complex, high-risk programme

> 50

untestable programme with very high risk

Halstead complexity measures

Statically analysing procedure that calculates the difficulty of the programme, the effort and the implementation time from the number of operators and operands.

Maintainability Index

is based on the cyclomatic complexity, the Halstead complexity measures and the number of lines of code [3]:

Index

Maintainability

0–25

unmaintainable

25–50

worrying

50–75

in need of improvement

75–100

Superhero code

Installation

Wily can be easily installed with

$ uv add wily

You can then check the installation with

$ uv run wily --help
Usage: wily [OPTIONS] COMMAND [ARGS]...
  Version: 1.19.0
  🦊 Inspect and search through the complexity of your source code. To get
  started, run setup:
    $ wily setup 

Configuration

A wily.cfg file can be created in the project directory with the list of available operators:

[wily]
# list of operators, choose from cyclomatic, maintainability, mccabe and raw
operators = cyclomatic,raw
# archiver to use, defaults to git
archiver = git
# path to analyse, defaults to .
path = /path/to/target
# max revisions to archive, defaults to 50
max_revisions = 20

Python code in .ipynb files is also usually recognised automatically. However, you may be able to disable this for a Jupyter notebook with

ipynb_support = false

or for individual cells with

ipynb_cells = false

Use

… as a command line tool

  1. Building a cache with the statistics of the project

    Note

    Wily assumes that your project folder is a Git repository. However, Wily does not create a cache if the working directory is dirty.

    $ uv run wily build
    
  2. Show metric

    $ uv run wily report
    

    This outputs both the metric and the delta to the previous revision.

  3. Show ranking

    $ uv run wily rank
    

    This shows the ranking of all files in a directory or a single file based on the specified metric, if present in .wily/.

  4. Show graph

    $ uv run wily graph
    

    This displays a graph in the default browser.

  5. Show build directory information

    $ uv run wily index
    
  6. List the metrics available in the Wily operators

    $ uv run wily list-metrics
    

… as pre-commit hook

You can also use Wily as a pre-commit framework. To do this, you would have to add the following to the pre-commit-config.yaml configuration file, for example:

repos:
-   repo: local
    hooks:
    -   id: wily
        name: wily
        entry: wily diff
        verbose: true
        language: python
        additional_dependencies: [wily]

… in a CI/CD pipeline

Usually Wily compares the complexity with the previous revision. However, you can also specify other references, for example HEAD^1 with

$ uv run wily build src/
$ uv run wily diff src/ -r HEAD^1