From 1b91c8d66ab6f15c2b5946c5ceba9fe907a3976e Mon Sep 17 00:00:00 2001 From: Ian Cordasco Date: Sun, 21 Feb 2016 11:12:56 -0600 Subject: [PATCH] Start working on the code that runs checks --- flake8/checker.py | 100 ++++++++++++++++++++++++++++++++++++++++++++++ flake8/utils.py | 26 ++++++++++++ 2 files changed, 126 insertions(+) create mode 100644 flake8/checker.py diff --git a/flake8/checker.py b/flake8/checker.py new file mode 100644 index 0000000..2883555 --- /dev/null +++ b/flake8/checker.py @@ -0,0 +1,100 @@ +"""Checker Manager and Checker classes.""" +import logging + +LOG = logging.getLogger(__name__) + +try: + import multiprocessing +except ImportError: + multiprocessing = None + +from flake8 import utils + + +class Manager(object): + """Manage the parallelism and checker instances for each plugin and file. + + This class will be responsible for the following: + + - Determining the parallelism of Flake8, e.g.: + + * Do we use :mod:`multiprocessing` or is it unavailable? + + * Do we automatically decide on the number of jobs to use or did the + user provide that? + + - Falling back to a serial way of processing files if we run into an + OSError related to :mod:`multiprocessing` + + - Organizing the results of each checker so we can group the output + together and make our output deterministic. + """ + + def __init__(self, options, arguments, checker_plugins): + """Initialize our Manager instance. + + :param options: + The options parsed from config files and CLI. + :type options: + optparse.Values + :param list arguments: + The extra arguments parsed from the CLI (if any) + :param checker_plugins: + The plugins representing checks parsed from entry-points. + :type checker_plugins: + flake8.plugins.manager.Checkers + """ + self.arguments = arguments + self.options = options + self.checks = checker_plugins + self.jobs = self._job_count() + + def _job_count(self): + # First we walk through all of our error cases: + # - multiprocessing library is not present + # - we're running on windows in which case we know we have significant + # implemenation issues + # - the user provided stdin and that's not something we can handle + # well + # - we're processing a diff, which again does not work well with + # multiprocessing and which really shouldn't require multiprocessing + # - the user provided some awful input + if not multiprocessing: + LOG.warning('The multiprocessing module is not available. ' + 'Ignoring --jobs arguments.') + return None + + if utils.is_windows(): + LOG.warning('The --jobs option is not available on Windows. ' + 'Ignoring --jobs arguments.') + return None + + if utils.is_using_stdin(self.arguments): + LOG.warning('The --jobs option is not compatible with supplying ' + 'input using - . Ignoring --jobs arguments.') + return None + + if self.options.diff: + LOG.warning('The --diff option was specified with --jobs but ' + 'they are not compatible. Ignoring --jobs arguments.') + return None + + jobs = self.options.jobs + if jobs != 'auto' and not jobs.isdigit(): + LOG.warning('"%s" is not a valid parameter to --jobs. Must be one ' + 'of "auto" or a numerical value, e.g., 4.', jobs) + return None + + # If the value is "auto", we want to let the multiprocessing library + # decide the number based on the number of CPUs. However, if that + # function is not implemented for this particular value of Python we + # default to 1 + if jobs == 'auto': + try: + return multiprocessing.cpu_count() + except NotImplementedError: + return 1 + + # Otherwise, we know jobs should be an integer and we can just convert + # it to an integer + return int(jobs) diff --git a/flake8/utils.py b/flake8/utils.py index 1165470..e642d26 100644 --- a/flake8/utils.py +++ b/flake8/utils.py @@ -63,3 +63,29 @@ def stdin_get_value(): cached_type = io.StringIO stdin_get_value.cached_stdin = cached_type(stdin_value) return cached_value.getvalue() + + +def is_windows(): + # type: () -> bool + """Determine if we're running on Windows. + + :returns: + True if running on Windows, otherwise False + :rtype: + bool + """ + return os.name == 'nt' + + +def is_using_stdin(paths): + # type: (List[str]) -> bool + """Determine if we're going to read from stdin. + + :param list paths: + The paths that we're going to check. + :returns: + True if stdin (-) is in the path, otherwise False + :rtype: + bool + """ + return '-' in paths