What Happens When You Run Flake8

Given Flake8 3.0’s new organization and structure, it might be a bit much for some people to understand what happens from when you call flake8 on the command-line to when it completes. This section aims to give you something of a technical overview of what exactly happens.

Invocation

The exact way that we end up in our main function for Flake8 depends on how you invoke it. If you do something like:

flake8

Then your shell looks up where flake8 the executable lives and executes it. In almost every case, this is a tiny python script generated by setuptools using the console script entry points that Flake8 declares in its setup.py. This might look something like:

#!/path/to/python<version>
# EASY-INSTALL-ENTRY-SCRIPT: 'flake8==3.0.0','console_scripts','flake8'
__requires__ = 'flake8==3.0.0'
import sys
from pkg_resources import load_entry_point

if __name__ == '__main__':
    sys.exit(
        load_entry_point('flake8==3.0.0', 'console_scripts', 'flake8')()
    )

If instead you invoke it like:

python -m flake8

Then you’re relying on Python to find flake8.__main__ and run that. In both cases, however, you end up in flake8.main.cli.main(). This is the primary way that users will end up starting Flake8. This function creates an instance of Application.

via Setuptools

If you’re invoking Flake8 from your setup.py then you actually end up in flake8.main.setuptools_command.Flake8.run(). This then collects the files that are included in the package information and creates an instance of Application.

via Git or Mercurial

In both cases, they call their respective hook functions which create instances of Application.

Application Logic

When we create our Application instance, we record the start time and parse our command-line arguments so we can configure the verbosity of Flake8’s logging. For the most part, every path then calls run() which in turn calls:

Our Git hook, however, runs these individually.

Application Initialization

initialize() loads all of our plugins, registers the options for those plugins, parses the command-line arguments, makes our formatter (as selected by the user), makes our StyleGuide and finally makes our file checker manager.

Running Our Checks

run_checks() then creates an instance of flake8.checker.FileChecker for each file to be checked after aggregating all of the files that are not excluded and match the provided file-patterns. Then, if we’re on a system that supports multiprocessing and flake8 --jobs is either auto or a number greater than 1, we will begin processing the files in subprocesses. Otherwise, we’ll run the checks in parallel.

After we start running the checks, we start aggregating the reported violations in the main process. After the checks are done running, we record the end time.

Reporting Violations

Next, the application takes the violations from the file checker manager, and feeds them through the StyleGuide. This relies on a DecisionEngine instance to determine whether the particular error code is selected or ignored and then appropriately sends it to the formatter (or not).

Reporting Benchmarks

Finally, if the user has asked to see benchmarks (i.e., flake8 --benchmark) then we print the benchmarks.

Exiting

Once run() has finished, we then call exit() which looks at how many errors were reported and whether the user specified flake8 --exit-zero and exits with the appropriate exit code.