diff options
Diffstat (limited to 'old/flake8/engine.py')
| -rw-r--r-- | old/flake8/engine.py | 316 |
1 files changed, 316 insertions, 0 deletions
diff --git a/old/flake8/engine.py b/old/flake8/engine.py new file mode 100644 index 0000000..816f1ee --- /dev/null +++ b/old/flake8/engine.py @@ -0,0 +1,316 @@ +# -*- coding: utf-8 -*- +import errno +import io +import platform +import re +import sys +import warnings + +import pep8 + +from flake8 import __version__ +from flake8 import callbacks +from flake8.reporter import (multiprocessing, BaseQReport, FileQReport, + QueueReport) +from flake8 import util + +_flake8_noqa = re.compile(r'\s*# flake8[:=]\s*noqa', re.I).search + +EXTRA_EXCLUDE = ['.tox', '.eggs', '*.egg'] + +pep8.PROJECT_CONFIG += ('.flake8',) + + +def _load_entry_point(entry_point, verify_requirements): + """Based on the version of setuptools load an entry-point correctly. + + setuptools 11.3 deprecated `require=False` in the call to EntryPoint.load. + To load entry points correctly after that without requiring all + dependencies be present, the proper way is to call EntryPoint.resolve. + + This function will provide backwards compatibility for older versions of + setuptools while also ensuring we do the right thing for the future. + """ + if hasattr(entry_point, 'resolve') and hasattr(entry_point, 'require'): + if verify_requirements: + entry_point.require() + plugin = entry_point.resolve() + else: + plugin = entry_point.load(require=verify_requirements) + + return plugin + + +def _register_extensions(): + """Register all the extensions.""" + extensions = util.OrderedSet() + extensions.add(('pep8', pep8.__version__)) + parser_hooks = [] + options_hooks = [] + ignored_hooks = [] + try: + from pkg_resources import iter_entry_points + except ImportError: + pass + else: + for entry in iter_entry_points('flake8.extension'): + # Do not verify that the requirements versions are valid + checker = _load_entry_point(entry, verify_requirements=False) + pep8.register_check(checker, codes=[entry.name]) + extensions.add((checker.name, checker.version)) + if hasattr(checker, 'add_options'): + parser_hooks.append(checker.add_options) + if hasattr(checker, 'parse_options'): + options_hooks.append(checker.parse_options) + if getattr(checker, 'off_by_default', False) is True: + ignored_hooks.append(entry.name) + return extensions, parser_hooks, options_hooks, ignored_hooks + + +def get_parser(): + """This returns an instance of optparse.OptionParser with all the + extensions registered and options set. This wraps ``pep8.get_parser``. + """ + (extensions, parser_hooks, options_hooks, ignored) = _register_extensions() + details = ', '.join('%s: %s' % ext for ext in extensions) + python_version = get_python_version() + parser = pep8.get_parser('flake8', '%s (%s) %s' % ( + __version__, details, python_version + )) + for opt in ('--repeat', '--testsuite', '--doctest'): + try: + parser.remove_option(opt) + except ValueError: + pass + + if multiprocessing: + parser.config_options.append('jobs') + parser.add_option('-j', '--jobs', type='string', default='auto', + help="number of jobs to run simultaneously, " + "or 'auto'. This is ignored on Windows.") + + parser.add_option('--exit-zero', action='store_true', + help="exit with code 0 even if there are errors") + for parser_hook in parser_hooks: + parser_hook(parser) + # See comment above regarding why this has to be a callback. + parser.add_option('--install-hook', default=False, dest='install_hook', + help='Install the appropriate hook for this ' + 'repository.', action='callback', + callback=callbacks.install_vcs_hook) + parser.add_option('--output-file', default=None, + help='Redirect report to a file.', + type='string', nargs=1, action='callback', + callback=callbacks.redirect_stdout) + parser.add_option('--enable-extensions', default='', + dest='enable_extensions', + help='Enable plugins and extensions that are disabled ' + 'by default', + type='string') + parser.config_options.extend(['output-file', 'enable-extensions']) + parser.ignored_extensions = ignored + return parser, options_hooks + + +class NoQAStyleGuide(pep8.StyleGuide): + + def input_file(self, filename, lines=None, expected=None, line_offset=0): + """Run all checks on a Python source file.""" + if self.options.verbose: + print('checking %s' % filename) + fchecker = self.checker_class( + filename, lines=lines, options=self.options) + # Any "flake8: noqa" comments to ignore the entire file? + if any(_flake8_noqa(line) for line in fchecker.lines): + return 0 + return fchecker.check_all(expected=expected, line_offset=line_offset) + + +class StyleGuide(object): + """A wrapper StyleGuide object for Flake8 usage. + + This allows for OSErrors to be caught in the styleguide and special logic + to be used to handle those errors. + """ + + # Reasoning for error numbers is in-line below + serial_retry_errors = set([ + # ENOSPC: Added by sigmavirus24 + # > On some operating systems (OSX), multiprocessing may cause an + # > ENOSPC error while trying to trying to create a Semaphore. + # > In those cases, we should replace the customized Queue Report + # > class with pep8's StandardReport class to ensure users don't run + # > into this problem. + # > (See also: https://gitlab.com/pycqa/flake8/issues/74) + errno.ENOSPC, + # NOTE(sigmavirus24): When adding to this list, include the reasoning + # on the lines before the error code and always append your error + # code. Further, please always add a trailing `,` to reduce the visual + # noise in diffs. + ]) + + def __init__(self, **kwargs): + # This allows us to inject a mocked StyleGuide in the tests. + self._styleguide = kwargs.pop('styleguide', NoQAStyleGuide(**kwargs)) + + @property + def options(self): + return self._styleguide.options + + @property + def paths(self): + return self._styleguide.paths + + def _retry_serial(self, func, *args, **kwargs): + """This will retry the passed function in serial if necessary. + + In the event that we encounter an OSError with an errno in + :attr:`serial_retry_errors`, this function will retry this function + using pep8's default Report class which operates in serial. + """ + try: + return func(*args, **kwargs) + except OSError as oserr: + if oserr.errno in self.serial_retry_errors: + self.init_report(pep8.StandardReport) + else: + raise + return func(*args, **kwargs) + + def check_files(self, paths=None): + return self._retry_serial(self._styleguide.check_files, paths=paths) + + def excluded(self, filename, parent=None): + return self._styleguide.excluded(filename, parent=parent) + + def init_report(self, reporter=None): + return self._styleguide.init_report(reporter) + + def input_file(self, filename, lines=None, expected=None, line_offset=0): + return self._retry_serial( + self._styleguide.input_file, + filename=filename, + lines=lines, + expected=expected, + line_offset=line_offset, + ) + + +def _parse_multi_options(options, split_token=','): + r"""Split and strip and discard empties. + + Turns the following: + + A, + B, + + into ["A", "B"]. + + Credit: Kristian Glass as contributed to pep8 + """ + if options: + return [o.strip() for o in options.split(split_token) if o.strip()] + else: + return options + + +def _disable_extensions(parser, options): + ignored_extensions = set(getattr(parser, 'ignored_extensions', [])) + enabled = set(_parse_multi_options(options.enable_extensions)) + + # Remove any of the selected extensions from the extensions ignored by + # default. + ignored_extensions -= enabled + + # Whatever is left afterwards should be unioned with options.ignore and + # options.ignore should be updated with that. + options.ignore = tuple(ignored_extensions.union(options.ignore)) + + +def get_style_guide(**kwargs): + """Parse the options and configure the checker. This returns a sub-class + of ``pep8.StyleGuide``.""" + kwargs['parser'], options_hooks = get_parser() + styleguide = StyleGuide(**kwargs) + options = styleguide.options + _disable_extensions(kwargs['parser'], options) + + if options.exclude and not isinstance(options.exclude, list): + options.exclude = pep8.normalize_paths(options.exclude) + elif not options.exclude: + options.exclude = [] + + # Add patterns in EXTRA_EXCLUDE to the list of excluded patterns + options.exclude.extend(pep8.normalize_paths(EXTRA_EXCLUDE)) + + for options_hook in options_hooks: + options_hook(options) + + if util.warn_when_using_jobs(options): + if not multiprocessing: + warnings.warn("The multiprocessing module is not available. " + "Ignoring --jobs arguments.") + if util.is_windows(): + warnings.warn("The --jobs option is not available on Windows. " + "Ignoring --jobs arguments.") + if util.is_using_stdin(styleguide.paths): + warnings.warn("The --jobs option is not compatible with supplying " + "input using - . Ignoring --jobs arguments.") + if options.diff: + warnings.warn("The --diff option was specified with --jobs but " + "they are not compatible. Ignoring --jobs arguments." + ) + + if options.diff: + options.jobs = None + + force_disable_jobs = util.force_disable_jobs(styleguide) + + if multiprocessing and options.jobs and not force_disable_jobs: + if options.jobs.isdigit(): + n_jobs = int(options.jobs) + else: + try: + n_jobs = multiprocessing.cpu_count() + except NotImplementedError: + n_jobs = 1 + if n_jobs > 1: + options.jobs = n_jobs + reporter = QueueReport + if options.quiet: + reporter = BaseQReport + if options.quiet == 1: + reporter = FileQReport + report = styleguide.init_report(reporter) + report.input_file = styleguide.input_file + styleguide.runner = report.task_queue.put + + return styleguide + + +def get_python_version(): + # The implementation isn't all that important. + try: + impl = platform.python_implementation() + " " + except AttributeError: # Python 2.5 + impl = '' + return '%s%s on %s' % (impl, platform.python_version(), platform.system()) + + +def make_stdin_get_value(original): + def stdin_get_value(): + if not hasattr(stdin_get_value, 'cached_stdin'): + value = original() + if sys.version_info < (3, 0): + stdin = io.BytesIO(value) + else: + stdin = io.StringIO(value) + stdin_get_value.cached_stdin = stdin + else: + stdin = stdin_get_value.cached_stdin + return stdin.getvalue() + + return stdin_get_value + + +pep8.stdin_get_value = make_stdin_get_value(pep8.stdin_get_value) |
