Permalink
Find file Copy path
Fetching contributors…
Cannot retrieve contributors at this time
131 lines (93 sloc) 4.49 KB

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:

.. prompt:: bash

    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 :file:`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:

.. prompt:: bash

    python -m flake8

Then you're relying on Python to find :mod:`flake8.__main__` and run that. In both cases, however, you end up in :func:`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 :meth:`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 :meth:`~flake8.main.application.Application.run` which in turn calls:

Our Git hook, however, runs these individually.

Application Initialization

:meth:`~flake8.main.application.Application.initialize` loads all of our :term:`plugin`s, registers the options for those plugins, parses the command-line arguments, makes our formatter (as selected by the user), makes our :class:`~flake8.style_guide.StyleGuide` and finally makes our :class:`file checker manager <flake8.checker.Manager>`.

Running Our Checks

:meth:`~flake8.main.application.Application.run_checks` then creates an instance of :class:`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 :mod:`multiprocessing` and :option:`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 :term:`violation`s 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 :class:`~flake8.style_guide.StyleGuide`. This relies on a :class:`~flake8.style_guide.DecisionEngine` instance to determine whether the particular :term:`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., :option:`flake8 --benchmark`) then we print the benchmarks.

Exiting

Once :meth:`~flake8.main.application.Application.run` has finished, we then call :meth:`~flake8.main.application.Application.exit` which looks at how many errors were reported and whether the user specified :option:`flake8 --exit-zero` and exits with the appropriate exit code.