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.
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|.
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
via Git or Mercurial
In both cases, they call their respective
hook functions which create
instances of |Application|.
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.
: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
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.
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).
Finally, if the user has asked to see benchmarks (i.e., :option:`flake8 --benchmark`) then we print the benchmarks.
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.